delete
@@ -1,41 +0,0 @@
|
||||
# DataTable unified header design QA
|
||||
|
||||
- Source visual truth: `C:\Users\user\AppData\Local\Temp\codex-clipboard-3cfee13a-b444-4ae7-84d0-2141c3fada51.png`
|
||||
- Implementation screenshot: `C:\Users\user\.codex\visualizations\2026\08\02\019fc172-c8b8-7253-83ff-1261f079edf3\table-header-item-focused.png`
|
||||
- Combined focused comparison: `C:\Users\user\.codex\visualizations\2026\08\02\019fc172-c8b8-7253-83ff-1261f079edf3\table-header-reference-comparison.png`
|
||||
- Viewport: 1920 x 1200 CSS px
|
||||
- Density: deviceScaleFactor 2
|
||||
- Source pixels: 338 x 43; effective header crop 326 x 33, normalized to 593 x 60
|
||||
- Implementation pixels: 1120 x 60; CSS size 560 x 30
|
||||
- State: normal sortable table header, with sort interaction tested separately
|
||||
|
||||
## Full-view comparison evidence
|
||||
|
||||
SkillDamageDetail, CompactGradientRow, and ItemRow panel captures confirm that the shared header treatment remains legible and aligned in each table layout. The page contains 29 component panels with no console errors or broken images.
|
||||
|
||||
## Focused comparison evidence
|
||||
|
||||
The combined comparison normalizes the reference and implementation header height. Both use a near-black outer edge, gold-brown inner line, brown-to-black vertical gradient, muted gold label, square corners, and a solid downward sort triangle. A focused comparison is required because these border and glyph details are too small to judge in the full board.
|
||||
|
||||
## Required fidelity surfaces
|
||||
|
||||
- Fonts and typography: existing DCalc/SimSun stack retained; muted gold labels remain crisp at the component scale.
|
||||
- Spacing and layout rhythm: all four DataTable header variants are 30px high; 1px column gaps and internal padding are consistent.
|
||||
- Colors and visual tokens: shared colors reuse the existing `#4a3c26` border and `#bc9e58` text palette, with one common brown-black gradient.
|
||||
- Image quality and asset fidelity: no raster asset is required or introduced; the reference contains only code-native table UI.
|
||||
- Copy and content: existing table labels are unchanged.
|
||||
|
||||
## Comparison history
|
||||
|
||||
1. First pass found the generic header cell at 29px while the other variants were 30px. Removed the inherited row bottom border; all header and cell heights now measure 30px.
|
||||
2. Second pass found ItemRow `锻造` and `拍卖信息` sort arrows clipped by narrow tracks. Expanded only those aligned header/body tracks; the final capture shows complete labels and triangles.
|
||||
|
||||
## Findings
|
||||
|
||||
No actionable P0, P1, or P2 mismatch remains.
|
||||
|
||||
## Remaining risk
|
||||
|
||||
Only Chrome was rendered. Other browser font rasterization may differ slightly.
|
||||
|
||||
final result: passed
|
||||
@@ -1,639 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=1920, initial-scale=1" />
|
||||
<title>DNF UI Component Library — Abstracted Preview</title>
|
||||
<link rel="icon" href="src-web/shared/img/sprite_interface.NPK/windowcommon.chn.img/301.PNG" />
|
||||
<link rel="stylesheet" href="src-web/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section class="board" id="board-1">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">Foundations & Construction Anatomy</h1>
|
||||
<div class="board-subtitle">截图定义视觉语法,素材定义构造方式;组件不包含任何游戏截图裁片</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>01 / 06</strong>FOUNDATIONS · TOKENS · ASSETS</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="component-reference" data-component-src="src-web/foundations/index.html#colors"></div>
|
||||
|
||||
<div class="grid cols-3" style="height:350px;margin-bottom:18px;">
|
||||
<div class="component-reference" data-component-src="src-web/button/index.html#construction"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/dialog/index.html#construction"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/shared/index.html#glyphs"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-2" style="height:276px;">
|
||||
<div class="component-reference" data-component-src="src-web/foundations/index.html#typography"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/foundations/index.html#architecture"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · TOKEN-FIRST</span><span>SEMANTIC STATES ≠ ITEM QUALITY</span></div>
|
||||
</section>
|
||||
|
||||
<section class="board" id="board-2">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">Core Controls</h1>
|
||||
<div class="board-subtitle">可替换文案、图标和状态;保持深蓝动作面、黄铜边线与紧凑密度</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>02 / 06</strong>BUTTON · FIELD · SELECTION · RATE</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="component-reference" data-component-src="src-web/button/index.html#showcase"></div>
|
||||
|
||||
<div class="grid cols-2" style="height:430px;margin-bottom:18px;">
|
||||
<div class="component-reference" data-component-src="src-web/input/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/select/index.html#showcase"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-2" style="height:292px;">
|
||||
<div class="component-reference" data-component-src="src-web/form-controls/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/slider/index.html#showcase"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · NORMALIZED COMPONENTS</span><span>TREE SELECTED = OUTLINE ONLY · QUALITY TONE PRESERVED</span></div>
|
||||
</section>
|
||||
|
||||
<section class="board" id="board-3">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">Navigation & Overlays</h1>
|
||||
<div class="board-subtitle">相同行为共享 primitive,不同 anatomy 保持独立 visual family</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>03 / 06</strong>TABS · DISCLOSURE · MENU · WINDOW</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="grid cols-2" style="height:275px;margin-bottom:18px;">
|
||||
<div class="component-reference" data-component-src="src-web/tabs/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/menu/index.html#showcase"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-3" style="height:265px;margin-bottom:18px;">
|
||||
<div class="component-reference" data-component-src="src-web/navigation/index.html#favorite-drawer"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/navigation/index.html#settings-nav"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/data-section/index.html#showcase"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-2" style="height:442px;">
|
||||
<div class="component-reference" data-component-src="src-web/dialog/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/scrollbar/index.html#showcase"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · VISUAL FAMILY BOUNDARIES</span><span>DIALOG BODY SHELL ≠ CONTENT WELL</span></div>
|
||||
</section>
|
||||
|
||||
<section class="board" id="board-4">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">Data Display & Product Patterns</h1>
|
||||
<div class="board-subtitle">由小组件组成设置表单、数据表、稀有度槽位和状态反馈,不把整张界面做成组件</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>04 / 06</strong>FORM ROW · TABLE · BADGE · QUALITY</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="grid cols-2" style="height:560px;margin-bottom:18px;grid-template-columns:.92fr 1.28fr;">
|
||||
<div class="component-reference" data-component-src="src-web/settings/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/data-table/index.html#composition"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-3" style="height:390px;grid-template-columns:1.25fr .8fr 1fr;">
|
||||
<div class="component-reference" data-component-src="src-web/rarity/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/rarity/index.html#badges"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/foundations/index.html#evidence"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · PRODUCT PATTERNS</span><span>SMALL COMPONENTS → COMPOSED DNF INTERFACES</span></div>
|
||||
</section>
|
||||
|
||||
<section class="board" id="board-5">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">Search & Complex Dialog Composition</h1>
|
||||
<div class="board-subtitle">搜索组件保持原生输入语法;复杂弹窗由 WindowDialog、List、Table 与 Plain Scrollbar 组合</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>05 / 06</strong>AUTOCOMPLETE · SEARCH TREE · DIALOG PRESET</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="component-reference" data-component-src="src-web/autocomplete/index.html#showcase"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/complex-dialog/index.html#preset"></div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · COMPOSITION TEMPLATE</span><span>WINDOW PRIMITIVE + LIST + TABLE + PLAIN SCROLLBAR</span></div>
|
||||
</section>
|
||||
|
||||
<section class="board" id="board-6">
|
||||
<header class="board-header">
|
||||
<div>
|
||||
<div class="board-kicker">DNF UI Component Library / Abstracted Preview</div>
|
||||
<h1 class="board-title">DataTable Density & Item Variants</h1>
|
||||
<div class="board-subtitle">同一表格语义,拆分技能明细、紧凑记录、DataTable ItemRow 与无表头 ShopItemRow</div>
|
||||
</div>
|
||||
<div class="board-index"><strong>06 / 06</strong>SORT · COMPACT · ITEM ROW · SHOP ITEM</div>
|
||||
</header>
|
||||
|
||||
<div class="content table-variant-board">
|
||||
<div class="component-reference" data-component-src="src-web/data-table/index.html#skill"></div>
|
||||
|
||||
<div class="grid cols-3 table-variant-grid">
|
||||
<div class="component-reference" data-component-src="src-web/data-table/index.html#compact"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/data-table/index.html#item"></div>
|
||||
|
||||
<div class="component-reference" data-component-src="src-web/shop-item-row/index.html#showcase"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-note"><span>PREVIEW V4 · DATATABLE VARIANT FAMILIES</span><span>SORTABLE HEADER + SELECTABLE ROW + SUMMARY + GROUP NOTE</span></div>
|
||||
</section>
|
||||
|
||||
<script src="src-web/shared/component-loader.js"></script>
|
||||
<script>
|
||||
window.componentsReady.then(() => {
|
||||
document.querySelectorAll('.panel').forEach((panel) => {
|
||||
const windows = [...panel.querySelectorAll('.window')];
|
||||
if (!windows.length) return;
|
||||
|
||||
const focusWindow = (activeWindow) => {
|
||||
windows.forEach((windowNode) => {
|
||||
const isActive = windowNode === activeWindow;
|
||||
windowNode.classList.toggle('is-focused', isActive);
|
||||
windowNode.classList.toggle('is-unfocused', !isActive);
|
||||
});
|
||||
};
|
||||
|
||||
windows.forEach((windowNode) => {
|
||||
const titlebar = windowNode.querySelector(':scope > .window-titlebar');
|
||||
if (titlebar && !titlebar.querySelector('.window-title-effect')) {
|
||||
const effect = document.createElement('img');
|
||||
effect.className = 'window-title-effect';
|
||||
effect.src = 'src-web/dialog/img/sprite_interface.NPK/windowheadereffect.img/0.PNG';
|
||||
effect.alt = '';
|
||||
effect.setAttribute('aria-hidden', 'true');
|
||||
titlebar.appendChild(effect);
|
||||
}
|
||||
windowNode.addEventListener('pointerdown', () => focusWindow(windowNode));
|
||||
});
|
||||
|
||||
focusWindow(windows[0]);
|
||||
});
|
||||
|
||||
let windowHeaderEffectFrame = 0;
|
||||
window.setInterval(() => {
|
||||
windowHeaderEffectFrame = (windowHeaderEffectFrame + 1) % 45;
|
||||
document.querySelectorAll('.window.is-focused > .window-titlebar .window-title-effect').forEach((effect) => {
|
||||
effect.src = `src-web/dialog/img/sprite_interface.NPK/windowheadereffect.img/${windowHeaderEffectFrame}.PNG`;
|
||||
});
|
||||
}, 66);
|
||||
|
||||
document.querySelectorAll('[data-tabs]').forEach((tabs) => {
|
||||
const marker = tabs.querySelector(':scope > .tab-marker');
|
||||
const equalizeItems = () => {
|
||||
const labels = [...tabs.querySelectorAll('.game-tab .tab-label')];
|
||||
if (!labels.length) return;
|
||||
const widestLabel = Math.max(0, ...labels.map((label) => label.getBoundingClientRect().width));
|
||||
const tabsStyle = getComputedStyle(tabs);
|
||||
const buttonStyle = getComputedStyle(labels[0].closest('.game-tab'));
|
||||
const groupPadding = parseFloat(tabsStyle.paddingLeft) + parseFloat(tabsStyle.paddingRight);
|
||||
const itemPadding = parseFloat(buttonStyle.paddingLeft) + parseFloat(buttonStyle.paddingRight);
|
||||
const contentWidth = Math.ceil(widestLabel + itemPadding);
|
||||
const parentWidth = tabs.parentElement?.clientWidth ?? tabs.clientWidth;
|
||||
const availableWidth = Math.max(0, parentWidth - groupPadding);
|
||||
const itemWidth = Math.min(contentWidth, availableWidth / labels.length);
|
||||
tabs.style.setProperty('--tab-item-width', `${itemWidth}px`);
|
||||
tabs.style.setProperty('--tab-group-width', `${itemWidth * labels.length + groupPadding}px`);
|
||||
};
|
||||
const positionMarker = (tab, animate = true) => {
|
||||
if (!marker || !tab) return;
|
||||
const tabsBox = tabs.getBoundingClientRect();
|
||||
const tabBox = tab.getBoundingClientRect();
|
||||
if (!animate) marker.classList.remove('is-ready');
|
||||
marker.style.left = `${tabBox.left - tabsBox.left + tabBox.width / 2}px`;
|
||||
if (!marker.classList.contains('is-ready')) {
|
||||
requestAnimationFrame(() => marker.classList.add('is-ready'));
|
||||
}
|
||||
};
|
||||
equalizeItems();
|
||||
positionMarker(tabs.querySelector('.game-tab.selected'), false);
|
||||
document.fonts?.ready.then(() => {
|
||||
equalizeItems();
|
||||
positionMarker(tabs.querySelector('.game-tab.selected'), false);
|
||||
});
|
||||
tabs.querySelectorAll('.game-tab').forEach((tab) => {
|
||||
tab.addEventListener('click', () => {
|
||||
tabs.querySelectorAll('.game-tab').forEach((item) => {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
tab.classList.add('selected');
|
||||
positionMarker(tab);
|
||||
});
|
||||
});
|
||||
if ('ResizeObserver' in window) {
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
equalizeItems();
|
||||
positionMarker(tabs.querySelector('.game-tab.selected'), false);
|
||||
});
|
||||
resizeObserver.observe(tabs);
|
||||
if (tabs.parentElement) resizeObserver.observe(tabs.parentElement);
|
||||
}
|
||||
});
|
||||
|
||||
const onKeyboardActivate = (element, action) => {
|
||||
element?.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
action(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-select-demo]').forEach((select) => {
|
||||
const trigger = select.querySelector('[role="combobox"]');
|
||||
const value = select.querySelector('[data-select-value]');
|
||||
const setOpen = (open) => {
|
||||
select.classList.toggle('is-open', open);
|
||||
trigger?.setAttribute('aria-expanded', String(open));
|
||||
};
|
||||
const toggle = () => setOpen(!select.classList.contains('is-open'));
|
||||
trigger?.addEventListener('click', toggle);
|
||||
onKeyboardActivate(trigger, toggle);
|
||||
select.querySelectorAll('[role="option"]').forEach((option) => {
|
||||
const choose = () => {
|
||||
select.querySelectorAll('[role="option"]').forEach((item) => {
|
||||
item.classList.toggle('selected', item === option);
|
||||
item.classList.remove('focused');
|
||||
item.setAttribute('aria-selected', String(item === option));
|
||||
});
|
||||
if (value) value.textContent = option.textContent;
|
||||
setOpen(false);
|
||||
trigger?.focus();
|
||||
};
|
||||
option.addEventListener('click', choose);
|
||||
onKeyboardActivate(option, choose);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-tree-select]').forEach((treeSelect) => {
|
||||
const trigger = treeSelect.querySelector('[role="combobox"]');
|
||||
const value = treeSelect.querySelector('[data-tree-select-value]');
|
||||
const parent = treeSelect.querySelector('.tree-parent');
|
||||
const setOpen = (open) => {
|
||||
treeSelect.classList.toggle('is-open', open);
|
||||
trigger?.setAttribute('aria-expanded', String(open));
|
||||
};
|
||||
const toggle = () => setOpen(!treeSelect.classList.contains('is-open'));
|
||||
trigger?.addEventListener('click', toggle);
|
||||
onKeyboardActivate(trigger, toggle);
|
||||
const toggleBranch = () => {
|
||||
const collapsed = !treeSelect.classList.contains('is-tree-collapsed');
|
||||
treeSelect.classList.toggle('is-tree-collapsed', collapsed);
|
||||
parent?.setAttribute('aria-expanded', String(!collapsed));
|
||||
};
|
||||
parent?.addEventListener('click', toggleBranch);
|
||||
onKeyboardActivate(parent, toggleBranch);
|
||||
treeSelect.querySelectorAll('.tree-select-item:not(.tree-parent)').forEach((item) => {
|
||||
const choose = () => {
|
||||
treeSelect.querySelectorAll('.tree-select-item:not(.tree-parent)').forEach((option) => {
|
||||
option.classList.toggle('is-selected', option === item);
|
||||
option.setAttribute('aria-selected', String(option === item));
|
||||
});
|
||||
if (value) value.textContent = item.textContent;
|
||||
setOpen(false);
|
||||
trigger?.focus();
|
||||
};
|
||||
item.addEventListener('click', choose);
|
||||
onKeyboardActivate(item, choose);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-checkbox]').forEach((checkbox) => {
|
||||
const toggle = () => {
|
||||
const checked = checkbox.getAttribute('aria-checked') !== 'true';
|
||||
checkbox.setAttribute('aria-checked', String(checked));
|
||||
checkbox.querySelector('.checkbox-control')?.classList.toggle('is-checked', checked);
|
||||
const label = checkbox.querySelector('[data-control-label]');
|
||||
if (label) label.textContent = `交互示例 · ${checked ? '已选择' : '未选择'}`;
|
||||
};
|
||||
checkbox.addEventListener('click', toggle);
|
||||
onKeyboardActivate(checkbox, toggle);
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-radio-group]').forEach((group) => {
|
||||
const radios = [...group.querySelectorAll('[data-radio]')];
|
||||
const selectRadio = (radio) => {
|
||||
radios.forEach((item) => {
|
||||
const selected = item === radio;
|
||||
item.setAttribute('aria-checked', String(selected));
|
||||
item.tabIndex = selected ? 0 : -1;
|
||||
});
|
||||
radio.focus();
|
||||
};
|
||||
radios.forEach((radio, index) => {
|
||||
radio.addEventListener('click', () => selectRadio(radio));
|
||||
radio.addEventListener('keydown', (event) => {
|
||||
if (!['ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft'].includes(event.key)) return;
|
||||
event.preventDefault();
|
||||
const direction = event.key === 'ArrowDown' || event.key === 'ArrowRight' ? 1 : -1;
|
||||
selectRadio(radios[(index + direction + radios.length) % radios.length]);
|
||||
});
|
||||
onKeyboardActivate(radio, () => selectRadio(radio));
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-switch]').forEach((switchControl) => {
|
||||
const label = switchControl.querySelector('[data-control-label]');
|
||||
const render = (checked) => {
|
||||
if (label) label.textContent = `Interactive · ${checked ? 'On' : 'Off'}`;
|
||||
};
|
||||
const toggle = () => {
|
||||
const checked = switchControl.getAttribute('aria-checked') !== 'true';
|
||||
switchControl.setAttribute('aria-checked', String(checked));
|
||||
render(checked);
|
||||
};
|
||||
switchControl.addEventListener('click', toggle);
|
||||
onKeyboardActivate(switchControl, toggle);
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-rate]').forEach((rate) => {
|
||||
const stars = [...rate.querySelectorAll('[data-rate-item]')];
|
||||
const render = (value) => stars.forEach((star, index) => {
|
||||
star.src = `src-web/form-controls/img/sprite_interface2_popup_menu.NPK/popup_icon_npc.img/${index < value ? 126 : 149}.PNG`;
|
||||
});
|
||||
const setValue = (value) => {
|
||||
const next = Math.max(0, Math.min(5, value));
|
||||
rate.setAttribute('aria-valuenow', String(next));
|
||||
render(next);
|
||||
};
|
||||
stars.forEach((star, index) => {
|
||||
star.addEventListener('pointerenter', () => render(index + 1));
|
||||
star.addEventListener('click', () => setValue(index + 1));
|
||||
});
|
||||
rate.addEventListener('pointerleave', () => render(Number(rate.getAttribute('aria-valuenow'))));
|
||||
rate.addEventListener('keydown', (event) => {
|
||||
const current = Number(rate.getAttribute('aria-valuenow'));
|
||||
if (event.key === 'ArrowRight' || event.key === 'ArrowUp') setValue(current + 1);
|
||||
else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') setValue(current - 1);
|
||||
else if (event.key === 'Home') setValue(0);
|
||||
else if (event.key === 'End') setValue(5);
|
||||
else return;
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-slider]').forEach((slider) => {
|
||||
const track = slider.querySelector('.slider-track');
|
||||
const valueLabel = slider.querySelector('.slider-value');
|
||||
const setValue = (value) => {
|
||||
const next = Math.max(0, Math.min(100, Math.round(value)));
|
||||
slider.style.setProperty('--value', `${next}%`);
|
||||
slider.setAttribute('aria-valuenow', String(next));
|
||||
if (valueLabel) valueLabel.textContent = `${next}%`;
|
||||
};
|
||||
const setFromPointer = (event) => {
|
||||
const rect = track.getBoundingClientRect();
|
||||
setValue(((event.clientX - rect.left) / rect.width) * 100);
|
||||
};
|
||||
slider.addEventListener('pointerdown', (event) => {
|
||||
slider.classList.add('is-dragging');
|
||||
slider.setPointerCapture(event.pointerId);
|
||||
setFromPointer(event);
|
||||
});
|
||||
slider.addEventListener('pointermove', (event) => {
|
||||
if (slider.classList.contains('is-dragging')) setFromPointer(event);
|
||||
});
|
||||
const stopDragging = () => slider.classList.remove('is-dragging');
|
||||
slider.addEventListener('pointerup', stopDragging);
|
||||
slider.addEventListener('pointercancel', stopDragging);
|
||||
slider.addEventListener('keydown', (event) => {
|
||||
const current = Number(slider.getAttribute('aria-valuenow'));
|
||||
if (event.key === 'ArrowRight' || event.key === 'ArrowUp') setValue(current + 1);
|
||||
else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') setValue(current - 1);
|
||||
else if (event.key === 'Home') setValue(0);
|
||||
else if (event.key === 'End') setValue(100);
|
||||
else return;
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-autocomplete]').forEach((autocomplete) => {
|
||||
const trigger = autocomplete.querySelector('[role="combobox"]');
|
||||
const menu = autocomplete.querySelector('[role="listbox"]');
|
||||
const value = autocomplete.querySelector('[data-autocomplete-value]');
|
||||
const setOpen = (open) => {
|
||||
if (menu) menu.hidden = !open;
|
||||
trigger?.setAttribute('aria-expanded', String(open));
|
||||
};
|
||||
const toggle = () => setOpen(trigger?.getAttribute('aria-expanded') !== 'true');
|
||||
trigger?.addEventListener('click', toggle);
|
||||
onKeyboardActivate(trigger, toggle);
|
||||
autocomplete.querySelectorAll('[role="option"]').forEach((option) => {
|
||||
const choose = () => {
|
||||
autocomplete.querySelectorAll('[role="option"]').forEach((item) => {
|
||||
item.classList.toggle('selected', item === option);
|
||||
item.setAttribute('aria-selected', String(item === option));
|
||||
});
|
||||
if (value) value.textContent = option.textContent;
|
||||
setOpen(false);
|
||||
trigger?.focus();
|
||||
};
|
||||
option.addEventListener('click', choose);
|
||||
onKeyboardActivate(option, choose);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-cascader]').forEach((cascader) => {
|
||||
const trigger = cascader.querySelector('.cascader-trigger.primary');
|
||||
const value = cascader.querySelector('.cascader-value');
|
||||
trigger?.addEventListener('click', () => cascader.classList.toggle('is-open'));
|
||||
cascader.querySelectorAll('.cascader-option').forEach((option) => {
|
||||
option.addEventListener('click', () => {
|
||||
cascader.querySelectorAll('.cascader-option').forEach((item) => item.classList.remove('focused'));
|
||||
option.classList.add('focused');
|
||||
value.textContent = option.textContent;
|
||||
cascader.classList.remove('is-open');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const setDisclosureState = (section, expanded) => {
|
||||
const trigger = section.querySelector('.disclosure-head');
|
||||
const body = section.querySelector('.disclosure-body');
|
||||
const icon = trigger?.querySelector('img');
|
||||
const state = trigger?.querySelector('.disclosure-state');
|
||||
trigger?.setAttribute('aria-expanded', String(expanded));
|
||||
section.classList.toggle('is-collapsed', !expanded);
|
||||
if (body) body.hidden = !expanded;
|
||||
if (icon) icon.src = expanded ? icon.dataset.expandedIcon : icon.dataset.collapsedIcon;
|
||||
if (state) state.textContent = expanded ? '已展开' : '未展开';
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-disclosure]').forEach((section) => {
|
||||
const trigger = section.querySelector('.disclosure-head');
|
||||
trigger?.addEventListener('click', () => {
|
||||
const expanded = trigger.getAttribute('aria-expanded') !== 'true';
|
||||
if (expanded) {
|
||||
section.closest('.data-section-stack')?.querySelectorAll('[data-disclosure]').forEach((sibling) => {
|
||||
if (sibling !== section) setDisclosureState(sibling, false);
|
||||
});
|
||||
}
|
||||
setDisclosureState(section, expanded);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-favorite-drawer]').forEach((drawer) => {
|
||||
const trigger = drawer.querySelector('.disclosure-head');
|
||||
const body = drawer.querySelector('.disclosure-body');
|
||||
const state = drawer.querySelector('.favorite-drawer-state');
|
||||
const arrow = drawer.querySelector('.favorite-drawer-arrow');
|
||||
trigger?.addEventListener('click', () => {
|
||||
const expanded = trigger.getAttribute('aria-expanded') !== 'true';
|
||||
trigger.setAttribute('aria-expanded', String(expanded));
|
||||
drawer.classList.toggle('is-collapsed', !expanded);
|
||||
if (body) body.hidden = !expanded;
|
||||
if (state) state.textContent = expanded ? '已展开' : '已收起';
|
||||
if (arrow) arrow.textContent = expanded ? '▲' : '▼';
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-number-input]').forEach((numberInput) => {
|
||||
const value = numberInput.querySelector('[data-number-value]');
|
||||
numberInput.querySelectorAll('[data-step]').forEach((control) => {
|
||||
control.addEventListener('click', () => {
|
||||
const next = Number(value?.textContent || 0) + Number(control.dataset.step || 0);
|
||||
if (value) value.textContent = String(Math.max(0, next));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-sortable-table]').forEach((table) => {
|
||||
table.querySelectorAll('.sortable-header').forEach((header) => {
|
||||
header.addEventListener('click', () => {
|
||||
const wasSorted = header.classList.contains('is-sorted');
|
||||
const wasDescending = header.getAttribute('aria-sort') === 'descending';
|
||||
table.querySelectorAll('.sortable-header').forEach((item) => {
|
||||
item.classList.remove('is-sorted');
|
||||
item.removeAttribute('aria-sort');
|
||||
const glyph = item.querySelector('.sort-glyph');
|
||||
if (glyph) glyph.textContent = '△';
|
||||
});
|
||||
const descending = wasSorted && !wasDescending;
|
||||
header.classList.add('is-sorted');
|
||||
header.setAttribute('aria-sort', descending ? 'descending' : 'ascending');
|
||||
const glyph = header.querySelector('.sort-glyph');
|
||||
if (glyph) glyph.textContent = descending ? '▽' : '△';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const selectTableRow = (row) => {
|
||||
row.closest('.data-table')?.querySelectorAll('[data-selectable-row]').forEach((item) => item.classList.remove('is-selected'));
|
||||
row.classList.add('is-selected');
|
||||
};
|
||||
document.querySelectorAll('[data-selectable-row]').forEach((row) => {
|
||||
row.addEventListener('click', () => selectTableRow(row));
|
||||
row.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
selectTableRow(row);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-selection-theme]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const panel = button.closest('.panel-body');
|
||||
const table = panel?.querySelector('[data-data-table]');
|
||||
panel?.querySelectorAll('[data-selection-theme]').forEach((item) => item.classList.toggle('is-active', item === button));
|
||||
table?.classList.toggle('selection-gold', button.dataset.selectionTheme === 'gold');
|
||||
table?.classList.toggle('selection-blue', button.dataset.selectionTheme === 'blue');
|
||||
});
|
||||
});
|
||||
|
||||
const updateDialogStatus = (control, message) => {
|
||||
const dialog = control.closest('.window');
|
||||
const status = dialog?.querySelector('.dialog-status');
|
||||
if (!status) return;
|
||||
status.textContent = message;
|
||||
status.classList.remove('is-updated');
|
||||
requestAnimationFrame(() => status.classList.add('is-updated'));
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-dialog-action]').forEach((control) => {
|
||||
control.addEventListener('click', () => {
|
||||
const message = control.dataset.dialogAction || '操作已执行';
|
||||
updateDialogStatus(control, message);
|
||||
if (message.includes('关闭')) {
|
||||
const dialog = control.closest('.window');
|
||||
dialog?.classList.remove('is-demo-dismissed');
|
||||
requestAnimationFrame(() => dialog?.classList.add('is-demo-dismissed'));
|
||||
window.setTimeout(() => dialog?.classList.remove('is-demo-dismissed'), 300);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-dialog-toggle]').forEach((control) => {
|
||||
control.addEventListener('click', () => {
|
||||
const next = control.getAttribute('aria-pressed') !== 'true';
|
||||
control.setAttribute('aria-pressed', String(next));
|
||||
const checkbox = control.querySelector('.checkbox-control');
|
||||
checkbox?.classList.toggle('is-checked', next);
|
||||
const label = control.classList.contains('sheet-filter-button')
|
||||
? `筛选${next ? '已展开' : '已收起'}`
|
||||
: control.classList.contains('show-all')
|
||||
? `查看全部${next ? '已开启' : '已关闭'}`
|
||||
: `显示模式${next ? '已切换' : '已还原'}`;
|
||||
updateDialogStatus(control, label);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-preset-edit]').forEach((control) => {
|
||||
control.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
const row = control.closest('.preset-row');
|
||||
const active = !row?.classList.contains('is-renaming');
|
||||
row?.classList.toggle('is-renaming', active);
|
||||
control.setAttribute('aria-pressed', String(active));
|
||||
updateDialogStatus(control, active ? '预设已进入重命名状态' : '预设名称已确认');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-preset-delete]').forEach((control) => {
|
||||
control.addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
const row = control.closest('.preset-row');
|
||||
const removed = !row?.classList.contains('is-demo-deleted');
|
||||
row?.classList.toggle('is-demo-deleted', removed);
|
||||
control.setAttribute('aria-pressed', String(removed));
|
||||
updateDialogStatus(control, removed ? '预设已标记移除,再次点击可恢复' : '预设已恢复');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,13 +0,0 @@
|
||||
# Component source layout
|
||||
|
||||
Each component folder contains:
|
||||
|
||||
- `index.html`: one or more named HTML templates. Root pages load them with `index.html#fragment`.
|
||||
- `style/index.css`: the component styles.
|
||||
- `component.js`: the local-file compatible registry generated from `index.html`.
|
||||
- `img/`: only the image assets referenced by that component.
|
||||
|
||||
`shared/` contains global tokens, base styles, the component loader, and shared glyph samples.
|
||||
The complete pre-organization snapshot is stored under `../old/`.
|
||||
|
||||
After editing a component `index.html`, run `python src-web/sync-components.py` from the project root.
|
||||
@@ -1,4 +0,0 @@
|
||||
(() => {
|
||||
window.componentRegistry ||= {};
|
||||
window.componentRegistry["src-web/autocomplete/index.html"] = {"showcase":"<div class=\"panel\" style=\"height:330px;margin-bottom:18px;\">\n <div class=\"panel-heading\"><div class=\"panel-title\">Autocomplete</div><div class=\"panel-note\">Two visual families over the same combobox behavior</div></div>\n <div class=\"panel-body autocomplete-grid\">\n <div class=\"autocomplete-family flat-autocomplete\" data-autocomplete>\n <div class=\"family-head\"><span>ComboboxFlat</span><span class=\"spec-chip captured\">CAPTURED</span></div>\n <div class=\"autocomplete-line dnf-ui\">\n <div class=\"field select-field focus autocomplete-field\" role=\"combobox\" tabindex=\"0\" aria-expanded=\"true\" aria-controls=\"autocomplete-flat-menu\"><span class=\"field-label\" data-autocomplete-value>DNF</span></div>\n </div>\n <div class=\"autocomplete-menu dnf-ui\" id=\"autocomplete-flat-menu\" role=\"listbox\">\n <div class=\"autocomplete-item selected\" role=\"option\" tabindex=\"0\" aria-selected=\"true\">DNF Toonies(1天)</div>\n <div class=\"autocomplete-item\" role=\"option\" tabindex=\"0\" aria-selected=\"false\">DNF Toonies(3天)</div>\n <div class=\"autocomplete-item q-epic\" role=\"option\" tabindex=\"0\" aria-selected=\"false\">DNF毒战者</div>\n <div class=\"autocomplete-item q-rare\" role=\"option\" tabindex=\"0\" aria-selected=\"false\">DNF智者</div>\n <div class=\"autocomplete-item q-artifact\" role=\"option\" tabindex=\"0\" aria-selected=\"false\">闪耀之DNF勇士</div>\n </div>\n </div>\n\n <div class=\"autocomplete-family search-tree-family\">\n <div class=\"family-head\"><span>SearchTree</span><span class=\"spec-chip captured\">CAPTURED</span></div>\n <div class=\"search-toolbar dnf-ui\">\n <img class=\"search-icon\" src=\"src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG\" alt=\"search\">\n <div class=\"field select-field has-select-icon focus autocomplete-field\"><span class=\"field-label\">西风</span><img class=\"clear-icon\" src=\"src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/582.PNG\" alt=\"clear\"></div>\n <div class=\"btn-shell compact-shell\"><div class=\"dnf-btn normal dnf-ui\">搜索</div></div>\n <div class=\"btn-shell compact-shell\"><div class=\"dnf-btn normal dnf-ui\">刷新</div></div>\n </div>\n <div class=\"search-tree dnf-ui\">\n <div class=\"search-tree-row root\"><img src=\"src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG\">剧情角色名称</div>\n <div class=\"search-tree-row branch\"><img src=\"src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG\">素喃</div>\n <div class=\"search-tree-row leaf selected\">西风</div>\n <div class=\"search-tree-row leaf\">阿斯卡</div>\n <div class=\"search-tree-row leaf\">小铁柱</div>\n <div class=\"search-tree-row branch\"><img src=\"src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG\">黄昏之海(寂静城)</div>\n </div>\n </div>\n </div>\n </div>"};
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 690 B |
|
Before Width: | Height: | Size: 555 B |
|
Before Width: | Height: | Size: 232 B |
|
Before Width: | Height: | Size: 990 B |
@@ -1,54 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=1920, initial-scale=1">
|
||||
<base href="../../">
|
||||
<title>autocomplete 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" style="height:330px;margin-bottom:18px;">
|
||||
<div class="panel-heading"><div class="panel-title">Autocomplete</div><div class="panel-note">Two visual families over the same combobox behavior</div></div>
|
||||
<div class="panel-body autocomplete-grid">
|
||||
<div class="autocomplete-family flat-autocomplete" data-autocomplete>
|
||||
<div class="family-head"><span>ComboboxFlat</span><span class="spec-chip captured">CAPTURED</span></div>
|
||||
<div class="autocomplete-line dnf-ui">
|
||||
<div class="field select-field focus autocomplete-field" role="combobox" tabindex="0" aria-expanded="true" aria-controls="autocomplete-flat-menu"><span class="field-label" data-autocomplete-value>DNF</span></div>
|
||||
</div>
|
||||
<div class="autocomplete-menu dnf-ui" id="autocomplete-flat-menu" role="listbox">
|
||||
<div class="autocomplete-item selected" role="option" tabindex="0" aria-selected="true">DNF Toonies(1天)</div>
|
||||
<div class="autocomplete-item" role="option" tabindex="0" aria-selected="false">DNF Toonies(3天)</div>
|
||||
<div class="autocomplete-item q-epic" role="option" tabindex="0" aria-selected="false">DNF毒战者</div>
|
||||
<div class="autocomplete-item q-rare" role="option" tabindex="0" aria-selected="false">DNF智者</div>
|
||||
<div class="autocomplete-item q-artifact" role="option" tabindex="0" aria-selected="false">闪耀之DNF勇士</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="autocomplete-family search-tree-family">
|
||||
<div class="family-head"><span>SearchTree</span><span class="spec-chip captured">CAPTURED</span></div>
|
||||
<div class="search-toolbar dnf-ui">
|
||||
<img class="search-icon" src="src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="search">
|
||||
<div class="field select-field has-select-icon focus autocomplete-field"><span class="field-label">西风</span><img class="clear-icon" src="src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/582.PNG" alt="clear"></div>
|
||||
<div class="btn-shell compact-shell"><div class="dnf-btn normal dnf-ui">搜索</div></div>
|
||||
<div class="btn-shell compact-shell"><div class="dnf-btn normal dnf-ui">刷新</div></div>
|
||||
</div>
|
||||
<div class="search-tree dnf-ui">
|
||||
<div class="search-tree-row root"><img src="src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG">剧情角色名称</div>
|
||||
<div class="search-tree-row branch"><img src="src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG">素喃</div>
|
||||
<div class="search-tree-row leaf selected">西风</div>
|
||||
<div class="search-tree-row leaf">阿斯卡</div>
|
||||
<div class="search-tree-row leaf">小铁柱</div>
|
||||
<div class="search-tree-row branch"><img src="src-web/autocomplete/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG">黄昏之海(寂静城)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
/* Source module: autocomplete.css */
|
||||
.autocomplete-grid { display:grid;grid-template-columns:.9fr 1.1fr;gap:22px;height:calc(100% - 46px); }
|
||||
.autocomplete-family { min-width:0;padding:10px 12px;border:1px solid #292b27;background:#070807; }
|
||||
.family-head { height:24px;display:flex;align-items:center;justify-content:space-between;color:var(--gold);font-size:13px; }
|
||||
.autocomplete-line,.search-toolbar { display:flex;align-items:center;gap:6px; }
|
||||
.search-icon { flex:0 0 auto;width:auto;height:auto;max-width:18px;max-height:18px;image-rendering:pixelated; }
|
||||
.autocomplete-field { min-width:0;flex:1; }
|
||||
.clear-icon { flex:0 0 auto;width:9px;height:9px;margin:0 1px 0 4px;image-rendering:pixelated; }
|
||||
.autocomplete-menu { margin:1px 0 0 24px;border:1px solid #5c4a2c;background:#010201;box-shadow:0 8px 18px #000; }
|
||||
.flat-autocomplete .autocomplete-menu { margin-left:0; }
|
||||
.autocomplete-item { height:27px;padding:0 9px;display:flex;align-items:center;border-bottom:1px solid #24231f;color:var(--gold);background:#030403; }
|
||||
.autocomplete-item:hover { color:#f3d777;background:#101612;cursor:pointer; }
|
||||
.autocomplete-item:active { color:#fff0a4;background:#07121b; }
|
||||
.autocomplete-item:focus-visible { outline:1px solid var(--focus);outline-offset:-2px; }
|
||||
.autocomplete-item.selected { color:var(--selected);background:#1b1508;box-shadow:inset 2px 0 0 var(--selected); }
|
||||
.compact-shell { padding:2px;border-radius:0; }
|
||||
.compact-shell .dnf-btn { min-width:58px;height:30px;padding:0 8px; }
|
||||
.search-tree { height:170px;margin:4px 0 0 24px;padding:3px 0;border:1px solid #4f4229;background:#010201;overflow:hidden; }
|
||||
.search-tree-row { height:26px;padding:0 9px;display:flex;align-items:center;gap:6px;border-bottom:1px solid #24231f;color:var(--gold); }
|
||||
.search-tree-row img { max-width:12px;max-height:12px;image-rendering:pixelated; }
|
||||
.search-tree-row.branch { padding-left:28px;color:#c6b46f; }
|
||||
.search-tree-row.leaf { padding-left:50px; }
|
||||
.search-tree-row.selected { color:var(--selected);background:#1a1509;box-shadow:inset 2px 0 0 var(--selected); }
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,66 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=1920, initial-scale=1">
|
||||
<base href="../../">
|
||||
<title>button 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="construction">
|
||||
<div class="panel">
|
||||
<div class="panel-heading"><div class="panel-title">3-slice control surface</div><div class="spec-chip asset">SOURCE ASSET</div></div>
|
||||
<div class="panel-body">
|
||||
<div class="anatomy">
|
||||
<div class="asset-tile"><img src="src-web/button/img/sprite_interface_ninepatch_resource.NPK/ninepatch_resource.img/24.PNG" width="102" alt="button source asset"></div>
|
||||
<div class="anatomy-list">
|
||||
<div class="anatomy-line"><strong>Left cap</strong><span>固定像素,不横向拉伸</span></div>
|
||||
<div class="anatomy-line"><strong>Center</strong><span>仅中段伸缩,承载文字</span></div>
|
||||
<div class="anatomy-line"><strong>Right cap</strong><span>保留边角和金属高光</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="rule-label">Responsive reconstruction</div>
|
||||
<div class="slice-demo">
|
||||
<span class="cut left"></span><span class="cut right"></span>
|
||||
<span class="slice-label" style="left:0">CAP</span><span class="slice-label" style="left:46%">STRETCHABLE FILL</span><span class="slice-label" style="right:0">CAP</span>
|
||||
</div>
|
||||
<div style="height:28px"></div>
|
||||
<div class="btn-shell"><div class="dnf-btn large normal dnf-ui"><span class="btn-icon">+</span>创建预设</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="showcase">
|
||||
<div class="panel button-showcase-panel" style="height:292px;margin-bottom:18px;">
|
||||
<div class="panel-heading"><div class="panel-title">TextButton / IconButton</div><div class="spec-row"><span class="spec-chip captured">CSS + NINE-PATCH PRIMARY</span><span class="spec-chip asset">ninepatch_resource.img</span></div></div>
|
||||
<div class="panel-body">
|
||||
<div class="sample-grid button-state-grid" style="grid-template-columns:repeat(5,1fr);">
|
||||
<div class="button-implementation-label">Implementation / CSS<small>原生渐变与描边 · 可编辑</small></div>
|
||||
<div class="sample-cell"><div class="sample-label">Rest</div><div class="btn-shell"><div class="dnf-btn normal dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Hover</div><div class="btn-shell"><div class="dnf-btn hover dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Pressed</div><div class="btn-shell"><div class="dnf-btn pressed dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Disabled</div><div class="btn-shell"><div class="dnf-btn disabled dnf-ui">购买</div></div></div>
|
||||
|
||||
<div class="button-implementation-label">Implementation / CSS Replica<small>CSS gradient + inner glow · primary</small></div>
|
||||
<div class="sample-cell"><div class="sample-label">Rest</div><div class="btn-shell"><div class="dnf-btn image normal dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Hover</div><div class="btn-shell"><div class="dnf-btn image hover dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Pressed</div><div class="btn-shell"><div class="dnf-btn image pressed dnf-ui"><span class="btn-icon">+</span>创建角色</div></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Disabled</div><div class="btn-shell"><div class="dnf-btn image disabled dnf-ui">购买</div></div></div>
|
||||
|
||||
<div class="button-implementation-label">CSS / Tone family<small>derived states · hover / press interactive</small></div>
|
||||
<div class="sample-cell"><div class="sample-label">Default · 4–7</div><div class="btn-shell"><button type="button" class="dnf-btn raster-tone normal dnf-ui">确认</button></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Green · 12–15</div><div class="btn-shell"><button type="button" class="dnf-btn raster-tone tone-green normal dnf-ui">应用</button></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Orange Red · 20–23</div><div class="btn-shell"><button type="button" class="dnf-btn raster-tone tone-orange normal dnf-ui">取消</button></div></div>
|
||||
<div class="sample-cell"><div class="sample-label">Disabled · captured</div><div class="btn-shell"><button type="button" class="dnf-btn raster-tone disabled dnf-ui" disabled>确认</button></div></div>
|
||||
</div>
|
||||
<div class="spec-row" style="margin-top:14px"><span class="spec-chip">Corner Radius = 0</span><span class="spec-chip">Shadow = None</span><span class="spec-chip">Size = Compact · Default · Large</span><span class="spec-chip">LeadingIcon = Boolean</span><span class="spec-chip">Label = Text</span><span class="spec-chip captured">Hover = Lighter 1 Tone</span><span class="spec-chip captured">Pressed = Hover Tone + Y 1px</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,204 +0,0 @@
|
||||
/* Source module: button.css */
|
||||
.btn-shell {
|
||||
display: inline-flex;
|
||||
padding: 4px;
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.dnf-btn {
|
||||
appearance: none;
|
||||
position: relative;
|
||||
height: 30px;
|
||||
min-width: 110px;
|
||||
padding: 0 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 7px;
|
||||
color: var(--gold);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0;
|
||||
background:
|
||||
linear-gradient(180deg, #1f355e 0%, #1d2f53 55%, #1a2849 100%) padding-box,
|
||||
linear-gradient(180deg, #684f2d 0%, #483423 100%) border-box;
|
||||
box-shadow: none;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button.dnf-btn {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.dnf-btn.normal:not(.raster-tone):not(.image):hover,
|
||||
button.dnf-btn.normal:not(.raster-tone):not(.image):focus-visible {
|
||||
color: #eee2aa;
|
||||
background:
|
||||
linear-gradient(180deg, #29457f 0%, #273f74 55%, #24386a 100%) padding-box,
|
||||
linear-gradient(180deg, #725f4e 0%, #524444 100%) border-box;
|
||||
outline: none;
|
||||
}
|
||||
button.dnf-btn.normal:not(.raster-tone):not(.image):active {
|
||||
color: #eee2aa;
|
||||
transform: translateY(1px);
|
||||
background:
|
||||
linear-gradient(180deg, #29457f 0%, #273f74 55%, #24386a 100%) padding-box,
|
||||
linear-gradient(180deg, #725f4e 0%, #524444 100%) border-box;
|
||||
}
|
||||
button.dnf-btn:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dnf-btn.normal {
|
||||
background:
|
||||
linear-gradient(180deg, #1f355e 0%, #1d2f53 55%, #1a2849 100%) padding-box,
|
||||
linear-gradient(180deg, #684f2d 0%, #483423 100%) border-box;
|
||||
}
|
||||
.dnf-btn.hover {
|
||||
color: #eee2aa;
|
||||
background:
|
||||
linear-gradient(180deg, #29457f 0%, #273f74 55%, #24386a 100%) padding-box,
|
||||
linear-gradient(180deg, #725f4e 0%, #524444 100%) border-box;
|
||||
}
|
||||
.dnf-btn.pressed {
|
||||
transform: translateY(1px);
|
||||
background:
|
||||
linear-gradient(180deg, #29457f 0%, #263e73 58%, #213462 100%) padding-box,
|
||||
linear-gradient(180deg, #725f4e 0%, #524444 100%) border-box;
|
||||
}
|
||||
.dnf-btn.disabled {
|
||||
color: #666566;
|
||||
background:
|
||||
linear-gradient(180deg, #2c2c2c 0%, #272727 55%, #222 100%) padding-box,
|
||||
linear-gradient(180deg, #343434 0%, #262626 100%) border-box;
|
||||
}
|
||||
.dnf-btn.large {
|
||||
height: 44px;
|
||||
min-width: 168px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* CSS replica of the compact NinePatch family. State colors are derived from the base tone. */
|
||||
.dnf-btn.image,
|
||||
.dnf-btn.raster-tone {
|
||||
--button-top: var(--control-blue-top);
|
||||
--button-bottom: var(--control-blue-bottom);
|
||||
--button-edge-top: var(--control-edge-top);
|
||||
--button-edge-bottom: var(--control-edge-bottom);
|
||||
--button-state-top: var(--button-top);
|
||||
--button-state-bottom: var(--button-bottom);
|
||||
--button-state-edge-top: var(--button-edge-top);
|
||||
--button-state-edge-bottom: var(--button-edge-bottom);
|
||||
--button-hover-r: 10;
|
||||
--button-hover-g: 16;
|
||||
--button-hover-b: 33;
|
||||
height: 26px;
|
||||
min-width: 112px;
|
||||
padding: 0 10px;
|
||||
isolation:isolate;
|
||||
border:1px solid rgba(0,0,0,.6);
|
||||
border-radius: 0;
|
||||
background:transparent;
|
||||
box-shadow:none;
|
||||
}
|
||||
.dnf-btn.image::before,
|
||||
.dnf-btn.raster-tone::before {
|
||||
content:"";
|
||||
position:absolute;
|
||||
z-index:-1;
|
||||
inset:0;
|
||||
margin:1px;
|
||||
border:1px solid transparent;
|
||||
background:
|
||||
linear-gradient(180deg,var(--button-state-top),var(--button-state-bottom)) padding-box,
|
||||
linear-gradient(180deg,var(--button-state-edge-top),var(--button-state-edge-bottom)) border-box;
|
||||
box-shadow:inset 0 0 0 1px rgba(0,0,0,.12);
|
||||
pointer-events:none;
|
||||
}
|
||||
.dnf-btn.image.hover,
|
||||
.dnf-btn.raster-tone.normal:hover,
|
||||
.dnf-btn.raster-tone.hover {
|
||||
--button-state-top:rgb(from var(--button-top) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-bottom:rgb(from var(--button-bottom) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-edge-top:rgb(from var(--button-edge-top) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-edge-bottom:rgb(from var(--button-edge-bottom) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
}
|
||||
.dnf-btn.image.pressed,
|
||||
.dnf-btn.raster-tone.normal:active,
|
||||
.dnf-btn.raster-tone.pressed {
|
||||
--button-state-top:rgb(from var(--button-top) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-bottom:rgb(from var(--button-bottom) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-edge-top:rgb(from var(--button-edge-top) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
--button-state-edge-bottom:rgb(from var(--button-edge-bottom) calc(r + var(--button-hover-r)) calc(g + var(--button-hover-g)) calc(b + var(--button-hover-b)));
|
||||
transform:translateY(1px);
|
||||
}
|
||||
.dnf-btn.image.disabled,
|
||||
.dnf-btn.raster-tone.disabled {
|
||||
--button-state-top:var(--control-disabled-top);
|
||||
--button-state-bottom:var(--control-disabled-bottom);
|
||||
--button-state-edge-top:var(--control-disabled-edge-top);
|
||||
--button-state-edge-bottom:var(--control-disabled-edge-bottom);
|
||||
color:#666566;
|
||||
}
|
||||
.dnf-btn.raster-tone.tone-green {
|
||||
--button-top:var(--control-green-top);
|
||||
--button-bottom:var(--control-green-bottom);
|
||||
--button-hover-r:10;
|
||||
--button-hover-g:33;
|
||||
--button-hover-b:14;
|
||||
}
|
||||
.dnf-btn.raster-tone.tone-orange {
|
||||
--button-top:var(--control-orange-top);
|
||||
--button-bottom:var(--control-orange-bottom);
|
||||
--button-hover-r:33;
|
||||
--button-hover-g:22;
|
||||
--button-hover-b:10;
|
||||
}
|
||||
|
||||
.button-showcase-panel .panel-body { padding:10px 18px; }
|
||||
.button-state-grid { gap:4px 14px; }
|
||||
.button-state-grid .sample-cell { height:44px;padding:4px 12px;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:8px; }
|
||||
.button-state-grid .sample-label { margin:0; }
|
||||
.button-state-grid .button-implementation-label { min-height:44px;padding:5px 10px; }
|
||||
.button-showcase-panel .spec-row[style] { margin-top:8px!important; }
|
||||
|
||||
.button-implementation-label {
|
||||
min-height: 52px;
|
||||
padding: 8px 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
border-left: 2px solid var(--brass);
|
||||
background: #080908;
|
||||
color: var(--gold);
|
||||
font-size: 13px;
|
||||
}
|
||||
.button-implementation-label small {
|
||||
margin-top: 4px;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.dnf-btn:has(> .btn-icon),
|
||||
.dnf-btn:has(> .button-glyph) { padding-inline:30px; }
|
||||
.dnf-btn > .btn-icon,
|
||||
.dnf-btn > .button-glyph { position:absolute;left:10px;top:50%;transform:translateY(-50%); }
|
||||
.btn-icon { font: 18px/1 Georgia, serif; color: #e4c98f; }
|
||||
|
||||
.icon-btn {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #7a6238;
|
||||
background: linear-gradient(#2e4779, #1b2b4f);
|
||||
box-shadow: inset 0 0 0 1px #12203d, 0 0 0 3px #111317;
|
||||
color: #ddc47e;
|
||||
}
|
||||
|
||||
.icon-btn img, .pixel { image-rendering: pixelated; }
|
||||
|
Before Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 690 B |
|
Before Width: | Height: | Size: 981 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 975 B |
|
Before Width: | Height: | Size: 992 B |
@@ -1,64 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=1920, initial-scale=1">
|
||||
<base href="../../">
|
||||
<title>complex-dialog 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="preset">
|
||||
<div class="panel" style="height:660px;">
|
||||
<div class="panel-heading"><div class="panel-title">PresetManagementDialog / composition template</div><div class="spec-row"><span class="spec-chip captured">DEFAULT</span><span class="spec-chip captured">RENAMING</span><span class="spec-chip captured">SELECTED ROW ACTIONS</span><span class="spec-chip captured">SHOW ALL / SCROLLABLE</span></div></div>
|
||||
<div class="panel-body preset-stage">
|
||||
<div class="window preset-window">
|
||||
<div class="window-titlebar dnf-ui"><span class="title">管理设置</span><button type="button" class="dialog-icon-button dialog-close-button" aria-label="关闭管理设置" data-dialog-action="关闭请求已触发"><img class="close asset-2x" src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon_2x.img/6.PNG" alt=""></button></div>
|
||||
<div class="preset-body-shell dnf-ui">
|
||||
<div class="preset-intro dialog-content-well">※ 可以针对自己的游戏习惯作出选择,一次性变更多项设置。<br>※ 如果预设已满,请使用文件保存功能。</div>
|
||||
<div class="preset-main">
|
||||
<section class="preset-column preset-list-well">
|
||||
<div class="preset-section-head">我的游戏设置</div>
|
||||
<div class="preset-row selected"><img class="preset-radio asset-2x" src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon_2x.img/32.PNG"><span class="preset-name">西瓜°_07/31</span><span class="preset-row-actions"><button type="button" class="preset-row-action" aria-label="重命名预设" aria-pressed="false" data-preset-edit><img src="src-web/complex-dialog/img/sprite_interface2_option.NPK/option.img/88.PNG" alt=""></button><button type="button" class="preset-row-action" aria-label="移除预设" aria-pressed="false" data-preset-delete><img src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon.chn.img/42.PNG" alt=""></button></span></div>
|
||||
<div class="preset-row"><img class="preset-radio asset-2x" src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon_2x.img/30.PNG"><span>迪酱_07/31</span></div>
|
||||
<button type="button" class="preset-add" data-dialog-action="已创建一个演示预设"><img src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG" alt=""> 新建预设</button>
|
||||
<div class="preset-spacer"></div>
|
||||
<div class="preset-actions">
|
||||
<div class="btn-shell"><button type="button" class="dnf-btn normal" data-dialog-action="当前设置已保存"><img class="button-glyph" src="src-web/complex-dialog/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG" alt="">保存当前设置</button></div>
|
||||
<div class="btn-shell"><button type="button" class="dnf-btn normal" data-dialog-action="已打开设置文件选择">导入设置文件</button></div>
|
||||
<div class="btn-shell"><button type="button" class="dnf-btn normal" data-dialog-action="选定设置已导出">将选定设置保存为文件</button></div>
|
||||
<div class="preset-separator"></div>
|
||||
<div class="btn-shell"><button type="button" class="dnf-btn normal" data-dialog-action="已恢复默认设置">恢复默认设置</button></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="preset-column preset-diff-well">
|
||||
<div class="preset-section-head"><span>西瓜°_07/31</span><button type="button" class="show-all" aria-pressed="true" data-dialog-toggle><span class="checkbox-control is-checked"></span> 查看全部</button></div>
|
||||
<div class="preset-diff-scroll">
|
||||
<div class="preset-diff-list">
|
||||
<div class="preset-group-title">保存账号设置</div>
|
||||
<div class="diff-row"><span>装备信息对比</span><em>ON</em><b>→</b><strong>OFF</strong></div>
|
||||
<div class="preset-group-title">保存角色设置</div>
|
||||
<div class="diff-row"><span>光环效果</span><em>OFF</em><b>→</b><strong>ON</strong></div>
|
||||
<div class="diff-row"><span>角色技能效果透明</span><em>32%</em><b>→</b><strong>12%</strong></div>
|
||||
<div class="diff-row"><span>角色道具特效透明</span><em>16%</em><b>→</b><strong>13%</strong></div>
|
||||
<div class="preset-group-title">本地储存选项</div>
|
||||
<div class="diff-row muted"><span>画质提升</span><em>ON</em><b>→</b><strong>ON</strong></div>
|
||||
<div class="diff-row muted"><span>垂直同步</span><em>OFF</em><b>→</b><strong>OFF</strong></div>
|
||||
</div>
|
||||
<div class="scrollbar compact-scroll"><div class="scroll-arrow" aria-hidden="true"></div><div class="scroll-track"><div class="scroll-thumb" style="top:34px;height:82px"></div></div><div class="scroll-arrow" aria-hidden="true"></div></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="window-footer dialog-footer preset-footer"><div class="btn-shell back-action"><button type="button" class="dnf-btn normal dnf-ui" data-dialog-action="已返回上一层">返回</button></div><output class="dialog-status" aria-live="polite"></output><div class="footer-actions"><div class="btn-shell"><button type="button" class="dnf-btn normal dnf-ui" data-dialog-action="设置已应用">应用</button></div><div class="btn-shell"><button type="button" class="dnf-btn normal dnf-ui" data-dialog-action="关闭请求已触发">关闭</button></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,87 +0,0 @@
|
||||
/* Source module: complex-dialog.css */
|
||||
.preset-stage { height:calc(100% - 46px);padding:14px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.18); }
|
||||
.preset-window { width:1280px;height:574px;display:flex;flex-direction:column;background:rgba(4,5,5,.82); }
|
||||
.preset-window > .window-titlebar { flex:0 0 31px; }
|
||||
.preset-body-shell { flex:1;min-height:0;padding:9px;display:flex;flex-direction:column;gap:8px;background:rgba(4,5,5,.82); }
|
||||
.preset-intro { flex:0 0 68px;display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.45;color:#b7a467; }
|
||||
.preset-intro.dialog-content-well { min-height:68px; }
|
||||
.preset-main { flex:1;min-height:0;display:grid;grid-template-columns:.46fr .54fr;gap:10px; }
|
||||
.preset-column { min-width:0;min-height:0;display:flex;flex-direction:column;border:1px solid #30332f;background:#000; }
|
||||
.preset-section-head { flex:0 0 32px;padding:0 9px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #504329;background:#171916;color:#d2ba6f;font-size:13px; }
|
||||
.preset-row { flex:0 0 33px;padding:0 9px;display:grid;grid-template-columns:20px 1fr auto;align-items:center;border-bottom:1px solid #272823;background:#090a09;color:#a9965e; }
|
||||
.preset-row:nth-child(3) { background:#1d1e1c; }
|
||||
.preset-row.selected { color:#f1d46d;box-shadow:inset 0 0 0 1px #3d99d0;background:#07121b; }
|
||||
.preset-radio { width:14px;height:14px;image-rendering:auto; }
|
||||
.preset-row-actions { display:flex;gap:5px; }
|
||||
.preset-row-actions img { max-width:13px;max-height:13px;image-rendering:pixelated; }
|
||||
.preset-row-action { appearance:none;width:20px;height:20px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:0;background:none;cursor:pointer; }
|
||||
.preset-row-action img { filter:brightness(1);transform:translateY(0); }
|
||||
.preset-row-action:hover img,.preset-row-action:focus-visible img,.preset-row-action:active img,.preset-row-action[aria-pressed="true"] img { filter:brightness(1.28); }
|
||||
.preset-row-action:focus-visible { outline:1px solid rgba(225,204,135,.72);outline-offset:-2px; }
|
||||
.preset-row-action:active img { transform:translateY(1px); }
|
||||
.preset-row.is-renaming .preset-name { color:#fff0a5;text-decoration:underline;text-decoration-style:dotted;text-underline-offset:3px; }
|
||||
.preset-row.is-demo-deleted { opacity:.46; }
|
||||
.preset-row.is-demo-deleted .preset-name { text-decoration:line-through; }
|
||||
.preset-add { appearance:none;flex:0 0 35px;display:flex;align-items:center;justify-content:center;gap:6px;border:0;border-bottom:1px solid #242520;color:#d5b04c;background:#030403;font:inherit;cursor:pointer; }
|
||||
.preset-add:hover,.preset-add:focus-visible,.preset-add:active { color:#ffe28a;background:#11130f;outline:none; }
|
||||
.preset-add:active { transform:translateY(1px); }
|
||||
.preset-add img,.button-glyph { max-width:12px;max-height:12px;image-rendering:pixelated; }
|
||||
.preset-spacer { flex:1;background:#020302; }
|
||||
.preset-actions { flex:0 0 auto;padding:9px 0 8px;display:grid;gap:5px;justify-content:center;border-top:1px solid #292a26;background:#030403; }
|
||||
.preset-actions .btn-shell { padding:2px;border-radius:0; }
|
||||
.preset-actions .dnf-btn { width:270px;height:28px; }
|
||||
.preset-separator { height:1px;margin:3px -38px;background:#2b2d29; }
|
||||
.show-all { appearance:none;padding:2px 3px;display:flex;align-items:center;gap:5px;border:0;background:none;color:inherit;font:inherit;cursor:pointer; }
|
||||
.show-all:hover,.show-all:focus-visible,.show-all:active { color:#f1dc91;outline:none; }
|
||||
.show-all:active { transform:translateY(1px); }
|
||||
.show-all img { image-rendering:pixelated; }
|
||||
.preset-diff-scroll { flex:1;min-height:0;display:grid;grid-template-columns:1fr 15px;background:#020403; }
|
||||
.preset-diff-list { min-width:0;padding:4px 9px;overflow:hidden; }
|
||||
.preset-group-title { height:28px;display:flex;align-items:center;border-bottom:1px solid #26333a;color:#ba9d51;font-size:13px; }
|
||||
.diff-row { height:28px;display:grid;grid-template-columns:1fr 64px 28px 64px;align-items:center;border-bottom:1px solid #222c30;color:#b49f67; }
|
||||
.diff-row em { color:#777b77;font-style:normal;text-align:center; }
|
||||
.diff-row b { color:#747a76;font-weight:400;text-align:center; }
|
||||
.diff-row strong { color:var(--selected);font-weight:500;text-align:center; }
|
||||
.diff-row.muted strong { color:#888b84; }
|
||||
.compact-scroll { width:15px;height:100%; }
|
||||
.preset-footer { flex:0 0 42px;position:relative;justify-content:center; }
|
||||
.preset-footer .dialog-status { position:absolute;left:112px;max-width:270px;overflow:hidden;text-overflow:ellipsis; }
|
||||
.preset-footer .back-action { position:absolute;left:8px; }
|
||||
.footer-actions { display:flex;gap:8px; }
|
||||
.preset-footer .dnf-btn { min-width:78px; }
|
||||
|
||||
.anatomy {
|
||||
display:grid;
|
||||
grid-template-columns:120px 1fr;
|
||||
gap:18px;
|
||||
align-items:center;
|
||||
}
|
||||
.asset-tile { min-height:78px;display:flex;align-items:center;justify-content:center;background:#262726;border:1px dashed #5f5e58; }
|
||||
.asset-tile img { image-rendering:pixelated; }
|
||||
.anatomy-list { display:grid;gap:7px; }
|
||||
.anatomy-line { display:grid;grid-template-columns:76px 1fr;gap:9px;color:var(--text-3);font-size:11px; }
|
||||
.anatomy-line strong { color:var(--gold);font-weight:500; }
|
||||
|
||||
.slice-demo {
|
||||
position:relative;
|
||||
height:64px;
|
||||
border:5px solid transparent;
|
||||
border-radius:2px;
|
||||
background:
|
||||
linear-gradient(180deg, #1f355e 0%, #1d2f53 55%, #1a2849 100%) padding-box,
|
||||
linear-gradient(180deg, #684f2d 0%, #483423 100%) border-box;
|
||||
}
|
||||
.slice-demo .cut { position:absolute;top:-6px;bottom:-6px;width:1px;border-left:1px dashed var(--focus); }
|
||||
.slice-demo .cut.left { left:7px; }.slice-demo .cut.right { right:7px; }
|
||||
.slice-demo .slice-label { position:absolute;top:69px;color:var(--text-3);font-size:9px; }
|
||||
|
||||
.nine-grid { display:grid;grid-template-columns:22px 1fr 22px;grid-template-rows:22px 76px 22px;width:260px;height:120px; }
|
||||
.nine-grid > div { border:1px dashed rgba(75,167,211,.55);background:linear-gradient(#242b31,#0b0e10); }
|
||||
.nine-grid .center { background:linear-gradient(#15191c,#090a0b); }
|
||||
|
||||
.callout-list { margin:0;padding:0;list-style:none;display:grid;gap:9px;color:var(--text-2);font-size:12px; }
|
||||
.callout-list li { display:flex;align-items:flex-start;gap:8px; }
|
||||
.callout-list li::before { content:"";width:5px;height:5px;margin-top:6px;background:var(--selected);box-shadow:0 0 6px rgba(218,164,29,.4); }
|
||||
|
||||
.footer-note { position:absolute;left:46px;right:46px;bottom:20px;display:flex;justify-content:space-between;color:#767773;font-size:10px;letter-spacing:.4px; }
|
||||
.token-label { color:var(--text-3);font:10px/1.35 Consolas,monospace; }
|
||||
@@ -1,4 +0,0 @@
|
||||
(() => {
|
||||
window.componentRegistry ||= {};
|
||||
window.componentRegistry["src-web/data-section/index.html"] = {"showcase":"<div class=\"panel\">\n <div class=\"panel-heading\"><div class=\"panel-title\">DataSection</div><span class=\"spec-chip captured\">FAMILY C</span></div>\n <div class=\"panel-body\">\n <div class=\"data-section-stack\">\n <div class=\"disclosure dnf-ui\" data-disclosure>\n <button type=\"button\" class=\"disclosure-head\" aria-expanded=\"true\">\n <img src=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG\" data-expanded-icon=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG\" data-collapsed-icon=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG\" alt=\"\">\n <span>基本信息</span>\n <span class=\"disclosure-state\">已展开</span>\n </button>\n <div class=\"disclosure-body\">\n <div class=\"tree-row\"><span class=\"attribute-label-tone\" style=\"flex:1\">魔法暴击</span><span class=\"attribute-value-tone\">+113.5%</span></div>\n <div class=\"tree-row\"><span style=\"flex:1\">技能等级</span><span class=\"attribute-value-tone\">46</span></div>\n <div class=\"tree-row\"><span class=\"disabled-tone\" style=\"flex:1\">精神</span><span class=\"disabled-tone\">不可用</span></div>\n </div>\n </div>\n <div class=\"disclosure dnf-ui is-collapsed\" data-disclosure>\n <button type=\"button\" class=\"disclosure-head\" aria-expanded=\"false\">\n <img src=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG\" data-expanded-icon=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG\" data-collapsed-icon=\"src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG\" alt=\"\">\n <span>详细属性</span>\n <span class=\"disclosure-state\">未展开</span>\n </button>\n <div class=\"disclosure-body\" hidden>\n <div class=\"tree-row\"><span style=\"flex:1\">攻击强化</span><span class=\"attribute-value-tone\">+24.6%</span></div>\n <div class=\"tree-row\"><span style=\"flex:1\">技能范围</span><span class=\"attribute-value-tone\">+15%</span></div>\n </div>\n </div>\n </div>\n <div class=\"spec-row\" style=\"margin-top:12px\"><span class=\"spec-chip\">Expanded</span><span class=\"spec-chip\">Collapsed</span><span class=\"spec-chip\">Interactive</span><span class=\"spec-chip\">Data rows</span></div>\n </div>\n </div>"};
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 690 B |
|
Before Width: | Height: | Size: 555 B |
@@ -1,49 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=1920, initial-scale=1">
|
||||
<base href="../../">
|
||||
<title>data-section 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">DataSection</div><span class="spec-chip captured">FAMILY C</span></div>
|
||||
<div class="panel-body">
|
||||
<div class="data-section-stack">
|
||||
<div class="disclosure dnf-ui" data-disclosure>
|
||||
<button type="button" class="disclosure-head" aria-expanded="true">
|
||||
<img src="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG" data-expanded-icon="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG" data-collapsed-icon="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG" alt="">
|
||||
<span>基本信息</span>
|
||||
<span class="disclosure-state">已展开</span>
|
||||
</button>
|
||||
<div class="disclosure-body">
|
||||
<div class="tree-row"><span class="attribute-label-tone" style="flex:1">魔法暴击</span><span class="attribute-value-tone">+113.5%</span></div>
|
||||
<div class="tree-row"><span style="flex:1">技能等级</span><span class="attribute-value-tone">46</span></div>
|
||||
<div class="tree-row"><span class="disabled-tone" style="flex:1">精神</span><span class="disabled-tone">不可用</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="disclosure dnf-ui is-collapsed" data-disclosure>
|
||||
<button type="button" class="disclosure-head" aria-expanded="false">
|
||||
<img src="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG" data-expanded-icon="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/565.PNG" data-collapsed-icon="src-web/data-section/img/sprite_interface.NPK/windowcommon.chn.img/561.PNG" alt="">
|
||||
<span>详细属性</span>
|
||||
<span class="disclosure-state">未展开</span>
|
||||
</button>
|
||||
<div class="disclosure-body" hidden>
|
||||
<div class="tree-row"><span style="flex:1">攻击强化</span><span class="attribute-value-tone">+24.6%</span></div>
|
||||
<div class="tree-row"><span style="flex:1">技能范围</span><span class="attribute-value-tone">+15%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spec-row" style="margin-top:12px"><span class="spec-chip">Expanded</span><span class="spec-chip">Collapsed</span><span class="spec-chip">Interactive</span><span class="spec-chip">Data rows</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,21 +0,0 @@
|
||||
/* Source module: data-section.css */
|
||||
.disclosure {
|
||||
border: 1px solid #4b3d26;
|
||||
background: #070807;
|
||||
color: var(--gold);
|
||||
}
|
||||
.disclosure-head { min-height: 32px; padding: 0 9px; display:flex;align-items:center;gap:7px;background:linear-gradient(#2a2925,#10110f);border-bottom:1px solid #25221b; }
|
||||
.disclosure-head.focus { outline: 1px solid var(--focus); outline-offset: -2px; }
|
||||
.disclosure-body { padding: 7px 9px; }
|
||||
.tree-row { height: 25px; padding-left: calc(var(--depth,0) * 16px); display:flex;align-items:center;gap:6px;color:#c9bb7e;border-bottom:1px solid #24231f; }
|
||||
.tree-row.focus { outline:1px solid var(--focus); outline-offset:-2px;background:#07131b; }
|
||||
.tree-row.selected { color:#f1d667;background:#302711; }
|
||||
|
||||
.data-section-stack { display:flex;flex-direction:column;gap:7px; }
|
||||
.disclosure-head { width:100%;border:0;color:inherit;font:inherit;text-align:left;cursor:pointer; }
|
||||
.disclosure-head:focus-visible { outline:1px solid var(--selected);outline-offset:-2px; }
|
||||
.disclosure-head img { flex:0 0 auto;max-width:13px;max-height:13px;image-rendering:pixelated; }
|
||||
.disclosure-state { margin-left:auto;color:var(--text-3);font-size:10px; }
|
||||
.disclosure.is-collapsed .disclosure-head { border-bottom:0; }
|
||||
.disclosure.is-collapsed .disclosure-state { color:#857a57; }
|
||||
.disclosure-body[hidden] { display:none; }
|
||||
|
Before Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 990 B |
|
Before Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 992 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,98 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=1920, initial-scale=1">
|
||||
<base href="../../">
|
||||
<title>data-table 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="composition">
|
||||
<div class="panel">
|
||||
<div class="panel-heading"><div class="panel-title">DataTable / StatTable composition</div><div class="panel-note">Dense rows, semantic text, real raster icon slots</div></div>
|
||||
<div class="panel-body">
|
||||
<div class="table-toolbar dnf-ui"><span>Selection</span><button type="button" class="table-mode-button is-active" data-selection-theme="gold">Gold</button><button type="button" class="table-mode-button" data-selection-theme="blue">Blue</button></div>
|
||||
<div class="data-table data-table-core selection-gold dnf-ui" data-data-table data-sortable-table>
|
||||
<div class="table-row header"><div>图标</div><button type="button" class="sortable-header">名称<span class="sort-glyph">△</span></button><button type="button" class="sortable-header is-sorted" aria-sort="ascending">强化<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">状态<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">区域<span class="sort-glyph">△</span></button></div>
|
||||
<div class="table-row data-row is-selected" tabindex="0" data-selectable-row><div class="table-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/0.PNG"></div><div class="rare-text">魔剑共鸣核心</div><div>+12</div><div class="success">出售完成</div><div>湖北 4</div></div>
|
||||
<div class="table-row data-row" tabindex="0" data-selectable-row><div class="table-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/1.PNG"></div><div class="epic-text">史诗灵魂结晶</div><div>+10</div><div class="status">购买完成</div><div>跨区</div></div>
|
||||
<div class="table-row table-note-row"><div><strong>养猪</strong><span>备注:团队共享养成角色</span><span class="table-note-actions"><img src="src-web/data-table/img/sprite_interface2_option.NPK/option.img/88.PNG" alt="编辑"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/42.PNG" alt="删除"></span></div></div>
|
||||
<div class="table-row data-row" tabindex="0" data-selectable-row><div class="table-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/2.PNG"></div><div class="rare-text">稀有装备增幅券</div><div>+0</div><div class="danger">购买失败</div><div>西北 1</div></div>
|
||||
<div class="table-row data-row" tabindex="0" data-selectable-row><div class="table-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/3.PNG"></div><div class="epic-text">太初之光碎片</div><div>+13</div><div class="success">已完成</div><div>华东</div></div>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:12px"><div class="spec-row"><span class="spec-chip">Density = Compact · Default</span><span class="spec-chip">ContentState = Populated · Empty</span></div><div class="pager dnf-ui"><span class="pager-btn">◀</span><span>1 / 2</span><span class="pager-btn active">▶</span></div></div>
|
||||
<div class="divider"></div>
|
||||
<div class="sample-label">LinearProgress · milestones</div>
|
||||
<div class="progress" style="--value:68%"><div class="progress-fill"></div><i class="progress-marker" style="--left:25%"></i><i class="progress-marker" style="--left:68%"></i><i class="progress-marker" style="--left:90%"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="skill">
|
||||
<div class="panel skill-table-panel">
|
||||
<div class="panel-heading"><div class="panel-title">DataTable / SkillDamageDetail</div><div class="panel-note">No zebra striping · fixed summary · bottom utility row</div></div>
|
||||
<div class="panel-body">
|
||||
<div class="data-table skill-damage-table dnf-ui">
|
||||
<div class="skill-table-row header"><div>技能</div><div>使用次数</div><div>总伤害</div><div>平均伤害</div><div>伤害占比</div><div></div></div>
|
||||
<div class="skill-table-body">
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>1.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/0.PNG" alt="技能 1"></div><div>34</div><div>953,379,872,000</div><div>28,040,584,470</div><div>25.9%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>2.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/1.PNG" alt="技能 2"></div><div>1</div><div>615,930,416,128</div><div>615,930,416,128</div><div>16.7%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>3.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/2.PNG" alt="技能 3"></div><div>1</div><div>367,626,199,040</div><div>367,626,199,040</div><div>10.0%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>4.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/3.PNG" alt="技能 4"></div><div>1</div><div>335,615,315,968</div><div>335,615,315,968</div><div>9.1%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>5.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/4.PNG" alt="技能 5"></div><div>1</div><div>238,860,883,968</div><div>238,860,883,968</div><div>6.5%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>6.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/5.PNG" alt="技能 6"></div><div>10</div><div>164,943,300,413</div><div>16,494,330,041</div><div>4.5%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>7.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/6.PNG" alt="技能 7"></div><div>4</div><div>163,055,895,552</div><div>40,763,973,888</div><div>4.4%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>8.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/7.PNG" alt="技能 8"></div><div>2</div><div>155,930,977,504</div><div>77,965,488,752</div><div>4.2%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-row"><div class="skill-name-cell"><b>9.</b><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/8.PNG" alt="技能 9"></div><div>2</div><div>148,375,164,928</div><div>74,187,582,464</div><div>4.0%</div><button type="button" class="table-action-button" aria-label="查看技能详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
</div>
|
||||
<div class="skill-table-row skill-summary"><div>总和</div><div>—</div><div>3,678,555,852,653</div><div>—</div><div></div><button type="button" class="table-action-button" aria-label="查看总伤害详情"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon_2x.img/24.PNG" alt=""></button></div>
|
||||
<div class="skill-table-footer"><button type="button">使用设置</button></div>
|
||||
<div class="skill-table-scrollbar" aria-hidden="true"><div class="skill-scroll-arrow"></div><div class="skill-scroll-track"><div class="skill-scroll-thumb"></div></div><div class="skill-scroll-arrow"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="compact">
|
||||
<div class="panel compact-table-panel">
|
||||
<div class="panel-heading"><div class="panel-title">DataTable / CompactGradientRow</div><div class="panel-note">30px unified header · 20px row · square corners</div></div>
|
||||
<div class="panel-body">
|
||||
<div class="data-table compact-data-table dnf-ui" data-sortable-table>
|
||||
<div class="compact-table-row header"><button type="button" class="sortable-header">日期<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">大区名称<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">角色名<span class="sort-glyph">△</span></button></div>
|
||||
<div class="compact-table-body">
|
||||
<div class="compact-table-row"><div>07/31</div><div>跨五</div><div>绝唱</div></div>
|
||||
<div class="compact-table-row"><div>07/30</div><div>湖北 4</div><div>西瓜°</div></div>
|
||||
<div class="compact-table-row"><div>07/29</div><div>跨一</div><div>Mikiyla</div></div>
|
||||
<div class="compact-table-row"><div>07/28</div><div>华东</div><div>浅笑ツ</div></div>
|
||||
<div class="compact-table-row"><div>07/27</div><div>跨六</div><div>武神四月</div></div>
|
||||
<div class="compact-table-row"><div>07/26</div><div>湖北 4</div><div>蛋猪超人</div></div>
|
||||
</div>
|
||||
<div class="compact-table-scrollbar" aria-hidden="true"><div class="skill-scroll-arrow"></div><div class="skill-scroll-track"><div class="skill-scroll-thumb"></div></div><div class="skill-scroll-arrow"></div></div>
|
||||
</div>
|
||||
<div class="spec-row table-variant-spec"><span class="spec-chip">Density = Compact</span><span class="spec-chip">Radius = 0</span><span class="spec-chip">Gap = 5</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="item">
|
||||
<div class="panel item-table-panel">
|
||||
<div class="panel-heading"><div class="panel-title">DataTable / ItemRow</div><div class="panel-note">CSS 43 rest · 44 hover · 46 selected</div></div>
|
||||
<div class="panel-body">
|
||||
<div class="data-table item-data-table dnf-ui" data-sortable-table>
|
||||
<div class="item-table-row header"><button type="button" class="sortable-header">强化<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">锻造<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">名称<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">拍卖信息<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">状态<span class="sort-glyph">△</span></button><button type="button" class="sortable-header">大区 / 角色名<span class="sort-glyph">△</span></button></div>
|
||||
<div class="item-table-body">
|
||||
<div class="item-table-row" tabindex="0" data-selectable-row><i class="item-row-frame" aria-hidden="true"></i><div class="item-row-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/7.PNG"></div><div>+0</div><div>+0</div><div class="q-artifact">人造神 3 号纳波尔宝珠</div><div><button type="button" class="inspect-button"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="查看"></button></div><div class="status">购买完成</div><div>湖北 4<br>绝唱</div></div>
|
||||
<div class="item-table-row" tabindex="0" data-selectable-row><i class="item-row-frame" aria-hidden="true"></i><div class="item-row-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/8.PNG"></div><div>+0</div><div>+0</div><div class="q-epic">果味整夏收集箱宝珠自选</div><div><button type="button" class="inspect-button"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="查看"></button></div><div class="success">出售完成</div><div>湖北 4<br>绝唱</div></div>
|
||||
<div class="item-table-row is-selected" tabindex="0" data-selectable-row><i class="item-row-frame" aria-hidden="true"></i><div class="item-row-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/9.PNG"></div><div>+2</div><div>+0</div><div class="q-rare">魔法封印转换灵魂</div><div><button type="button" class="inspect-button"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="查看"></button></div><div class="status">购买完成</div><div>湖北 4<br>蛋猪超人</div></div>
|
||||
<div class="item-table-row" tabindex="0" data-selectable-row><i class="item-row-frame" aria-hidden="true"></i><div class="item-row-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/3.PNG"></div><div>+0</div><div>+0</div><div class="q-epic">史诗灵魂结晶</div><div><button type="button" class="inspect-button"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="查看"></button></div><div class="status">购买完成</div><div>湖北 4<br>蛋猪超人</div></div>
|
||||
<div class="item-table-row" tabindex="0" data-selectable-row><i class="item-row-frame" aria-hidden="true"></i><div class="item-row-icon"><img src="src-web/data-table/img/sprite_item.NPK/equipmentskill.img/4.PNG"></div><div>+0</div><div>+0</div><div class="q-epic">史诗灵魂结晶</div><div><button type="button" class="inspect-button"><img src="src-web/data-table/img/sprite_interface.NPK/windowcommon.chn.img/652.PNG" alt="查看"></button></div><div class="status">购买完成</div><div>湖北 4<br>蛋猪超人</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spec-row table-variant-spec"><span class="spec-chip captured">Rest / Hover / Selected = CSS</span><span class="spec-chip">Height = 38</span><span class="spec-chip">Header = Sortable</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
document.querySelectorAll('template').forEach((template) => document.body.append(template.content.cloneNode(true)));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,135 +0,0 @@
|
||||
/* Source module: data-table.css */
|
||||
.data-table { border:1px solid #4a3c26;border-radius:0;background:#030403;overflow:hidden; }
|
||||
.table-toolbar { height:26px;margin-bottom:6px;display:flex;align-items:center;justify-content:flex-end;gap:5px;color:var(--text-3);font-size:10px; }
|
||||
.table-mode-button { appearance:none;height:20px;padding:0 8px;border:1px solid #3c3b31;border-radius:0;background:#0c0d0c;color:#918967;font:10px/1 "DCalc",SimSun,sans-serif; }
|
||||
.table-mode-button.is-active { border-color:#806329;color:#e2c968;background:#1a160d; }
|
||||
|
||||
.sortable-header { appearance:none;min-width:0;height:100%;padding:0 9px;display:flex;align-items:center;justify-content:space-between;gap:7px;border-radius:0;color:#bc9e58;font:11px/1 "DCalc",SimSun,sans-serif;text-align:left;cursor:pointer; }
|
||||
.sortable-header:hover { --table-header-top:color-mix(in srgb,#352817 84%,#fff);--table-header-mid:color-mix(in srgb,#1b170d 88%,#fff); }
|
||||
.sortable-header:active,
|
||||
.sortable-header.is-pressed { --table-header-top:#211a10;--table-header-mid:#15130c;transform:translateY(1px); }
|
||||
.sortable-header.is-sorted { color:#bc9e58; }
|
||||
.sort-glyph { flex:0 0 auto;width:10px;color:currentColor;font-size:0;line-height:1;text-align:center; }
|
||||
.sort-glyph::before { content:"▼";font:10px/1 SimSun,"DCalc",serif; }
|
||||
|
||||
.sortable-header,
|
||||
.table-row.header > div,
|
||||
.skill-table-row.header > *,
|
||||
.compact-table-row.header > *,
|
||||
.item-table-row.header > * {
|
||||
--table-header-top:#352817;
|
||||
--table-header-mid:#1b170d;
|
||||
--table-header-bottom:#090a07;
|
||||
border:1px solid #070806;
|
||||
background:linear-gradient(180deg,var(--table-header-top) 0%,var(--table-header-mid) 48%,var(--table-header-bottom) 100%);
|
||||
box-shadow:inset 0 0 0 1px #4a3c26,inset 0 1px 0 #65502a;
|
||||
color:#bc9e58;
|
||||
}
|
||||
|
||||
.table-row { min-height:38px;display:grid;grid-template-columns:46px 1.8fr .7fr .8fr .7fr;align-items:center;border-bottom:1px solid #2c2b26;color:#d2c78f; }
|
||||
.table-row > div { min-width:0;padding:5px 9px;border-right:1px solid #292720;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
|
||||
.table-row.header { min-height:30px;height:30px;column-gap:1px;border-bottom:0;background:#030403;color:#bc9e58;font-size:11px; }
|
||||
.table-row.header > div { height:100%;display:flex;align-items:center; }
|
||||
.table-row.data-row { cursor:pointer; }
|
||||
.table-row.data-row:nth-of-type(odd) { background:#101210; }
|
||||
.data-table-core.selection-gold .data-row.is-selected { position:relative;background:linear-gradient(90deg,#352b11 0,#161207 60%,#090a08 100%);outline:1px solid #d6ad37;outline-offset:-1px;box-shadow:inset 0 0 0 1px #6d5218; }
|
||||
.data-table-core.selection-blue .data-row.is-selected { position:relative;background:linear-gradient(90deg,#132b43 0,#0b1824 58%,#070a0d 100%);outline:1px solid #3b91bd;outline-offset:-1px;box-shadow:inset 0 0 0 1px #174963; }
|
||||
.table-note-row { min-height:34px;display:block;background:linear-gradient(90deg,#17130b,#080908); }
|
||||
.table-note-row > div { height:34px;padding:0 10px;display:flex;align-items:center;gap:14px;border:0;color:#9e936d; }
|
||||
.table-note-row strong { color:#d7bc62;font-weight:400; }
|
||||
.table-note-row .table-note-actions { margin-left:auto;display:flex;gap:9px; }
|
||||
.table-note-row img { max-width:13px;max-height:13px;image-rendering:pixelated; }
|
||||
.table-row .status { color:var(--info); }.table-row .success { color:var(--success); }.table-row .danger { color:var(--danger); }
|
||||
.table-row .epic-text { color:var(--quality-epic); }.table-row .rare-text { color:var(--quality-artifact); }
|
||||
.table-icon { display:flex;align-items:center;justify-content:center; }.table-icon img { width:28px;height:28px;image-rendering:pixelated; }
|
||||
|
||||
.progress { position:relative;height:14px;background:#0a0b0a;border:1px solid #3c3425; }.progress-fill { height:100%;width:var(--value,50%);background:linear-gradient(#9abe23,#63820a);box-shadow:inset 0 0 0 1px #cce43c; }.progress-marker { position:absolute;top:-5px;width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid #d7bd61;left:var(--left,50%); }
|
||||
.badge-demo { display:flex;gap:18px;align-items:center; }.badge-anchor { position:relative;width:42px;height:42px;display:flex;align-items:center;justify-content:center;border:1px solid #48412f;background:#171817;border-radius:8px; }.badge-anchor > img:first-child { max-width:24px;max-height:24px;image-rendering:pixelated; }.alert-badge { position:absolute;right:-2px;top:-2px;width:12px;height:12px;image-rendering:pixelated; }.level-badge { width:42px;height:54px;display:flex;align-items:center;justify-content:center;border:1px solid #6b5432;background:linear-gradient(#22231f,#111210);color:#e3bf46;font-size:11px; }
|
||||
|
||||
.table-variant-board { display:grid;grid-template-rows:560px minmax(0,1fr);gap:18px; }
|
||||
.table-variant-grid { min-height:0; }.table-variant-grid > .panel { min-height:0; }.table-variant-grid .panel-body { height:calc(100% - 46px);display:flex;flex-direction:column; }.table-variant-spec { margin-top:auto;padding-top:10px; }
|
||||
.skill-damage-table { position:relative;height:472px;padding-right:15px;display:flex;flex-direction:column;border-color:#463820;background:#010201; }
|
||||
.skill-table-row { display:grid;grid-template-columns:.56fr 1fr 1fr 1fr .74fr 42px;align-items:center;color:#c6a659;font-size:13px;font-variant-numeric:tabular-nums; }
|
||||
.skill-table-row > * { min-width:0;padding:0 11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
|
||||
.skill-table-row.header { flex:0 0 30px;column-gap:1px;background:#030403;color:#bc9e58;font-size:14px;text-align:center; }
|
||||
.skill-table-row.header > * { height:30px;padding:0 6px;display:flex;align-items:center;justify-content:center; }
|
||||
.skill-table-row.header > :nth-child(5) { grid-column:5 / 7; }
|
||||
.skill-table-row.header > :nth-child(6) { display:none; }
|
||||
.skill-table-body { flex:0 0 360px;min-height:0;overflow:hidden;background:#010201; }
|
||||
.skill-table-body .skill-table-row { height:40px;border:0;background:#010201; }
|
||||
.skill-name-cell { display:grid!important;grid-template-columns:24px 36px;align-items:center;gap:5px;padding-left:8px!important; }
|
||||
.skill-name-cell b { color:#c7a557;font-weight:400;text-align:right; }
|
||||
.skill-name-cell img { width:34px;height:34px;image-rendering:pixelated;filter:sepia(.9) saturate(3.2) hue-rotate(350deg) brightness(1.08) contrast(1.04); }
|
||||
.table-action-button,.inspect-button {
|
||||
--action-top:#1261a4;
|
||||
--action-bottom:#071f3b;
|
||||
--action-edge-top:#5b472a;
|
||||
--action-edge-bottom:#5b472a;
|
||||
appearance:none;
|
||||
padding:0;
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
border:2px solid transparent;
|
||||
border-radius:0;
|
||||
background:
|
||||
linear-gradient(180deg,var(--action-top),var(--action-bottom)) padding-box,
|
||||
linear-gradient(180deg,var(--action-edge-top),var(--action-edge-bottom)) border-box;
|
||||
box-shadow:0 0 0 1px rgba(0,0,0,.3),inset 0 0 0 1px #0f0f0f;
|
||||
line-height:0;
|
||||
cursor:pointer;
|
||||
}
|
||||
.table-action-button:hover,.inspect-button:hover { --action-top:#1d9bdb;--action-bottom:#0b325e;--action-edge-top:#927243;--action-edge-bottom:#927243; }
|
||||
.table-action-button:active,.inspect-button:active { --action-top:#1d9bdb;--action-bottom:#0b325e;--action-edge-top:#927243;--action-edge-bottom:#927243;transform:translateY(1px); }
|
||||
.table-action-button:disabled,.inspect-button:disabled { --action-top:#5b5b5b;--action-bottom:#212121;--action-edge-top:#424242;--action-edge-bottom:#424242;cursor:default; }
|
||||
.table-action-button { width:28px;height:28px; }.table-action-button img { max-width:16px;max-height:16px;image-rendering:auto; }
|
||||
.skill-summary { flex:0 0 47px;border-top:1px solid #47463f;border-bottom:1px solid #383832;background:#010201;color:#c8a75d; }
|
||||
.skill-summary > :first-child { padding-left:28px;font-size:18px;font-weight:700; }
|
||||
.skill-table-footer { flex:0 0 34px;padding:0 10px;display:flex;align-items:center;border-bottom:1px solid #33342f;background:#010201; }
|
||||
.skill-table-footer button { appearance:none;height:28px;padding:0 15px 0 1px;border:0;border-right:1px solid #51514a;border-radius:0;background:none;color:#d1af62;font:700 17px/1 "DCalc",SimSun,sans-serif; }
|
||||
.skill-table-scrollbar { position:absolute;top:30px;right:0;bottom:81px;width:15px;display:grid;grid-template-rows:15px 1fr 15px;border-left:1px solid #2b2924;background:#050606; }
|
||||
.skill-scroll-arrow { display:flex;align-items:center;justify-content:center;border:1px solid #514229;background:linear-gradient(#24241f,#10110f); }
|
||||
.skill-scroll-arrow::before { content:"";width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:4px solid #a98b46;filter:drop-shadow(0 1px 0 #000); }
|
||||
.skill-scroll-arrow:last-child::before { border-bottom:0;border-top:4px solid #a98b46; }
|
||||
.skill-scroll-track { position:relative;background:linear-gradient(90deg,#080908,#151513,#070807); }
|
||||
.skill-scroll-thumb { position:absolute;left:2px;right:2px;top:8px;height:78px;border:1px solid #68532d;background:linear-gradient(90deg,#1b1d1c,#363530,#161817); }
|
||||
|
||||
.compact-data-table { position:relative;height:184px;padding:4px 18px 5px 5px;border:1px solid #4b3b2a;background:#020302;overflow:hidden; }
|
||||
.compact-table-row { height:20px;display:grid;grid-template-columns:.78fr .82fr 1.2fr;align-items:center;color:#c9bd84;font-size:11px; }
|
||||
.compact-table-row > * { min-width:0;padding:0 9px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
|
||||
.compact-table-row.header { height:30px;margin-bottom:5px;column-gap:1px; }
|
||||
.compact-table-body { display:flex;flex-direction:column;gap:5px; }
|
||||
.compact-table-body .compact-table-row { height:20px;border:1px solid #222522;border-radius:0;background:linear-gradient(180deg,#171917 0,#0d0f0e 42%,#070808 100%);box-shadow:inset 0 1px 0 #202220,inset 0 -1px 0 #050605; }
|
||||
.compact-table-scrollbar { position:absolute;top:4px;right:3px;bottom:5px;width:12px;display:grid;grid-template-rows:16px 1fr 16px;border-left:1px solid #20221f;background:#050606; }
|
||||
.compact-table-scrollbar .skill-scroll-arrow { border-color:#31342f;background:linear-gradient(#171917,#0b0c0b); }
|
||||
.compact-table-scrollbar .skill-scroll-arrow::before { border-left-width:3px;border-right-width:3px;border-bottom-width:4px;opacity:.72; }
|
||||
.compact-table-scrollbar .skill-scroll-arrow:last-child::before { border-bottom:0;border-top:4px solid #8b794d; }
|
||||
.compact-table-scrollbar .skill-scroll-thumb { top:8px;height:54px;border-color:#4b4433;background:linear-gradient(90deg,#111312,#2a2b27,#101211); }
|
||||
|
||||
/* DataTable ItemRow: 43 rest, 44 hover, 46 selected. */
|
||||
.item-data-table { border:0;background:transparent;overflow:visible; }
|
||||
.item-table-row { position:relative;min-height:38px;display:grid;grid-template-columns:34px 32px 50px minmax(90px,1.55fr) 76px .92fr 1.1fr;align-items:center;color:#cabd82;font-size:11px;isolation:isolate; }
|
||||
.item-table-row > *:not(.item-row-frame) { min-width:0;padding:0 7px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
|
||||
.item-table-row.header { min-height:30px;height:30px;margin-bottom:5px;column-gap:1px;grid-template-columns:66px 50px minmax(90px,1.55fr) 76px .92fr 1.1fr; }
|
||||
.item-table-body { display:flex;flex-direction:column;gap:4px; }
|
||||
.item-table-body .item-table-row {
|
||||
--dt-outer:rgba(0,0,0,.012);--dt-middle:#000;--dt-accent:rgba(43,43,43,.85);--dt-inner:rgba(18,18,18,.73);
|
||||
--dt-surface:linear-gradient(180deg,rgba(29,29,29,.7),rgba(13,13,13,.7));
|
||||
cursor:pointer;
|
||||
}
|
||||
.item-table-body .item-table-row:hover { --dt-outer:#000820;--dt-middle:#082068;--dt-accent:#1888b8;--dt-inner:#082040;--dt-surface:#000810; }
|
||||
.item-table-body .item-table-row.is-selected { --dt-outer:#201808;--dt-middle:#604818;--dt-accent:#e8a828;--dt-inner:#302008;--dt-surface:#100800; }
|
||||
.item-table-body .item-table-row::before,
|
||||
.item-table-body .item-table-row::after,
|
||||
.item-row-frame,
|
||||
.item-row-frame::before,
|
||||
.item-row-frame::after { content:"";position:absolute;pointer-events:none; }
|
||||
.item-table-body .item-table-row::before { z-index:-3;inset:0;background:var(--dt-outer);border-radius:4px; }
|
||||
.item-table-body .item-row-frame { z-index:-2;inset:1px;background:var(--dt-middle);border-radius:3px;clip-path:none;filter:none; }
|
||||
.item-table-body .item-row-frame::before { inset:1px;background:var(--dt-accent);border-radius:2px;clip-path:none; }
|
||||
.item-table-body .item-row-frame::after { inset:2px;background:var(--dt-inner);border-radius:1px;clip-path:none; }
|
||||
.item-table-body .item-table-row::after { z-index:-1;inset:4px;background:var(--dt-surface);border-radius:1px;clip-path:none;filter:none; }
|
||||
.item-row-icon { width:32px;height:34px;padding:0!important;display:flex;align-items:center;justify-content:center; }
|
||||
.item-row-icon img { max-width:26px;max-height:26px;image-rendering:pixelated; }
|
||||
.inspect-button { width:28px;height:24px; }
|
||||
.inspect-button img { max-width:16px;max-height:16px;image-rendering:pixelated; }
|
||||
|
Before Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 316 B |
|
Before Width: | Height: | Size: 433 B |
|
Before Width: | Height: | Size: 975 B |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 676 B |
|
Before Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |