aimeat 1.16.2 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.env.example +6 -1
- package/dist/locales/en.json +166 -4
- package/dist/locales/fi.json +166 -4
- package/dist/public/components/Card.js +17 -3
- package/dist/public/components/Collapsible.js +39 -0
- package/dist/public/components/CopyButton.js +55 -24
- package/dist/public/components/DataTable.js +57 -0
- package/dist/public/components/EmptyState.js +28 -0
- package/dist/public/components/KeyValueRow.js +37 -0
- package/dist/public/components/Modal.js +22 -5
- package/dist/public/components/Pagination.js +70 -0
- package/dist/public/components/SearchBar.js +44 -0
- package/dist/public/components/StatusDot.js +29 -0
- package/dist/public/components/TagList.js +53 -0
- package/dist/public/components/ToggleSwitch.js +28 -0
- package/dist/public/components/index.js +41 -1
- package/dist/public/css/components/tags.css +24 -0
- package/dist/public/css/style-testbed.css +135 -0
- package/dist/public/css/theme.css +556 -34
- package/dist/public/css/views/admin-agent-integration.css +2 -33
- package/dist/public/css/views/admin.css +730 -686
- package/dist/public/css/views/agents-detail.css +402 -14
- package/dist/public/css/views/help.css +2 -1
- package/dist/public/css/views/hobbies.css +53 -33
- package/dist/public/css/views/marketplace.css +73 -60
- package/dist/public/css/views/openclaw.css +12 -6
- package/dist/public/css/views/portal-classic.css +34 -26
- package/dist/public/css/views/portal-dev.css +41 -32
- package/dist/public/css/views/portal.css +14 -18
- package/dist/public/css/views/profile.css +252 -164
- package/dist/public/css/views/public-knowledge-viewer.css +18 -6
- package/dist/public/css/views/scheduler.css +100 -0
- package/dist/public/js/format.js +41 -0
- package/dist/public/js/services/agent-tasks.js +14 -1
- package/dist/public/js/services/generator-spec-validate.js +5 -1
- package/dist/public/js/services/schedules.js +53 -0
- package/dist/public/js/style-testbed.js +170 -0
- package/dist/public/js/theme.js +114 -0
- package/dist/public/spa.html +74 -16
- package/dist/public/style-testbed.html +420 -0
- package/dist/public/views/admin/agent-integration-tab.js +23 -38
- package/dist/public/views/admin/agent-tasks-tab.js +14 -21
- package/dist/public/views/admin/chat-instances-tab.js +1 -1
- package/dist/public/views/admin/config-tab.js +7 -2
- package/dist/public/views/admin/cortex-tab.js +20 -14
- package/dist/public/views/admin/csm-tab.js +22 -18
- package/dist/public/views/admin/directory-tab.js +3 -3
- package/dist/public/views/admin/email-tab.js +23 -28
- package/dist/public/views/admin/federation-tab.js +15 -5
- package/dist/public/views/admin/generator-debug-tab.js +10 -8
- package/dist/public/views/admin/genesis-tab.js +4 -4
- package/dist/public/views/admin/ghii-tab.js +3 -3
- package/dist/public/views/admin/knowledge-tab.js +15 -5
- package/dist/public/views/admin/matching-tab.js +3 -3
- package/dist/public/views/admin/memory-tab.js +16 -20
- package/dist/public/views/admin/msm-tab.js +30 -17
- package/dist/public/views/admin/overview-tab.js +7 -7
- package/dist/public/views/admin/packages-tab.js +10 -9
- package/dist/public/views/admin/portal-tab.js +14 -4
- package/dist/public/views/admin/prompts-tab.js +5 -5
- package/dist/public/views/admin/push-tab.js +15 -4
- package/dist/public/views/admin/realtime-tab.js +3 -3
- package/dist/public/views/admin/services-tab.js +18 -27
- package/dist/public/views/admin/shared.js +48 -58
- package/dist/public/views/admin/sharing-groups-tab.js +5 -10
- package/dist/public/views/admin/stats-tab.js +3 -3
- package/dist/public/views/guides.js +9 -13
- package/dist/public/views/help.js +3 -24
- package/dist/public/views/hobbies.js +47 -41
- package/dist/public/views/marketplace.js +42 -34
- package/dist/public/views/openclaw.js +0 -1
- package/dist/public/views/portal-classic.js +4 -15
- package/dist/public/views/portal-dev.js +28 -30
- package/dist/public/views/portal.js +16 -21
- package/dist/public/views/portfolio.js +11 -12
- package/dist/public/views/profile/access-tab.js +250 -1
- package/dist/public/views/profile/agents/agent-card.js +75 -4
- package/dist/public/views/profile/agents/tab-activity.js +15 -13
- package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
- package/dist/public/views/profile/agents/tab-integration.js +37 -60
- package/dist/public/views/profile/agents/tab-messages.js +10 -1
- package/dist/public/views/profile/agents/tab-quality.js +25 -19
- package/dist/public/views/profile/agents/tab-schedules.js +110 -0
- package/dist/public/views/profile/agents-activity-subtab.js +4 -4
- package/dist/public/views/profile/agents-services-subtab.js +5 -4
- package/dist/public/views/profile/agents-tab.js +141 -37
- package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
- package/dist/public/views/profile/calibrator-batch.js +5 -11
- package/dist/public/views/profile/calibrator-tab.js +4 -9
- package/dist/public/views/profile/chat-sessions-tab.js +9 -5
- package/dist/public/views/profile/email-tab.js +2 -2
- package/dist/public/views/profile/extensions-tab.js +27 -22
- package/dist/public/views/profile/federation-tab.js +4 -1
- package/dist/public/views/profile/foundry-detail.js +22 -23
- package/dist/public/views/profile/foundry-tab.js +12 -13
- package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
- package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
- package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
- package/dist/public/views/profile/generator-detail.js +26 -30
- package/dist/public/views/profile/generator-tab.js +5 -5
- package/dist/public/views/profile/knowledge-tab.js +12 -12
- package/dist/public/views/profile/landing-page.js +100 -149
- package/dist/public/views/profile/memory-tab.js +15 -11
- package/dist/public/views/profile/node-stats-tab.js +3 -3
- package/dist/public/views/profile/nodes-tab.js +10 -3
- package/dist/public/views/profile/notifications-tab.js +3 -3
- package/dist/public/views/profile/packages-tab.js +14 -14
- package/dist/public/views/profile/scheduler-tab.js +340 -0
- package/dist/public/views/profile/services-tab.js +1 -1
- package/dist/public/views/profile/shared.js +16 -12
- package/dist/public/views/profile/wallet-tab.js +27 -50
- package/dist/public/views/profile/work-tab.js +29 -31
- package/dist/public/views/profile.js +24 -0
- package/dist/public/views/public-knowledge-viewer.js +9 -18
- package/dist/src/auth/middleware.d.ts +3 -2
- package/dist/src/auth/middleware.d.ts.map +1 -1
- package/dist/src/auth/middleware.js +78 -3
- package/dist/src/auth/middleware.js.map +1 -1
- package/dist/src/cli/init-wizard.d.ts.map +1 -1
- package/dist/src/cli/init-wizard.js +13 -1
- package/dist/src/cli/init-wizard.js.map +1 -1
- package/dist/src/config.d.ts +6 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +12 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +708 -8
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/mcp/agent-schedules.d.ts +23 -0
- package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
- package/dist/src/mcp/agent-schedules.js +175 -0
- package/dist/src/mcp/agent-schedules.js.map +1 -0
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +6 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +55 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +12 -0
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +2 -0
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/models/agent-task-schemas.d.ts +6 -0
- package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-task-schemas.js +6 -0
- package/dist/src/models/agent-task-schemas.js.map +1 -1
- package/dist/src/models/schemas.d.ts +1 -0
- package/dist/src/models/schemas.d.ts.map +1 -1
- package/dist/src/models/schemas.js +4 -0
- package/dist/src/models/schemas.js.map +1 -1
- package/dist/src/routes/access-tokens.d.ts +17 -0
- package/dist/src/routes/access-tokens.d.ts.map +1 -0
- package/dist/src/routes/access-tokens.js +164 -0
- package/dist/src/routes/access-tokens.js.map +1 -0
- package/dist/src/routes/agent-tasks.d.ts +2 -0
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +118 -23
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/agents.d.ts.map +1 -1
- package/dist/src/routes/agents.js +46 -0
- package/dist/src/routes/agents.js.map +1 -1
- package/dist/src/routes/ai.d.ts +6 -9
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +26 -175
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +104 -34
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +77 -4
- package/dist/src/routes/auth.js.map +1 -1
- package/dist/src/routes/cortex.d.ts +2 -1
- package/dist/src/routes/cortex.d.ts.map +1 -1
- package/dist/src/routes/cortex.js +13 -8
- package/dist/src/routes/cortex.js.map +1 -1
- package/dist/src/routes/extensions.d.ts.map +1 -1
- package/dist/src/routes/extensions.js +85 -51
- package/dist/src/routes/extensions.js.map +1 -1
- package/dist/src/routes/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +109 -43
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/ghii.d.ts.map +1 -1
- package/dist/src/routes/ghii.js +34 -13
- package/dist/src/routes/ghii.js.map +1 -1
- package/dist/src/routes/libs.d.ts +15 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +178 -55
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +1 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/schedules.d.ts +33 -0
- package/dist/src/routes/schedules.d.ts.map +1 -0
- package/dist/src/routes/schedules.js +380 -0
- package/dist/src/routes/schedules.js.map +1 -0
- package/dist/src/server-bootstrap/config-init.js +2 -2
- package/dist/src/server-bootstrap/config-init.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +7 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +2 -1
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/access-token.d.ts +28 -0
- package/dist/src/services/access-token.d.ts.map +1 -0
- package/dist/src/services/access-token.js +37 -0
- package/dist/src/services/access-token.js.map +1 -0
- package/dist/src/services/ai-completion.d.ts +83 -0
- package/dist/src/services/ai-completion.d.ts.map +1 -0
- package/dist/src/services/ai-completion.js +187 -0
- package/dist/src/services/ai-completion.js.map +1 -0
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +3 -0
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
- package/dist/src/services/generator-prompt-seeds.js +6 -3
- package/dist/src/services/generator-prompt-seeds.js.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.js +6 -2
- package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
- package/dist/src/services/generator-registration.d.ts +12 -4
- package/dist/src/services/generator-registration.d.ts.map +1 -1
- package/dist/src/services/generator-registration.js +71 -0
- package/dist/src/services/generator-registration.js.map +1 -1
- package/dist/src/services/generator-validate.d.ts +10 -0
- package/dist/src/services/generator-validate.d.ts.map +1 -1
- package/dist/src/services/generator-validate.js +180 -36
- package/dist/src/services/generator-validate.js.map +1 -1
- package/dist/src/services/owner-session.d.ts +43 -0
- package/dist/src/services/owner-session.d.ts.map +1 -0
- package/dist/src/services/owner-session.js +175 -0
- package/dist/src/services/owner-session.js.map +1 -0
- package/dist/src/services/schedule-constraints.d.ts +65 -0
- package/dist/src/services/schedule-constraints.d.ts.map +1 -0
- package/dist/src/services/schedule-constraints.js +106 -0
- package/dist/src/services/schedule-constraints.js.map +1 -0
- package/dist/src/services/scheduler.d.ts +34 -0
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +266 -22
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +19 -0
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/storage/interface.d.ts +48 -4
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +187 -9
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +131 -8
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
- package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +79 -8
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
- package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/pat.repository.js +14 -0
- package/dist/src/storage/repositories/pat.repository.js.map +1 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.d.ts +51 -0
- package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.js +12 -0
- package/dist/src/storage/repositories/session.repository.js.map +1 -1
- package/dist/src/utils/env-config.d.ts.map +1 -1
- package/dist/src/utils/env-config.js +25 -1
- package/dist/src/utils/env-config.js.map +1 -1
- package/dist/src/utils/env-validator.d.ts.map +1 -1
- package/dist/src/utils/env-validator.js +4 -0
- package/dist/src/utils/env-validator.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +48 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file DataTable.js
|
|
7
|
+
* @description Canonical generic table primitive — renders a plain
|
|
8
|
+
* `<table class="data-table ${className}">` (optionally inside a `.scrollable`
|
|
9
|
+
* wrapper) backed by the shared `.data-table` block in theme.css, so the table
|
|
10
|
+
* look (header row, cell padding, borders, hover) is one tokenized source of
|
|
11
|
+
* truth that flips correctly in dark mode. Unlike the admin `DataTable` (which
|
|
12
|
+
* wraps this in an `.adm-card`), this component renders NO card/container — the
|
|
13
|
+
* caller supplies its own wrapper (`.card`, `.adm-card`, etc.).
|
|
14
|
+
* @structure DataTable({ headers, rows, scroll, className })
|
|
15
|
+
* - headers: array of column header cells (string or VNode)
|
|
16
|
+
* - rows: array of rows; each row is an array of cells. A cell may be:
|
|
17
|
+
* • a primitive/VNode → rendered as plain `<td>`
|
|
18
|
+
* • `{ text, mono?, title?, _html? }` → `<td class="mono"? title=...>`;
|
|
19
|
+
* when `_html: true`, `text` is rendered as raw HTML (see SECURITY).
|
|
20
|
+
* - scroll: when truthy, wraps the table in `<div class="scrollable">`
|
|
21
|
+
* - className: extra class(es) appended to `.data-table` (e.g. for column-width
|
|
22
|
+
* or per-view tweaks)
|
|
23
|
+
* @usage
|
|
24
|
+
* import { DataTable } from '/components/index.js';
|
|
25
|
+
* html`<div class="card"><${DataTable} headers=${['Key','Value']} rows=${rows} /></div>`
|
|
26
|
+
*
|
|
27
|
+
* SECURITY: When a cell object has `_html: true`, `cell.text` is rendered as raw
|
|
28
|
+
* HTML via dangerouslySetInnerHTML. Callers MUST ensure `cell.text` is sanitized
|
|
29
|
+
* (use escHtml() for any user-generated content). Only use `_html` for trusted,
|
|
30
|
+
* server-generated markup like badges.
|
|
31
|
+
*
|
|
32
|
+
* @version-history
|
|
33
|
+
* v1.0.0 — 2026-06-02 — Component unification (#13): created canonical generic
|
|
34
|
+
* DataTable (same _html/mono cell protocol as admin's), backing the shared
|
|
35
|
+
* .data-table CSS. The admin shared.js DataTable now wraps this in .adm-card.
|
|
36
|
+
*/
|
|
37
|
+
export function DataTable({ headers, rows, scroll, className }) {
|
|
38
|
+
const cls = `data-table${className ? ` ${className}` : ''}`;
|
|
39
|
+
const table = html`<table class=${cls}>
|
|
40
|
+
<thead><tr>${headers.map(hd => html`<th>${hd}</th>`)}</tr></thead>
|
|
41
|
+
<tbody>
|
|
42
|
+
${rows.map(row => html`<tr>
|
|
43
|
+
${row.map(cell => {
|
|
44
|
+
if (cell && typeof cell === 'object' && cell._html) {
|
|
45
|
+
return html`<td class=${cell.mono ? 'mono' : ''} title=${cell.title || ''}
|
|
46
|
+
dangerouslySetInnerHTML=${{ __html: cell.text }}></td>`;
|
|
47
|
+
}
|
|
48
|
+
if (cell && typeof cell === 'object' && cell.mono) {
|
|
49
|
+
return html`<td class="mono" title=${cell.title || ''}>${cell.text}</td>`;
|
|
50
|
+
}
|
|
51
|
+
return html`<td>${cell}</td>`;
|
|
52
|
+
})}
|
|
53
|
+
</tr>`)}
|
|
54
|
+
</tbody>
|
|
55
|
+
</table>`;
|
|
56
|
+
return scroll ? html`<div class="scrollable">${table}</div>` : table;
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file EmptyState.js
|
|
3
|
+
* @description Canonical empty-state placeholder — a centered muted message with an
|
|
4
|
+
* optional icon. Replaces the per-view clones (pf-empty / mk-empty / hb-empty /
|
|
5
|
+
* agd-empty / pkg-empty …) and the bare `<div class="empty">` scattered across the
|
|
6
|
+
* frontend. Renders the themed `.empty` class so it flips with dark/light mode.
|
|
7
|
+
* @structure EmptyState({ icon?, text, children? })
|
|
8
|
+
* @usage import { EmptyState } from '/components/EmptyState.js';
|
|
9
|
+
* html`<${EmptyState} text=${t('x.empty')} />`
|
|
10
|
+
* html`<${EmptyState} icon="🎯" text=${t('x.noMatches')} />`
|
|
11
|
+
* @version-history
|
|
12
|
+
* v1.0.0 — 2026-06-02 — Component unification (#9): single empty-state primitive
|
|
13
|
+
* (themed .empty + optional .empty-icon); admin Empty() delegates to it.
|
|
14
|
+
*/
|
|
15
|
+
import { h } from 'preact';
|
|
16
|
+
import htm from 'htm';
|
|
17
|
+
const html = htm.bind(h);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* EmptyState — centered muted placeholder.
|
|
21
|
+
* @param {{ icon?: string, text?: any, children?: any }} props
|
|
22
|
+
*/
|
|
23
|
+
export function EmptyState({ icon, text, children }) {
|
|
24
|
+
return html`<div class="empty">
|
|
25
|
+
${icon ? html`<span class="empty-icon">${icon}</span>` : ''}
|
|
26
|
+
${text != null ? text : children}
|
|
27
|
+
</div>`;
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file KeyValueRow.js
|
|
7
|
+
* @description Canonical key/value detail row — a label/value pair laid out as
|
|
8
|
+
* flex space-between with a muted label and an emphasized value, separated by
|
|
9
|
+
* a subtle bottom border. Backed by `.kv-row` / `.kv-label` / `.kv-value` in
|
|
10
|
+
* theme.css; all colors come from theme tokens so it flips correctly in dark
|
|
11
|
+
* mode. Consolidates the common label+value-pair shape (the admin .adm-erow /
|
|
12
|
+
* .adm-hrow and the profile .pf-agd-info-row families). The existing per-view
|
|
13
|
+
* classes are intentionally left in place where their look differs (admin rows
|
|
14
|
+
* are mono/bordered, the profile agent-detail rows are borderless) — use this
|
|
15
|
+
* for NEW detail lists rather than reinventing the markup.
|
|
16
|
+
* @structure KeyValueRow({ label, value, badge?, mono? }) — renders
|
|
17
|
+
* `<div class="kv-row"><span class="kv-label">${label}</span>
|
|
18
|
+
* <span class="kv-value[ mono]">${value | badge}</span></div>`.
|
|
19
|
+
* - `mono` — render the value in the monospace font (for ids, hashes, amounts).
|
|
20
|
+
* - `badge` — a semantic badge tone (success|warn|danger|info); when set, the
|
|
21
|
+
* value is wrapped in a `.badge badge-${badge}` chip instead of plain text.
|
|
22
|
+
* @usage
|
|
23
|
+
* import { KeyValueRow } from '/components/index.js';
|
|
24
|
+
* html`<${KeyValueRow} label=${t('field.id')} value=${id} mono />`
|
|
25
|
+
* html`<${KeyValueRow} label=${t('field.status')} value=${status} badge="success" />`
|
|
26
|
+
* @version-history
|
|
27
|
+
* v1.0.0 — 2026-06-02 — Component unification (#21): created canonical
|
|
28
|
+
* key/value detail row backed by .kv-row in theme.css.
|
|
29
|
+
*/
|
|
30
|
+
export function KeyValueRow({ label, value, badge, mono }) {
|
|
31
|
+
return html`<div class="kv-row">
|
|
32
|
+
<span class="kv-label">${label}</span>
|
|
33
|
+
<span class="kv-value${mono ? ' mono' : ''}">${
|
|
34
|
+
badge ? html`<span class="badge badge-${badge}">${value}</span>` : value
|
|
35
|
+
}</span>
|
|
36
|
+
</div>`;
|
|
37
|
+
}
|
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
* v1.0.0 — 2026-03-10 — Initial Modal component
|
|
12
12
|
* v1.1.0 — 2026-03-14 — Add ConfirmDialog with danger variant
|
|
13
13
|
* v1.2.0 — 2026-03-16 — Add useConfirm hook for easy confirm() replacement
|
|
14
|
+
* v1.3.0 — 2026-06-02 — Fix: memoise useConfirm's ConfirmUI (useCallback) so it
|
|
15
|
+
* keeps a stable component identity. Previously it was redefined every render,
|
|
16
|
+
* so any re-render of the host (e.g. the agents list polling) unmounted +
|
|
17
|
+
* remounted the open dialog, causing it to strobe/flicker.
|
|
18
|
+
* v1.4.0 — 2026-06-02 — Add optional `className` prop on Modal (applied to the
|
|
19
|
+
* .modal box) so views can pass width modifiers (e.g. scope-modal,
|
|
20
|
+
* ext-modal-narrow) when migrating their inline overlays to <Modal> (#2).
|
|
14
21
|
*/
|
|
15
22
|
import { h } from 'preact';
|
|
16
23
|
import { useState, useEffect, useCallback } from 'preact/hooks';
|
|
@@ -20,9 +27,10 @@ import { t } from '/js/i18n.js';
|
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
29
|
* Modal — overlay dialog with close on Escape and backdrop click.
|
|
23
|
-
* @param {{ open: boolean, onClose: () => void, title?: string, children: any }} props
|
|
30
|
+
* @param {{ open: boolean, onClose: () => void, title?: string, className?: string, children: any }} props
|
|
31
|
+
* - className: optional extra class on the .modal box (e.g. a width modifier)
|
|
24
32
|
*/
|
|
25
|
-
export function Modal({ open, onClose, title, children }) {
|
|
33
|
+
export function Modal({ open, onClose, title, className = '', children }) {
|
|
26
34
|
useEffect(() => {
|
|
27
35
|
if (!open) return;
|
|
28
36
|
const handler = (e) => { if (e.key === 'Escape') onClose(); };
|
|
@@ -37,7 +45,7 @@ export function Modal({ open, onClose, title, children }) {
|
|
|
37
45
|
if (!open) return null;
|
|
38
46
|
return html`
|
|
39
47
|
<div class="modal-overlay" onClick=${onBackdrop}>
|
|
40
|
-
<div class="modal">
|
|
48
|
+
<div class="modal ${className}">
|
|
41
49
|
<div class="modal-header">
|
|
42
50
|
${title && html`<h3>${title}</h3>`}
|
|
43
51
|
<button class="modal-close" onClick=${onClose}>✕</button>
|
|
@@ -103,7 +111,16 @@ export function useConfirm() {
|
|
|
103
111
|
|
|
104
112
|
const close = useCallback(() => setState(null), []);
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
// ConfirmUI MUST keep a stable identity across unrelated re-renders of the
|
|
115
|
+
// host component (e.g. the agents list polls every ~5-10s and refreshes on
|
|
116
|
+
// SSE live-updates while a delete confirm is open). When ConfirmUI was a plain
|
|
117
|
+
// function redefined on every render, Preact saw a new component *type* each
|
|
118
|
+
// time and unmounted+remounted the whole dialog — re-initialising its
|
|
119
|
+
// backdrop-filter overlay and making it strobe (appear/disappear rapidly
|
|
120
|
+
// during a burst of re-renders). Memoising on [state, close] means the
|
|
121
|
+
// reference only changes when the dialog actually opens/closes, so polling no
|
|
122
|
+
// longer remounts it.
|
|
123
|
+
const ConfirmUI = useCallback(() => {
|
|
107
124
|
if (!state) return null;
|
|
108
125
|
return html`<${ConfirmDialog}
|
|
109
126
|
open=${true}
|
|
@@ -115,7 +132,7 @@ export function useConfirm() {
|
|
|
115
132
|
cancelLabel=${state.cancelLabel}
|
|
116
133
|
danger=${state.danger}
|
|
117
134
|
/>`;
|
|
118
|
-
}
|
|
135
|
+
}, [state, close]);
|
|
119
136
|
|
|
120
137
|
return { confirm, ConfirmUI };
|
|
121
138
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file Pagination.js
|
|
7
|
+
* @description Canonical pagination primitives backed by `.pagination` /
|
|
8
|
+
* `.load-more` in theme.css. Consolidates the near-identical per-view
|
|
9
|
+
* prev/page/next clones (.adm-mem-pagination, and the prev/"Page X"/next
|
|
10
|
+
* shape of .mk-pagination) and the "Load more" button pattern. All colors
|
|
11
|
+
* come from theme tokens so both flip correctly in dark mode.
|
|
12
|
+
*
|
|
13
|
+
* Two exports:
|
|
14
|
+
* - `Pagination` — a prev / "Page X / Y" / next control (arrow buttons with a
|
|
15
|
+
* disabled state at the ends). Matches the existing admin pagination shape.
|
|
16
|
+
* Does NOT render numbered page buttons (the .hb-pagination numbered variant
|
|
17
|
+
* is intentionally left in place — different UI).
|
|
18
|
+
* - `LoadMore` — a centered "load more" button (themed `.load-more` wrapper +
|
|
19
|
+
* canonical `.btn-outline`), with an optional loading state.
|
|
20
|
+
* @structure
|
|
21
|
+
* Pagination({ page, totalPages, onPage, prevLabel?, nextLabel?, pageLabel? })
|
|
22
|
+
* — `page` is 1-based; `onPage(n)` fires with the requested page. Buttons
|
|
23
|
+
* auto-disable at the first/last page. `pageLabel` overrides the default
|
|
24
|
+
* "{page} / {totalPages}" middle text (pass a string or node).
|
|
25
|
+
* LoadMore({ onMore, loading?, label? })
|
|
26
|
+
* — renders a centered `.btn-outline`; disabled + shows `label` unchanged
|
|
27
|
+
* while `loading` is truthy (caller supplies any "loading…" text itself).
|
|
28
|
+
* @usage
|
|
29
|
+
* import { Pagination, LoadMore } from '/components/index.js';
|
|
30
|
+
* html`<${Pagination} page=${page} totalPages=${pages} onPage=${go}
|
|
31
|
+
* prevLabel=${t('common.prev')} nextLabel=${t('common.next')} />`
|
|
32
|
+
* html`<${LoadMore} onMore=${loadMore} loading=${loading}
|
|
33
|
+
* label=${t('pkv.loadMore')} />`
|
|
34
|
+
* @version-history
|
|
35
|
+
* v1.0.0 — 2026-06-02 — Component unification (#17): canonical Pagination +
|
|
36
|
+
* LoadMore, backed by .pagination / .load-more in theme.css.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Pagination — prev / "Page X / Y" / next control with arrow buttons.
|
|
41
|
+
* @param {{ page: number, totalPages: number, onPage: (n:number)=>void,
|
|
42
|
+
* prevLabel?: string, nextLabel?: string, pageLabel?: any }} props
|
|
43
|
+
*/
|
|
44
|
+
export function Pagination({ page, totalPages, onPage, prevLabel, nextLabel, pageLabel }) {
|
|
45
|
+
return html`<div class="pagination">
|
|
46
|
+
<button
|
|
47
|
+
class="btn-outline btn-sm"
|
|
48
|
+
disabled=${page <= 1}
|
|
49
|
+
onClick=${() => onPage(page - 1)}
|
|
50
|
+
>← ${prevLabel ?? 'Prev'}</button>
|
|
51
|
+
<span class="pagination-info">${pageLabel ?? html`${page} / ${totalPages}`}</span>
|
|
52
|
+
<button
|
|
53
|
+
class="btn-outline btn-sm"
|
|
54
|
+
disabled=${page >= totalPages}
|
|
55
|
+
onClick=${() => onPage(page + 1)}
|
|
56
|
+
>${nextLabel ?? 'Next'} →</button>
|
|
57
|
+
</div>`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* LoadMore — centered "load more" button.
|
|
62
|
+
* @param {{ onMore: ()=>void, loading?: boolean, label?: any }} props
|
|
63
|
+
*/
|
|
64
|
+
export function LoadMore({ onMore, loading, label }) {
|
|
65
|
+
return html`<div class="load-more">
|
|
66
|
+
<button class="btn-outline" disabled=${!!loading} onClick=${onMore}>
|
|
67
|
+
${label ?? 'Load more'}
|
|
68
|
+
</button>
|
|
69
|
+
</div>`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file SearchBar.js
|
|
7
|
+
* @description Canonical search-bar shell — a flex row wrapping a single
|
|
8
|
+
* `type="search"` input that reuses the canonical `.input-field` (theme.css)
|
|
9
|
+
* for its styling. Provides one place to define the search-toolbar layout so
|
|
10
|
+
* per-view hand-rolled search inputs (.pkv-search, .cap-search-input,
|
|
11
|
+
* .pf-agd-search-input, the profile .search-bar + .input-field combo) can
|
|
12
|
+
* converge. The shell layout lives in `.search-bar` / `.search-bar-input`
|
|
13
|
+
* (theme.css); all input visuals (border, focus ring, placeholder, dark-mode
|
|
14
|
+
* flip) come from `.input-field`, so colors are fully token-driven.
|
|
15
|
+
* @structure SearchBar({ value, onInput, placeholder?, onSubmit?, ariaLabel? }) —
|
|
16
|
+
* renders `<div class="search-bar"><input class="input-field search-bar-input"
|
|
17
|
+
* type="search" .../></div>`. When `onSubmit` is supplied, pressing Enter calls
|
|
18
|
+
* `onSubmit(currentValue)`.
|
|
19
|
+
* @usage
|
|
20
|
+
* import { SearchBar } from '/components/index.js';
|
|
21
|
+
* html`<${SearchBar} value=${q} onInput=${e => setQ(e.target.value)}
|
|
22
|
+
* placeholder=${t('common.search')} />`
|
|
23
|
+
* @version-history
|
|
24
|
+
* v1.0.0 — 2026-06-02 — Component unification (#24): created canonical
|
|
25
|
+
* search-bar shell backed by .search-bar / .search-bar-input in theme.css.
|
|
26
|
+
*/
|
|
27
|
+
export function SearchBar({ value, onInput, placeholder, onSubmit, ariaLabel }) {
|
|
28
|
+
const onKeyDown = onSubmit
|
|
29
|
+
? (e) => { if (e.key === 'Enter') onSubmit(e.target.value); }
|
|
30
|
+
: undefined;
|
|
31
|
+
return html`
|
|
32
|
+
<div class="search-bar">
|
|
33
|
+
<input
|
|
34
|
+
class="input-field search-bar-input"
|
|
35
|
+
type="search"
|
|
36
|
+
placeholder=${placeholder}
|
|
37
|
+
aria-label=${ariaLabel || placeholder}
|
|
38
|
+
value=${value}
|
|
39
|
+
onInput=${onInput}
|
|
40
|
+
onKeyDown=${onKeyDown}
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file StatusDot.js
|
|
7
|
+
* @description Canonical status-indicator dot — a small colored circle whose
|
|
8
|
+
* color is driven by a semantic status token (online/healthy → success,
|
|
9
|
+
* syncing/pending → warn, error/offline → danger, idle/muted → text-muted).
|
|
10
|
+
* Consolidates the per-view bespoke dots (.live-dot, .peer-dot, .pn-status-dot,
|
|
11
|
+
* .ext-status-dot, .dv-dot) into one component backed by `.status-dot` in
|
|
12
|
+
* theme.css. All colors come from theme tokens so the dot flips correctly in
|
|
13
|
+
* dark mode.
|
|
14
|
+
* @structure StatusDot({ status, title? }) — renders
|
|
15
|
+
* `<span class="status-dot status-dot--${status}" title=${title}></span>`.
|
|
16
|
+
* Recognized statuses: online, active, healthy, live (→ success);
|
|
17
|
+
* warn, syncing, pending (→ warn); error, offline, down (→ danger);
|
|
18
|
+
* idle, muted (→ text-muted). `live` additionally pulses.
|
|
19
|
+
* @usage
|
|
20
|
+
* import { StatusDot } from '/components/index.js';
|
|
21
|
+
* html`<${StatusDot} status="online" title=${t('...')} />`
|
|
22
|
+
* @version-history
|
|
23
|
+
* v1.0.0 — 2026-06-02 — Component unification (#11): created canonical
|
|
24
|
+
* status-dot, replacing .live-dot / .peer-dot / .pn-status-dot /
|
|
25
|
+
* .ext-status-dot / .dv-dot bespoke classes.
|
|
26
|
+
*/
|
|
27
|
+
export function StatusDot({ status, title }) {
|
|
28
|
+
return html`<span class="status-dot status-dot--${status}" title=${title}></span>`;
|
|
29
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { h } from 'preact';
|
|
2
|
+
import htm from 'htm';
|
|
3
|
+
const html = htm.bind(h);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file TagList.js
|
|
7
|
+
* @description Canonical tag/chip row — renders a flex row of tag chips using the
|
|
8
|
+
* shared `.tag-cloud` + `.tag-pill` classes from css/components/tags.css, with an
|
|
9
|
+
* optional `+N` overflow pill when the list exceeds `max`. Consolidates the many
|
|
10
|
+
* per-view bespoke tag clones (mk-tag, hb-tag, pkv-tag, pkg-tag, kpkg-tag,
|
|
11
|
+
* cap-tag, file-tag, etc.) into one component whose colors come entirely from
|
|
12
|
+
* theme tokens, so chips flip correctly in dark mode.
|
|
13
|
+
* @structure TagList({ tags, max?, prefix?, onTag? }) — renders
|
|
14
|
+
* `<div class="tag-cloud">` containing one `<span class="tag-pill">` per tag.
|
|
15
|
+
* - `tags` — array of strings (falsy/empty → renders nothing).
|
|
16
|
+
* - `max` — when set and `tags.length > max`, only the first `max` chips are
|
|
17
|
+
* shown followed by a `+N` overflow pill.
|
|
18
|
+
* - `prefix`— optional decorator wrapping each label (e.g. `'#'` → `#foo`).
|
|
19
|
+
* - `onTag` — optional click handler `(tag) => void`; when provided chips get a
|
|
20
|
+
* `tag-pill--clickable` flag and an onClick wiring.
|
|
21
|
+
* @usage
|
|
22
|
+
* import { TagList } from '/components/index.js';
|
|
23
|
+
* html`<${TagList} tags=${manifest.tags} max=${5} />`
|
|
24
|
+
* html`<${TagList} tags=${interests} onTag=${name => goTo('search', { interest: name })} />`
|
|
25
|
+
* @version-history
|
|
26
|
+
* v1.0.0 — 2026-06-02 — Component unification (#16): created canonical tag/chip
|
|
27
|
+
* list backed by .tag-pill / .tag-cloud, replacing scattered bespoke tag CSS
|
|
28
|
+
* clones and a +N overflow pattern.
|
|
29
|
+
*/
|
|
30
|
+
export function TagList({ tags, max, prefix = '', onTag }) {
|
|
31
|
+
const list = Array.isArray(tags) ? tags : [];
|
|
32
|
+
if (list.length === 0) return null;
|
|
33
|
+
|
|
34
|
+
const limited = typeof max === 'number' && list.length > max;
|
|
35
|
+
const shown = limited ? list.slice(0, max) : list;
|
|
36
|
+
const overflow = limited ? list.length - max : 0;
|
|
37
|
+
const clickable = typeof onTag === 'function';
|
|
38
|
+
|
|
39
|
+
const chipClass = clickable ? 'tag-pill tag-pill--clickable' : 'tag-pill';
|
|
40
|
+
|
|
41
|
+
return html`
|
|
42
|
+
<div class="tag-cloud">
|
|
43
|
+
${shown.map((tag) => html`
|
|
44
|
+
<span
|
|
45
|
+
key=${tag}
|
|
46
|
+
class=${chipClass}
|
|
47
|
+
onClick=${clickable ? () => onTag(tag) : undefined}
|
|
48
|
+
>${prefix}${tag}</span>
|
|
49
|
+
`)}
|
|
50
|
+
${overflow > 0 && html`<span class="tag-pill tag-pill--overflow">+${overflow}</span>`}
|
|
51
|
+
</div>
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ToggleSwitch.js
|
|
3
|
+
* @description Canonical on/off toggle switch (checkbox styled as a sliding pill).
|
|
4
|
+
* Relocated from profile/shared.js (where it was a mis-placed generic primitive)
|
|
5
|
+
* and de-`pf-`-prefixed. Renders the themed .toggle* classes so it flips with
|
|
6
|
+
* dark/light mode. profile/shared.js re-exports it for back-compat.
|
|
7
|
+
* @structure ToggleSwitch({ checked, onChange, label? })
|
|
8
|
+
* @usage import { ToggleSwitch } from '/components/ToggleSwitch.js';
|
|
9
|
+
* html`<${ToggleSwitch} checked=${on} onChange=${e => setOn(e.target.checked)} label=${t('x')} />`
|
|
10
|
+
* @version-history
|
|
11
|
+
* v1.0.0 — 2026-06-02 — Component unification (#14): promote the toggle to /components,
|
|
12
|
+
* tokenize the off-state track (#D1D5DB → var(--border)) for dark mode.
|
|
13
|
+
*/
|
|
14
|
+
import { h } from 'preact';
|
|
15
|
+
import htm from 'htm';
|
|
16
|
+
const html = htm.bind(h);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* ToggleSwitch — accessible checkbox rendered as a sliding pill.
|
|
20
|
+
* @param {{ checked: boolean, onChange: (e: Event) => void, label?: any }} props
|
|
21
|
+
*/
|
|
22
|
+
export function ToggleSwitch({ checked, onChange, label }) {
|
|
23
|
+
return html`<label class="toggle">
|
|
24
|
+
<input type="checkbox" checked=${checked} onChange=${onChange} class="toggle-input" />
|
|
25
|
+
<span class="toggle-slider"></span>
|
|
26
|
+
${label && html`<span class="toggle-label">${label}</span>`}
|
|
27
|
+
</label>`;
|
|
28
|
+
}
|
|
@@ -1,8 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.js
|
|
3
|
+
* @description Barrel re-export for the canonical design-system primitives in
|
|
4
|
+
* /components. Prefer importing shared primitives from here (e.g.
|
|
5
|
+
* `import { Modal, ConfirmDialog, Markdown } from '/components/index.js'`)
|
|
6
|
+
* over deep-importing the individual component files.
|
|
7
|
+
* @version-history
|
|
8
|
+
* v1.8.0 — 2026-06-02 — Component unification (#23): export Collapsible — the
|
|
9
|
+
* canonical expand/collapse (chevron) section consolidating the per-view
|
|
10
|
+
* .expand-btn + .pf-chevron / .scope-advanced-toggle / .pkv-entry-arrow toggles.
|
|
11
|
+
* v1.7.0 — 2026-06-02 — Component unification (#13): export DataTable — the
|
|
12
|
+
* canonical generic table primitive (plain `<table class="data-table">`,
|
|
13
|
+
* same _html/mono cell protocol as admin's, no card wrapper) backing the
|
|
14
|
+
* shared .data-table CSS. Admin's shared.js DataTable now wraps this.
|
|
15
|
+
* v1.6.0 — 2026-06-02 — Component unification (#24): export SearchBar — the
|
|
16
|
+
* canonical search-bar shell (`type="search"` input on `.input-field`),
|
|
17
|
+
* consolidating the per-view hand-rolled search inputs.
|
|
18
|
+
* v1.5.0 — 2026-06-02 — Component unification (#21): export KeyValueRow — the
|
|
19
|
+
* canonical label/value detail row backed by .kv-row in theme.css.
|
|
20
|
+
* v1.4.0 — 2026-06-02 — Component unification (#17): export Pagination + LoadMore
|
|
21
|
+
* (canonical prev/page/next control and centered load-more button).
|
|
22
|
+
* v1.3.0 — 2026-06-02 — Component unification (#16): export TagList — the
|
|
23
|
+
* canonical tag/chip row (with `+N` overflow) consolidating the per-view
|
|
24
|
+
* bespoke tag CSS clones.
|
|
25
|
+
* v1.2.0 — 2026-06-02 — Component unification (#11): export StatusDot — the
|
|
26
|
+
* canonical status-indicator dot consolidating the per-view bespoke dots.
|
|
27
|
+
* v1.1.0 — 2026-06-02 — Component unification (#28): export ConfirmDialog
|
|
28
|
+
* (from Modal.js) and Markdown + sanitizeHref (from Markdown.js), which
|
|
29
|
+
* were previously reachable only via deep import.
|
|
30
|
+
*/
|
|
1
31
|
export { Alert } from './Alert.js';
|
|
2
32
|
export { useToast } from './Toast.js';
|
|
3
33
|
export { Spinner } from './Spinner.js';
|
|
4
|
-
export {
|
|
34
|
+
export { EmptyState } from './EmptyState.js';
|
|
35
|
+
export { ToggleSwitch } from './ToggleSwitch.js';
|
|
36
|
+
export { Modal, ConfirmDialog, useConfirm } from './Modal.js';
|
|
5
37
|
export { CopyButton } from './CopyButton.js';
|
|
6
38
|
export { FormField } from './FormField.js';
|
|
7
39
|
export { Card } from './Card.js';
|
|
40
|
+
export { StatusDot } from './StatusDot.js';
|
|
41
|
+
export { TagList } from './TagList.js';
|
|
42
|
+
export { Pagination, LoadMore } from './Pagination.js';
|
|
43
|
+
export { KeyValueRow } from './KeyValueRow.js';
|
|
44
|
+
export { SearchBar } from './SearchBar.js';
|
|
45
|
+
export { DataTable } from './DataTable.js';
|
|
46
|
+
export { Collapsible } from './Collapsible.js';
|
|
47
|
+
export { Markdown, sanitizeHref } from './Markdown.js';
|
|
8
48
|
export { useViewCSS } from './useViewCSS.js';
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file tags.css
|
|
3
|
+
* @description Shared tag/chip styles — the canonical `.tag-pill` / `.tag-cloud` /
|
|
4
|
+
* `.tag-editor` classes backing the TagList component (/components/TagList.js).
|
|
5
|
+
* All colors come from theme tokens so chips flip correctly in dark mode.
|
|
6
|
+
* @structure .tag-cloud (flex row) · .tag-pill (chip, +active/clear/clickable/
|
|
7
|
+
* overflow modifiers) · .tag-editor (+pills/input) — the editable variant.
|
|
8
|
+
* @usage Loaded via useViewCSS / view <link>; rendered by /components/TagList.js.
|
|
9
|
+
* @version-history
|
|
10
|
+
* v1.1.0 — 2026-06-02 — Component unification (#16): add layout-only
|
|
11
|
+
* .tag-pill--clickable / .tag-pill--overflow flags for TagList; add file
|
|
12
|
+
* header. No color changes.
|
|
13
|
+
* v1.0.0 — initial shared tag component styles.
|
|
14
|
+
*/
|
|
15
|
+
|
|
1
16
|
/* ── Shared Tag Components ── */
|
|
2
17
|
|
|
3
18
|
.tag-cloud {
|
|
@@ -29,6 +44,15 @@
|
|
|
29
44
|
border-color: var(--accent, #E8564A);
|
|
30
45
|
}
|
|
31
46
|
|
|
47
|
+
/* Layout-only modifiers — no color change vs. base .tag-pill. */
|
|
48
|
+
.tag-pill--clickable {
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.tag-pill--overflow {
|
|
53
|
+
cursor: default;
|
|
54
|
+
}
|
|
55
|
+
|
|
32
56
|
.tag-clear {
|
|
33
57
|
color: var(--text-dim, #6B7280);
|
|
34
58
|
font-style: italic;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @file style-testbed.css
|
|
3
|
+
* @description Layout/chrome for the dev style-decision testbed
|
|
4
|
+
* (style-testbed.html). All page chrome uses theme.css tokens so it flips
|
|
5
|
+
* with the light/dark toggle. The .stb-* prefix avoids colliding with the
|
|
6
|
+
* real component classes being showcased. Critically, .stb-specimens.pf /
|
|
7
|
+
* .stb-specimens.adm RESET the profile/admin container layout (max-width,
|
|
8
|
+
* margin, padding) so those wrappers act purely as selector scopes for the
|
|
9
|
+
* clone overrides without imposing their page-container geometry.
|
|
10
|
+
* @version-history
|
|
11
|
+
* v1.0.0 — 2026-06-02 — Initial testbed layout
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.stb {
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0 0 280px; /* leave room for the sticky output bar */
|
|
17
|
+
background: var(--bg);
|
|
18
|
+
color: var(--text);
|
|
19
|
+
font-family: var(--font, system-ui, sans-serif);
|
|
20
|
+
font-size: 0.9rem;
|
|
21
|
+
line-height: 1.45;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ── Header ── */
|
|
25
|
+
.stb-header {
|
|
26
|
+
padding: 1.25rem 1.5rem;
|
|
27
|
+
border-bottom: 1px solid var(--border);
|
|
28
|
+
background: var(--bg-card);
|
|
29
|
+
}
|
|
30
|
+
.stb-header-row {
|
|
31
|
+
display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
|
|
32
|
+
}
|
|
33
|
+
.stb-title { font-size: 1.25rem; font-weight: 800; margin: 0; }
|
|
34
|
+
.stb-controls { display: flex; align-items: center; gap: 0.5rem; }
|
|
35
|
+
.stb-theme-label { color: var(--text-dim); font-size: 0.8rem; }
|
|
36
|
+
.stb-theme-btn {
|
|
37
|
+
padding: 6px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
38
|
+
background: var(--bg); color: var(--text); cursor: pointer; font-size: 0.82rem;
|
|
39
|
+
}
|
|
40
|
+
.stb-theme-btn.stb-active { border-color: var(--accent); color: var(--accent); font-weight: 600; }
|
|
41
|
+
.stb-intro { max-width: 1100px; margin: 0.75rem 0 0; color: var(--text); }
|
|
42
|
+
.stb-intro.stb-muted { color: var(--text-dim); font-size: 0.82rem; }
|
|
43
|
+
.stb code { font-family: var(--font-mono, monospace); font-size: 0.85em; background: var(--bg-dim); padding: 1px 5px; border-radius: 4px; }
|
|
44
|
+
|
|
45
|
+
/* ── Families ── */
|
|
46
|
+
.stb-main { padding: 0 1.5rem; }
|
|
47
|
+
.stb-family { padding: 1.5rem 0; border-bottom: 1px dashed var(--border); }
|
|
48
|
+
.stb-fam-title { font-size: 1.05rem; font-weight: 700; margin: 0 0 0.25rem; }
|
|
49
|
+
.stb-fam-desc { color: var(--text-dim); margin: 0 0 1rem; max-width: 1100px; font-size: 0.84rem; }
|
|
50
|
+
|
|
51
|
+
/* ── Variant cards (canonical + each clone) ── */
|
|
52
|
+
.stb-variant-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: stretch; }
|
|
53
|
+
.stb-variant {
|
|
54
|
+
flex: 1 1 280px; min-width: 260px; max-width: 360px;
|
|
55
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
56
|
+
background: var(--bg-card); padding: 12px; display: flex; flex-direction: column; gap: 8px;
|
|
57
|
+
}
|
|
58
|
+
.stb-variant-row-stats .stb-variant { max-width: 300px; }
|
|
59
|
+
.stb-canonical { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
|
|
60
|
+
.stb-dead { opacity: 0.92; border-style: dashed; }
|
|
61
|
+
|
|
62
|
+
.stb-variant-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-height: 22px; }
|
|
63
|
+
.stb-vname { font-size: 0.78rem; font-weight: 600; }
|
|
64
|
+
.stb-tag {
|
|
65
|
+
font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
|
|
66
|
+
padding: 1px 6px; border-radius: 10px; background: var(--bg-dim); color: var(--text-dim);
|
|
67
|
+
border: 1px solid var(--border); white-space: nowrap;
|
|
68
|
+
}
|
|
69
|
+
.stb-ref { background: var(--accent-subtle, var(--bg-dim)); color: var(--accent); border-color: var(--accent); }
|
|
70
|
+
.stb-warn { background: var(--warn-bg, var(--bg-dim)); color: var(--warn-fg, var(--text)); border-color: var(--warn-border, var(--border)); }
|
|
71
|
+
.stb-dead-tag { background: var(--danger-bg, var(--bg-dim)); color: var(--danger-fg, var(--text)); border-color: var(--danger-border, var(--border)); }
|
|
72
|
+
.stb-admin-tag { background: var(--bg-dim); color: var(--text-dim); }
|
|
73
|
+
|
|
74
|
+
/* Specimen containers */
|
|
75
|
+
.stb-specimens {
|
|
76
|
+
display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
|
|
77
|
+
padding: 10px; border-radius: var(--radius-sm); background: var(--bg);
|
|
78
|
+
border: 1px dashed var(--border); min-height: 48px;
|
|
79
|
+
}
|
|
80
|
+
.stb-specimens-col { flex-direction: column; align-items: stretch; }
|
|
81
|
+
.stb-specimens-relative { position: relative; }
|
|
82
|
+
.stb-mini-note { font-size: 0.7rem; color: var(--text-dim); }
|
|
83
|
+
|
|
84
|
+
/* SCOPE RESET — keep .pf/.adm as selector scopes, drop their page-container layout */
|
|
85
|
+
.stb-specimens.pf,
|
|
86
|
+
.stb-specimens.adm {
|
|
87
|
+
max-width: none !important;
|
|
88
|
+
margin: 0 !important;
|
|
89
|
+
padding: 10px !important;
|
|
90
|
+
position: static !important;
|
|
91
|
+
z-index: auto !important;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.stb-diff { font-size: 0.72rem; color: var(--text-dim); margin: 0; }
|
|
95
|
+
.stb-map { font-size: 0.72rem; color: var(--text); margin: 0; opacity: 0.9; }
|
|
96
|
+
.stb-map code { font-size: 0.92em; }
|
|
97
|
+
.stb-map.stb-map-warn { color: var(--warn-fg, var(--accent)); }
|
|
98
|
+
|
|
99
|
+
/* Decision select (injected by JS into .stb-decide-wrap) */
|
|
100
|
+
.stb-decide-wrap { margin-top: auto; }
|
|
101
|
+
.stb-decide {
|
|
102
|
+
width: 100%; padding: 6px 8px; font-size: 0.78rem;
|
|
103
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
104
|
+
background: var(--bg); color: var(--text); cursor: pointer;
|
|
105
|
+
}
|
|
106
|
+
.stb-decide.stb-chosen { border-color: var(--accent); font-weight: 600; }
|
|
107
|
+
|
|
108
|
+
/* Family note */
|
|
109
|
+
.stb-note-wrap { display: block; margin-top: 12px; font-size: 0.8rem; color: var(--text-dim); }
|
|
110
|
+
.stb-note {
|
|
111
|
+
width: 100%; max-width: 700px; margin-top: 4px; padding: 7px 10px; font-size: 0.82rem;
|
|
112
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
113
|
+
background: var(--bg); color: var(--text); display: block;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ── Sticky output bar ── */
|
|
117
|
+
.stb-output-bar {
|
|
118
|
+
position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
|
|
119
|
+
background: var(--bg-card); border-top: 2px solid var(--accent);
|
|
120
|
+
padding: 10px 1.5rem 12px; box-shadow: 0 -6px 20px rgba(0,0,0,0.18);
|
|
121
|
+
}
|
|
122
|
+
.stb-output-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
|
123
|
+
.stb-output-title { font-size: 0.85rem; font-weight: 700; }
|
|
124
|
+
.stb-output-count { color: var(--text-dim); font-weight: 500; font-size: 0.78rem; }
|
|
125
|
+
.stb-copy-btn {
|
|
126
|
+
padding: 6px 14px; border: none; border-radius: var(--radius-sm);
|
|
127
|
+
background: var(--accent); color: var(--on-inverted, #fff); cursor: pointer; font-size: 0.8rem; font-weight: 600;
|
|
128
|
+
}
|
|
129
|
+
.stb-copy-btn.stb-copied { background: var(--success-fg, #16a34a); }
|
|
130
|
+
.stb-output {
|
|
131
|
+
width: 100%; box-sizing: border-box; resize: vertical;
|
|
132
|
+
font-family: var(--font-mono, monospace); font-size: 0.78rem; line-height: 1.4;
|
|
133
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
134
|
+
background: var(--bg); color: var(--text); padding: 8px 10px;
|
|
135
|
+
}
|