feat: replace header emoji buttons with reference Lucide-style icons

Add users, plus, and dual-monitor SVG icons with matching 32px circular button styles from Design Planning Hub.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
EENE Dashboard
2026-06-06 00:19:45 +09:00
parent 64d0314873
commit 6ab2dae634
3 changed files with 164 additions and 16 deletions

View File

@@ -1,3 +1,7 @@
import { useState } from 'react';
import { isDetailWindowOpen } from '../../lib/dualMonitor';
import { DualMonitorIcon, PlusIcon, UsersIcon } from './HeaderIcons';
interface Stats { interface Stats {
total: number; total: number;
inProgress: number; inProgress: number;
@@ -15,9 +19,6 @@ interface DashboardHeaderProps {
onOpenTaskManager: () => void; onOpenTaskManager: () => void;
} }
const ICON_BTN =
'team-status-btn-new grid h-8 w-8 shrink-0 place-items-center rounded-full border-[1.5px] border-[#1a4d42] bg-[linear-gradient(180deg,#0d3f34_0%,#051f19_100%)] text-[#cef1eb] shadow-[0_0_0_1px_#000,0_2px_2px_rgba(0,0,0,0.60)] transition hover:brightness-125';
const STAT_ACCENT = { const STAT_ACCENT = {
: 'text-[#ffdb3a]', : 'text-[#ffdb3a]',
IN_PROGRESS: 'text-[#10b981]', IN_PROGRESS: 'text-[#10b981]',
@@ -34,8 +35,15 @@ export function DashboardHeader({
onOpenDetailWindow, onOpenDetailWindow,
onOpenTaskManager, onOpenTaskManager,
}: DashboardHeaderProps) { }: DashboardHeaderProps) {
const [detailViewActive, setDetailViewActive] = useState(isDetailWindowOpen);
const quarterLabel = quarter.replace(/^(\d{4})-Q(\d)$/, '$1 $2분기 업무'); const quarterLabel = quarter.replace(/^(\d{4})-Q(\d)$/, '$1 $2분기 업무');
const handleOpenDetailWindow = () => {
void Promise.resolve(onOpenDetailWindow()).then(() => {
setDetailViewActive(isDetailWindowOpen());
});
};
const statItems = [ const statItems = [
{ label: '전체', value: stats.total, statusKey: '전체' as const }, { label: '전체', value: stats.total, statusKey: '전체' as const },
{ label: '진행', value: stats.inProgress, statusKey: 'IN_PROGRESS' as const }, { label: '진행', value: stats.inProgress, statusKey: 'IN_PROGRESS' as const },
@@ -52,8 +60,8 @@ export function DashboardHeader({
<span>|</span> <span>|</span>
<span>People Growth Hub</span> <span>People Growth Hub</span>
</span> </span>
<button type="button" title="팀 현황" className={`${ICON_BTN} text-[15px]`}> <button type="button" title="팀 현황" className="team-status-btn-new">
👥 <UsersIcon size={16} />
</button> </button>
</div> </div>
@@ -78,21 +86,16 @@ export function DashboardHeader({
</div> </div>
<div className="side-right-actions shrink-0"> <div className="side-right-actions shrink-0">
<button <button type="button" onClick={onOpenTaskManager} title="신규 프로젝트 추가" className="header-action-btn-new">
type="button" <PlusIcon size={16} />
onClick={onOpenTaskManager}
title="업무관리"
className={`header-action-btn-new ${ICON_BTN} text-[18px] font-bold leading-none`}
>
+
</button> </button>
<button <button
type="button" type="button"
onClick={onOpenDetailWindow} onClick={handleOpenDetailWindow}
title="우측 모니터에 상세 창 열기" title="듀얼뷰"
className={`header-view-btn-new ${ICON_BTN} text-[16px] leading-none`} className={`header-view-btn-new ${detailViewActive ? 'active' : ''}`}
> >
🖥 <DualMonitorIcon size={16} />
</button> </button>
</div> </div>
</header> </header>

View File

@@ -0,0 +1,73 @@
import type { ReactNode } from 'react';
interface IconProps {
size?: number;
className?: string;
}
function LucideSvg({ size = 16, className, children }: IconProps & { children: ReactNode }) {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={className}
aria-hidden
>
{children}
</svg>
);
}
/** 참고 사이트 lucide `users` */
export function UsersIcon({ size = 16, className }: IconProps) {
return (
<LucideSvg size={size} className={className}>
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
<path d="M16 3.128a4 4 0 0 1 0 7.744" />
<path d="M22 21v-2a4 4 0 0 0-3-3.87" />
<circle cx="9" cy="7" r="4" />
</LucideSvg>
);
}
/** 참고 사이트 lucide `plus` */
export function PlusIcon({ size = 16, className }: IconProps) {
return (
<LucideSvg size={size} className={className}>
<path d="M5 12h14" />
<path d="M12 5v14" />
</LucideSvg>
);
}
function MonitorIcon({ size = 16, className }: IconProps) {
return (
<LucideSvg size={size} className={className}>
<rect width="20" height="14" x="2" y="3" rx="2" />
<line x1="8" x2="16" y1="21" y2="21" />
<line x1="12" x2="12" y1="17" y2="21" />
</LucideSvg>
);
}
/** 참고 사이트 `dual-monitor-icon-wrap` — monitor 2개 겹침 */
export function DualMonitorIcon({ size = 16, className }: IconProps) {
const monitorSize = size * 0.75;
return (
<div
className={`dual-monitor-icon-wrap ${className ?? ''}`}
style={{ width: size, height: size }}
aria-hidden
>
<MonitorIcon size={monitorSize} className="m-icon m-back" />
<MonitorIcon size={monitorSize} className="m-icon m-front" />
</div>
);
}

View File

@@ -115,6 +115,78 @@ body,
gap: 12px; gap: 12px;
} }
/* F12 — 헤더 원형 아이콘 버튼 (team / + / 듀얼모니터) */
.header-action-btn-new,
.header-view-btn-new,
.team-status-btn-new {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1.5px solid #1a4d42;
border-radius: 50%;
color: #cef1eb;
cursor: pointer;
background: linear-gradient(180deg, #0d3f34 0%, #051f19 100%);
box-shadow: 0 0 0 1px #000, 0 2px 2px rgba(0, 0, 0, 0.6);
transition: all 0.2s ease-in-out;
}
.header-action-btn-new svg,
.header-view-btn-new svg,
.team-status-btn-new svg {
color: inherit;
filter: none;
}
.header-action-btn-new:hover,
.header-view-btn-new:hover,
.team-status-btn-new:hover {
color: #fff;
border-color: #36816d;
background: linear-gradient(180deg, #115244 0%, #072b23 100%);
transform: translateY(-1px);
box-shadow:
0 0 0 1px #000,
0 0 8px rgba(36, 204, 158, 0.4),
0 4px 8px rgba(0, 0, 0, 0.7);
}
.header-action-btn-new:active,
.header-action-btn-new.active,
.header-view-btn-new.active,
.team-status-btn-new.active {
color: #cef1eb;
border-color: #1a4d42;
background: linear-gradient(180deg, #072b23 0%, #051f19 100%);
transform: translateY(0);
box-shadow: 0 0 0 1px #000, 0 1px 2px rgba(0, 0, 0, 0.6);
}
.dual-monitor-icon-wrap {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.dual-monitor-icon-wrap .m-icon {
position: absolute;
}
.dual-monitor-icon-wrap .m-back {
top: 0;
left: -3px;
opacity: 0.5;
}
.dual-monitor-icon-wrap .m-front {
right: -3px;
bottom: 0;
}
/* F12 Design Planning Hub — 타이틀 */ /* F12 Design Planning Hub — 타이틀 */
.main_tit { .main_tit {
color: #bad8ca; color: #bad8ca;