@xpert-ai/plugin-live-dashboard 0.3.1 → 0.4.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/.xpertai-plugin/plugin.json +10 -2
- package/README.md +6 -0
- package/assets/branding/cover-v1.prompt.txt +27 -0
- package/assets/branding/cover-v1.webp +0 -0
- package/assets/previews/customer-brief.png +0 -0
- package/assets/previews/profit-atlas.png +0 -0
- package/assets/previews/trend-workspace.png +0 -0
- package/dist/index.js +6 -3
- package/dist/lib/agent.schema.d.ts +43 -37
- package/dist/lib/agent.schema.js +2 -1
- package/dist/lib/app-config.d.ts +62 -0
- package/dist/lib/app-config.js +38 -0
- package/dist/lib/artifact-type.provider.d.ts +15 -0
- package/dist/lib/artifact-type.provider.js +78 -0
- package/dist/lib/assistant-template.d.ts +1 -2
- package/dist/lib/assistant-template.js +3 -52
- package/dist/lib/content.provider.js +13 -5
- package/dist/lib/dashboard-navigation.d.ts +58 -14
- package/dist/lib/dashboard-navigation.js +11 -10
- package/dist/lib/dashboard-view.schema.d.ts +197 -46
- package/dist/lib/dashboard-view.schema.js +8 -1
- package/dist/lib/dashboard.service.d.ts +39 -2
- package/dist/lib/dashboard.service.js +52 -28
- package/dist/lib/document-libraries.d.ts +1 -1
- package/dist/lib/document-libraries.js +3 -2
- package/dist/lib/document-network.d.ts +1 -1
- package/dist/lib/document-network.js +2 -6
- package/dist/lib/editing-feedback.d.ts +5 -0
- package/dist/lib/editing-feedback.js +19 -0
- package/dist/lib/editing-patch.d.ts +22 -0
- package/dist/lib/editing-patch.js +46 -0
- package/dist/lib/editing-session.d.ts +167 -0
- package/dist/lib/editing-session.js +53 -0
- package/dist/lib/editing.d.ts +92 -60
- package/dist/lib/editing.js +36 -24
- package/dist/lib/html-guidance.d.ts +1 -1
- package/dist/lib/html-guidance.js +1 -1
- package/dist/lib/middleware.js +42 -18
- package/dist/lib/monitor.d.ts +70 -0
- package/dist/lib/monitor.js +101 -0
- package/dist/lib/plugin.js +4 -1
- package/dist/lib/project.d.ts +106 -0
- package/dist/lib/project.js +17 -0
- package/dist/lib/projects.schema.d.ts +49 -0
- package/dist/lib/projects.schema.js +7 -0
- package/dist/lib/projects.service.d.ts +23 -0
- package/dist/lib/projects.service.js +65 -0
- package/dist/lib/resource-card.js +1 -1
- package/dist/lib/runtime-context.d.ts +3 -0
- package/dist/lib/runtime-context.js +13 -0
- package/dist/lib/save-evidence.d.ts +1 -1
- package/dist/lib/templates.d.ts +2 -0
- package/dist/lib/templates.js +55 -0
- package/dist/lib/view.provider.d.ts +97 -7
- package/dist/lib/view.provider.js +39 -10
- package/dist/libraries/TREND-WORKSPACE-ICONS-LICENSE.txt +43 -0
- package/dist/libraries/catalog.json +1 -1
- package/dist/remote/app.css +1 -1
- package/dist/remote/app.js +33 -33
- package/dist/remote/build-manifest.json +115 -32
- package/dist/sandbox-actions/action.json +1 -1
- package/dist/sandbox-actions/bundle/host.js +2 -2
- package/dist/sandbox-actions/bundle/resource-cache.mjs +2 -1
- package/dist/sandbox-actions/bundle/validate.mjs +1 -1
- package/docs/docs.json +7 -0
- package/docs/frontend-libraries.mdx +12 -4
- package/docs/html-mode.md +3 -3
- package/docs/quick-start-acceptance.mdx +50 -0
- package/docs/quick-start.mdx +64 -0
- package/docs/superstore.mdx +38 -0
- package/docs/team-sharing.mdx +6 -2
- package/docs/trend-workspace-acceptance.mdx +43 -0
- package/docs/trend-workspace.mdx +30 -0
- package/docs/verification.mdx +4 -2
- package/docs/visual-styles-acceptance.mdx +40 -0
- package/docs/visual-styles.mdx +46 -0
- package/package.json +23 -17
- package/skills/live-dashboard/SKILL.md +27 -3
- package/skills/live-dashboard/examples/README.md +25 -0
- package/skills/live-dashboard/examples/catalog.json +79 -0
- package/skills/live-dashboard/examples/production-quality/README.md +25 -0
- package/skills/live-dashboard/examples/production-quality/dashboard.html +129 -0
- package/skills/live-dashboard/examples/production-quality/definition.json +67 -0
- package/skills/live-dashboard/examples/production-quality/demo.csv +7 -0
- package/skills/live-dashboard/examples/production-quality/demo.json +44 -0
- package/skills/live-dashboard/examples/production-quality/expected.json +26 -0
- package/skills/live-dashboard/examples/production-quality/preview.png +0 -0
- package/skills/live-dashboard/examples/production-quality/query.json +53 -0
- package/skills/live-dashboard/examples/regional-sales/README.md +25 -0
- package/skills/live-dashboard/examples/regional-sales/dashboard-create.json +35 -0
- package/skills/live-dashboard/examples/regional-sales/definition.json +35 -0
- package/skills/live-dashboard/examples/regional-sales/demo.csv +5 -0
- package/skills/live-dashboard/examples/regional-sales/demo.json +18 -0
- package/skills/live-dashboard/examples/regional-sales/expected.json +19 -0
- package/skills/live-dashboard/examples/regional-sales/preview.png +0 -0
- package/skills/live-dashboard/examples/regional-sales/query.json +45 -0
- package/skills/live-dashboard/examples/sales-overview/README.md +25 -0
- package/skills/live-dashboard/examples/sales-overview/dashboard.html +129 -0
- package/skills/live-dashboard/examples/sales-overview/definition.json +57 -0
- package/skills/live-dashboard/examples/sales-overview/demo.csv +7 -0
- package/skills/live-dashboard/examples/sales-overview/demo.json +38 -0
- package/skills/live-dashboard/examples/sales-overview/expected.json +22 -0
- package/skills/live-dashboard/examples/sales-overview/preview.png +0 -0
- package/skills/live-dashboard/examples/sales-overview/query.json +52 -0
- package/skills/live-dashboard/examples/superstore/README.md +64 -0
- package/skills/live-dashboard/examples/superstore/THIRD_PARTY_LICENSE.txt +207 -0
- package/skills/live-dashboard/examples/superstore/build_data.py +155 -0
- package/skills/live-dashboard/examples/superstore/build_pages.py +129 -0
- package/skills/live-dashboard/examples/superstore/checks.json +104 -0
- package/skills/live-dashboard/examples/superstore/customers-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers.html +316 -0
- package/skills/live-dashboard/examples/superstore/customers.png +0 -0
- package/skills/live-dashboard/examples/superstore/customers.queries.json +512 -0
- package/skills/live-dashboard/examples/superstore/expected.json +4069 -0
- package/skills/live-dashboard/examples/superstore/import.json +200 -0
- package/skills/live-dashboard/examples/superstore/orders.csv +10195 -0
- package/skills/live-dashboard/examples/superstore/overview-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview.html +310 -0
- package/skills/live-dashboard/examples/superstore/overview.png +0 -0
- package/skills/live-dashboard/examples/superstore/overview.queries.json +636 -0
- package/skills/live-dashboard/examples/superstore/page.js +109 -0
- package/skills/live-dashboard/examples/superstore/profitability-mobile-dark.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability-select.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability.html +307 -0
- package/skills/live-dashboard/examples/superstore/profitability.png +0 -0
- package/skills/live-dashboard/examples/superstore/profitability.queries.json +334 -0
- package/skills/live-dashboard/examples/superstore/provenance.json +24 -0
- package/skills/live-dashboard/examples/superstore/semantic-model.json +220 -0
- package/skills/live-dashboard/examples/superstore/test_data.py +62 -0
- package/skills/live-dashboard/references/html-runtime.md +1 -1
- package/skills/live-dashboard/themes/README.md +50 -0
- package/skills/live-dashboard/themes/customer-brief/README.md +47 -0
- package/skills/live-dashboard/themes/customer-brief/charts.js +17 -0
- package/skills/live-dashboard/themes/customer-brief/layout.html +22 -0
- package/skills/live-dashboard/themes/customer-brief/theme.css +108 -0
- package/skills/live-dashboard/themes/profit-atlas/README.md +43 -0
- package/skills/live-dashboard/themes/profit-atlas/charts.js +30 -0
- package/skills/live-dashboard/themes/profit-atlas/layout.html +19 -0
- package/skills/live-dashboard/themes/profit-atlas/theme.css +75 -0
- package/skills/live-dashboard/themes/trend-workspace/ICON_LICENSE.txt +43 -0
- package/skills/live-dashboard/themes/trend-workspace/README.md +144 -0
- package/skills/live-dashboard/themes/trend-workspace/charts.js +60 -0
- package/skills/live-dashboard/themes/trend-workspace/icons.js +11 -0
- package/skills/live-dashboard/themes/trend-workspace/layout.html +45 -0
- package/skills/live-dashboard/themes/trend-workspace/select.js +127 -0
- package/skills/live-dashboard/themes/trend-workspace/theme.css +137 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Dashboard visual styles — choose by the analysis task
|
|
2
|
+
|
|
3
|
+
These are three distinct authoring systems, not one mandatory appearance for every
|
|
4
|
+
dashboard. User direction wins. Preserve a saved dashboard's theme when changing
|
|
5
|
+
data or copy; only change it when the user asks for a redesign.
|
|
6
|
+
|
|
7
|
+
| Theme | Use for | Composition | Library / global |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| [Trend Workspace](trend-workspace/README.md) | Operating overview, time trends | Pale-blue KPI rail, aligned independent trend scales, lower comparisons | `trend-workspace` / `window.TrendWorkspace` |
|
|
10
|
+
| [Profit Atlas](profit-atlas/README.md) | Profitability, contribution, losses | Dark analysis desk, horizontal metrics, dominant scatter and signed ranking | `profit-atlas` / `window.ProfitAtlas` |
|
|
11
|
+
| [Customer Brief](customer-brief/README.md) | Customer structure, returns, management briefing | Warm paper, serif hierarchy, metric ribbon, grouped return metrics | `customer-brief` / `window.CustomerBrief` |
|
|
12
|
+
|
|
13
|
+
For the three-page Superstore suite, use each row for its corresponding page.
|
|
14
|
+
For a different dataset, first establish the business question and fields; select
|
|
15
|
+
the matching composition, then adapt it. Do not force every dataset into a scatter
|
|
16
|
+
plot, invent missing return metrics, or infer theme selection from a title at runtime.
|
|
17
|
+
Record the explicit choice in `data-dashboard-theme="<id>@1"` and save with
|
|
18
|
+
`libraries:["echarts","<id>"]`. Choose exactly one visual theme; do not stack theme
|
|
19
|
+
libraries. Call `dashboard_libraries` to verify availability before authoring.
|
|
20
|
+
|
|
21
|
+
All three expose `enhanceSelect(nativeSelect)` and `charts.line/horizontal/scatter`.
|
|
22
|
+
The host injects pinned CSS/JS; you author the business layout and governed query
|
|
23
|
+
runtime. Complete examples and query plans are in `examples/superstore/`. No local
|
|
24
|
+
repository, Python generator or this developer's computer is required by the Agent.
|
|
25
|
+
|
|
26
|
+
## Shared behavior and editing rules
|
|
27
|
+
|
|
28
|
+
- Read the selected theme guide and its layout fragment, plus the complete relevant
|
|
29
|
+
example. The existing [typed select contract](trend-workspace/README.md#select-component-contract)
|
|
30
|
+
and [data adaptation contract](trend-workspace/README.md#adapt-to-a-new-dataset)
|
|
31
|
+
apply to every theme. The shared source is `trend-workspace/select.js`, `icons.js`
|
|
32
|
+
and `charts.js`; each theme bundle already contains them and their icon license.
|
|
33
|
+
- Keep business values out of the HTML. Discover and validate the actual source,
|
|
34
|
+
use independent backend totals, query every affected Binding on a filter change,
|
|
35
|
+
and clear stale values on loading, empty, truncated or failed queries.
|
|
36
|
+
- For existing Artifacts, use `dashboard_open`, read its current editing copy and
|
|
37
|
+
retain `saveArguments`, Binding IDs, source, controls, title and all existing DOM
|
|
38
|
+
IDs. Moving a chart does not require changing its ID. Do not create duplicates.
|
|
39
|
+
- Use bounded exact SandboxFile edits to the returned `htmlPath`; never overwrite
|
|
40
|
+
an existing editing copy with `sandbox_write_file`. Keep old/new replacements
|
|
41
|
+
around 4,000 UTF-8 bytes or less. New long documents can be written then appended.
|
|
42
|
+
- Save through `dashboard_update` with the explicit new theme library only when
|
|
43
|
+
redesign was requested. Successful draft receipts are required; publishing is a
|
|
44
|
+
separate human decision. Existing saved library bytes remain frozen.
|
|
45
|
+
- Verify a real filter and refresh across KPIs, charts and detail rows. Check keyboard
|
|
46
|
+
selection, Escape, focus, menu bounds, 390px layout and theme contrast. Rendered
|
|
47
|
+
visual checks are required; report them as pending if no browser is available.
|
|
48
|
+
|
|
49
|
+
The host project/dashboard cascade and Publish/More toolbar stay outside authored
|
|
50
|
+
HTML. These styles do not add capabilities, data access, project sharing or jobs.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Customer Brief v1 — editorial customer and returns report
|
|
2
|
+
|
|
3
|
+
Use this style for the approved warm customer brief or an explicitly chosen
|
|
4
|
+
management report. Read [theme selection and shared rules](../README.md) first.
|
|
5
|
+
Keep the current theme on unrelated edits; this is not a mandatory default.
|
|
6
|
+
|
|
7
|
+
## Installed assets and runtime
|
|
8
|
+
|
|
9
|
+
Read `theme.css`, `charts.js`, `layout.html` and the complete
|
|
10
|
+
`examples/superstore/customers.html`. Call `dashboard_libraries`, then use
|
|
11
|
+
`libraries:["echarts","customer-brief"]`; the global is `window.CustomerBrief`.
|
|
12
|
+
Shared select, icons/license and chart primitives are already bundled. Do not load
|
|
13
|
+
another theme library or retype its component implementation.
|
|
14
|
+
|
|
15
|
+
## Visual contract
|
|
16
|
+
|
|
17
|
+
- Warm paper-white canvas, forest ink, sage comparisons and terracotta returns.
|
|
18
|
+
Headings and large metrics use a local serif stack (Songti SC / Noto Serif CJK /
|
|
19
|
+
SimSun / system serif); body, controls and tables remain readable sans-serif.
|
|
20
|
+
No external font request is required. Low-light mode has matching warm tokens.
|
|
21
|
+
- Large title, a horizontal customer/order/value ribbon and a single grouped return
|
|
22
|
+
area. Put return percentage before return count visually, retaining metric IDs.
|
|
23
|
+
No KPI sidebar, card grid, decorative avatars, gauges or unsupported risk badges.
|
|
24
|
+
- Two numbered sections compare customer groups and regions; keep common zero
|
|
25
|
+
baselines. Numbers are direct labels. Color differentiates groups, not an invented
|
|
26
|
+
business threshold. Show exact values again in a complete compact table.
|
|
27
|
+
- At 760px the return group and plots stack; at 390px three compact filters remain
|
|
28
|
+
keyboard-accessible, and only the named table region may scroll horizontally.
|
|
29
|
+
|
|
30
|
+
## Authoring
|
|
31
|
+
|
|
32
|
+
Set `<body data-dashboard-theme="customer-brief@1">`, then use `brief-header`,
|
|
33
|
+
`brief-metrics`, `brief-primary-metrics`, `brief-return-metrics` and `brief-plots`.
|
|
34
|
+
Use `charts.horizontal(chart, rows, {dimension,measure,label,palette:[...]})` with
|
|
35
|
+
explicit color token names: `['blue','segment-two','segment-three']` for the ordered
|
|
36
|
+
customer comparisons; `['returns']` and `decimals:0` for return-order counts.
|
|
37
|
+
Other datasets must supply their own real grouping, measures and units.
|
|
38
|
+
|
|
39
|
+
Customer counts must be independently deduplicated for the current scope. Return
|
|
40
|
+
share is returned orders divided by orders, not returned items divided by quantities.
|
|
41
|
+
Return-associated sales are not refunds or lost revenue. Do not sum group customer
|
|
42
|
+
counts to invent a total, or add these return metrics to sources that do not have them.
|
|
43
|
+
|
|
44
|
+
For existing HTML, keep Binding IDs and all metric/chart IDs while rearranging the
|
|
45
|
+
DOM. Read the current editing copy, make bounded exact edits and save the explicit
|
|
46
|
+
theme choice through `dashboard_update`. Test a real region filter and restoration,
|
|
47
|
+
including every KPI, plot and detail row. A save receipt alone is not visual QA.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Explicit palette options distinguish ranked customer segments from return counts.
|
|
2
|
+
const CustomerBriefCharts = (() => {
|
|
3
|
+
function horizontal(chart, rows, options) {
|
|
4
|
+
TrendWorkspaceCharts.horizontal(chart, rows, options);
|
|
5
|
+
const token = name => getComputedStyle(document.body).getPropertyValue('--' + name).trim();
|
|
6
|
+
const narrow = chart.getWidth() < 420;
|
|
7
|
+
const colors = options.palette || ['blue'];
|
|
8
|
+
chart.setOption({grid: {left: narrow ? 80 : 104, right: options.decimals === 0 ? 40 : 112, top: 12, bottom: 28},
|
|
9
|
+
xAxis: {axisLabel: {fontSize: 12}}, yAxis: {axisLabel: {fontSize: narrow ? 12 : 15}},
|
|
10
|
+
series: [{id: options.measure, barMaxWidth: 28,
|
|
11
|
+
label: {fontSize: narrow ? 12 : 15},
|
|
12
|
+
data: rows.map((row, index) => ({value: Number(row[options.measure]),
|
|
13
|
+
itemStyle: {color: token(Number(row[options.measure]) < 0 ? 'red' : colors[index % colors.length])}}))}]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return {...TrendWorkspaceCharts, horizontal};
|
|
17
|
+
})();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- Structural fragment; add verified controls, data bindings and the SDK runtime. -->
|
|
2
|
+
<body data-dashboard-theme="customer-brief@1">
|
|
3
|
+
<main class="workspace">
|
|
4
|
+
<header class="brief-header">
|
|
5
|
+
<div><h1>Customer report</h1><p class="description">Business question</p><span class="demo">Source and period</span></div>
|
|
6
|
+
<div class="filters" aria-label="Analysis filters"><!-- Typed filter-field controls --></div>
|
|
7
|
+
</header>
|
|
8
|
+
<section class="brief-metrics" aria-label="Current scope metrics">
|
|
9
|
+
<div class="brief-primary-metrics"><!-- Customer, order and value metrics --></div>
|
|
10
|
+
<div class="brief-return-metrics"><!-- Rate then count; keep original IDs --></div>
|
|
11
|
+
</section>
|
|
12
|
+
<div class="analysis">
|
|
13
|
+
<div class="brief-plots">
|
|
14
|
+
<section class="panel"><h2>01 Customer groups</h2><div class="chart" id="chart-primary"></div></section>
|
|
15
|
+
<section class="panel"><h2>02 Regional returns</h2><div class="chart" id="chart-secondary"></div></section>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="full-details"><section class="details"><!-- Complete accessible detail table --></section></div>
|
|
18
|
+
<p id="status" class="status" role="status"></p>
|
|
19
|
+
</div>
|
|
20
|
+
<footer><span>Source period</span><span id="freshness"></span></footer>
|
|
21
|
+
</main>
|
|
22
|
+
</body>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* Customer Brief: a warm editorial document, with a matching low-light palette. */
|
|
2
|
+
body[data-dashboard-theme="customer-brief@1"] {
|
|
3
|
+
color-scheme: light;
|
|
4
|
+
--paper: #f7f5ef;
|
|
5
|
+
--control: #eeeee5;
|
|
6
|
+
--ink: #163d34;
|
|
7
|
+
--muted: #697577;
|
|
8
|
+
--line: #d7d2c6;
|
|
9
|
+
--blue: #245247;
|
|
10
|
+
--teal: #567f6d;
|
|
11
|
+
--red: #9e4932;
|
|
12
|
+
--returns: #b76b52;
|
|
13
|
+
--returns-paper: #f1e7e0;
|
|
14
|
+
--segment-two: #8b9f80;
|
|
15
|
+
--segment-three: #b2b597;
|
|
16
|
+
--selected: #e3e9df;
|
|
17
|
+
--focus: #316455;
|
|
18
|
+
--shadow: 0 8px 24px #183d331a;
|
|
19
|
+
--radius: 12px;
|
|
20
|
+
--editorial: "Songti SC", "Noto Serif CJK SC", "SimSun", ui-serif, serif;
|
|
21
|
+
}
|
|
22
|
+
body[data-dashboard-theme="customer-brief@1"].dark {
|
|
23
|
+
color-scheme: dark;
|
|
24
|
+
--paper: #19231f;
|
|
25
|
+
--control: #27342b;
|
|
26
|
+
--ink: #e7ede2;
|
|
27
|
+
--muted: #bac5ba;
|
|
28
|
+
--line: #4a5649;
|
|
29
|
+
--blue: #bad1b9;
|
|
30
|
+
--teal: #abc4a7;
|
|
31
|
+
--red: #f4b59d;
|
|
32
|
+
--returns: #d69a80;
|
|
33
|
+
--returns-paper: #3b3028;
|
|
34
|
+
--segment-two: #9bb193;
|
|
35
|
+
--segment-three: #7f9878;
|
|
36
|
+
--selected: #344b3d;
|
|
37
|
+
--focus: #c0d2b5;
|
|
38
|
+
}
|
|
39
|
+
body[data-dashboard-theme="customer-brief@1"] .workspace { display: block; padding: 28px 36px 0; }
|
|
40
|
+
.brief-header { display: flex; justify-content: space-between; align-items: center; gap: 24px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
|
|
41
|
+
.brief-header h1 { font: 700 58px/1.2 var(--editorial); letter-spacing: -1px; }
|
|
42
|
+
.brief-header .description { margin-top: 8px; font: 20px/1.4 var(--editorial); color: var(--ink); }
|
|
43
|
+
.brief-header .demo { margin: 8px 0 0; font-size: 13px; }
|
|
44
|
+
.brief-header .filters { flex-wrap: nowrap; padding: 0; gap: 14px; }
|
|
45
|
+
.brief-header .filter-field { width: 184px; }
|
|
46
|
+
.brief-header .filter-trigger { min-height: 70px; background: transparent; }
|
|
47
|
+
.brief-header .filter-value { font-size: 18px; }
|
|
48
|
+
.brief-metrics { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 20px; padding: 20px 0 16px; border-bottom: 1px solid var(--line); }
|
|
49
|
+
.brief-primary-metrics, .brief-return-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: center; }
|
|
50
|
+
.brief-return-metrics { grid-template-columns: 1fr 1fr; padding: 12px 16px; border-radius: 10px; background: var(--returns-paper); }
|
|
51
|
+
.brief-metrics .metric { grid-column: auto; display: flex; flex-direction: column; padding: 0 22px; border: 0; border-left: 1px solid var(--line); }
|
|
52
|
+
.brief-metrics .metric:first-child { border-left: 0; padding-left: 14px; }
|
|
53
|
+
.brief-metrics .metric:last-child { padding-right: 0; }
|
|
54
|
+
.brief-metrics .metric p { order: 2; font: 20px/1.35 var(--editorial); color: var(--ink); }
|
|
55
|
+
.brief-metrics .metric output { order: 1; font: 700 clamp(38px, 5.1vw, 74px)/1.15 var(--editorial); letter-spacing: -1px; margin: 0 0 4px; }
|
|
56
|
+
.brief-metrics .metric small { order: 3; margin-top: 5px; }
|
|
57
|
+
.brief-return-metrics .metric { padding-inline: 20px; }
|
|
58
|
+
.brief-return-metrics .metric output { color: var(--red); }
|
|
59
|
+
.brief-plots { display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); gap: 24px; padding: 22px 0; }
|
|
60
|
+
.brief-plots h2 { font: 700 26px/1.3 var(--editorial); }
|
|
61
|
+
.brief-plots .section-number { margin-right: 14px; font-size: 30px; }
|
|
62
|
+
.brief-plots .panel:last-child { border-left: 1px solid var(--line); padding-left: 24px; }
|
|
63
|
+
.brief-plots .note { font-size: 13px; }
|
|
64
|
+
.brief-plots .chart { height: 275px; margin-top: 12px; }
|
|
65
|
+
body[data-dashboard-theme="customer-brief@1"] .details { padding: 16px 0 4px; }
|
|
66
|
+
body[data-dashboard-theme="customer-brief@1"] .details h2 { font: 700 26px/1.3 var(--editorial); }
|
|
67
|
+
body[data-dashboard-theme="customer-brief@1"] .details > .note { display: none; }
|
|
68
|
+
body[data-dashboard-theme="customer-brief@1"] .table-scroll { max-height: 300px; border: 1px solid var(--line); border-radius: 10px; margin-top: 12px; }
|
|
69
|
+
body[data-dashboard-theme="customer-brief@1"] table { font-size: 15px; }
|
|
70
|
+
body[data-dashboard-theme="customer-brief@1"] th, body[data-dashboard-theme="customer-brief@1"] td { padding: 10px 12px; }
|
|
71
|
+
body[data-dashboard-theme="customer-brief@1"] th { color: var(--ink); font-size: 14px; }
|
|
72
|
+
body[data-dashboard-theme="customer-brief@1"] td:nth-child(6) { color: var(--red); }
|
|
73
|
+
body[data-dashboard-theme="customer-brief@1"] .table-bar { display: none; }
|
|
74
|
+
body[data-dashboard-theme="customer-brief@1"] .status { padding: 8px 0 0; }
|
|
75
|
+
body[data-dashboard-theme="customer-brief@1"] .methodology { padding: 4px 0 12px; }
|
|
76
|
+
body[data-dashboard-theme="customer-brief@1"] footer { padding: 10px 0; }
|
|
77
|
+
@media (max-width: 1100px) {
|
|
78
|
+
.brief-header { flex-wrap: wrap; gap: 18px; }
|
|
79
|
+
.brief-header h1 { font-size: 40px; }
|
|
80
|
+
.brief-header .filters { margin-left: auto; }
|
|
81
|
+
.brief-metrics { gap: 12px; }
|
|
82
|
+
.brief-metrics .metric { padding-inline: 10px; }
|
|
83
|
+
.brief-metrics .metric output { font-size: 42px; }
|
|
84
|
+
.brief-metrics .metric p { font-size: 16px; }
|
|
85
|
+
}
|
|
86
|
+
@media (max-width: 760px) {
|
|
87
|
+
.brief-metrics { grid-template-columns: 1fr; }
|
|
88
|
+
.brief-return-metrics .metric:first-child { padding-left: 10px; }
|
|
89
|
+
.brief-plots { grid-template-columns: 1fr; }
|
|
90
|
+
.brief-plots .panel:last-child { border-left: 0; border-top: 1px solid var(--line); padding: 20px 0 0; }
|
|
91
|
+
}
|
|
92
|
+
@media (max-width: 680px) {
|
|
93
|
+
body[data-dashboard-theme="customer-brief@1"] .workspace { padding: 20px 16px 0; }
|
|
94
|
+
.brief-header { display: block; }
|
|
95
|
+
.brief-header h1 { font-size: 34px; }
|
|
96
|
+
.brief-header .description { font-size: 18px; }
|
|
97
|
+
.brief-header .filters { display: grid; margin-top: 20px; gap: 8px; }
|
|
98
|
+
.brief-header .filter-field { width: auto; }
|
|
99
|
+
.brief-header .filter-trigger { min-height: 62px; }
|
|
100
|
+
.brief-header .filter-value { font-size: 13px; }
|
|
101
|
+
.brief-metrics .metric output { font-size: 32px; }
|
|
102
|
+
.brief-metrics .metric small { font-size: 12px; }
|
|
103
|
+
.brief-primary-metrics .metric:first-child { grid-column: auto; padding-left: 0; }
|
|
104
|
+
.brief-return-metrics .metric:first-child { grid-column: auto; }
|
|
105
|
+
.brief-return-metrics .metric output { font-size: 42px; }
|
|
106
|
+
.brief-plots h2, body[data-dashboard-theme="customer-brief@1"] .details h2 { font-size: 23px; }
|
|
107
|
+
.brief-plots .chart { height: 260px; }
|
|
108
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Profit Atlas v1 — profitability analysis desk
|
|
2
|
+
|
|
3
|
+
Use this style for the approved dark profitability screen or an explicitly chosen
|
|
4
|
+
contribution/loss analysis. Read [theme selection and shared rules](../README.md)
|
|
5
|
+
first. This is one optional style; it does not replace Trend Workspace.
|
|
6
|
+
|
|
7
|
+
## Installed assets and runtime
|
|
8
|
+
|
|
9
|
+
Read `theme.css`, `charts.js`, `layout.html` and the complete
|
|
10
|
+
`examples/superstore/profitability.html`. Call `dashboard_libraries`, then use
|
|
11
|
+
`libraries:["echarts","profit-atlas"]`; the global is `window.ProfitAtlas`.
|
|
12
|
+
The bundle includes the shared typed select, Lucide icons/license and base chart
|
|
13
|
+
primitives. Do not also load `trend-workspace` or copy public component code into HTML.
|
|
14
|
+
|
|
15
|
+
## Visual contract
|
|
16
|
+
|
|
17
|
+
- Graphite canvas, off-white text, quiet grid lines; mint positive profit, coral
|
|
18
|
+
negative profit. The document deliberately stays dark in either host theme.
|
|
19
|
+
- Full-width header and a continuous five-or-fewer metric ribbon. No left KPI rail,
|
|
20
|
+
repeated floating cards, neon glow, gradients or invented growth indicators.
|
|
21
|
+
- Primary scatter occupies roughly 65% of the analysis width; the other 35% holds
|
|
22
|
+
a signed ranked bar chart. Both have explicit units and a visible zero baseline.
|
|
23
|
+
- Positive and negative ranking values remain visible; dense positive scatter clusters use hover details to avoid overlapping labels.
|
|
24
|
+
On narrow screens, preserve labels for negative items and stack the plots.
|
|
25
|
+
- The compact detail table is ordered by the business metric (profit ascending in
|
|
26
|
+
this example), so losses appear first. Keep all rows in its named scroll region;
|
|
27
|
+
do not silently truncate the query to the three rows seen in the design reference.
|
|
28
|
+
- Use system sans typography, 36px desktop title, 25–37px tabular KPIs, 14px body.
|
|
29
|
+
Dropdowns retain the two-line caption/value contract with dark matching surfaces.
|
|
30
|
+
|
|
31
|
+
## Authoring
|
|
32
|
+
|
|
33
|
+
Set `<body data-dashboard-theme="profit-atlas@1">`, compose `atlas-header`,
|
|
34
|
+
`atlas-metrics`, `atlas-plots`, and a full-width details section as in `layout.html`.
|
|
35
|
+
`charts.scatter(chart, rows, {dimension,x,y,xLabel,yLabel})` takes explicit fields;
|
|
36
|
+
`charts.horizontal(chart, rows, {dimension,measure,label,color:'teal'})` draws signed
|
|
37
|
+
rankings. Sorting and backend totals remain the business runtime's responsibility.
|
|
38
|
+
|
|
39
|
+
Do not manufacture profit or financial meaning for unrelated data. For another
|
|
40
|
+
two-measure comparison, supply its real units and decide whether the zero reference
|
|
41
|
+
and negative labels are meaningful. Preserve all Binding and component IDs during
|
|
42
|
+
a style-only upgrade. After saving, verify the exact target Artifact and a real
|
|
43
|
+
filter; report visual acceptance separately from a successful save receipt.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Extend the shared chart primitives; fields and labels remain explicit inputs.
|
|
2
|
+
const ProfitAtlasCharts = (() => {
|
|
3
|
+
const token = name => getComputedStyle(document.body).getPropertyValue('--' + name).trim();
|
|
4
|
+
function horizontal(chart, rows, options) {
|
|
5
|
+
TrendWorkspaceCharts.horizontal(chart, rows, options);
|
|
6
|
+
chart.setOption({grid: {left: 82, right: 78},
|
|
7
|
+
series: [{id: options.measure, barMaxWidth: 16, label: {fontSize: 12}}],
|
|
8
|
+
xAxis: {splitLine: {show: false}},
|
|
9
|
+
yAxis: {axisLabel: {fontSize: 12}}});
|
|
10
|
+
}
|
|
11
|
+
function scatter(chart, rows, options) {
|
|
12
|
+
TrendWorkspaceCharts.scatter(chart, rows, options);
|
|
13
|
+
const narrow = chart.getWidth() < 600;
|
|
14
|
+
const maximum = Math.max(0, ...rows.map(row => Number(row[options.x])));
|
|
15
|
+
chart.setOption({grid: {left: 46, right: 32, top: 30, bottom: 46},
|
|
16
|
+
xAxis: {splitLine: {lineStyle: {type: 'dashed'}}},
|
|
17
|
+
yAxis: {splitLine: {lineStyle: {type: 'dashed'}}},
|
|
18
|
+
series: [{id: 'scatter', symbolSize: 10, labelLayout: {hideOverlap: true},
|
|
19
|
+
data: rows.map(row => {
|
|
20
|
+
const negative = Number(row[options.y]) < 0;
|
|
21
|
+
return {value: [Number(row[options.x]), Number(row[options.y])], name: row[options.dimension],
|
|
22
|
+
itemStyle: {color: token(negative ? 'red' : 'teal'), opacity: 1},
|
|
23
|
+
label: {show: negative || (!narrow && (Number(row[options.x]) >= maximum * .15 || Number(row[options.y]) >= 12000)), formatter: String(row[options.dimension]),
|
|
24
|
+
position: Number(row[options.x]) > maximum * .9 ? 'left' : 'right',
|
|
25
|
+
color: token(negative ? 'red' : 'ink'), fontSize: 12}};
|
|
26
|
+
})}]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return {line: TrendWorkspaceCharts.line, horizontal, scatter};
|
|
30
|
+
})();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Structural fragment; add verified controls, data bindings and the SDK runtime. -->
|
|
2
|
+
<body data-dashboard-theme="profit-atlas@1">
|
|
3
|
+
<main class="workspace">
|
|
4
|
+
<header class="atlas-header">
|
|
5
|
+
<div><h1>Analysis title</h1><p class="description">Business question</p><span class="demo">Source and period</span></div>
|
|
6
|
+
<div class="filters" aria-label="Analysis filters"><!-- Typed filter-field controls --></div>
|
|
7
|
+
</header>
|
|
8
|
+
<section class="atlas-metrics" aria-label="Current scope metrics"><!-- Metric outputs --></section>
|
|
9
|
+
<div class="analysis">
|
|
10
|
+
<div class="atlas-plots">
|
|
11
|
+
<section class="panel"><h2>Measure relationship</h2><div class="chart" id="chart-secondary"></div></section>
|
|
12
|
+
<section class="panel"><h2>Contribution ranking</h2><div class="chart" id="chart-primary"></div></section>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="full-details"><section class="details"><!-- Complete accessible detail table --></section></div>
|
|
15
|
+
<p id="status" class="status" role="status"></p>
|
|
16
|
+
</div>
|
|
17
|
+
<footer><span>Source period</span><span id="freshness"></span></footer>
|
|
18
|
+
</main>
|
|
19
|
+
</body>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* Profit Atlas: a deliberate dark document theme, independent of the host chrome. */
|
|
2
|
+
body[data-dashboard-theme="profit-atlas@1"] {
|
|
3
|
+
color-scheme: dark;
|
|
4
|
+
--paper: #10181f;
|
|
5
|
+
--control: #17222c;
|
|
6
|
+
--ink: #f0f4f7;
|
|
7
|
+
--muted: #aebdcb;
|
|
8
|
+
--line: #30414e;
|
|
9
|
+
--blue: #62d9c1;
|
|
10
|
+
--teal: #53d6ba;
|
|
11
|
+
--red: #ff8b90;
|
|
12
|
+
--selected: #203c39;
|
|
13
|
+
--focus: #89e4d0;
|
|
14
|
+
--shadow: 0 8px 24px #0006;
|
|
15
|
+
--radius: 8px;
|
|
16
|
+
}
|
|
17
|
+
body[data-dashboard-theme="profit-atlas@1"] .workspace { display: block; }
|
|
18
|
+
.atlas-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 28px; padding: 22px 34px 18px; }
|
|
19
|
+
.atlas-header h1 { font-size: 36px; line-height: 1.25; letter-spacing: -.6px; }
|
|
20
|
+
.atlas-header .description { margin-top: 4px; font-size: 15px; }
|
|
21
|
+
.atlas-header .demo { margin: 6px 0 0; font-size: 13px; }
|
|
22
|
+
.atlas-header .filters { padding: 6px 0 0; flex-wrap: nowrap; gap: 14px; }
|
|
23
|
+
.atlas-header .filter-field { width: 168px; }
|
|
24
|
+
.atlas-header .filter-trigger { min-height: 62px; }
|
|
25
|
+
.atlas-metrics { display: grid; grid-template-columns: 1.15fr 1.1fr .95fr .9fr .75fr; margin: 0; padding: 18px 34px; border-block: 1px solid var(--line); }
|
|
26
|
+
.atlas-metrics .metric { grid-column: auto; padding: 0 26px; border: 0; border-left: 1px solid var(--line); }
|
|
27
|
+
.atlas-metrics .metric:first-child { padding-left: 0; border-left: 0; }
|
|
28
|
+
.atlas-metrics .metric:last-child { padding-right: 0; }
|
|
29
|
+
.atlas-metrics .metric output { font-size: clamp(25px, 2.55vw, 37px); letter-spacing: -.6px; margin: 6px 0 0; }
|
|
30
|
+
.atlas-metrics .metric:nth-child(2) output { color: var(--teal); }
|
|
31
|
+
.atlas-metrics .metric small { display: none; }
|
|
32
|
+
.atlas-plots { display: grid; grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr); gap: 32px; padding: 24px 34px 20px; }
|
|
33
|
+
.atlas-plots .panel { min-width: 0; }
|
|
34
|
+
.atlas-plots .panel:last-child { padding-left: 28px; border-left: 1px solid var(--line); }
|
|
35
|
+
.atlas-plots h2 { font-size: 22px; }
|
|
36
|
+
.atlas-plots .note { font-size: 13px; }
|
|
37
|
+
.atlas-plots .chart { height: 448px; margin-top: 12px; }
|
|
38
|
+
body[data-dashboard-theme="profit-atlas@1"] .details { padding: 12px 34px 14px; }
|
|
39
|
+
body[data-dashboard-theme="profit-atlas@1"] .details h2 { display: inline; font-size: 20px; }
|
|
40
|
+
body[data-dashboard-theme="profit-atlas@1"] .details > .note { display: inline; margin-left: 18px; }
|
|
41
|
+
body[data-dashboard-theme="profit-atlas@1"] .table-scroll { max-height: 150px; margin-top: 10px; border: 1px solid var(--line); border-radius: 7px; }
|
|
42
|
+
body[data-dashboard-theme="profit-atlas@1"] th, body[data-dashboard-theme="profit-atlas@1"] td { padding: 7px 16px; }
|
|
43
|
+
body[data-dashboard-theme="profit-atlas@1"] .table-bar { display: none; }
|
|
44
|
+
body[data-dashboard-theme="profit-atlas@1"] .status { padding: 0 34px; }
|
|
45
|
+
body[data-dashboard-theme="profit-atlas@1"] .methodology { padding: 4px 34px 12px; }
|
|
46
|
+
body[data-dashboard-theme="profit-atlas@1"] footer { padding: 10px 34px; }
|
|
47
|
+
@media (max-width: 1100px) {
|
|
48
|
+
.atlas-header { flex-wrap: wrap; gap: 14px; }
|
|
49
|
+
.atlas-header .filters { margin-left: auto; }
|
|
50
|
+
.atlas-metrics .metric { padding-inline: 14px; }
|
|
51
|
+
.atlas-metrics .metric output { font-size: 25px; }
|
|
52
|
+
.atlas-plots { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; }
|
|
53
|
+
.atlas-plots .panel:last-child { padding-left: 18px; }
|
|
54
|
+
}
|
|
55
|
+
@media (max-width: 760px) {
|
|
56
|
+
.atlas-plots { grid-template-columns: 1fr; }
|
|
57
|
+
.atlas-plots .panel:last-child { padding: 20px 0 0; border-left: 0; border-top: 1px solid var(--line); }
|
|
58
|
+
}
|
|
59
|
+
@media (max-width: 680px) {
|
|
60
|
+
.atlas-header { display: block; padding: 20px 16px; }
|
|
61
|
+
.atlas-header h1 { font-size: 28px; }
|
|
62
|
+
.atlas-header .filters { display: grid; margin-top: 20px; padding: 0; gap: 8px; }
|
|
63
|
+
.atlas-header .filter-field { width: auto; }
|
|
64
|
+
.atlas-metrics { grid-template-columns: 1fr 1fr; gap: 18px 12px; padding: 18px 16px; }
|
|
65
|
+
.atlas-metrics .metric, .atlas-metrics .metric:last-child { padding: 0; border: 0; }
|
|
66
|
+
.atlas-metrics .metric:first-child { grid-column: 1 / -1; }
|
|
67
|
+
.atlas-metrics .metric output { font-size: 28px; }
|
|
68
|
+
.atlas-plots { padding: 20px 16px; }
|
|
69
|
+
.atlas-plots .chart { height: 390px; }
|
|
70
|
+
.atlas-plots .panel:last-child .chart { height: 448px; }
|
|
71
|
+
body[data-dashboard-theme="profit-atlas@1"] .details { padding: 16px; }
|
|
72
|
+
body[data-dashboard-theme="profit-atlas@1"] .details > .note { display: block; margin: 6px 0 0; }
|
|
73
|
+
body[data-dashboard-theme="profit-atlas@1"] .table-scroll { max-height: 250px; }
|
|
74
|
+
body[data-dashboard-theme="profit-atlas@1"] .status, body[data-dashboard-theme="profit-atlas@1"] .methodology, body[data-dashboard-theme="profit-atlas@1"] footer { padding-inline: 16px; }
|
|
75
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucide Icons and Contributors
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
The following Lucide icons are derived from the Feather project:
|
|
20
|
+
|
|
21
|
+
airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
|
|
22
|
+
|
|
23
|
+
The MIT License (MIT) (for the icons listed above)
|
|
24
|
+
|
|
25
|
+
Copyright (c) 2013-present Cole Bemis
|
|
26
|
+
|
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
28
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
29
|
+
in the Software without restriction, including without limitation the rights
|
|
30
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
31
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
32
|
+
furnished to do so, subject to the following conditions:
|
|
33
|
+
|
|
34
|
+
The above copyright notice and this permission notice shall be included in all
|
|
35
|
+
copies or substantial portions of the Software.
|
|
36
|
+
|
|
37
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
38
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
39
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
40
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
41
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
42
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
43
|
+
SOFTWARE.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Trend Workspace v1 — Agent authoring contract
|
|
2
|
+
|
|
3
|
+
Use this theme when the user asks for the enterprise BI style, the left KPI rail,
|
|
4
|
+
the trend-first design, or the polished two-line dropdown filters. It is a reusable
|
|
5
|
+
design system, not a fixed Superstore screenshot. Author the business HTML in the
|
|
6
|
+
current Project and save it through dashboard tools yourself.
|
|
7
|
+
|
|
8
|
+
## Read and reuse
|
|
9
|
+
|
|
10
|
+
Read these files with `read_skill_file`, resolving paths relative to the installed
|
|
11
|
+
live-dashboard skill. Read complete files; do not use a truncated preview as source.
|
|
12
|
+
|
|
13
|
+
1. `theme.css`: tokens, layout, typography, responsive/dark states, filter appearance.
|
|
14
|
+
2. `icons.js`: two exact Lucide library icons; keep `ICON_LICENSE.txt` attribution.
|
|
15
|
+
3. `select.js`: keyboard-accessible dropdown enhancement of a typed native select.
|
|
16
|
+
4. `charts.js`: ECharts line, ranked bar and scatter recipes with explicit fields.
|
|
17
|
+
5. `layout.html`: structural fragment explaining placement, not a standalone page.
|
|
18
|
+
6. The main skill's `references/html-runtime.md` and lifecycle example.
|
|
19
|
+
|
|
20
|
+
Call `dashboard_libraries` and save with `libraries:["echarts","trend-workspace"]`.
|
|
21
|
+
The host injects the theme CSS, icons, select and chart code from its versioned,
|
|
22
|
+
SHA-256-pinned document library. Do not retype those shared modules in every HTML.
|
|
23
|
+
They remain in the skill for inspection and adaptation. No CDN or relative URLs.
|
|
24
|
+
|
|
25
|
+
Use `window.TrendWorkspace.enhanceSelect(select)` and
|
|
26
|
+
`window.TrendWorkspace.charts.line/horizontal/scatter(...)`. The library does not
|
|
27
|
+
query data or insert business content. You write the layout, configuration and
|
|
28
|
+
SDK query/subscription runtime, then save the draft. Existing saved library bytes
|
|
29
|
+
remain frozen when a later plugin version is installed; opt in to library upgrades.
|
|
30
|
+
Keep source lines below 500 UTF-8 bytes; do not minify.
|
|
31
|
+
|
|
32
|
+
Full worked examples are `examples/superstore/overview.html`, `profitability.html`
|
|
33
|
+
and `customers.html`. Their `build_pages.py` is a developer packaging helper; the
|
|
34
|
+
Agent does not need Python, the repository or this developer's computer. The
|
|
35
|
+
installed skill contains every CSS/JS asset and complete HTML example.
|
|
36
|
+
|
|
37
|
+
## Visual invariants
|
|
38
|
+
|
|
39
|
+
- White analysis surface, pale blue KPI rail, navy text. Sales blue, profit teal,
|
|
40
|
+
negative values red. Never encode a business threshold by an invented color rule.
|
|
41
|
+
- Desktop rail is about 22% of the content width. Put title, source/demo label and
|
|
42
|
+
five or fewer important KPIs in it; large first KPI, quieter supporting totals.
|
|
43
|
+
- Top-right filter strip; the analysis area contains one main chart region and
|
|
44
|
+
compact supporting ranking/table regions. Avoid equal-size card grids.
|
|
45
|
+
- Sales and profit time series use aligned time axes with **separate, clearly
|
|
46
|
+
labelled value scales**. Do not smooth away negative months or seasonal spikes.
|
|
47
|
+
- Ranked bars are descending with direct values; bars use zero as baseline.
|
|
48
|
+
Profit rankings preserve negative values. Scatter plots retain a zero-profit
|
|
49
|
+
reference and name negative items; keep numeric detail in the accompanying table.
|
|
50
|
+
- Use `system-ui, "PingFang SC", sans-serif`, tabular numbers, headings 24–26px,
|
|
51
|
+
KPI values 28–40px, controls/body 14px, supporting labels at least 12px.
|
|
52
|
+
- No browser chrome, decorative charts, fabricated growth badges or chart images.
|
|
53
|
+
Real ECharts remains interactive; the design reference is not a data source.
|
|
54
|
+
- At 680px the rail becomes a top summary; charts stack and filters retain three
|
|
55
|
+
accessible compact fields. Only the named table region may scroll horizontally.
|
|
56
|
+
- Dark mode comes from `await live.ready()` and `.dark`; do not read localStorage.
|
|
57
|
+
|
|
58
|
+
## Select component contract
|
|
59
|
+
|
|
60
|
+
Use one `.filter-field` per verified control:
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<div class="filter-field">
|
|
64
|
+
<label for="filter-region">区域</label>
|
|
65
|
+
<select id="filter-region" data-dashboard-control="region" disabled></select>
|
|
66
|
+
</div>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
After receiving `live.ready()`, populate it from verified allowed values. Preserve
|
|
70
|
+
JSON types in option values, e.g. `new Option(label, JSON.stringify(value))` and
|
|
71
|
+
`JSON.parse(select.value)` in the change handler. Call
|
|
72
|
+
`window.TrendWorkspace.enhanceSelect(select)` only after populating options and current value.
|
|
73
|
+
The component renders the two-line caption/value trigger, focus ring and menu.
|
|
74
|
+
|
|
75
|
+
Keep the native select and its ID as the typed data-control contract. It becomes
|
|
76
|
+
hidden after enhancement; do not render another independent data control with the
|
|
77
|
+
same ID. Selecting a menu row dispatches the select's normal `change` event.
|
|
78
|
+
Every change must query **all** affected Bindings; visual selection is not proof
|
|
79
|
+
of a data query. Set native `select.disabled` while querying; the custom trigger
|
|
80
|
+
tracks it. The menu supports arrows, Home/End, Enter/Space, Escape, Tab, typeahead,
|
|
81
|
+
click outside and an explicit selected check. Do not replace it with a CSS-only
|
|
82
|
+
fake menu. Four options do not need search or an Apply button.
|
|
83
|
+
|
|
84
|
+
The project/dashboard selector and Publish/More toolbar belong to the host View.
|
|
85
|
+
Do not duplicate those controls inside the authored HTML.
|
|
86
|
+
|
|
87
|
+
## Adapt to a new dataset
|
|
88
|
+
|
|
89
|
+
1. Discover the real source and field schema. Define the business question, grain,
|
|
90
|
+
units, source period, denominator and allowed filters before choosing charts.
|
|
91
|
+
2. Select layout by task: time trend uses overview's main region + lower band;
|
|
92
|
+
product contribution uses two related plots; customer structure uses compact
|
|
93
|
+
comparisons and a table. Keep the same rail, controls and tokens.
|
|
94
|
+
3. Map actual fields explicitly into `window.TrendWorkspace.charts.line`, `.horizontal`
|
|
95
|
+
or `.scatter`; arguments name `dimension`, `measure` or `x`/`y` and labels.
|
|
96
|
+
Do not infer semantics from a field name or reuse Superstore field names blindly.
|
|
97
|
+
4. Build KPI calculations from independent backend totals. Ratios use the same
|
|
98
|
+
filtered numerator/denominator. Distinct counts must not be summed across groups.
|
|
99
|
+
5. Subscribe to every saved Binding; render only when the complete current result
|
|
100
|
+
set has arrived. Clear previous results on filter changes, denied/failed queries,
|
|
101
|
+
truncation and empty scopes. Source timestamps must come from query freshness.
|
|
102
|
+
6. Preserve decimal strings for financial display; only validated finite numbers
|
|
103
|
+
enter charts/ratios. Use DOM textContent for labels, not untrusted innerHTML.
|
|
104
|
+
7. Write the complete HTML with SandboxFile, preview/test each query and filter,
|
|
105
|
+
then save a real draft. Do not deliver a static screenshot instead.
|
|
106
|
+
|
|
107
|
+
## Upgrade an existing dashboard to this theme
|
|
108
|
+
|
|
109
|
+
Use `dashboard_list` in the current project and exact Artifact IDs. Open each
|
|
110
|
+
explicit target with `dashboard_open`, read its current editing copy, and retain
|
|
111
|
+
the returned `saveArguments`. Preserve Binding IDs, sources, controls, units,
|
|
112
|
+
title/Artifact identity and all existing HTML IDs. Add `chart-profit` only when
|
|
113
|
+
splitting an existing sales/profit trend; retain `chart-primary` and `chart-secondary`.
|
|
114
|
+
|
|
115
|
+
For the unmodified Superstore recipe, the current full HTML already composes this
|
|
116
|
+
theme and the same binding contract. You may reuse that page after verifying the
|
|
117
|
+
opened dashboard has the expected bindings and no user customizations. Replace
|
|
118
|
+
the **opened editing file** with exact SandboxFile edits, then use
|
|
119
|
+
`dashboard_update` with its saved envelope, htmlPath and
|
|
120
|
+
`libraries:["echarts","trend-workspace"]`. Never create a duplicate
|
|
121
|
+
Artifact to avoid editing. For customized or other-data dashboards, transplant
|
|
122
|
+
the theme assets and structural sections while retaining their business runtime.
|
|
123
|
+
|
|
124
|
+
For existing files, split edits into logical CSS, layout and script sections;
|
|
125
|
+
keep each old/new text under about 4,000 UTF-8 bytes. Never send a whole old + new
|
|
126
|
+
page in one tool call. Use `sandbox_multi_edit_file` with a few bounded edits, or
|
|
127
|
+
insert complete sections before a unique temporary marker. Remove temporary
|
|
128
|
+
markers before saving. Never use sandbox_write_file on an existing editing copy.
|
|
129
|
+
For a new long file, create the first section and append the remaining sections
|
|
130
|
+
with sandbox_append_file. Complete and inspect the document before any save. A failed or partial file edit
|
|
131
|
+
is not a saved dashboard. Keep three-page upgrades sequential, one page per save.
|
|
132
|
+
|
|
133
|
+
## Acceptance before reporting success
|
|
134
|
+
|
|
135
|
+
- Verify actual successful draft receipts, title and intended Artifact IDs.
|
|
136
|
+
- Open the saved page: rail, separate trend scales, direct-value ranking and
|
|
137
|
+
two-line select triggers must be present; do not rely on a theme-name attribute.
|
|
138
|
+
- Change a real filter; all KPIs, plots and detail rows must reflect the new scope.
|
|
139
|
+
- Check open-menu selected state, keyboard selection/Escape, viewport edges,
|
|
140
|
+
loading, empty/error/recovery, 390px layout and dark-mode contrast.
|
|
141
|
+
- Confirm refresh does not reset the controls and the page uses current results.
|
|
142
|
+
- Preserve user customizations and leave formal publication to the human.
|
|
143
|
+
- If no rendered inspection capability is available, report that visual QA is
|
|
144
|
+
pending. Never claim a screenshot comparison from source code alone.
|