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

503 lines
17 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;
-moz-osx-font-smoothing: grayscale;
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-item {
display: flex;
align-items: center;
}
.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);
min-width: 0;
}
.page-header {
margin-bottom: var(--space-md);
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.page-title {
font-size: 28px;
font-weight: 600;
letter-spacing: -0.02em;
color: var(--text-primary);
}
.section-title {
font-family: var(--font-sans);
font-size: 14px;
font-weight: 600;
border-bottom: 1px solid var(--border-color);
padding-bottom: var(--space-sm);
margin-bottom: var(--space-lg);
display: flex;
justify-content: space-between;
}
.settings-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-xxl);
}
.settings-section {
display: flex;
flex-direction: column;
}
.settings-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-md) 0;
border-bottom: 1px solid #222;
}
.settings-row:last-child {
border-bottom: none;
}
.setting-info {
display: flex;
flex-direction: column;
gap: 2px;
}
.setting-label {
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
}
.setting-desc {
font-size: 12px;
color: var(--text-secondary);
}
.switch {
position: relative;
display: inline-block;
width: 34px;
height: 18px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #2a2a2a;
transition: .2s;
border: 1px solid var(--border-color);
}
.slider:before {
position: absolute;
content: "";
height: 10px;
width: 10px;
left: 3px;
bottom: 3px;
background-color: var(--text-secondary);
transition: .2s;
}
input:checked + .slider {
background-color: #151515;
border-color: var(--text-primary);
}
input:checked + .slider:before {
transform: translateX(16px);
background-color: var(--text-primary);
}
.bracket-input-group {
display: flex;
align-items: center;
color: var(--text-secondary);
font-family: var(--font-mono);
}
.bracket-input {
background: transparent;
border: none;
color: var(--text-primary);
font-family: var(--font-mono);
font-size: 14px;
width: 60px;
text-align: center;
outline: none;
padding: 0 4px;
}
.bracket-input:focus {
color: var(--accent-hover);
}
.action-bar {
margin-top: auto;
padding-top: var(--space-xl);
display: flex;
justify-content: flex-end;
gap: var(--space-md);
}
.btn {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
padding: var(--space-sm) var(--space-lg);
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.btn:hover {
border-color: var(--text-primary);
color: var(--text-primary);
}
.btn-primary {
background: var(--text-primary);
color: var(--bg-main);
border-color: var(--text-primary);
}
.btn-primary:hover {
background: transparent;
color: var(--text-primary);
}
</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" 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 active" 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">CONFIG:</span>v2.0.4-STABLE</div>
</header>
<div class="settings-grid" vid="31">
<section class="settings-section" vid="32">
<div class="section-title" vid="33">
<span vid="34">ADMIN PROTOCOL RULES</span>
<span class="label-meta" vid="35">SEC: 01</span>
</div>
<div class="settings-row" vid="36">
<div class="setting-info" vid="37">
<div class="setting-label" vid="38">강제 2단계 인증 (2FA)</div>
<div class="setting-desc" vid="39">모든 관리자 계정에 대해 생체 인식 또는 하드웨어 키 요구.</div>
</div>
<label class="switch" vid="40">
<input type="checkbox" checked="" vid="41">
<span class="slider" vid="42"></span>
</label>
</div>
<div class="settings-row" vid="43">
<div class="setting-info" vid="44">
<div class="setting-label" vid="45">세션 유효 시간</div>
<div class="setting-desc" vid="46">비활동 시 관리 콘솔 자동 로그아웃 시간(분).</div>
</div>
<div class="bracket-input-group" vid="47">
[ <input type="text" class="bracket-input" value="15" vid="48"> ]
</div>
</div>
<div class="settings-row" vid="49">
<div class="setting-info" vid="50">
<div class="setting-label" vid="51">IP 화이트리스트</div>
<div class="setting-desc" vid="52">지정된 대역에서만 관리자 권한 접근 허용.</div>
</div>
<label class="switch" vid="53">
<input type="checkbox" vid="54">
<span class="slider" vid="55"></span>
</label>
</div>
</section>
<section class="settings-section" vid="56">
<div class="section-title" vid="57">
<span vid="58">BACKUP &amp; REDUNDANCY</span>
<span class="label-meta" vid="59">SEC: 02</span>
</div>
<div class="settings-row" vid="60">
<div class="setting-info" vid="61">
<div class="setting-label" vid="62">자동 백업 활성화</div>
<div class="setting-desc" vid="63">전체 시스템 상태의 주기적인 스냅샷 생성.</div>
</div>
<label class="switch" vid="64">
<input type="checkbox" checked="" vid="65">
<span class="slider" vid="66"></span>
</label>
</div>
<div class="settings-row" vid="67">
<div class="setting-info" vid="68">
<div class="setting-label" vid="69">백업 주기 (시간)</div>
<div class="setting-desc" vid="70">스냅샷 생성 간격 설정.</div>
</div>
<div class="bracket-input-group" vid="71">
[ <input type="text" class="bracket-input" value="08:00" vid="72"> ]
</div>
</div>
<div class="settings-row" vid="73">
<div class="setting-info" vid="74">
<div class="setting-label" vid="75">보관 주기 (일)</div>
<div class="setting-desc" vid="76">백업 데이터 자동 삭제 전 유지 기간.</div>
</div>
<div class="bracket-input-group" vid="77">
[ <input type="text" class="bracket-input" value="30" vid="78"> ]
</div>
</div>
</section>
<section class="settings-section" vid="79">
<div class="section-title" vid="80">
<span vid="81">SYNC QUEUE THRESHOLDS</span>
<span class="label-meta" vid="82">SEC: 03</span>
</div>
<div class="settings-row" vid="83">
<div class="setting-info" vid="84">
<div class="setting-label" vid="85">대기열 경고 임계값</div>
<div class="setting-desc" vid="86">동기화 대기 항목이 설정치를 초과할 시 경보 발생.</div>
</div>
<div class="bracket-input-group" vid="87">
[ <input type="text" class="bracket-input" value="500" vid="88"> ]
</div>
</div>
<div class="settings-row" vid="89">
<div class="setting-info" vid="90">
<div class="setting-label" vid="91">자동 스케일링</div>
<div class="setting-desc" vid="92">부하 증가 시 임시 노드 리소스 할당.</div>
</div>
<label class="switch" vid="93">
<input type="checkbox" checked="" vid="94">
<span class="slider" vid="95"></span>
</label>
</div>
</section>
<section class="settings-section" vid="96">
<div class="section-title" vid="97">
<span vid="98">NODE ALERT TRIGGERS</span>
<span class="label-meta" vid="99">SEC: 04</span>
</div>
<div class="settings-row" vid="100">
<div class="setting-info" vid="101">
<div class="setting-label" vid="102">CPU 사용량 임계값 (%)</div>
<div class="setting-desc" vid="103">시스템 부하 경고 기준점.</div>
</div>
<div class="bracket-input-group" vid="104">
[ <input type="text" class="bracket-input" value="90" vid="105"> ]
</div>
</div>
<div class="settings-row" vid="106">
<div class="setting-info" vid="107">
<div class="setting-label" vid="108">레이턴시 경보 (ms)</div>
<div class="setting-desc" vid="109">응답 속도 지연에 대한 임계값 설정.</div>
</div>
<div class="bracket-input-group" vid="110">
[ <input type="text" class="bracket-input" value="250" vid="111"> ]
</div>
</div>
<div class="settings-row" vid="112">
<div class="setting-info" vid="113">
<div class="setting-label" vid="114">노드 오프라인 알림</div>
<div class="setting-desc" vid="115">활성 노드 연결 해제 시 즉시 알림.</div>
</div>
<label class="switch" vid="116">
<input type="checkbox" checked="" vid="117">
<span class="slider" vid="118"></span>
</label>
</div>
</section>
</div>
<div class="action-bar" vid="119">
<button class="btn" vid="120">초기화</button>
<button class="btn btn-primary" vid="121">설정 저장</button>
</div>
</main>
</div>
</body></html>
```