Màn hình cài đặt (hai cột)
Khi cài đặt đã chia thành nhiều nhóm — dùng khi danh sách nhóm bên trái và nội dung bên phải dễ dùng hơn một trang dài.
Xem trước trực tiếp
Nguồn
<script>document.body.className="dc-bleed"</script>
<div class="dc-set">
<header class="dc-set__bar">
<h1 class="dc-set__bar-title">미소식품 · 설정</h1>
<span class="dc-set__bar-right">모든 변경이 저장되었습니다</span>
</header>
<div class="dc-set__body">
<nav class="dc-set__side" aria-label="설정 갈래">
<p class="dc-set__side-title">설정</p>
<ul class="dc-set__nav">
<li><a class="dc-set__nav-link dc-set__nav-link--on" href="#" aria-current="page">프로필 · 알림</a></li>
<li><a class="dc-set__nav-link" href="#">사업장 정보</a></li>
<li><a class="dc-set__nav-link" href="#">팀원 권한</a></li>
<li><a class="dc-set__nav-link" href="#">결제 · 청구서</a></li>
<li><a class="dc-set__nav-link" href="#">보안 · 로그인</a></li>
<li><a class="dc-set__nav-link" href="#">연동 · API 키</a></li>
</ul>
</nav>
<main class="dc-set__main">
<section class="dc-set__sec" aria-labelledby="dc-set-p">
<div class="dc-set__sec-head">
<h2 class="dc-set__sec-title" id="dc-set-p">프로필</h2>
<p class="dc-set__sec-sub">서류에 담당자로 표시되는 이름입니다.</p>
</div>
<div class="dc-set__profile">
<span class="dc-set__avatar" aria-hidden="true">김</span>
<button class="dc-set__btn-ghost" type="button">사진 바꾸기</button>
</div>
<div class="dc-set__fields">
<div class="dc-set__field">
<label class="dc-set__label" for="dc-set-name">이름</label>
<input class="dc-set__input" id="dc-set-name" type="text" value="김현수">
</div>
<div class="dc-set__field">
<label class="dc-set__label" for="dc-set-mail">업무 이메일</label>
<input class="dc-set__input" id="dc-set-mail" type="email" value="[email protected]">
<p class="dc-set__hint">청구서와 보안 알림이 이 주소로 갑니다.</p>
</div>
<div class="dc-set__field">
<label class="dc-set__label" for="dc-set-lang">서류 기본 언어</label>
<select class="dc-set__select" id="dc-set-lang">
<option selected>한국어</option>
<option>English</option>
<option>Tiếng Việt</option>
<option>नेपाली</option>
</select>
</div>
</div>
</section>
<section class="dc-set__sec" aria-labelledby="dc-set-n">
<div class="dc-set__sec-head">
<h2 class="dc-set__sec-title" id="dc-set-n">알림</h2>
<p class="dc-set__sec-sub">켜고 끄면 곧바로 적용됩니다.</p>
</div>
<ul class="dc-set__rows">
<li class="dc-set__row">
<span class="dc-set__row-text">
<span class="dc-set__row-name">서명 완료 알림</span>
<span class="dc-set__row-desc">직원이 근로계약서에 서명하면 이메일로 알립니다.</span>
</span>
<label class="dc-set__switch" for="dc-set-s1">
<span class="dc-sr">서명 완료 알림</span>
<input class="dc-set__switch-input" id="dc-set-s1" type="checkbox" checked>
<span class="dc-set__switch-track" aria-hidden="true"></span>
</label>
</li>
<li class="dc-set__row">
<span class="dc-set__row-text">
<span class="dc-set__row-name">급여 마감 3일 전 알림</span>
<span class="dc-set__row-desc">매달 22일에 확정해야 할 명세서를 모아 보냅니다.</span>
</span>
<label class="dc-set__switch" for="dc-set-s2">
<span class="dc-sr">급여 마감 3일 전 알림</span>
<input class="dc-set__switch-input" id="dc-set-s2" type="checkbox" checked>
<span class="dc-set__switch-track" aria-hidden="true"></span>
</label>
</li>
<li class="dc-set__row">
<span class="dc-set__row-text">
<span class="dc-set__row-name">주간 요약 메일</span>
<span class="dc-set__row-desc">월요일 아침에 지난주 서류 현황을 한 통으로 받습니다.</span>
</span>
<label class="dc-set__switch" for="dc-set-s3">
<span class="dc-sr">주간 요약 메일</span>
<input class="dc-set__switch-input" id="dc-set-s3" type="checkbox">
<span class="dc-set__switch-track" aria-hidden="true"></span>
</label>
</li>
</ul>
</section>
<section class="dc-set__sec dc-set__danger" aria-labelledby="dc-set-d">
<div class="dc-set__sec-head">
<h2 class="dc-set__sec-title" id="dc-set-d">사업장 삭제</h2>
<p class="dc-set__danger-text">직원 42명의 계약서와 명세서가 함께 지워집니다. 30일 안에는 고객센터를 통해 되돌릴 수 있습니다.</p>
</div>
<button class="dc-set__danger-btn" type="button">사업장 삭제 절차 시작</button>
</section>
</main>
</div>
</div>
.dc-set { display:flex; flex-direction:column; min-height:700px; background:var(--dc-bg); color:var(--dc-text); font-family:var(--dc-font); }
.dc-set__bar { position:sticky; top:0; z-index:2; display:flex; align-items:center; justify-content:space-between; gap:var(--dc-3); min-height:56px; padding:0 var(--dc-5); background:var(--dc-surface); border-bottom:1px solid var(--dc-line); }
.dc-set__bar-title { font-size:15px; font-weight:700; letter-spacing:-.01em; }
.dc-set__bar-right { font-size:12px; color:var(--dc-text-mute); }
.dc-set__body { display:grid; grid-template-columns:232px minmax(0, 1fr); flex:1; }
.dc-set__side { padding:var(--dc-5) var(--dc-3); border-right:1px solid var(--dc-line); background:var(--dc-sunken); }
.dc-set__side-title { padding:0 var(--dc-3) var(--dc-2); font-size:12px; font-weight:700; color:var(--dc-text-mute); letter-spacing:.04em; }
.dc-set__nav { display:flex; flex-direction:column; gap:var(--dc-1); }
.dc-set__nav-link { display:flex; align-items:center; min-height:44px; padding:0 var(--dc-3); border-radius:var(--dc-r-sm); color:var(--dc-text-sub); font-size:14px; text-decoration:none; }
.dc-set__nav-link:hover { background:var(--dc-surface); color:var(--dc-text); }
.dc-set__nav-link--on { background:var(--dc-brand-soft); color:var(--dc-brand-text); font-weight:700; }
.dc-set__main { display:flex; flex-direction:column; gap:var(--dc-5); max-width:720px; padding:var(--dc-6) var(--dc-6) var(--dc-8); }
.dc-set__sec { display:flex; flex-direction:column; gap:var(--dc-4); padding:var(--dc-5); border:1px solid var(--dc-line); border-radius:var(--dc-r-lg); background:var(--dc-surface); }
.dc-set__sec-head { display:flex; flex-direction:column; gap:var(--dc-1); }
.dc-set__sec-title { font-size:17px; font-weight:700; }
.dc-set__sec-sub { font-size:13px; color:var(--dc-text-sub); }
.dc-set__profile { display:flex; align-items:center; gap:var(--dc-3); }
.dc-set__avatar { display:grid; place-items:center; width:56px; height:56px; border-radius:var(--dc-r-full); background:var(--dc-brand-soft); color:var(--dc-brand-text); font-size:20px; font-weight:700; }
.dc-set__fields { display:flex; flex-direction:column; gap:var(--dc-4); }
.dc-set__field { display:flex; flex-direction:column; gap:var(--dc-2); max-width:380px; }
.dc-set__label { font-size:13px; font-weight:600; }
.dc-set__input, .dc-set__select { width:100%; min-height:44px; padding:0 var(--dc-3); border:1px solid var(--dc-line-field); border-radius:var(--dc-r-sm); background:var(--dc-surface); color:var(--dc-text); font-size:14px; }
.dc-set__input:focus, .dc-set__select:focus { border-color:var(--dc-brand); box-shadow:0 0 0 3px var(--dc-brand-soft); outline:none; }
.dc-set__hint { font-size:12px; color:var(--dc-text-mute); }
.dc-set__rows { display:flex; flex-direction:column; }
.dc-set__row { display:flex; align-items:center; justify-content:space-between; gap:var(--dc-4); padding:var(--dc-3) 0; border-top:1px solid var(--dc-line); }
.dc-set__row:first-child { border-top:none; }
.dc-set__row-text { display:flex; flex-direction:column; gap:2px; }
.dc-set__row-name { font-size:14px; font-weight:600; }
.dc-set__row-desc { font-size:12px; color:var(--dc-text-sub); line-height:1.5; }
.dc-set__switch { position:relative; display:inline-flex; align-items:center; justify-content:center; width:52px; min-width:52px; height:44px; cursor:pointer; }
.dc-set__switch-input { position:absolute; width:1px; height:1px; opacity:0; }
.dc-set__switch-track { position:relative; display:block; width:44px; height:26px; border-radius:var(--dc-r-full); background:var(--dc-line-bold); transition:background var(--dc-fast); }
.dc-set__switch-track::after { content:""; position:absolute; top:3px; left:3px; width:20px; height:20px; border-radius:var(--dc-r-full); background:var(--dc-surface); box-shadow:var(--dc-sh-1); transition:transform var(--dc-fast); }
.dc-set__switch-input:checked + .dc-set__switch-track { background:var(--dc-brand); }
.dc-set__switch-input:checked + .dc-set__switch-track::after { transform:translateX(18px); }
.dc-set__switch-input:focus-visible + .dc-set__switch-track { outline:2px solid var(--dc-brand); outline-offset:2px; }
.dc-set__danger { border-color:var(--dc-danger); }
.dc-set__danger-text { font-size:13px; color:var(--dc-text-sub); line-height:1.6; }
.dc-set__danger-btn { align-self:flex-start; min-height:44px; padding:0 var(--dc-4); border:1px solid var(--dc-danger); border-radius:var(--dc-r-sm); background:var(--dc-danger-soft); color:var(--dc-danger); font-size:14px; font-weight:700; }
.dc-set__btn-ghost { min-height:44px; padding:0 var(--dc-4); border:1px solid var(--dc-line-field); border-radius:var(--dc-r-sm); background:var(--dc-surface); color:var(--dc-text); font-size:13px; font-weight:600; }
.dc-set__btn-ghost:hover { background:var(--dc-sunken); }
.dc-set__saving { position:sticky; bottom:0; display:flex; align-items:center; justify-content:space-between; gap:var(--dc-4); flex-wrap:wrap; padding:var(--dc-3) var(--dc-4); border:1px solid var(--dc-brand); border-radius:var(--dc-r-md); background:var(--dc-brand-soft); box-shadow:var(--dc-sh-2); }
.dc-set__saving-text { font-size:13px; font-weight:600; color:var(--dc-brand-text); }
.dc-set__saving-acts { display:flex; align-items:center; gap:var(--dc-2); }
.dc-set__save { min-height:44px; padding:0 var(--dc-4); border:1px solid transparent; border-radius:var(--dc-r-sm); background:var(--dc-brand); color:var(--dc-text-on); font-size:13px; font-weight:700; }
.dc-set__save:hover { background:var(--dc-brand-hi); }
@media (max-width:900px) {
.dc-set__body { grid-template-columns:1fr; }
.dc-set__side { border-right:none; border-bottom:1px solid var(--dc-line); }
.dc-set__nav { flex-direction:row; overflow-x:auto; }
.dc-set__main { padding:var(--dc-4) var(--dc-4) var(--dc-7); }
}
Cách dùng
- Danh sách bên trái giữ khoảng bảy mục; nhiều hơn thì hãy gộp nhóm
- Đánh dấu nhóm đang xem bằng aria-current, không chỉ bằng màu
- Chỉ dùng công tắc cho thứ áp dụng ngay khi bật; giá trị cần lưu thì để ở ô nhập
- Đặt hành động nguy hiểm thành khối riêng ở dưới cùng
Điểm cần lưu ý
- Khi còn thay đổi chưa lưu, hiện thanh dưới để người dùng biết trước khi rời trang
- Công tắc tự làm có thể ẩn checkbox nhưng không được bỏ nó — tiêu điểm bàn phím và :checked đến từ đó
- Màn hình hẹp thì gộp thành một cột và đưa danh sách nhóm lên trên