feat(ui): 콘솔 재디자인 적용 (Toss 스타일) + Pico v2 호환 수정
디자인 핸드오프(design_handoff_console_redesign)를 실제 앱에 반영.
CSS 드롭인 교체 + 최소 마크업 추가, HTMX 훅·id·data 속성은 모두 보존.
- app.css: 재디자인 토큰/컴포넌트로 교체(요약카드 호버 리프트, 표
제브라, 중앙 경고형 배포 모달, secondary/ghost/danger 버튼 체계,
진행률·상태칩·스켈레톤 등).
- base.html: 브랜드 로고 큐브(.brand-mark) 추가 + 데모 배너.
- repo_list: 요약 카드 .card-top/.card-ico + 검색 돋보기 아이콘.
- table_wrap: 회전형 정렬 인디케이터, 동기화 버튼 아이콘.
- progress: .sync-head/.sync-pct/.is-active/.indeterminate 구조.
- deploy_modal: 중앙 경고형 + 현재→대상 프리뷰 카드 + 타입-투-컨펌
체크/X 시각 상태.
- deploy_success: 그려지는 체크 원 배너.
- version_list: 표 → .version-item 카드 리스트.
Pico v2 호환(미리보기는 pico-shim 기준이라 안 드러났던 것):
- Pico 의 `:is(...).secondary`(0,2,0)·hover(0,4,0) 특정성을 이기도록
오버라이드를 :is() 형태로 상향 → 동기화 버튼 흰배경+파란글씨 유지,
hover 시 어두워지던 문제 해결.
- `input[type=search]` 의 Pico 기본 돋보기 배경 제거(아이콘 중복).
- `td` 배경을 투명 처리해 tr 제브라/hover 가 보이도록(Pico 의
`td{background:var(--pico-background-color)}` 가 덮던 문제), 줄무늬
색을 --bg-alt 로 또렷하게.
- .row-action 을 40px 고정 → 버튼↔진행률↔배지 교체 시 높이 흔들림·
위아래 테두리 잘림 해소.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
425
design_handoff_console_redesign/preview.html
Normal file
425
design_handoff_console_redesign/preview.html
Normal file
@@ -0,0 +1,425 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>폐쇄망 콘솔 — 재디자인 미리보기</title>
|
||||
<!-- FOUC 방지 + 테마 복원 (실제 base.html 의 인라인 스크립트와 동일 동작) -->
|
||||
<script>
|
||||
(function () {
|
||||
var t = localStorage.getItem("theme");
|
||||
if (t) document.documentElement.setAttribute("data-theme", t);
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="pico-shim.css" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<style>
|
||||
/* 미리보기 하니스 전용 (배포 CSS 아님) */
|
||||
.demo-note {
|
||||
max-width: 1040px;
|
||||
margin: 28px auto 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.demo-note .callout {
|
||||
background: var(--surface-2);
|
||||
color: var(--accent-hover);
|
||||
border-radius: 12px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.state-grid { display: grid; gap: 18px; }
|
||||
hr.sep { border: none; border-top: 1px solid var(--border); margin: 0 0 28px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 데모 배너 -->
|
||||
<div class="demo-banner">
|
||||
<span class="demo-dot"></span>
|
||||
<span><strong>데모 모드</strong> · 가짜 저장소 데이터입니다. 실제 Pulp 서버와 연동되어 있지 않습니다.</span>
|
||||
</div>
|
||||
|
||||
<!-- 상단 내비 -->
|
||||
<nav class="app-nav">
|
||||
<div class="container">
|
||||
<p class="brand"><span class="brand-mark">P</span>Pulp <span class="accent">Console</span></p>
|
||||
<button class="theme-toggle" id="theme-toggle" aria-label="테마 전환">
|
||||
<svg class="icon moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
||||
<svg class="icon sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="demo-note">
|
||||
<div class="callout">
|
||||
<b>재디자인 미리보기 (확정안).</b> 요약 카드 = 화이트+호버 리프트, 저장소 표 = 제브라, 배포 모달 = 중앙 경고형.
|
||||
동기화 버튼은 흰 배경·파란 글씨로, 새로고침(중립 아웃라인)과 구분됩니다. 우상단 아이콘으로 라이트·다크를 전환해 보세요.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- ═══════════ 대시보드 ═══════════ -->
|
||||
<section>
|
||||
<div class="status-row" style="margin-bottom:24px">
|
||||
<span class="status-label">연결 상태</span>
|
||||
<span class="status-line status-ok">Pulp 서버 연결됨</span>
|
||||
<span class="status-line status-demo">데모 데이터</span>
|
||||
</div>
|
||||
|
||||
<div class="summary">
|
||||
<div class="card is-accent">
|
||||
<div class="card-top">
|
||||
<span class="label">전체 저장소</span>
|
||||
<span class="card-ico"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg></span>
|
||||
</div>
|
||||
<div class="value is-accent">18</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-top">
|
||||
<span class="label">동기화 중</span>
|
||||
<span class="card-ico"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg></span>
|
||||
</div>
|
||||
<div class="value">2</div>
|
||||
</div>
|
||||
<div class="card is-success">
|
||||
<div class="card-top">
|
||||
<span class="label">GPG 통과</span>
|
||||
<span class="card-ico"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 8.5 8 10 4.6-1.5 8-5 8-10V5z"/><path d="m9 12 2 2 4-4"/></svg></span>
|
||||
</div>
|
||||
<div class="value is-success">16</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-top">
|
||||
<span class="label">총 패키지</span>
|
||||
<span class="card-ico"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="m3.3 7 8.7 5 8.7-5M12 22V12"/></svg></span>
|
||||
</div>
|
||||
<div class="value">48,120</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-head">
|
||||
<h2>저장소</h2>
|
||||
<button class="ghost btn-sm btn-icon" id="refresh-btn">
|
||||
<svg class="icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
새로고침
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="list-toolbar">
|
||||
<svg class="search-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input class="repo-search" type="search" placeholder="저장소 이름으로 검색…" />
|
||||
</div>
|
||||
|
||||
<div class="table-card" id="repo-table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><a class="th-sort is-active" href="#">저장소 <span class="sort-ind">▲</span></a></th>
|
||||
<th>검증</th>
|
||||
<th><a class="th-sort" href="#">최신 버전</a></th>
|
||||
<th class="num"><a class="th-sort" href="#">패키지</a></th>
|
||||
<th><a class="th-sort" href="#">마지막 동기화</a></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="repo-list">
|
||||
<tr>
|
||||
<td class="repo-name"><a href="#versions">rhel8-baseos</a></td>
|
||||
<td><span class="badge badge-pass">GPG 통과</span></td>
|
||||
<td class="mono">v142</td>
|
||||
<td class="num">9,204</td>
|
||||
<td class="mono">2026-07-09 04:12</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<button class="secondary btn-sm btn-icon" onclick="document.getElementById('modal').showModal()">
|
||||
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
동기화
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="repo-name"><a href="#versions">rhel8-appstream</a></td>
|
||||
<td><span class="badge badge-pass">GPG 통과</span></td>
|
||||
<td class="mono">v98</td>
|
||||
<td class="num">12,880</td>
|
||||
<td class="mono">동기화 중…</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<div class="sync-progress is-active">
|
||||
<div class="sync-head">
|
||||
<small>동기화 중</small>
|
||||
<small class="sync-pct">64%</small>
|
||||
</div>
|
||||
<progress value="64" max="100"></progress>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="repo-name"><a href="#versions">ubuntu2204-main</a></td>
|
||||
<td><span class="badge badge-warn">서명 확인 필요</span></td>
|
||||
<td class="mono">v51</td>
|
||||
<td class="num">6,412</td>
|
||||
<td class="mono">2026-07-08 23:40</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<button class="secondary btn-sm btn-icon" onclick="document.getElementById('modal').showModal()">
|
||||
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
동기화
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="repo-name"><a href="#versions">epel8-extras</a></td>
|
||||
<td><span class="badge badge-deployed">운영 배포됨</span></td>
|
||||
<td class="mono">v220</td>
|
||||
<td class="num">3,051</td>
|
||||
<td class="mono">2026-07-09 01:05</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<button class="secondary btn-sm btn-icon" onclick="document.getElementById('modal').showModal()">
|
||||
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
동기화
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="repo-name"><a href="#versions">centos-stream9</a></td>
|
||||
<td><span class="badge badge-unset">미검증</span></td>
|
||||
<td class="mono">v7</td>
|
||||
<td class="num">1,120</td>
|
||||
<td class="mono">2026-07-07 18:22</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<button class="secondary btn-sm btn-icon" onclick="document.getElementById('modal').showModal()">
|
||||
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
동기화
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pager">
|
||||
<button class="ghost btn-sm" disabled>이전</button>
|
||||
<span class="mono">1–5 / 18</span>
|
||||
<button class="ghost btn-sm">다음</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="sep" />
|
||||
|
||||
<!-- ═══════════ 상태 · 인터랙션 데모 ═══════════ -->
|
||||
<section>
|
||||
<div class="section-head"><h2>상태 · 인터랙션 데모</h2></div>
|
||||
<div class="state-grid">
|
||||
<div class="flash-banner">
|
||||
<span class="flash-check"><svg viewBox="0 0 24 24"><path d="m5 13 4 4L19 7"/></svg></span>
|
||||
<span>운영 배포 완료 · <span class="mono">rhel8-baseos v142</span></span>
|
||||
<span class="flash-sub">3,204개 패키지 반영</span>
|
||||
<span class="flash-warn">되돌리기: 이전 버전 재배포</span>
|
||||
</div>
|
||||
|
||||
<div class="table-card" style="padding:20px">
|
||||
<div style="display:flex;align-items:center;gap:16px;flex-wrap:wrap">
|
||||
<button class="secondary" id="sync-demo-btn">동기화 시작 (진행 애니메이션)</button>
|
||||
<div class="sync-progress" id="sync-demo" style="width:220px;display:none">
|
||||
<div class="sync-head"><small id="sync-demo-label">준비 중</small><small class="sync-pct" id="sync-demo-pct">0%</small></div>
|
||||
<progress id="sync-demo-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
<button class="secondary" style="width:auto" id="loading-demo">로딩 상태</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-card">
|
||||
<div class="empty-note">
|
||||
<span class="empty-ico"><svg class="icon" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg></span>
|
||||
<div class="empty-title">검색 결과가 없습니다</div>
|
||||
<div class="empty-sub"><span class="mono">"nginx"</span> 와 일치하는 저장소가 없어요. 다른 키워드로 검색해 보세요.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-note">
|
||||
<svg class="icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></svg>
|
||||
<span>Pulp 서버에 연결할 수 없습니다. 네트워크 및 서비스 상태를 확인하세요.</span>
|
||||
</div>
|
||||
|
||||
<div class="table-card" style="padding:18px">
|
||||
<div style="display:flex;flex-direction:column;gap:14px">
|
||||
<div class="skeleton skeleton-row" style="width:40%"></div>
|
||||
<div class="skeleton skeleton-row" style="width:70%"></div>
|
||||
<div class="skeleton skeleton-row" style="width:55%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="sep" />
|
||||
|
||||
<!-- ═══════════ 버전 목록 (저장소 상세 — 저장소 이름 클릭 시 화면) ═══════════ -->
|
||||
<section id="versions">
|
||||
<a href="#" role="button" class="ghost btn-sm btn-icon back-btn">
|
||||
<svg class="icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
|
||||
대시보드
|
||||
</a>
|
||||
<div class="section-head">
|
||||
<h2 class="mono">rhel8-baseos</h2>
|
||||
<button class="secondary btn-sm btn-icon" onclick="document.getElementById('modal').showModal()">
|
||||
<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0 0 20.5 15"/></svg>
|
||||
동기화
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="verify-detail">
|
||||
<span class="badge badge-pass">GPG 통과</span>
|
||||
<small>서명 검증 통과 · 2026-07-09 04:12 · 키 0x3A9F…C21</small>
|
||||
</div>
|
||||
|
||||
<div class="version-list">
|
||||
<div class="version-item">
|
||||
<span class="ver-no">v142</span>
|
||||
<span class="badge badge-deployed">운영 중</span>
|
||||
<span class="ver-meta">2026-07-09 04:12 · 9,204 pkgs</span>
|
||||
<span class="spacer"></span>
|
||||
<button class="ghost btn-sm" disabled>현재 운영 버전</button>
|
||||
</div>
|
||||
<div class="version-item">
|
||||
<span class="ver-no">v141</span>
|
||||
<span class="ver-meta">2026-07-08 22:03 · 9,180 pkgs · <span class="delta-add">+40</span> <span class="delta-del">−16</span></span>
|
||||
<span class="spacer"></span>
|
||||
<button class="secondary btn-sm" onclick="document.getElementById('modal').showModal()">이 버전 배포</button>
|
||||
</div>
|
||||
<div class="version-item">
|
||||
<span class="ver-no">v140</span>
|
||||
<span class="ver-meta">2026-07-08 09:15 · 9,001 pkgs · <span class="delta-add">+112</span></span>
|
||||
<span class="spacer"></span>
|
||||
<button class="secondary btn-sm" onclick="document.getElementById('modal').showModal()">이 버전 배포</button>
|
||||
</div>
|
||||
<div class="version-item">
|
||||
<span class="ver-no">v139</span>
|
||||
<span class="ver-meta">2026-07-07 20:41 · 8,889 pkgs</span>
|
||||
<span class="spacer"></span>
|
||||
<button class="secondary btn-sm" onclick="document.getElementById('modal').showModal()">이 버전 배포</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- ═══════════ 배포 확인 모달 (중앙 경고형) ═══════════ -->
|
||||
<dialog id="modal">
|
||||
<article class="deploy-modal">
|
||||
<div class="modal-head">
|
||||
<span class="warn-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></svg></span>
|
||||
<div>
|
||||
<h3>운영 배포 확인</h3>
|
||||
<span class="head-sub">되돌리기 어려운 작업입니다</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="deploy-note" style="text-align:center"><span class="repo-hl">rhel8-baseos</span> 저장소를 운영에 배포합니다.</p>
|
||||
<div class="deploy-preview">
|
||||
<div class="pv-box">
|
||||
<div class="pv-label">현재 (운영)</div>
|
||||
<div class="pv-ver">v140</div>
|
||||
<div class="pv-pkg">9,001 pkgs</div>
|
||||
</div>
|
||||
<div class="pv-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div>
|
||||
<div class="pv-box pv-target">
|
||||
<div class="pv-label">대상</div>
|
||||
<div class="pv-ver">v142</div>
|
||||
<div class="pv-pkg">9,204 pkgs · <span class="delta-add">+203</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="confirm-label">확인을 위해 저장소 이름 <span class="repo-hl">rhel8-baseos</span> 을 입력하세요.
|
||||
<div class="confirm-field" data-confirm="rhel8-baseos">
|
||||
<input type="text" autocomplete="off" placeholder="rhel8-baseos" />
|
||||
<svg class="confirm-state ok" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="m5 13 4 4L19 7"/></svg>
|
||||
<svg class="confirm-state bad" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
||||
</div>
|
||||
</label>
|
||||
<div class="modal-actions">
|
||||
<button class="ghost" onclick="this.closest('dialog').close()">취소</button>
|
||||
<button class="danger" id="deploy-confirm-btn" disabled>운영에 배포</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</dialog>
|
||||
|
||||
<script>
|
||||
// 테마 토글 (실제 base.html 동작과 동일)
|
||||
document.getElementById("theme-toggle").addEventListener("click", function () {
|
||||
var el = document.documentElement;
|
||||
var next = el.getAttribute("data-theme") === "dark" ? "light" : "dark";
|
||||
el.setAttribute("data-theme", next);
|
||||
localStorage.setItem("theme", next);
|
||||
});
|
||||
|
||||
// 타입-투-컨펌: 입력값이 data-confirm 과 일치하면 확정 버튼 활성 + 시각 상태
|
||||
(function () {
|
||||
var field = document.querySelector("#modal .confirm-field");
|
||||
var input = field.querySelector("input");
|
||||
var target = field.getAttribute("data-confirm");
|
||||
var btn = document.getElementById("deploy-confirm-btn");
|
||||
input.addEventListener("input", function () {
|
||||
var v = input.value.trim();
|
||||
field.classList.remove("is-valid", "is-invalid");
|
||||
if (v === "") { btn.disabled = true; return; }
|
||||
if (v === target) {
|
||||
field.classList.add("is-valid");
|
||||
btn.disabled = false;
|
||||
} else {
|
||||
field.classList.add("is-invalid");
|
||||
btn.disabled = true;
|
||||
}
|
||||
});
|
||||
btn.addEventListener("click", function () {
|
||||
if (btn.disabled) return;
|
||||
btn.classList.add("is-loading");
|
||||
btn.textContent = "배포 중";
|
||||
setTimeout(function () {
|
||||
btn.closest("dialog").close();
|
||||
btn.classList.remove("is-loading");
|
||||
btn.textContent = "운영에 배포";
|
||||
btn.disabled = true;
|
||||
field.classList.remove("is-valid", "is-invalid");
|
||||
input.value = "";
|
||||
}, 1400);
|
||||
});
|
||||
})();
|
||||
|
||||
// 진행바 데모
|
||||
document.getElementById("sync-demo-btn").addEventListener("click", function () {
|
||||
var wrap = document.getElementById("sync-demo");
|
||||
var bar = document.getElementById("sync-demo-bar");
|
||||
var pct = document.getElementById("sync-demo-pct");
|
||||
var label = document.getElementById("sync-demo-label");
|
||||
wrap.style.display = "flex";
|
||||
wrap.classList.add("indeterminate");
|
||||
label.textContent = "연결 중…";
|
||||
var v = 0;
|
||||
setTimeout(function () {
|
||||
wrap.classList.remove("indeterminate");
|
||||
label.textContent = "패키지 내려받는 중";
|
||||
var t = setInterval(function () {
|
||||
v += Math.max(1, Math.round((100 - v) * 0.12));
|
||||
if (v >= 100) { v = 100; clearInterval(t); label.textContent = "완료"; }
|
||||
bar.value = v;
|
||||
pct.textContent = v + "%";
|
||||
}, 240);
|
||||
}, 900);
|
||||
});
|
||||
|
||||
// 로딩 버튼 데모
|
||||
document.getElementById("loading-demo").addEventListener("click", function () {
|
||||
var b = this;
|
||||
b.classList.add("is-loading");
|
||||
setTimeout(function () { b.classList.remove("is-loading"); }, 1600);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user