This commit is contained in:
2026-08-04 17:57:01 +08:00
parent 768fd4a3a9
commit f77034edd7
641 changed files with 26137 additions and 0 deletions
@@ -0,0 +1,4 @@
(() => {
window.componentRegistry ||= {};
window.componentRegistry["src-web/form-controls/index.html"] = {"showcase":"<div class=\"panel\">\n <div class=\"panel-heading\"><div class=\"panel-title\">Checkbox / RadioGroup / Switch / Rate</div><div class=\"panel-note\">Value state is independent from interaction</div></div>\n <div class=\"panel-body\">\n <div class=\"grid cols-4\" style=\"gap:18px\">\n <div>\n <div class=\"rule-label\">Checkbox</div>\n <div class=\"check-row dnf-ui\" data-checkbox role=\"checkbox\" tabindex=\"0\" aria-checked=\"false\"><span class=\"checkbox-control\"></span><span data-control-label>交互示例 · 未选择</span></div>\n <div class=\"check-row dnf-ui is-emphasized\"><span class=\"checkbox-control\"></span> Emphasized</div>\n <div class=\"check-row dnf-ui\"><span class=\"checkbox-control is-checked\"></span> 已选择</div>\n <div class=\"check-row dnf-ui control-disabled\"><span class=\"checkbox-control\"></span> 已禁用</div>\n </div>\n <div data-radio-group role=\"radiogroup\" aria-label=\"效果强度\">\n <div class=\"rule-label\">RadioGroup</div>\n <div class=\"radio-row dnf-ui\" data-radio role=\"radio\" tabindex=\"0\" aria-checked=\"true\">关闭</div>\n <div class=\"radio-row dnf-ui\" data-radio role=\"radio\" tabindex=\"-1\" aria-checked=\"false\">弱</div>\n <div class=\"radio-row dnf-ui\" data-radio role=\"radio\" tabindex=\"-1\" aria-checked=\"false\">强</div>\n <div class=\"radio-row dnf-ui control-disabled\">禁用</div>\n </div>\n <div>\n <div class=\"rule-label\">Switch</div>\n <div class=\"switch-row dnf-ui\" data-switch role=\"switch\" tabindex=\"0\" aria-checked=\"false\"><span data-control-label>Interactive · Off</span></div>\n <div class=\"switch-row dnf-ui is-hover\">Hover</div>\n <div class=\"switch-row dnf-ui is-on\">On</div>\n <div class=\"switch-row dnf-ui control-disabled\">Disabled</div>\n </div>\n <div>\n <div class=\"rule-label\">Rate · Value = 1 / 5</div>\n <div class=\"rate dnf-ui\" data-rate role=\"slider\" tabindex=\"0\" aria-label=\"评分\" aria-valuemin=\"0\" aria-valuemax=\"5\" aria-valuenow=\"1\">\n <img data-rate-item src=\"src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/126.PNG\" alt=\"第 1 星\">\n <img data-rate-item src=\"src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG\" alt=\"第 2 星\">\n <img data-rate-item src=\"src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG\" alt=\"第 3 星\">\n <img data-rate-item src=\"src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG\" alt=\"第 4 星\">\n <img data-rate-item src=\"src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG\" alt=\"第 5 星\">\n </div>\n <div class=\"token-label\" style=\"margin-top:12px\">Value = Number 0–5<br>Readonly = Boolean<br>Star = raster asset</div>\n </div>\n </div>\n <div class=\"divider\"></div>\n <div class=\"spec-row\"><span class=\"spec-chip\">Checked = Off · On · Mixed</span><span class=\"spec-chip\">Interaction = Rest · Hover · Focus · Disabled</span></div>\n </div>\n </div>"};
})();
Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

