@deepfuture/dui-templates 1.0.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/README.md +214 -0
- package/all.d.ts +10 -0
- package/all.js +20 -0
- package/content/briefing-block.d.ts +36 -0
- package/content/briefing-block.js +281 -0
- package/content/empty-state.d.ts +24 -0
- package/content/empty-state.js +187 -0
- package/content/index.d.ts +5 -0
- package/content/index.js +5 -0
- package/content/numbered-insight.d.ts +30 -0
- package/content/numbered-insight.js +242 -0
- package/dashboard/index.d.ts +5 -0
- package/dashboard/index.js +5 -0
- package/dashboard/page-header.d.ts +29 -0
- package/dashboard/page-header.js +218 -0
- package/dashboard/section-panel.d.ts +41 -0
- package/dashboard/section-panel.js +393 -0
- package/data/index.d.ts +5 -0
- package/data/index.js +4 -0
- package/data/key-value.d.ts +27 -0
- package/data/key-value.js +165 -0
- package/data/market-table.d.ts +40 -0
- package/data/market-table.js +270 -0
- package/feed/activity-item.d.ts +35 -0
- package/feed/activity-item.js +278 -0
- package/feed/feed-item.d.ts +32 -0
- package/feed/feed-item.js +260 -0
- package/feed/headline-item.d.ts +27 -0
- package/feed/headline-item.js +187 -0
- package/feed/index.d.ts +6 -0
- package/feed/index.js +6 -0
- package/feed/social-post.d.ts +31 -0
- package/feed/social-post.js +268 -0
- package/media/avatar-row.d.ts +31 -0
- package/media/avatar-row.js +164 -0
- package/media/index.d.ts +7 -0
- package/media/index.js +5 -0
- package/media/media-grid.d.ts +32 -0
- package/media/media-grid.js +199 -0
- package/metrics/index.d.ts +6 -0
- package/metrics/index.js +6 -0
- package/metrics/progress-bar.d.ts +31 -0
- package/metrics/progress-bar.js +212 -0
- package/metrics/risk-gauge.d.ts +31 -0
- package/metrics/risk-gauge.js +289 -0
- package/metrics/score-item.d.ts +33 -0
- package/metrics/score-item.js +253 -0
- package/metrics/stat-card.d.ts +29 -0
- package/metrics/stat-card.js +230 -0
- package/package.json +61 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { css, html, LitElement, nothing } from "lit";
|
|
36
|
+
import { property } from "lit/decorators.js";
|
|
37
|
+
import { base } from "@deepfuture/dui-core/base";
|
|
38
|
+
import "@deepfuture/dui-components/separator";
|
|
39
|
+
const styles = css `
|
|
40
|
+
:host {
|
|
41
|
+
display: block;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
header {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
gap: var(--space-3);
|
|
48
|
+
padding: var(--space-5) var(--space-6);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ── Title row ── */
|
|
52
|
+
.title-row {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: flex-start;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
gap: var(--space-4);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.title-group {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
gap: var(--space-1);
|
|
63
|
+
min-width: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.title {
|
|
67
|
+
font-family: var(--font-sans);
|
|
68
|
+
font-size: var(--text-2xl);
|
|
69
|
+
font-weight: var(--font-weight-semibold);
|
|
70
|
+
letter-spacing: var(--letter-spacing-normal);
|
|
71
|
+
line-height: var(--line-height-tight);
|
|
72
|
+
color: var(--foreground);
|
|
73
|
+
margin: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.subtitle {
|
|
77
|
+
font-family: var(--font-sans);
|
|
78
|
+
font-size: var(--text-sm);
|
|
79
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
80
|
+
line-height: var(--line-height-normal);
|
|
81
|
+
color: var(--text-2);
|
|
82
|
+
margin: 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* ── Actions slot ── */
|
|
86
|
+
.actions {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: var(--space-2);
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.actions[hidden] {
|
|
94
|
+
display: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ── Bottom border ── */
|
|
98
|
+
dui-separator {
|
|
99
|
+
margin-top: var(--space-1);
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
/**
|
|
103
|
+
* `<dui-page-header>` — Full-width top bar for dashboard pages.
|
|
104
|
+
*
|
|
105
|
+
* Renders an optional breadcrumb trail, a title, an optional subtitle,
|
|
106
|
+
* and trailing action buttons. A separator is rendered at the bottom.
|
|
107
|
+
*
|
|
108
|
+
* The `breadcrumbs` prop accepts a comma-separated string. The last segment
|
|
109
|
+
* is rendered as the current page; preceding segments render as links.
|
|
110
|
+
*
|
|
111
|
+
* @slot actions - Trailing action buttons or controls.
|
|
112
|
+
* @csspart header - The outer `<header>` container.
|
|
113
|
+
* @csspart breadcrumb - The breadcrumb navigation.
|
|
114
|
+
* @csspart title - The page title.
|
|
115
|
+
* @csspart subtitle - The subtitle paragraph.
|
|
116
|
+
*/
|
|
117
|
+
let DuiPageHeader = (() => {
|
|
118
|
+
let _classSuper = LitElement;
|
|
119
|
+
let _title_decorators;
|
|
120
|
+
let _title_initializers = [];
|
|
121
|
+
let _title_extraInitializers = [];
|
|
122
|
+
let _subtitle_decorators;
|
|
123
|
+
let _subtitle_initializers = [];
|
|
124
|
+
let _subtitle_extraInitializers = [];
|
|
125
|
+
let _breadcrumbs_decorators;
|
|
126
|
+
let _breadcrumbs_initializers = [];
|
|
127
|
+
let _breadcrumbs_extraInitializers = [];
|
|
128
|
+
return class DuiPageHeader extends _classSuper {
|
|
129
|
+
static {
|
|
130
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
131
|
+
_title_decorators = [property()];
|
|
132
|
+
_subtitle_decorators = [property()];
|
|
133
|
+
_breadcrumbs_decorators = [property()];
|
|
134
|
+
__esDecorate(this, null, _title_decorators, { kind: "accessor", name: "title", static: false, private: false, access: { has: obj => "title" in obj, get: obj => obj.title, set: (obj, value) => { obj.title = value; } }, metadata: _metadata }, _title_initializers, _title_extraInitializers);
|
|
135
|
+
__esDecorate(this, null, _subtitle_decorators, { kind: "accessor", name: "subtitle", static: false, private: false, access: { has: obj => "subtitle" in obj, get: obj => obj.subtitle, set: (obj, value) => { obj.subtitle = value; } }, metadata: _metadata }, _subtitle_initializers, _subtitle_extraInitializers);
|
|
136
|
+
__esDecorate(this, null, _breadcrumbs_decorators, { kind: "accessor", name: "breadcrumbs", static: false, private: false, access: { has: obj => "breadcrumbs" in obj, get: obj => obj.breadcrumbs, set: (obj, value) => { obj.breadcrumbs = value; } }, metadata: _metadata }, _breadcrumbs_initializers, _breadcrumbs_extraInitializers);
|
|
137
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
138
|
+
}
|
|
139
|
+
static tagName = "dui-page-header";
|
|
140
|
+
static styles = [base, styles];
|
|
141
|
+
#title_accessor_storage = __runInitializers(this, _title_initializers, "");
|
|
142
|
+
/** Page title displayed prominently. */
|
|
143
|
+
get title() { return this.#title_accessor_storage; }
|
|
144
|
+
set title(value) { this.#title_accessor_storage = value; }
|
|
145
|
+
#subtitle_accessor_storage = (__runInitializers(this, _title_extraInitializers), __runInitializers(this, _subtitle_initializers, ""));
|
|
146
|
+
/** Supporting text below the title. */
|
|
147
|
+
get subtitle() { return this.#subtitle_accessor_storage; }
|
|
148
|
+
set subtitle(value) { this.#subtitle_accessor_storage = value; }
|
|
149
|
+
#breadcrumbs_accessor_storage = (__runInitializers(this, _subtitle_extraInitializers), __runInitializers(this, _breadcrumbs_initializers, ""));
|
|
150
|
+
/** Comma-separated breadcrumb trail (e.g. "Home, Settings, Profile"). */
|
|
151
|
+
get breadcrumbs() { return this.#breadcrumbs_accessor_storage; }
|
|
152
|
+
set breadcrumbs(value) { this.#breadcrumbs_accessor_storage = value; }
|
|
153
|
+
#onSlotChange(e) {
|
|
154
|
+
const slot = e.target;
|
|
155
|
+
slot.parentElement.hidden = slot.assignedElements().length === 0;
|
|
156
|
+
}
|
|
157
|
+
#renderBreadcrumbs() {
|
|
158
|
+
if (!this.breadcrumbs)
|
|
159
|
+
return nothing;
|
|
160
|
+
const segments = this.breadcrumbs.split(",").map((s) => s.trim()).filter(Boolean);
|
|
161
|
+
if (segments.length === 0)
|
|
162
|
+
return nothing;
|
|
163
|
+
const items = [];
|
|
164
|
+
segments.forEach((segment, i) => {
|
|
165
|
+
const isLast = i === segments.length - 1;
|
|
166
|
+
if (i > 0) {
|
|
167
|
+
items.push(html `<dui-breadcrumb-separator></dui-breadcrumb-separator>`);
|
|
168
|
+
}
|
|
169
|
+
if (isLast) {
|
|
170
|
+
items.push(html `
|
|
171
|
+
<dui-breadcrumb-item>
|
|
172
|
+
<dui-breadcrumb-page>${segment}</dui-breadcrumb-page>
|
|
173
|
+
</dui-breadcrumb-item>
|
|
174
|
+
`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
items.push(html `
|
|
178
|
+
<dui-breadcrumb-item>
|
|
179
|
+
<dui-breadcrumb-link>
|
|
180
|
+
<a href="javascript:void(0)">${segment}</a>
|
|
181
|
+
</dui-breadcrumb-link>
|
|
182
|
+
</dui-breadcrumb-item>
|
|
183
|
+
`);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return html `
|
|
187
|
+
<dui-breadcrumb part="breadcrumb">${items}</dui-breadcrumb>
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
190
|
+
render() {
|
|
191
|
+
return html `
|
|
192
|
+
<header part="header">
|
|
193
|
+
${this.#renderBreadcrumbs()}
|
|
194
|
+
|
|
195
|
+
<div class="title-row">
|
|
196
|
+
<div class="title-group">
|
|
197
|
+
<h1 class="title" part="title">${this.title}</h1>
|
|
198
|
+
${this.subtitle
|
|
199
|
+
? html `<p class="subtitle" part="subtitle">${this.subtitle}</p>`
|
|
200
|
+
: nothing}
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<div class="actions" hidden>
|
|
204
|
+
<slot name="actions" @slotchange=${this.#onSlotChange}></slot>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</header>
|
|
208
|
+
<dui-separator></dui-separator>
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
constructor() {
|
|
212
|
+
super(...arguments);
|
|
213
|
+
__runInitializers(this, _breadcrumbs_extraInitializers);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
})();
|
|
217
|
+
export { DuiPageHeader };
|
|
218
|
+
customElements.define(DuiPageHeader.tagName, DuiPageHeader);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { LitElement, type TemplateResult } from "lit";
|
|
2
|
+
import "@deepfuture/dui-components/badge";
|
|
3
|
+
import "@deepfuture/dui-components/icon";
|
|
4
|
+
import "@deepfuture/dui-components/collapsible";
|
|
5
|
+
import "@deepfuture/dui-components/tooltip";
|
|
6
|
+
/**
|
|
7
|
+
* `<dui-section-panel>` — A bordered container with a header bar, the fundamental
|
|
8
|
+
* building block for dashboard panels.
|
|
9
|
+
*
|
|
10
|
+
* The header renders an optional icon (slotted), title, badge count, LIVE indicator,
|
|
11
|
+
* help tooltip, and trailing actions. The body is slotted.
|
|
12
|
+
*
|
|
13
|
+
* When `collapsible` is set, the panel wraps its body in a `<dui-collapsible>`,
|
|
14
|
+
* suppressing the collapsible's built-in indicator and rendering its own chevron.
|
|
15
|
+
*
|
|
16
|
+
* @slot - Body content.
|
|
17
|
+
* @slot icon - Optional leading icon (`<dui-icon>` recommended).
|
|
18
|
+
* @slot actions - Trailing actions in the header bar (buttons, menus, etc.).
|
|
19
|
+
* @csspart section - The outer `<section>` container.
|
|
20
|
+
* @csspart header - The header bar.
|
|
21
|
+
* @csspart body - The body content wrapper.
|
|
22
|
+
*/
|
|
23
|
+
export declare class DuiSectionPanel extends LitElement {
|
|
24
|
+
#private;
|
|
25
|
+
static tagName: "dui-section-panel";
|
|
26
|
+
static styles: import("lit").CSSResult[];
|
|
27
|
+
/** Panel title displayed in the header. */
|
|
28
|
+
accessor title: string;
|
|
29
|
+
/** Badge count shown after the title (e.g. "27"). */
|
|
30
|
+
accessor badge: string;
|
|
31
|
+
/** Show a pulsing LIVE indicator in the header. */
|
|
32
|
+
accessor live: boolean;
|
|
33
|
+
/** Tooltip text for a help "?" indicator. */
|
|
34
|
+
accessor help: string;
|
|
35
|
+
/** Enable collapsible mode — body can be toggled open/closed. */
|
|
36
|
+
accessor collapsible: boolean;
|
|
37
|
+
/** Whether the collapsible panel starts open (only relevant when collapsible). */
|
|
38
|
+
accessor defaultOpen: boolean;
|
|
39
|
+
connectedCallback(): void;
|
|
40
|
+
render(): TemplateResult;
|
|
41
|
+
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { css, html, LitElement, nothing } from "lit";
|
|
36
|
+
import { property } from "lit/decorators.js";
|
|
37
|
+
import { base } from "@deepfuture/dui-core/base";
|
|
38
|
+
import "@deepfuture/dui-components/badge";
|
|
39
|
+
import "@deepfuture/dui-components/icon";
|
|
40
|
+
import "@deepfuture/dui-components/collapsible";
|
|
41
|
+
import "@deepfuture/dui-components/tooltip";
|
|
42
|
+
const styles = css `
|
|
43
|
+
:host {
|
|
44
|
+
display: block;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
section {
|
|
48
|
+
border: var(--border-width-thin) solid var(--border);
|
|
49
|
+
border-radius: var(--radius-md);
|
|
50
|
+
background: var(--surface-1);
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ── Header bar ── */
|
|
55
|
+
.header {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: var(--space-2);
|
|
59
|
+
padding: var(--space-3) var(--space-4);
|
|
60
|
+
border-bottom: var(--border-width-thin) solid var(--border);
|
|
61
|
+
min-height: var(--space-5);
|
|
62
|
+
width: 100%;
|
|
63
|
+
transition: border var(--duration-normal) linear;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
:host([collapsible]:not([data-open])) .header {
|
|
68
|
+
/* Hide header bottom border on collapsible sections when the section is closed */
|
|
69
|
+
/* Or else we get double bottom borders. */
|
|
70
|
+
border-color: transparent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.header-left {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: var(--space-2);
|
|
77
|
+
min-width: 0;
|
|
78
|
+
flex: 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.icon-slot {
|
|
82
|
+
display: contents;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.icon-slot[hidden] {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.icon-slot ::slotted(dui-icon) {
|
|
90
|
+
--icon-size: 1rem;
|
|
91
|
+
--icon-color: var(--text-2);
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.title {
|
|
96
|
+
font-family: var(--font-sans);
|
|
97
|
+
font-size: var(--text-sm);
|
|
98
|
+
font-weight: var(--font-weight-semibold);
|
|
99
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
100
|
+
line-height: var(--line-height-snug);
|
|
101
|
+
color: var(--foreground);
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
overflow: hidden;
|
|
104
|
+
text-overflow: ellipsis;
|
|
105
|
+
min-width: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ── Indicators ── */
|
|
109
|
+
.live {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
gap: var(--space-1);
|
|
113
|
+
flex-shrink: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.live-dot {
|
|
117
|
+
display: inline-block;
|
|
118
|
+
width: var(--space-1_5);
|
|
119
|
+
height: var(--space-1_5);
|
|
120
|
+
border-radius: var(--radius-full);
|
|
121
|
+
background: var(--destructive);
|
|
122
|
+
animation: pulse-dot 2s ease-in-out infinite;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@keyframes pulse-dot {
|
|
126
|
+
0%, 100% { opacity: 1; }
|
|
127
|
+
50% { opacity: 0.35; }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.live-label {
|
|
131
|
+
font-family: var(--font-sans);
|
|
132
|
+
font-size: var(--text-2xs);
|
|
133
|
+
font-weight: var(--font-weight-semibold);
|
|
134
|
+
letter-spacing: var(--letter-spacing-widest);
|
|
135
|
+
text-transform: uppercase;
|
|
136
|
+
color: var(--destructive-text);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.help-btn {
|
|
140
|
+
display: inline-flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
width: var(--space-4);
|
|
144
|
+
height: var(--space-4);
|
|
145
|
+
border-radius: var(--radius-full);
|
|
146
|
+
border: var(--border-width-thin) solid var(--border);
|
|
147
|
+
background: transparent;
|
|
148
|
+
color: var(--text-3);
|
|
149
|
+
font-family: var(--font-sans);
|
|
150
|
+
font-size: var(--text-xs);
|
|
151
|
+
font-weight: var(--font-weight-medium);
|
|
152
|
+
cursor: help;
|
|
153
|
+
flex-shrink: 0;
|
|
154
|
+
line-height: 1;
|
|
155
|
+
transition: color var(--duration-fast) ease, border-color var(--duration-fast) ease;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.help-btn:hover {
|
|
159
|
+
color: var(--text-2);
|
|
160
|
+
border-color: var(--border-strong);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* ── Header trailing ── */
|
|
164
|
+
.header-right {
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
gap: var(--space-2);
|
|
168
|
+
flex-shrink: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.actions-slot {
|
|
172
|
+
display: contents;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.actions-slot[hidden] {
|
|
176
|
+
display: none;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* ── Body ── */
|
|
180
|
+
.body {
|
|
181
|
+
padding: var(--space-4);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* ── Collapsible overrides ── */
|
|
185
|
+
dui-collapsible {
|
|
186
|
+
/* Hide the theme's indicator — we render our own chevron */
|
|
187
|
+
--collapsible-indicator-display: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* Reset the theme's trigger chrome so our .header controls layout */
|
|
191
|
+
dui-collapsible::part(trigger) {
|
|
192
|
+
padding: 0;
|
|
193
|
+
height: auto;
|
|
194
|
+
border-radius: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
dui-collapsible::part(content) {
|
|
198
|
+
padding: 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ── Chevron ── */
|
|
202
|
+
.chevron {
|
|
203
|
+
display: inline-flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
justify-content: center;
|
|
206
|
+
flex-shrink: 0;
|
|
207
|
+
color: var(--text-3);
|
|
208
|
+
transition: transform var(--duration-fast) var(--ease-out-3);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
:host([data-open]) .chevron {
|
|
212
|
+
transform: rotate(180deg);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@media (prefers-reduced-motion: reduce) {
|
|
216
|
+
.chevron {
|
|
217
|
+
transition-duration: 0s;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
`;
|
|
221
|
+
/**
|
|
222
|
+
* `<dui-section-panel>` — A bordered container with a header bar, the fundamental
|
|
223
|
+
* building block for dashboard panels.
|
|
224
|
+
*
|
|
225
|
+
* The header renders an optional icon (slotted), title, badge count, LIVE indicator,
|
|
226
|
+
* help tooltip, and trailing actions. The body is slotted.
|
|
227
|
+
*
|
|
228
|
+
* When `collapsible` is set, the panel wraps its body in a `<dui-collapsible>`,
|
|
229
|
+
* suppressing the collapsible's built-in indicator and rendering its own chevron.
|
|
230
|
+
*
|
|
231
|
+
* @slot - Body content.
|
|
232
|
+
* @slot icon - Optional leading icon (`<dui-icon>` recommended).
|
|
233
|
+
* @slot actions - Trailing actions in the header bar (buttons, menus, etc.).
|
|
234
|
+
* @csspart section - The outer `<section>` container.
|
|
235
|
+
* @csspart header - The header bar.
|
|
236
|
+
* @csspart body - The body content wrapper.
|
|
237
|
+
*/
|
|
238
|
+
let DuiSectionPanel = (() => {
|
|
239
|
+
let _classSuper = LitElement;
|
|
240
|
+
let _title_decorators;
|
|
241
|
+
let _title_initializers = [];
|
|
242
|
+
let _title_extraInitializers = [];
|
|
243
|
+
let _badge_decorators;
|
|
244
|
+
let _badge_initializers = [];
|
|
245
|
+
let _badge_extraInitializers = [];
|
|
246
|
+
let _live_decorators;
|
|
247
|
+
let _live_initializers = [];
|
|
248
|
+
let _live_extraInitializers = [];
|
|
249
|
+
let _help_decorators;
|
|
250
|
+
let _help_initializers = [];
|
|
251
|
+
let _help_extraInitializers = [];
|
|
252
|
+
let _collapsible_decorators;
|
|
253
|
+
let _collapsible_initializers = [];
|
|
254
|
+
let _collapsible_extraInitializers = [];
|
|
255
|
+
let _defaultOpen_decorators;
|
|
256
|
+
let _defaultOpen_initializers = [];
|
|
257
|
+
let _defaultOpen_extraInitializers = [];
|
|
258
|
+
return class DuiSectionPanel extends _classSuper {
|
|
259
|
+
static {
|
|
260
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
261
|
+
_title_decorators = [property()];
|
|
262
|
+
_badge_decorators = [property()];
|
|
263
|
+
_live_decorators = [property({ type: Boolean })];
|
|
264
|
+
_help_decorators = [property()];
|
|
265
|
+
_collapsible_decorators = [property({ type: Boolean })];
|
|
266
|
+
_defaultOpen_decorators = [property({ type: Boolean, attribute: "default-open" })];
|
|
267
|
+
__esDecorate(this, null, _title_decorators, { kind: "accessor", name: "title", static: false, private: false, access: { has: obj => "title" in obj, get: obj => obj.title, set: (obj, value) => { obj.title = value; } }, metadata: _metadata }, _title_initializers, _title_extraInitializers);
|
|
268
|
+
__esDecorate(this, null, _badge_decorators, { kind: "accessor", name: "badge", static: false, private: false, access: { has: obj => "badge" in obj, get: obj => obj.badge, set: (obj, value) => { obj.badge = value; } }, metadata: _metadata }, _badge_initializers, _badge_extraInitializers);
|
|
269
|
+
__esDecorate(this, null, _live_decorators, { kind: "accessor", name: "live", static: false, private: false, access: { has: obj => "live" in obj, get: obj => obj.live, set: (obj, value) => { obj.live = value; } }, metadata: _metadata }, _live_initializers, _live_extraInitializers);
|
|
270
|
+
__esDecorate(this, null, _help_decorators, { kind: "accessor", name: "help", static: false, private: false, access: { has: obj => "help" in obj, get: obj => obj.help, set: (obj, value) => { obj.help = value; } }, metadata: _metadata }, _help_initializers, _help_extraInitializers);
|
|
271
|
+
__esDecorate(this, null, _collapsible_decorators, { kind: "accessor", name: "collapsible", static: false, private: false, access: { has: obj => "collapsible" in obj, get: obj => obj.collapsible, set: (obj, value) => { obj.collapsible = value; } }, metadata: _metadata }, _collapsible_initializers, _collapsible_extraInitializers);
|
|
272
|
+
__esDecorate(this, null, _defaultOpen_decorators, { kind: "accessor", name: "defaultOpen", static: false, private: false, access: { has: obj => "defaultOpen" in obj, get: obj => obj.defaultOpen, set: (obj, value) => { obj.defaultOpen = value; } }, metadata: _metadata }, _defaultOpen_initializers, _defaultOpen_extraInitializers);
|
|
273
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
274
|
+
}
|
|
275
|
+
static tagName = "dui-section-panel";
|
|
276
|
+
static styles = [base, styles];
|
|
277
|
+
#title_accessor_storage = __runInitializers(this, _title_initializers, "");
|
|
278
|
+
/** Panel title displayed in the header. */
|
|
279
|
+
get title() { return this.#title_accessor_storage; }
|
|
280
|
+
set title(value) { this.#title_accessor_storage = value; }
|
|
281
|
+
#badge_accessor_storage = (__runInitializers(this, _title_extraInitializers), __runInitializers(this, _badge_initializers, ""));
|
|
282
|
+
/** Badge count shown after the title (e.g. "27"). */
|
|
283
|
+
get badge() { return this.#badge_accessor_storage; }
|
|
284
|
+
set badge(value) { this.#badge_accessor_storage = value; }
|
|
285
|
+
#live_accessor_storage = (__runInitializers(this, _badge_extraInitializers), __runInitializers(this, _live_initializers, false));
|
|
286
|
+
/** Show a pulsing LIVE indicator in the header. */
|
|
287
|
+
get live() { return this.#live_accessor_storage; }
|
|
288
|
+
set live(value) { this.#live_accessor_storage = value; }
|
|
289
|
+
#help_accessor_storage = (__runInitializers(this, _live_extraInitializers), __runInitializers(this, _help_initializers, ""));
|
|
290
|
+
/** Tooltip text for a help "?" indicator. */
|
|
291
|
+
get help() { return this.#help_accessor_storage; }
|
|
292
|
+
set help(value) { this.#help_accessor_storage = value; }
|
|
293
|
+
#collapsible_accessor_storage = (__runInitializers(this, _help_extraInitializers), __runInitializers(this, _collapsible_initializers, false));
|
|
294
|
+
/** Enable collapsible mode — body can be toggled open/closed. */
|
|
295
|
+
get collapsible() { return this.#collapsible_accessor_storage; }
|
|
296
|
+
set collapsible(value) { this.#collapsible_accessor_storage = value; }
|
|
297
|
+
#defaultOpen_accessor_storage = (__runInitializers(this, _collapsible_extraInitializers), __runInitializers(this, _defaultOpen_initializers, true));
|
|
298
|
+
/** Whether the collapsible panel starts open (only relevant when collapsible). */
|
|
299
|
+
get defaultOpen() { return this.#defaultOpen_accessor_storage; }
|
|
300
|
+
set defaultOpen(value) { this.#defaultOpen_accessor_storage = value; }
|
|
301
|
+
#onSlotChange(e) {
|
|
302
|
+
const slot = e.target;
|
|
303
|
+
slot.parentElement.hidden = slot.assignedElements().length === 0;
|
|
304
|
+
}
|
|
305
|
+
#onOpenChange(e) {
|
|
306
|
+
this.toggleAttribute("data-open", e.detail.open);
|
|
307
|
+
}
|
|
308
|
+
connectedCallback() {
|
|
309
|
+
super.connectedCallback();
|
|
310
|
+
if (this.collapsible && this.defaultOpen) {
|
|
311
|
+
this.toggleAttribute("data-open", true);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
#renderHeaderContent() {
|
|
315
|
+
return html `
|
|
316
|
+
<div class="header-left">
|
|
317
|
+
<span class="icon-slot" hidden><slot name="icon" @slotchange=${this.#onSlotChange}></slot></span>
|
|
318
|
+
<span class="title">${this.title}</span>
|
|
319
|
+
${this.badge
|
|
320
|
+
? html `<dui-badge appearance="soft">${this.badge}</dui-badge>`
|
|
321
|
+
: nothing}
|
|
322
|
+
${this.live
|
|
323
|
+
? html `<span class="live">
|
|
324
|
+
<span class="live-dot"></span>
|
|
325
|
+
<span class="live-label">Live</span>
|
|
326
|
+
</span>`
|
|
327
|
+
: nothing}
|
|
328
|
+
${this.help
|
|
329
|
+
? html `
|
|
330
|
+
<dui-tooltip>
|
|
331
|
+
<dui-tooltip-trigger>
|
|
332
|
+
<button class="help-btn" aria-label="Help" @click=${this.#stopProp}>?</button>
|
|
333
|
+
</dui-tooltip-trigger>
|
|
334
|
+
<dui-tooltip-popup>${this.help}</dui-tooltip-popup>
|
|
335
|
+
</dui-tooltip>`
|
|
336
|
+
: nothing}
|
|
337
|
+
</div>
|
|
338
|
+
<div class="header-right">
|
|
339
|
+
<span class="actions-slot" hidden @click=${this.collapsible ? this.#stopProp : nothing}>
|
|
340
|
+
<slot name="actions" @slotchange=${this.#onSlotChange}></slot>
|
|
341
|
+
</span>
|
|
342
|
+
${this.collapsible
|
|
343
|
+
? html `<span class="chevron">
|
|
344
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none"
|
|
345
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
346
|
+
stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
|
|
347
|
+
</span>`
|
|
348
|
+
: nothing}
|
|
349
|
+
</div>
|
|
350
|
+
`;
|
|
351
|
+
}
|
|
352
|
+
render() {
|
|
353
|
+
if (this.collapsible) {
|
|
354
|
+
return html `
|
|
355
|
+
<section part="section">
|
|
356
|
+
<dui-collapsible
|
|
357
|
+
.defaultOpen=${this.defaultOpen}
|
|
358
|
+
@open-change=${this.#onOpenChange}
|
|
359
|
+
>
|
|
360
|
+
<div slot="trigger" class="header" part="header">
|
|
361
|
+
${this.#renderHeaderContent()}
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
<div class="body" part="body">
|
|
365
|
+
<slot></slot>
|
|
366
|
+
</div>
|
|
367
|
+
</dui-collapsible>
|
|
368
|
+
</section>
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
return html `
|
|
372
|
+
<section part="section">
|
|
373
|
+
<div class="header" part="header">
|
|
374
|
+
${this.#renderHeaderContent()}
|
|
375
|
+
</div>
|
|
376
|
+
<div class="body" part="body">
|
|
377
|
+
<slot></slot>
|
|
378
|
+
</div>
|
|
379
|
+
</section>
|
|
380
|
+
`;
|
|
381
|
+
}
|
|
382
|
+
/** Stop click propagation so actions/help in header don't trigger collapse. */
|
|
383
|
+
#stopProp(e) {
|
|
384
|
+
e.stopPropagation();
|
|
385
|
+
}
|
|
386
|
+
constructor() {
|
|
387
|
+
super(...arguments);
|
|
388
|
+
__runInitializers(this, _defaultOpen_extraInitializers);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
})();
|
|
392
|
+
export { DuiSectionPanel };
|
|
393
|
+
customElements.define(DuiSectionPanel.tagName, DuiSectionPanel);
|
package/data/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { DuiKeyValue } from "./key-value.js";
|
|
2
|
+
import { DuiMarketTable } from "./market-table.js";
|
|
3
|
+
export { DuiKeyValue, DuiMarketTable };
|
|
4
|
+
export type { MarketRow } from "./market-table.js";
|
|
5
|
+
export declare const dataFamily: (typeof DuiKeyValue | typeof DuiMarketTable)[];
|
package/data/index.js
ADDED