728x90
반응형
Flowbite UI 라이브러리를 이용해 웹페이지를 예쁘게 꾸미고, 상단 검색창 기능을 추가하는 방법을 실습합니다. 이 영상을 통해서 Node.js + Express + EJS + PostgreSQL 조합으로 DB 데이터를 출력하고, Flowbite로 웹디자인하고, 사용자가 입력한 검색어로 결과를 필터링할 수 있습니다.
영상 먼저 보고 싶은 분은 클릭
https://www.youtube.com/watch?v=u3_SopKPDxg
이 영상에서 다루는 내용
- 오픈소스 UI 라이브러리 이해하기
- Flowbite 소개 & 적용방법 두가지(NPM vs CDN)
- Flowbite를 사용하기 위한 필수코드(CDN 인클루드 방식) 설명
- Flowbite 템플릿 가져오는 방법 실습 및 DB 데이터 반복문 처리
- 검색창 검색기능 코딩(프론트엔드 EJS & 백엔드 Node.js)
Flowbite 시작하기
CDN 인클루드 방법
<!DOCTYPE html>
<html>
<head>
<title>뒤죽박죽 코딩</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
</head>
<body>
<!-- Flowbite 코드가 들어갈 영역 -->
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
</body>
Flowbite 적용하기
db.js
// Express 설정
const express = require('express');
const app = express();
// EJS 설정
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
// PG 설정
const pg = require('pg');
const dbconfig = {
host: 'localhost',
user: 'postgres',
password: '비밀번호',
database: 'postgres',
port: '5432'
};
const client = new pg.Client(dbconfig);
client.connect()
.then(() => {
console.log('PostgreSQL 연결 성공');
app.listen(3000, () => {
console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});
})
.catch(err => {
console.error('DB 연결 실패', err);
process.exit(1);
});
app.get('/market', (req, res) => {
client.query(`
SELECT id, market, korean_name, english_name
FROM markets
ORDER BY id ASC`)
.then(result => res.render('market_flowbite', { markets: result.rows }))
.catch(err => {
console.error('SELECT markets 에러', err);
res.status(500).send('DB 오류 발생: ' + err.message);
});
});
market_flowbite.ejs
<!DOCTYPE html>
<html>
<head>
<title>뒤죽박죽 코딩</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
</head>
<body>
<section class="bg-gray-50 dark:bg-gray-900 p-3 sm:p-5">
<div class="mx-auto max-w-screen-xl px-4 lg:px-12">
<!-- Start coding here -->
<div class="bg-white dark:bg-gray-800 relative shadow-md sm:rounded-lg overflow-hidden">
<div class="flex flex-col md:flex-row items-center justify-between space-y-3 md:space-y-0 md:space-x-4 p-4">
<div class="w-full md:w-1/2">
<form class="flex items-center">
<label for="simple-search" class="sr-only">Search</label>
<div class="relative w-full">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<svg aria-hidden="true" class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
</svg>
</div>
<input type="text" id="simple-search" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full pl-10 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="Search" required="">
</div>
</form>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" class="px-4 py-3">id</th>
<th scope="col" class="px-4 py-3">market</th>
<th scope="col" class="px-4 py-3">korean_name</th>
<th scope="col" class="px-4 py-3">english_name</th>
</tr>
</thead>
<tbody>
<% markets.forEach(market => { %>
<tr class="border-b dark:border-gray-700">
<td class="px-4 py-3"><%= market.id %></td>
<td class="px-4 py-3"><%= market.market %></td>
<td class="px-4 py-3"><%= market.korean_name %></td>
<td class="px-4 py-3"><%= market.english_name %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
</body>
</html>
검색창 검색기능 코딩
db.js
// Express 설정
const express = require('express');
const app = express();
// EJS 설정
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
// PG 설정
const pg = require('pg');
const dbconfig = {
host: 'localhost',
user: 'postgres',
password: '비밀번호',
database: 'postgres',
port: '5432'
};
const client = new pg.Client(dbconfig);
client.connect()
.then(() => {
console.log('PostgreSQL 연결 성공');
app.listen(3000, () => {
console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});
})
.catch(err => {
console.error('DB 연결 실패', err);
process.exit(1);
});
app.get('/market', (req, res) => {
client.query(`
SELECT id, market, korean_name, english_name
FROM markets
ORDER BY id ASC`)
.then(result => res.render('market_flowbite', { markets: result.rows }))
.catch(err => {
console.error('SELECT markets 에러', err);
res.status(500).send('DB 오류 발생: ' + err.message);
});
});
app.get('/search', (req, res) => {
const q = req.query.q;
client.query(`
SELECT id, market, korean_name, english_name
FROM markets
WHERE market ILIKE $1 OR
korean_name ILIKE $1 OR
english_name ILIKE $1
ORDER BY id ASC`, [`%${q}%`])
.then(result => res.render('market_flowbite', { markets: result.rows }))
.catch(err => {
console.error('SELECT markets 에러', err);
res.status(500).send('DB 오류 발생: ' + err.message);
});
});
market_flowbite.ejs
<!DOCTYPE html>
<html>
<head>
<title>뒤죽박죽 코딩</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
</head>
<body>
<section class="bg-gray-50 dark:bg-gray-900 p-3 sm:p-5">
<div class="mx-auto max-w-screen-xl px-4 lg:px-12">
<!-- Start coding here -->
<div class="bg-white dark:bg-gray-800 relative shadow-md sm:rounded-lg overflow-hidden">
<div class="flex flex-col md:flex-row items-center justify-between space-y-3 md:space-y-0 md:space-x-4 p-4">
<div class="w-full md:w-1/2">
<form class="flex items-center" action="/search" method="get">
<label for="simple-search" class="sr-only">Search</label>
<div class="relative w-full">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<svg aria-hidden="true" class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
</svg>
</div>
<input type="text" id="simple-search" name="q" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full pl-10 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="Search" required="">
</div>
</form>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" class="px-4 py-3">id</th>
<th scope="col" class="px-4 py-3">market</th>
<th scope="col" class="px-4 py-3">korean_name</th>
<th scope="col" class="px-4 py-3">english_name</th>
</tr>
</thead>
<tbody>
<% markets.forEach(market => { %>
<tr class="border-b dark:border-gray-700">
<td class="px-4 py-3"><%= market.id %></td>
<td class="px-4 py-3"><%= market.market %></td>
<td class="px-4 py-3"><%= market.korean_name %></td>
<td class="px-4 py-3"><%= market.english_name %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
</body>
</html>
728x90
반응형
'뒤죽박죽코딩 리뷰 > Node.js' 카테고리의 다른 글
| Node.js 로그인 화면에 Flowbite 디자인 적용하기 (0) | 2025.10.12 |
|---|---|
| Node.js 환경에서 세션과 쿠키로 로그인 기능 구현하기 (0) | 2025.09.29 |
| Node.js + EJS + PostgreSQL 환경에서 DB 데이터로 동적 웹페이지 만들기 (0) | 2025.09.06 |
| Node.js EJS 템플릿으로 동적 웹페이지 만들기 (0) | 2025.08.21 |
| Node.js와 Express로 웹서버 만들고 라우팅 실습하기 (2) | 2025.08.04 |
