관리자 페이지(Admin Dashboard)는 웹 개발에서 자주 만들게 되는 실무 프로젝트입니다. Bootstrap 5와 Font Awesome 5를 활용하여 효율적으로 제작해보겠습니다.
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<button class="navbar-toggler ms-auto" type="button" data-bs-toggle="collapse" data-bs-target="#navbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
<!-- 검색창 -->
<form class="d-flex">
<input class="form-control me-2 input-animation" type="search" placeholder="Search">
<button class="btn btn-outline-secondary" type="submit">Search</button>
</form>
<!-- 우측 메뉴 -->
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link position-relative" href="#">
<span class="badge bg-danger notification-badge">5</span>
<i class="fas fa-bell"></i>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="fas fa-envelope me-1"></i>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Minny Park</a>
</li>
</ul>
</div>
</div>
</nav>
정렬 클래스:
ms-auto: margin-start auto (오른쪽 정렬)me-auto: margin-end auto (왼쪽 정렬)d-flex: display flexjustify-content-between: 양쪽 끝으로 정렬.nav-link {
position: relative;
}
.notification-badge {
position: absolute;
top: -2px;
left: 15px;
font-size: 0.7rem;
padding: 2px 6px;
border-radius: 50%;
}
.input-animation {
width: 150px;
transition: width 0.8s ease;
}
.input-animation:focus {
width: 300px;
outline: none;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
<div class="container">
<h4 class="my-4">Dashboard</h4>
<div class="row g-4">
<div class="col-lg-3 col-md-6">
<div class="summary-card earnings">
<div class="card">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<p class="card-text text-muted mb-1">Earnings (Monthly)</p>
<h4 class="fw-bold text-primary">$40,000</h4>
</div>
<div class="icon-wrapper">
<i class="fas fa-calendar fa-2x text-primary"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="summary-card revenue">
<div class="card border-left-success">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<p class="card-text text-muted mb-1">Revenue (Annual)</p>
<h4 class="fw-bold text-success">$215,000</h4>
</div>
<div class="icon-wrapper">
<i class="fas fa-dollar-sign fa-2x text-success"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="summary-card tasks">
<div class="card border-left-info">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<p class="card-text text-muted mb-1">Tasks</p>
<h4 class="fw-bold text-info">50%</h4>
</div>
<div class="icon-wrapper">
<i class="fas fa-clipboard-list fa-2x text-info"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="summary-card requests">
<div class="card border-left-warning">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<p class="card-text text-muted mb-1">Pending Requests</p>
<h4 class="fw-bold text-warning">18</h4>
</div>
<div class="icon-wrapper">
<i class="fas fa-comments fa-2x text-warning"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
.summary-card .card {
border: none;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
transition: all 0.3s ease;
}
.summary-card .card:hover {
transform: translateY(-5px);
box-shadow: 0 0.25rem 2rem 0 rgba(58, 59, 69, 0.2);
}
.border-left-success {
border-left: 4px solid #1cc88a !important;
}
.border-left-info {
border-left: 4px solid #36b9cc !important;
}
.border-left-warning {
border-left: 4px solid #f6c23e !important;
}
.icon-wrapper {
opacity: 0.7;
}
<div class="container mt-5">
<div class="row">
<!-- 차트 영역 -->
<div class="col-lg-8">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="fw-bold text-primary mb-0">Earnings Overview</h6>
<div class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
Monthly
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Daily</a></li>
<li><a class="dropdown-item" href="#">Weekly</a></li>
<li><a class="dropdown-item" href="#">Monthly</a></li>
</ul>
</div>
</div>
<div class="card-body">
<canvas id="myChart" width="400" height="200"></canvas>
</div>
</div>
</div>
<!-- 태스크 리스트 영역 -->
<div class="col-lg-4">
<div class="card">
<div class="card-header">
<h6 class="fw-bold text-primary mb-0">Tasks</h6>
</div>
<div class="card-body">
<div class="task-item">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="task1">
<label class="form-check-label" for="task1">
Design new landing page
</label>
</div>
<small class="text-muted">Due: 2024-01-15</small>
</div>
<div class="task-item">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="task2" checked>
<label class="form-check-label text-muted" for="task2">
<s>Update user documentation</s>
</label>
</div>
<small class="text-muted">Completed</small>
</div>
<div class="task-item">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="task3">
<label class="form-check-label" for="task3">
Fix mobile responsive issues
</label>
</div>
<small class="text-danger">Overdue</small>
</div>
</div>
</div>
</div>
</div>
</div>
.task-item {
padding: 12px 0;
border-bottom: 1px solid #eaecf4;
}
.task-item:last-child {
border-bottom: none;
}
.task-item .form-check-label {
font-weight: 500;
cursor: pointer;
}
.task-item small {
display: block;
margin-top: 4px;
}
<body>
<!-- 사이드바 -->
<div class="sidebar">
<div class="sidebar-header p-3">
<h5 class="text-white mb-0">
<i class="fas fa-tachometer-alt me-2"></i>
<span class="sidebar-text">Admin</span>
</h5>
</div>
<div class="sidebar-menu">
<div class="menu-item">
<i class="fas fa-home"></i>
<span class="sidebar-text">Dashboard</span>
</div>
<div class="menu-item">
<i class="fas fa-users"></i>
<span class="sidebar-text">Users</span>
</div>
<div class="menu-item">
<i class="fas fa-chart-bar"></i>
<span class="sidebar-text">Analytics</span>
</div>
<div class="menu-item">
<i class="fas fa-cog"></i>
<span class="sidebar-text">Settings</span>
</div>
</div>
</div>
<!-- 메인 컨텐츠 -->
<div class="main-content">
<!-- 여기에 네비게이션과 대시보드 내용 -->
</div>
</body>
.sidebar {
width: 200px;
height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: fixed;
left: 0;
top: 0;
z-index: 1000;
transition: all 0.5s ease;
transform: translateX(-150px);
overflow: hidden;
}
.sidebar:hover {
transform: translateX(0);
}
.sidebar-header {
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.menu-item {
padding: 15px 20px;
color: rgba(255, 255, 255, 0.8);
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.menu-item:hover {
background: rgba(255, 255, 255, 0.1);
color: white;
padding-left: 30px;
}
.menu-item i {
width: 20px;
margin-right: 15px;
transition: all 0.5s ease;
transform: translateX(120px);
}
.sidebar:hover .menu-item i {
transform: translateX(0);
}
.sidebar-text {
transition: all 0.5s ease;
opacity: 0;
transform: translateX(20px);
}
.sidebar:hover .sidebar-text {
opacity: 1;
transform: translateX(0);
}
.main-content {
margin-left: 50px;
transition: margin-left 0.5s ease;
min-height: 100vh;
background: #f8f9fc;
}
.sidebar:hover ~ .main-content {
margin-left: 200px;
}
.demo-box {
width: 100px;
height: 100px;
background: #007bff;
margin: 50px;
transition: transform 0.5s ease;
}
/* X축 회전 (가로축 중심) */
.rotate-x:hover {
transform: rotateX(180deg);
}
/* Y축 회전 (세로축 중심) */
.rotate-y:hover {
transform: rotateY(180deg);
}
/* Z축 회전 (화면 수직축 중심) */
.rotate-z:hover {
transform: rotateZ(180deg);
}
/* 복합 회전 */
.rotate-combo:hover {
transform: rotateX(45deg) rotateY(45deg) rotateZ(45deg);
}
<div class="flip-container">
<div class="flip-outer">
<div class="flip-inner">
<div class="front">
<img src="profile.jpg" alt="Profile">
</div>
<div class="back">
<div class="back-content">
<h4>개발자 김철용</h4>
<p>Frontend Developer</p>
<p>React, Vue, Angular</p>
<div class="social-links">
<a href="#"><i class="fab fa-github"></i></a>
<a href="#"><i class="fab fa-linkedin"></i></a>
<a href="#"><i class="fab fa-twitter"></i></a>
</div>
</div>
</div>
</div>
</div>
</div>
.flip-container {
perspective: 1000px;
display: inline-block;
margin: 20px;
}
.flip-outer {
width: 300px;
height: 300px;
}
.flip-inner {
width: 100%;
height: 100%;
position: relative;
transition: transform 0.8s ease;
transform-style: preserve-3d;
cursor: pointer;
}
.flip-inner:hover {
transform: rotateY(180deg);
}
.front,
.back {
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.front {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
}
.front img {
width: 80%;
height: 80%;
object-fit: cover;
border-radius: 50%;
border: 5px solid white;
}
.back {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
transform: rotateY(180deg);
display: flex;
align-items: center;
justify-content: center;
color: white;
text-align: center;
}
.back-content h4 {
font-size: 1.5rem;
margin-bottom: 10px;
font-weight: bold;
}
.back-content p {
margin-bottom: 8px;
opacity: 0.9;
}
.social-links {
margin-top: 20px;
}
.social-links a {
color: white;
font-size: 1.5rem;
margin: 0 10px;
transition: transform 0.3s ease;
}
.social-links a:hover {
transform: scale(1.2);
}
transform-style: preserve-3dbackface-visibility: hiddenperspective<div class="card-grid">
<div class="flip-container">
<div class="flip-outer">
<div class="flip-inner">
<div class="front team-card">
<img src="team1.jpg" alt="Team Member 1">
<h5>Alice Johnson</h5>
</div>
<div class="back">
<div class="back-content">
<h4>Alice Johnson</h4>
<p>UI/UX Designer</p>
<p>5년 경력</p>
<p>Figma, Sketch, Adobe XD</p>
</div>
</div>
</div>
</div>
</div>
<!-- 더 많은 카드들... -->
</div>
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
padding: 40px;
max-width: 1200px;
margin: 0 auto;
}
.team-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30px;
text-align: center;
color: white;
}
.team-card img {
width: 120px;
height: 120px;
border-radius: 50%;
margin-bottom: 20px;
border: 4px solid white;
}
.team-card h5 {
margin: 0;
font-weight: 600;
}
.card-grid:hover .flip-container:not(:hover) {
opacity: 0.7;
transform: scale(0.95);
}
.flip-container {
transition: all 0.3s ease;
}
@media (max-width: 768px) {
.sidebar {
width: 100%;
height: auto;
position: static;
transform: none;
}
.sidebar:hover {
transform: none;
}
.main-content {
margin-left: 0;
}
.flip-outer {
width: 250px;
height: 250px;
}
.card-grid {
grid-template-columns: 1fr;
padding: 20px;
}
.input-animation:focus {
width: 200px;
}
}
@media (max-width: 480px) {
.flip-outer {
width: 200px;
height: 200px;
}
.summary-card .card-body {
flex-direction: column;
text-align: center;
}
.icon-wrapper {
margin-top: 15px;
}
}
/* GPU 가속 활용 */
.flip-inner {
will-change: transform;
}
/* 애니메이션 완료 후 will-change 제거 */
.flip-inner.animation-complete {
will-change: auto;
}
<!-- 키보드 네비게이션 지원 -->
<div class="flip-inner" tabindex="0" role="button" aria-label="프로필 카드 뒤집기">
<!-- 카드 내용 -->
</div>
.flip-inner:focus {
outline: 3px solid #007bff;
outline-offset: 2px;
}
.flip-inner:focus,
.flip-inner:hover {
transform: rotateY(180deg);
}
/* 구형 브라우저 대응 */
.flip-inner {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transition: transform 0.8s ease;
-moz-transition: transform 0.8s ease;
transition: transform 0.8s ease;
}
.front,
.back {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
}
Admin Dashboard와 인상적인 3D Flip 카드를 만들어보았습니다