+59
View File
@@ -0,0 +1,59 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=1920, initial-scale=1">
<base href="../../">
<title>form-controls component catalog</title>
<link rel="stylesheet" href="src-web/index.css">
</head>
<body>
<!-- Root pages load individual templates through index.html#fragment references. -->
<template id="showcase">
<div class="panel">
<div class="panel-heading"><div class="panel-title">Checkbox / RadioGroup / Switch / Rate</div><div class="panel-note">Value state is independent from interaction</div></div>
<div class="panel-body">
<div class="grid cols-4" style="gap:18px">
<div>
<div class="rule-label">Checkbox</div>
<div class="check-row dnf-ui" data-checkbox role="checkbox" tabindex="0" aria-checked="false"><span class="checkbox-control"></span><span data-control-label>交互示例 · 未选择</span></div>
<div class="check-row dnf-ui is-emphasized"><span class="checkbox-control"></span> Emphasized</div>
<div class="check-row dnf-ui"><span class="checkbox-control is-checked"></span> 已选择</div>
<div class="check-row dnf-ui control-disabled"><span class="checkbox-control"></span> 已禁用</div>
</div>
<div data-radio-group role="radiogroup" aria-label="效果强度">
<div class="rule-label">RadioGroup</div>
<div class="radio-row dnf-ui" data-radio role="radio" tabindex="0" aria-checked="true">关闭</div>
<div class="radio-row dnf-ui" data-radio role="radio" tabindex="-1" aria-checked="false">弱</div>
<div class="radio-row dnf-ui" data-radio role="radio" tabindex="-1" aria-checked="false">强</div>
<div class="radio-row dnf-ui control-disabled">禁用</div>
</div>
<div>
<div class="rule-label">Switch</div>
<div class="switch-row dnf-ui" data-switch role="switch" tabindex="0" aria-checked="false"><span data-control-label>Interactive · Off</span></div>
<div class="switch-row dnf-ui is-hover">Hover</div>
<div class="switch-row dnf-ui is-on">On</div>
<div class="switch-row dnf-ui control-disabled">Disabled</div>
</div>
<div>
<div class="rule-label">Rate · Value = 1 / 5</div>
<div class="rate dnf-ui" data-rate role="slider" tabindex="0" aria-label="评分" aria-valuemin="0" aria-valuemax="5" aria-valuenow="1">
<img data-rate-item src="src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/126.PNG" alt="第 1 星">
<img data-rate-item src="src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG" alt="第 2 星">
<img data-rate-item src="src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG" alt="第 3 星">
<img data-rate-item src="src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG" alt="第 4 星">
<img data-rate-item src="src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/149.PNG" alt="第 5 星">
</div>
<div class="token-label" style="margin-top:12px">Value = Number 0–5<br>Readonly = Boolean<br>Star = raster asset</div>
</div>
</div>
<div class="divider"></div>
<div class="spec-row"><span class="spec-chip">Checked = Off · On · Mixed</span><span class="spec-chip">Interaction = Rest · Hover · Focus · Disabled</span></div>
</div>
</div>
</template>
<script>
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
</script>
</body>
</html>
@@ -0,0 +1,183 @@
/* Source module: form-controls.css */
.fast-step { width:26px;height:28px;display:flex;flex-direction:column;gap:0;margin-left:3px;align-self:center; }
.fast-step-button {
--fast-r:0;
--fast-g:0;
--fast-b:0;
--fast-cap-dark:#080d17;
--fast-cap-core:#2f518f;
--fast-glyph:rgb(from #b69260 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b)));
appearance:none;
position:relative;
flex:0 0 14px;
width:26px;
height:14px;
padding:0;
border:0;
background:
linear-gradient(90deg,rgb(from #3c66b4 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 0 1px,transparent 1px 23px,rgb(from #3c66b4 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 23px) 1px 4px / 24px 9px no-repeat,
linear-gradient(180deg,rgb(from #325596 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))),rgb(from #1d2f53 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 46% 72%,rgb(from #2b4378 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b)))) 1px 4px / 24px 9px no-repeat,
linear-gradient(#000,#000) 0 3px / 26px 11px no-repeat;
color:var(--fast-glyph);
cursor:pointer;
}
.fast-step-button::before {
content:"";
position:absolute;
left:9px;
top:0;
width:7px;
height:3px;
background:
linear-gradient(#000,#000) center 0 / 3px 1px no-repeat,
linear-gradient(90deg,#000 0 1px,var(--fast-cap-dark) 1px 2px,var(--fast-cap-core) 2px 3px,var(--fast-cap-dark) 3px 4px,#000 4px) center 1px / 5px 1px no-repeat,
linear-gradient(90deg,#000 0 1px,var(--fast-cap-dark) 1px 2px,var(--fast-cap-core) 2px 5px,var(--fast-cap-dark) 5px 6px,#000 6px) center 2px / 7px 1px no-repeat;
pointer-events:none;
}
.fast-step-button + .fast-step-button {
background:
linear-gradient(90deg,rgb(from #3e6cbe calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 0 1px,transparent 1px 23px,rgb(from #3e6cbe calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 23px) 1px 1px / 24px 9px no-repeat,
linear-gradient(180deg,rgb(from #345a9e calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))),rgb(from #1d2f53 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b))) 46% 72%,rgb(from #2d4782 calc(r + var(--fast-r)) calc(g + var(--fast-g)) calc(b + var(--fast-b)))) 1px 1px / 24px 9px no-repeat,
linear-gradient(#000,#000) 0 0 / 26px 11px no-repeat;
}
.fast-step-button + .fast-step-button::before {
top:auto;
bottom:0;
background:
linear-gradient(90deg,#000 0 1px,var(--fast-cap-dark) 1px 2px,var(--fast-cap-core) 2px 5px,var(--fast-cap-dark) 5px 6px,#000 6px) center 0 / 7px 1px no-repeat,
linear-gradient(90deg,#000 0 1px,var(--fast-cap-dark) 1px 2px,var(--fast-cap-core) 2px 3px,var(--fast-cap-dark) 3px 4px,#000 4px) center 1px / 5px 1px no-repeat,
linear-gradient(#000,#000) center 2px / 3px 1px no-repeat;
}
.fast-step-button:hover,
.fast-step-button:active {
--fast-r:10;
--fast-g:16;
--fast-b:33;
--fast-cap-dark:#090f1b;
--fast-cap-core:#375da8;
}
.fast-step-button:active { background-position:1px 5px,1px 5px,0 3px; }
.fast-step-button:active::before { top:1px; }
.fast-step-button + .fast-step-button:active { background-position:1px 2px,1px 2px,0 0; }
.fast-step-button + .fast-step-button:active::before { top:auto;bottom:0; }
.fast-step-button:focus-visible { outline:1px solid var(--focus);outline-offset:1px; }
.fast-step-label {
position:absolute;
left:50%;
top:5px;
color:var(--fast-glyph);
font:400 7px/7px Arial,sans-serif;
letter-spacing:-.55px;
white-space:nowrap;
transform:translateX(-50%) scaleX(.9);
transform-origin:center;
pointer-events:none;
}
.fast-step-button + .fast-step-button .fast-step-label { top:2px; }
.fast-step-button:active .fast-step-label { transform:translate(-50%,1px) scaleX(.9); }
.check-row, .radio-row, .switch-row { display: flex; align-items: center; gap: 7px; min-height: 26px; color: var(--gold); font-size: 13px; }
.switch-row { position:relative; }
.check-row[data-checkbox], .radio-row[data-radio], .switch-row[data-switch] { cursor:pointer;user-select:none; }
.check-row[data-checkbox]:focus-visible, .radio-row[data-radio]:focus-visible, .switch-row[data-switch]:focus-visible { outline:1px solid var(--focus);outline-offset:-1px; }
.checkbox-control {
--check-edge-top:#635036;
--check-edge-bottom:#3c2e1b;
--check-top:#242424;
--check-bottom:#0f0f0f;
position:relative;
flex:0 0 auto;
width:16px;
height:16px;
display:flex;
align-items:center;
justify-content:center;
border:1px solid transparent;
background:linear-gradient(180deg,var(--check-top),var(--check-bottom)) padding-box,linear-gradient(180deg,var(--check-edge-top),var(--check-edge-bottom)) border-box;
box-shadow:0 0 0 1px rgba(0,0,0,.3),inset 0 1px 0 rgba(255,255,255,.025);
}
.checkbox-control::after {
content:"";
position:absolute;
width:18px;
height:14px;
background:linear-gradient(180deg,#dfb142,#eac75f);
clip-path:polygon(0 42%,7% 34%,39% 66%,94% 4%,100% 10%,39% 82%);
filter:drop-shadow(0 0 1px rgba(230,192,86,.45));
transform:scale(0);
transition:transform 70ms ease-out;
}
.checkbox-control.is-checked::after { transform:scale(1); }
.check-row:hover .checkbox-control,
.check-row.is-emphasized .checkbox-control { --check-edge-top:#bf9d6a;--check-edge-bottom:#947853;--check-top:#3a3a3a;--check-bottom:#181818; }
.check-row:active .checkbox-control { --check-edge-top:#bf9d6a;--check-edge-bottom:#947853;--check-top:#3a3a3a;--check-bottom:#181818;transform:translateY(1px); }
.check-row.control-disabled { opacity:1;filter:none;color:var(--disabled); }
.check-row.control-disabled .checkbox-control { --check-edge-top:#414141;--check-edge-bottom:#252525;--check-top:#1f1f1f;--check-bottom:#0d0d0d; }
.radio-row::before {
content:"";
box-sizing:border-box;
flex:0 0 auto;
width:14px;
height:14px;
border:1px solid #614f36;
border-radius:50%;
background:linear-gradient(180deg,#2e2e2e,#171717);
box-shadow:inset 0 1px 0 rgba(255,255,255,.04);
}
.radio-row[data-radio]:hover::before { border-color:#d6c889;background:linear-gradient(180deg,#4a4a4a,#252525);box-shadow:inset 0 1px 0 rgba(255,255,255,.05); }
.radio-row[data-radio][aria-checked="true"]::before {
border:1px solid transparent;
background:
linear-gradient(180deg,#dbaa3a 0%,#edd067 100%) padding-box,
linear-gradient(180deg,#f0dfa0 0%,#d3aa70 52%,#a17e50 100%) border-box;
box-shadow:inset 0 0 0 1px #272727;
}
.radio-row[data-radio]:active::before { transform:translateY(1px);filter:brightness(.82); }
.radio-row.control-disabled::before { border-color:#3b3b3b;background:linear-gradient(135deg,transparent 43%,#313131 46% 54%,transparent 57%),linear-gradient(180deg,#252525,#121212); }
.switch-row::before {
content:"";
box-sizing:border-box;
flex:0 0 auto;
width:28px;
height:16px;
border:1px solid transparent;
border-radius:8px / 50%;
background:linear-gradient(180deg,#141414,#0f0f0f) padding-box,linear-gradient(180deg,#846a48,#453520) border-box;
box-shadow:inset 0 1px 3px #090909;
}
.switch-row::after {
content:"";
box-sizing:border-box;
position:absolute;
left:2px;
top:50%;
width:12px;
height:12px;
border-radius:50%;
background:linear-gradient(180deg,var(--control-blue-top),var(--control-blue-bottom));
box-shadow:inset 0 1px 0 rgba(255,255,255,.04);
transform:translateY(-50%);
transition:transform 90ms ease-out;
}
.switch-row[data-switch]:hover::before,
.switch-row.is-hover::before { filter:brightness(1.04); }
.switch-row[data-switch]:hover::after,
.switch-row.is-hover::after { background:linear-gradient(180deg,#29457f,#24386a); }
.switch-row[data-switch][aria-checked="true"]::before,
.switch-row.is-on::before {
background:linear-gradient(#eccb65,#eccb65) padding-box,linear-gradient(180deg,#846a48,#453520) border-box;
box-shadow:inset 0 0 0 1px #0d0d0d,inset 0 0 2px 1px rgba(9,9,9,.12);
}
.switch-row[data-switch][aria-checked="true"]::after,
.switch-row.is-on::after { transform:translate(12px,-50%); }
.switch-row[data-switch]:active::after { transform:translateY(calc(-50% + 1px)); }
.switch-row[data-switch][aria-checked="true"]:active::after { transform:translate(12px,calc(-50% + 1px)); }
.switch-row.control-disabled::before { background:linear-gradient(180deg,#141414,#0f0f0f) padding-box,linear-gradient(180deg,#846a48,#453520) border-box;filter:none; }
.switch-row.control-disabled::after { left:3px;background:linear-gradient(180deg,#304b8a,#273f74);filter:none;opacity:.58; }
.control-disabled { opacity: .45; filter: grayscale(.8); }
.rate { width:max-content;min-height:46px;padding:8px 12px;display:flex;align-items:center;gap:2px;border-radius:22px;background:#1a1917;box-shadow:inset 0 1px 0 rgba(255,255,255,.025); }
.rate img { width:24px;height:auto;image-rendering:pixelated; }
.rate[data-rate] { cursor:pointer; }
.rate[data-rate]:focus-visible { outline:1px solid var(--focus);outline-offset:2px; }
.rate[data-rate] img:hover { filter:brightness(1.22);transform:translateY(-1px); }
.rate[data-rate] img:active { filter:brightness(.8);transform:translateY(1px); }