Files
hanarang-dashboard/.plans/design/references/03-sisters.html
harang-ai 5e6c7085d3 📐 디자인 v2: 전체 리디자인 + 모바일 반응형 설계
- DESIGN-SYSTEM.md: 색상/타이포/컴포넌트/반응형 규칙
- 6개 페이지 디자인 문서 재작성 (대시/프로젝트/자매/설정/활동로그/조직도)
- 관리자 페이지 디자인 가이드
- 원본 HTML 참조 파일 6개
- glassmorphism → 미니멀 터미널 UI
- 모바일 breakpoint: 768px/767px
2026-04-04 12:47:15 +09:00

473 lines
18 KiB
HTML

The code below contains a design. This design should be used to create a new app or be added to an existing one.
Look at the current open project to determine if a project exists. If no project is open, create a new Vite project then create this view in React after componentizing it.
If a project does exist, determine the framework being used and implement the design within that framework. Identify whether reusable components already exist that can be used to implement the design faithfully and if so use them, otherwise create new components. If other views already exist in the project, make sure to place the view in a sensible route and connect it to the other views.
Ensure the visual characteristics, layout, and interactions in the design are preserved with perfect fidelity.
Run the dev command so the user can see the app once finished.
```
<html lang="ko" vid="0"><head vid="1">
<meta charset="UTF-8" vid="2">
<meta name="viewport" content="width=device-width, initial-scale=1.0" vid="3">
<title vid="4">하나랑 - 자매 노드 관리</title>
<style vid="5">
:root {
--bg-main: #151515;
--bg-surface: #151515;
--text-primary: #F5F5F5;
--text-secondary: #8A8A8A;
--border-color: #333333;
--accent-hover: #FFFFFF;
--font-sans: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 40px;
--space-xxl: 64px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-sans);
background-color: var(--bg-main);
color: var(--text-primary);
line-height: 1.5;
font-size: 14px;
-webkit-font-smoothing: antialiased;
display: flex;
min-height: 100vh;
overflow-x: hidden;
}
.label-meta {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-primary);
}
.label-meta span {
color: var(--text-secondary);
margin-right: var(--space-sm);
}
.app-container {
display: flex;
width: 100%;
max-width: 1600px;
margin: 0 auto;
}
.sidebar {
width: 240px;
flex-shrink: 0;
border-right: 1px solid var(--border-color);
display: flex;
flex-direction: column;
padding: var(--space-xl) var(--space-lg);
position: sticky;
top: 0;
height: 100vh;
}
.logo-container {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: var(--space-xxl);
}
.logo-circle-full {
width: 20px;
height: 20px;
background-color: var(--text-primary);
border-radius: 50%;
}
.logo-circle-half {
width: 10px;
height: 20px;
background-color: var(--text-primary);
border-radius: 0 20px 20px 0;
}
.nav-menu {
list-style: none;
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.nav-link {
color: var(--text-secondary);
text-decoration: none;
font-size: 14px;
font-weight: 500;
padding: var(--space-sm) 0;
transition: color 0.2s ease;
display: block;
width: 100%;
}
.nav-link:hover, .nav-link.active {
color: var(--accent-hover);
}
.nav-link.active::before {
content: "[";
margin-right: 4px;
color: var(--text-secondary);
}
.nav-link.active::after {
content: "]";
margin-left: 4px;
color: var(--text-secondary);
}
.main-content {
flex-grow: 1;
padding: var(--space-xl) var(--space-xxl);
display: flex;
flex-direction: column;
gap: var(--space-xl);
}
.page-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
border-bottom: 1px solid var(--border-color);
padding-bottom: var(--space-md);
}
.page-title {
font-size: 28px;
font-weight: 600;
letter-spacing: -0.02em;
}
.node-grid {
display: flex;
flex-direction: column;
gap: var(--space-xl);
}
.node-entry {
display: grid;
grid-template-columns: 240px 1fr 300px;
gap: var(--space-xxl);
border-bottom: 1px solid var(--border-color);
padding-bottom: var(--space-xl);
}
.node-info {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.node-name {
font-size: 20px;
font-weight: 600;
display: flex;
align-items: center;
gap: var(--space-sm);
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #555;
}
.status-indicator.active {
background-color: #FFF;
box-shadow: 0 0 8px rgba(255,255,255,0.3);
}
.node-controls {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.btn-toggle {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-primary);
padding: 8px 12px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
cursor: pointer;
text-align: left;
width: fit-content;
transition: all 0.2s;
}
.btn-toggle:hover {
border-color: #666;
background: #1a1a1a;
}
.btn-toggle.active {
background: var(--text-primary);
color: var(--bg-main);
}
.capacity-section {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.graph-container {
height: 60px;
display: flex;
align-items: flex-end;
gap: 2px;
border-left: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
padding-left: 4px;
}
.graph-bar {
flex: 1;
background-color: #333;
transition: height 0.3s;
}
.graph-bar.highlight {
background-color: var(--text-primary);
}
.sync-history {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.sync-row {
display: flex;
justify-content: space-between;
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-secondary);
border-bottom: 1px solid #222;
padding-bottom: 4px;
}
.sync-row span:last-child {
color: var(--text-primary);
}
.meta-pair {
display: flex;
flex-direction: column;
gap: 2px;
}
.meta-pair .val {
font-size: 16px;
font-family: var(--font-mono);
}
</style>
</head>
<body vid="6">
<div class="app-container" vid="7">
<aside class="sidebar" vid="8">
<div class="logo-container" vid="9">
<div class="logo-circle-full" vid="10"></div>
<div class="logo-circle-half" vid="11"></div>
</div>
<nav vid="12">
<ul class="nav-menu" vid="13">
<li class="nav-item" vid="14"><a href="#" class="nav-link" vid="15">대시</a></li>
<li class="nav-item" vid="16"><a href="#" class="nav-link" vid="17">프로</a></li>
<li class="nav-item" vid="18"><a href="#" class="nav-link active" vid="19">자매</a></li>
<li class="nav-item" vid="20"><a href="#" class="nav-link" vid="21">조직</a></li>
<li class="nav-item" vid="22"><a href="#" class="nav-link" vid="23">설정</a></li>
<li class="nav-item" vid="24"><a href="#" class="nav-link" vid="25">관리</a></li>
</ul>
</nav>
</aside>
<main class="main-content" vid="26">
<header class="page-header" vid="27">
<h1 class="page-title" vid="28">자매 노드 관리</h1>
<div class="label-meta" vid="29"><span vid="30">TOTAL NODES:</span> 04</div>
</header>
<section class="node-grid" vid="31">
<div class="node-entry" vid="32">
<div class="node-info" vid="33">
<div class="node-name" vid="34">
<div class="status-indicator active" vid="35"></div>
하랑 (Primary)
</div>
<div class="meta-pair" vid="36">
<div class="label-meta" vid="37">Uptime</div>
<div class="val" vid="38">342:12:05</div>
</div>
<div class="node-controls" vid="39">
<button class="btn-toggle active" vid="40">ACTIVE</button>
<button class="btn-toggle" vid="41">REBOOT</button>
</div>
</div>
<div class="capacity-section" vid="42">
<div class="label-meta" vid="43">CAPACITY HISTORY (24H)</div>
<div class="graph-container" vid="44">
<div class="graph-bar" style="height: 40%" vid="45"></div>
<div class="graph-bar" style="height: 45%" vid="46"></div>
<div class="graph-bar" style="height: 60%" vid="47"></div>
<div class="graph-bar" style="height: 55%" vid="48"></div>
<div class="graph-bar" style="height: 70%" vid="49"></div>
<div class="graph-bar" style="height: 85%" vid="50"></div>
<div class="graph-bar highlight" style="height: 92%" vid="51"></div>
<div class="graph-bar highlight" style="height: 84%" vid="52"></div>
</div>
<div class="sync-row" vid="53"><span vid="54">LOAD INDEX</span><span vid="55">84.2%</span></div>
</div>
<div class="sync-history" vid="56">
<div class="label-meta" vid="57">SYNC LOG</div>
<div class="sync-row" vid="58"><span vid="59">14:05:22</span><span vid="60">SUCCESS</span></div>
<div class="sync-row" vid="61"><span vid="62">13:55:01</span><span vid="63">SUCCESS</span></div>
<div class="sync-row" vid="64"><span vid="65">13:44:10</span><span vid="66">SUCCESS</span></div>
</div>
</div>
<div class="node-entry" vid="67">
<div class="node-info" vid="68">
<div class="node-name" vid="69">
<div class="status-indicator active" vid="70"></div>
나랑 (Secondary)
</div>
<div class="meta-pair" vid="71">
<div class="label-meta" vid="72">Uptime</div>
<div class="val" vid="73">112:44:21</div>
</div>
<div class="node-controls" vid="74">
<button class="btn-toggle active" vid="75">ACTIVE</button>
<button class="btn-toggle" vid="76">REBOOT</button>
</div>
</div>
<div class="capacity-section" vid="77">
<div class="label-meta" vid="78">CAPACITY HISTORY (24H)</div>
<div class="graph-container" vid="79">
<div class="graph-bar" style="height: 30%" vid="80"></div>
<div class="graph-bar" style="height: 32%" vid="81"></div>
<div class="graph-bar" style="height: 35%" vid="82"></div>
<div class="graph-bar" style="height: 40%" vid="83"></div>
<div class="graph-bar" style="height: 38%" vid="84"></div>
<div class="graph-bar" style="height: 45%" vid="85"></div>
<div class="graph-bar highlight" style="height: 50%" vid="86"></div>
<div class="graph-bar highlight" style="height: 48%" vid="87"></div>
</div>
<div class="sync-row" vid="88"><span vid="89">LOAD INDEX</span><span vid="90">48.7%</span></div>
</div>
<div class="sync-history" vid="91">
<div class="label-meta" vid="92">SYNC LOG</div>
<div class="sync-row" vid="93"><span vid="94">14:02:11</span><span vid="95">SUCCESS</span></div>
<div class="sync-row" vid="96"><span vid="97">13:51:44</span><span vid="98">SUCCESS</span></div>
<div class="sync-row" vid="99"><span vid="100">13:40:02</span><span vid="101">SUCCESS</span></div>
</div>
</div>
<div class="node-entry" vid="102">
<div class="node-info" vid="103">
<div class="node-name" vid="104">
<div class="status-indicator" vid="105"></div>
다랑 (Standby)
</div>
<div class="meta-pair" vid="106">
<div class="label-meta" vid="107">Last Active</div>
<div class="val" vid="108">02:15:00 ago</div>
</div>
<div class="node-controls" vid="109">
<button class="btn-toggle" vid="110">STANDBY</button>
<button class="btn-toggle" vid="111">ACTIVATE</button>
</div>
</div>
<div class="capacity-section" vid="112">
<div class="label-meta" vid="113">CAPACITY HISTORY (24H)</div>
<div class="graph-container" vid="114">
<div class="graph-bar" style="height: 10%" vid="115"></div>
<div class="graph-bar" style="height: 10%" vid="116"></div>
<div class="graph-bar" style="height: 5%" vid="117"></div>
<div class="graph-bar" style="height: 5%" vid="118"></div>
<div class="graph-bar" style="height: 5%" vid="119"></div>
<div class="graph-bar" style="height: 5%" vid="120"></div>
<div class="graph-bar" style="height: 2%" vid="121"></div>
<div class="graph-bar" style="height: 2%" vid="122"></div>
</div>
<div class="sync-row" vid="123"><span vid="124">LOAD INDEX</span><span vid="125">0.0%</span></div>
</div>
<div class="sync-history" vid="126">
<div class="label-meta" vid="127">SYNC LOG</div>
<div class="sync-row" vid="128"><span vid="129">14:00:00</span><span vid="130">IDLE</span></div>
<div class="sync-row" vid="131"><span vid="132">13:45:00</span><span vid="133">IDLE</span></div>
<div class="sync-row" vid="134"><span vid="135">13:30:00</span><span vid="136">IDLE</span></div>
</div>
</div>
<div class="node-entry" vid="137">
<div class="node-info" vid="138">
<div class="node-name" vid="139">
<div class="status-indicator active" vid="140"></div>
이랑 (Sync)
</div>
<div class="meta-pair" vid="141">
<div class="label-meta" vid="142">Queue Depth</div>
<div class="val" vid="143">12 PKTS</div>
</div>
<div class="node-controls" vid="144">
<button class="btn-toggle active" vid="145">SYNCING</button>
<button class="btn-toggle" vid="146">FLUSH</button>
</div>
</div>
<div class="capacity-section" vid="147">
<div class="label-meta" vid="148">CAPACITY HISTORY (24H)</div>
<div class="graph-container" vid="149">
<div class="graph-bar" style="height: 20%" vid="150"></div>
<div class="graph-bar" style="height: 25%" vid="151"></div>
<div class="graph-bar" style="height: 15%" vid="152"></div>
<div class="graph-bar" style="height: 30%" vid="153"></div>
<div class="graph-bar" style="height: 40%" vid="154"></div>
<div class="graph-bar" style="height: 35%" vid="155"></div>
<div class="graph-bar highlight" style="height: 20%" vid="156"></div>
<div class="graph-bar highlight" style="height: 15%" vid="157"></div>
</div>
<div class="sync-row" vid="158"><span vid="159">LOAD INDEX</span><span vid="160">15.2%</span></div>
</div>
<div class="sync-history" vid="161">
<div class="label-meta" vid="162">SYNC LOG</div>
<div class="sync-row" vid="163"><span vid="164">14:06:01</span><span vid="165">SYNCING</span></div>
<div class="sync-row" vid="166"><span vid="167">14:05:45</span><span vid="168">SYNCING</span></div>
<div class="sync-row" vid="169"><span vid="170">14:05:30</span><span vid="171">SYNCING</span></div>
</div>
</div>
</section>
</main>
</div>
</body></html>
```