Node.js + Flowbite로 웹페이지 디자인 꾸미기

2025. 9. 15. 22:37·뒤죽박죽코딩 리뷰/Node.js
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
'뒤죽박죽코딩 리뷰/Node.js' 카테고리의 다른 글
  • Node.js 로그인 화면에 Flowbite 디자인 적용하기
  • Node.js 환경에서 세션과 쿠키로 로그인 기능 구현하기
  • Node.js + EJS + PostgreSQL 환경에서 DB 데이터로 동적 웹페이지 만들기
  • Node.js EJS 템플릿으로 동적 웹페이지 만들기
aboutRV
aboutRV
지식이 샘솟고 지혜가 쌓이는 공간, "어바웃리뷰"입니다. 코딩과 과학, 문학과 철학, 세상의 흐름까지 다양한 주제를 깊이 있고 쉽게 리뷰합니다. 읽는 이의 생각이 자라며 통찰이 쌓이는 "어바웃리뷰"에 당신을 초대합니다.
  • aboutRV
    어바웃리뷰
    aboutRV
  • 전체
    오늘
    어제
    • 분류 전체보기 (121)
      • 뒤죽박죽코딩 리뷰 (16)
        • Node.js (16)
      • 세계문학 리뷰 (105)
        • 한국문학 (22)
        • 러시아문학 (9)
        • 영미문학 (39)
        • 유럽대륙문학 (22)
        • 세계·기타문학 (7)
        • 문학 인사이트 (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • About
    • Contact
    • Privacy Policy
  • 최근 글

  • 인기 글

  • 태그

    독일문학
    한국문학
    프랑스문학
    이대한
    뒤죽박죽코딩
    항성
    데프콘
    고딕소설
    취미는과학
    장홍제
    세계문학전집
    러시아문학
    오헨리
    호밀밭의파수꾼
    정원기의삼국지인물열전
    웹서버
    영국문학
    node.js
    미국문학
    삼국지
  • 최근 댓글

  • 반응형
  • hELLO· Designed By정상우.v4.10.3
aboutRV
Node.js + Flowbite로 웹페이지 디자인 꾸미기
상단으로

티스토리툴바