mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 12:55:16 -07:00
feat(settings): move restart badge inline with option title
- Remove field-meta row (config path, advanced chip) from option rows - Inline live/restart status badge beside each option label - Extract getFieldTitleBadges into settings-field-layout module with tests
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import type { ConfigSettingsField } from '../types/settings';
|
||||
import { getFieldTitleBadges } from './settings-field-layout';
|
||||
|
||||
const advancedRestartField: ConfigSettingsField = {
|
||||
id: 'ankiConnect.knownWords.highlightEnabled',
|
||||
label: 'Enabled',
|
||||
description: 'Enable fast local highlighting for words already known in Anki.',
|
||||
configPath: 'ankiConnect.knownWords.highlightEnabled',
|
||||
category: 'mining-anki',
|
||||
section: 'Known Words',
|
||||
control: 'boolean',
|
||||
defaultValue: false,
|
||||
restartBehavior: 'restart',
|
||||
advanced: true,
|
||||
};
|
||||
|
||||
test('field title badges show restart status without config paths or advanced labels', () => {
|
||||
const badges = getFieldTitleBadges(advancedRestartField);
|
||||
|
||||
assert.deepEqual(badges, [
|
||||
{
|
||||
className: 'restart-chip restart',
|
||||
text: 'Restart',
|
||||
},
|
||||
]);
|
||||
assert.equal(JSON.stringify(badges).includes(advancedRestartField.configPath), false);
|
||||
assert.equal(JSON.stringify(badges).includes('Advanced'), false);
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { ConfigSettingsField } from '../types/settings';
|
||||
|
||||
export interface FieldTitleBadge {
|
||||
className: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function getFieldTitleBadges(field: ConfigSettingsField): FieldTitleBadge[] {
|
||||
return [
|
||||
{
|
||||
className: `restart-chip ${field.restartBehavior}`,
|
||||
text: field.restartBehavior === 'hot-reload' ? 'Live' : 'Restart',
|
||||
},
|
||||
];
|
||||
}
|
||||
+10
-20
@@ -20,6 +20,7 @@ import {
|
||||
setDraftValue,
|
||||
type SettingsDraft,
|
||||
} from './settings-model';
|
||||
import { getFieldTitleBadges } from './settings-field-layout';
|
||||
import { getSubtitleCssManagedConfigPaths, getSubtitleCssScopeForPath } from './subtitle-style-css';
|
||||
|
||||
declare global {
|
||||
@@ -112,24 +113,6 @@ function createElement<K extends keyof HTMLElementTagNameMap>(
|
||||
return element;
|
||||
}
|
||||
|
||||
function createFieldMeta(field: ConfigSettingsField): HTMLElement {
|
||||
const meta = createElement('div', 'field-meta');
|
||||
const path = createElement('code');
|
||||
path.textContent = field.configPath;
|
||||
meta.append(path);
|
||||
|
||||
const restart = createElement('span', `restart-chip ${field.restartBehavior}`);
|
||||
restart.textContent = field.restartBehavior === 'hot-reload' ? 'Live' : 'Restart';
|
||||
meta.append(restart);
|
||||
|
||||
if (field.advanced) {
|
||||
const advanced = createElement('span', 'advanced-chip');
|
||||
advanced.textContent = 'Advanced';
|
||||
meta.append(advanced);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
function valueForField(field: ConfigSettingsField): ConfigSettingsSnapshotValue {
|
||||
if (!state.draft) {
|
||||
return field.defaultValue;
|
||||
@@ -221,10 +204,17 @@ function renderField(field: ConfigSettingsField): HTMLElement {
|
||||
const row = createElement('article', 'field-row');
|
||||
const header = createElement('div', 'field-copy');
|
||||
const label = createElement('h3');
|
||||
label.textContent = field.label;
|
||||
const labelText = createElement('span', 'field-title-text');
|
||||
labelText.textContent = field.label;
|
||||
label.append(labelText);
|
||||
for (const badge of getFieldTitleBadges(field)) {
|
||||
const badgeEl = createElement('span', badge.className);
|
||||
badgeEl.textContent = badge.text;
|
||||
label.append(badgeEl);
|
||||
}
|
||||
const description = createElement('p');
|
||||
description.textContent = field.description;
|
||||
header.append(label, description, createFieldMeta(field));
|
||||
header.append(label, description);
|
||||
|
||||
const controlWrap = createElement('div', 'field-control');
|
||||
controlWrap.append(
|
||||
|
||||
+11
-15
@@ -546,6 +546,10 @@ code {
|
||||
}
|
||||
|
||||
.field-copy h3 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0 0 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
@@ -553,6 +557,10 @@ code {
|
||||
letter-spacing: -0.005em;
|
||||
}
|
||||
|
||||
.field-title-text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.field-copy p {
|
||||
max-width: 640px;
|
||||
margin: 0;
|
||||
@@ -561,16 +569,10 @@ code {
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.field-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.restart-chip {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.restart-chip,
|
||||
.advanced-chip {
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
@@ -594,12 +596,6 @@ code {
|
||||
color: var(--ctp-peach);
|
||||
}
|
||||
|
||||
.advanced-chip {
|
||||
border-color: rgba(198, 160, 246, 0.4);
|
||||
background: rgba(198, 160, 246, 0.1);
|
||||
color: var(--ctp-mauve);
|
||||
}
|
||||
|
||||
.field-control {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
Reference in New Issue
Block a user