@things-factory/ai-dashboard 0.0.0-stage → 10.1.213

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.
Files changed (108) hide show
  1. package/client/bootstrap.ts +25 -0
  2. package/client/components/card-dialogs.ts +422 -0
  3. package/client/components/card-library.ts +272 -0
  4. package/client/components/dashboard-card.ts +450 -0
  5. package/client/components/proposal-preview.ts +96 -0
  6. package/client/index.ts +3 -0
  7. package/client/pages/my-dashboard-page.ts +371 -0
  8. package/client/route.ts +8 -0
  9. package/client/tsconfig.json +13 -0
  10. package/client/utils/card-api.ts +110 -0
  11. package/client/utils/card-words.ts +80 -0
  12. package/dist-client/bootstrap.d.ts +2 -0
  13. package/dist-client/bootstrap.js +24 -0
  14. package/dist-client/bootstrap.js.map +1 -0
  15. package/dist-client/components/card-dialogs.d.ts +59 -0
  16. package/dist-client/components/card-dialogs.js +457 -0
  17. package/dist-client/components/card-dialogs.js.map +1 -0
  18. package/dist-client/components/card-library.d.ts +23 -0
  19. package/dist-client/components/card-library.js +276 -0
  20. package/dist-client/components/card-library.js.map +1 -0
  21. package/dist-client/components/dashboard-card.d.ts +35 -0
  22. package/dist-client/components/dashboard-card.js +490 -0
  23. package/dist-client/components/dashboard-card.js.map +1 -0
  24. package/dist-client/components/proposal-preview.d.ts +17 -0
  25. package/dist-client/components/proposal-preview.js +111 -0
  26. package/dist-client/components/proposal-preview.js.map +1 -0
  27. package/dist-client/index.d.ts +3 -0
  28. package/dist-client/index.js +4 -0
  29. package/dist-client/index.js.map +1 -0
  30. package/dist-client/pages/my-dashboard-page.d.ts +46 -0
  31. package/dist-client/pages/my-dashboard-page.js +376 -0
  32. package/dist-client/pages/my-dashboard-page.js.map +1 -0
  33. package/dist-client/route.d.ts +1 -0
  34. package/dist-client/route.js +9 -0
  35. package/dist-client/route.js.map +1 -0
  36. package/dist-client/tsconfig.tsbuildinfo +1 -0
  37. package/dist-client/utils/card-api.d.ts +95 -0
  38. package/dist-client/utils/card-api.js +39 -0
  39. package/dist-client/utils/card-api.js.map +1 -0
  40. package/dist-client/utils/card-words.d.ts +24 -0
  41. package/dist-client/utils/card-words.js +72 -0
  42. package/dist-client/utils/card-words.js.map +1 -0
  43. package/dist-server/index.d.ts +11 -0
  44. package/dist-server/index.js +19 -0
  45. package/dist-server/index.js.map +1 -0
  46. package/dist-server/role-tasks.d.ts +2 -0
  47. package/dist-server/role-tasks.js +13 -0
  48. package/dist-server/role-tasks.js.map +1 -0
  49. package/dist-server/service/card/card-access.d.ts +32 -0
  50. package/dist-server/service/card/card-access.js +45 -0
  51. package/dist-server/service/card/card-access.js.map +1 -0
  52. package/dist-server/service/card/card-definition.d.ts +100 -0
  53. package/dist-server/service/card/card-definition.js +237 -0
  54. package/dist-server/service/card/card-definition.js.map +1 -0
  55. package/dist-server/service/card/card-names.d.ts +5 -0
  56. package/dist-server/service/card/card-names.js +9 -0
  57. package/dist-server/service/card/card-names.js.map +1 -0
  58. package/dist-server/service/card/card-proposal.d.ts +21 -0
  59. package/dist-server/service/card/card-proposal.js +28 -0
  60. package/dist-server/service/card/card-proposal.js.map +1 -0
  61. package/dist-server/service/card/card-resolver.d.ts +29 -0
  62. package/dist-server/service/card/card-resolver.js +541 -0
  63. package/dist-server/service/card/card-resolver.js.map +1 -0
  64. package/dist-server/service/card/card-run.d.ts +48 -0
  65. package/dist-server/service/card/card-run.js +239 -0
  66. package/dist-server/service/card/card-run.js.map +1 -0
  67. package/dist-server/service/card/card-tool.d.ts +218 -0
  68. package/dist-server/service/card/card-tool.js +313 -0
  69. package/dist-server/service/card/card-tool.js.map +1 -0
  70. package/dist-server/service/card/card-types.d.ts +56 -0
  71. package/dist-server/service/card/card-types.js +212 -0
  72. package/dist-server/service/card/card-types.js.map +1 -0
  73. package/dist-server/service/card/dashboard-card.d.ts +87 -0
  74. package/dist-server/service/card/dashboard-card.js +388 -0
  75. package/dist-server/service/card/dashboard-card.js.map +1 -0
  76. package/dist-server/service/card/long-text.d.ts +6 -0
  77. package/dist-server/service/card/long-text.js +28 -0
  78. package/dist-server/service/card/long-text.js.map +1 -0
  79. package/dist-server/service/index.d.ts +12 -0
  80. package/dist-server/service/index.js +24 -0
  81. package/dist-server/service/index.js.map +1 -0
  82. package/dist-server/tsconfig.tsbuildinfo +1 -0
  83. package/package.json +47 -4
  84. package/server/index.ts +16 -0
  85. package/server/role-tasks.ts +12 -0
  86. package/server/service/card/card-access.test.ts +138 -0
  87. package/server/service/card/card-access.ts +53 -0
  88. package/server/service/card/card-definition.ts +298 -0
  89. package/server/service/card/card-names.ts +5 -0
  90. package/server/service/card/card-proposal.ts +37 -0
  91. package/server/service/card/card-resolver.ts +434 -0
  92. package/server/service/card/card-run.test.ts +237 -0
  93. package/server/service/card/card-run.ts +288 -0
  94. package/server/service/card/card-tool.ts +299 -0
  95. package/server/service/card/card-types.ts +145 -0
  96. package/server/service/card/dashboard-card.ts +301 -0
  97. package/server/service/card/long-text.ts +25 -0
  98. package/server/service/index.ts +16 -0
  99. package/test/translations.test.ts +42 -0
  100. package/things-factory.config.js +8 -0
  101. package/translations/en.json +126 -0
  102. package/translations/es.json +126 -0
  103. package/translations/ja.json +126 -0
  104. package/translations/ko.json +126 -0
  105. package/translations/ms.json +126 -0
  106. package/translations/zh.json +126 -0
  107. package/tsconfig.json +9 -0
  108. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-preview.js","sourceRoot":"","sources":["../../client/components/proposal-preview.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The preview under a card the conversation offers (ADR-0160 decisions 6, 9). The proposal holds the definition only;\n * the preview asks the server to run it as whoever is looking at the conversation, so a value is never kept in the\n * conversation and nobody sees data their own doors do not open.\n */\nimport '@material/web/icon/icon.js'\nimport '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\nimport { cardApi, type CardRun } from '../utils/card-api.js'\nimport { drawsNothing, issueLine, partialLine } from '../utils/card-words.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n@customElement('ai-dashboard-proposal-preview')\nexport class ProposalPreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n margin: 4px 0 8px;\n }\n\n .frame {\n padding: 10px 12px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 10px;\n background: var(--md-sys-color-surface-container-lowest);\n }\n\n .waiting,\n .note {\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .note {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 6px;\n --md-icon-size: 14px;\n }\n\n .issue {\n font-size: 12px;\n color: var(--md-sys-color-error);\n }\n\n .partial {\n color: var(--ui-warn, #b26a00);\n }\n `\n\n @property({ attribute: false }) proposal: any\n @property({ attribute: false }) sessionId?: string\n @property({ attribute: false }) proposalKey?: string\n\n @state() private run?: CardRun\n @state() private failed?: string\n private readFor?: string\n\n updated() {\n const key = this.sessionId && this.proposalKey ? `${this.sessionId}/${this.proposalKey}` : undefined\n if (key && key !== this.readFor) this.read(key)\n }\n\n private async read(key: string) {\n this.readFor = key\n try {\n const run = await cardApi.preview(this.sessionId!, this.proposalKey!)\n if (this.readFor === key) this.run = run\n } catch (error: any) {\n if (this.readFor === key) this.failed = error?.message ?? String(error)\n }\n }\n\n render() {\n if (this.failed) return html`<div class=\"frame issue\">${this.failed}</div>`\n if (!this.run) return html`<div class=\"frame waiting\">${t('ai-dashboard.preview.reading')}</div>`\n const issue = issueLine(this.run, t)\n const partial = partialLine(this.run, t)\n return html`<div class=\"frame\">\n ${issue\n ? html`<div class=\"issue\">${issue.text}</div>`\n : drawsNothing(this.run)\n ? html`<div class=\"waiting\">${t('ai-dashboard.card.nothing')}</div>`\n : html`<ox-assistant-workspace-view compact .workspace=${{ name: this.proposalKey, title: this.proposal?.card?.name ?? '', blocks: [this.run.block] }}></ox-assistant-workspace-view>`}\n ${partial ? html`<div class=\"note partial\"><md-icon>warning</md-icon>${partial}</div>` : nothing}\n <div class=\"note\"><md-icon>bolt</md-icon>${t('ai-dashboard.preview.note', { day: this.run.asOf })}</div>\n </div>`\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './utils/card-api.js';
2
+ export * from './utils/card-words.js';
3
+ export * from './components/dashboard-card.js';
@@ -0,0 +1,4 @@
1
+ export * from './utils/card-api.js';
2
+ export * from './utils/card-words.js';
3
+ export * from './components/dashboard-card.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA","sourcesContent":["export * from './utils/card-api.js'\nexport * from './utils/card-words.js'\nexport * from './components/dashboard-card.js'\n"]}
@@ -0,0 +1,46 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '../components/dashboard-card.js';
3
+ import '../components/card-library.js';
4
+ import { PageView } from '@operato/shell';
5
+ declare const MyDashboardPage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
6
+ export declare class MyDashboardPage extends MyDashboardPage_base {
7
+ static styles: import("lit").CSSResult[];
8
+ private places;
9
+ private loaded;
10
+ private error?;
11
+ private editing;
12
+ private onChanged;
13
+ get context(): {
14
+ title: string;
15
+ frame: string;
16
+ actions: ({
17
+ title: string;
18
+ action: () => void;
19
+ icon: string;
20
+ emphasis?: undefined;
21
+ } | {
22
+ title: string;
23
+ action: () => void;
24
+ icon: string;
25
+ emphasis: {
26
+ raised: boolean;
27
+ };
28
+ })[];
29
+ };
30
+ connectedCallback(): void;
31
+ disconnectedCallback(): void;
32
+ updated(changes: Map<string, unknown>): void;
33
+ pageUpdated(changes: any): Promise<void>;
34
+ private load;
35
+ render(): import("lit-html").TemplateResult<1>;
36
+ private renderBoard;
37
+ private renderEmpty;
38
+ /** Sends a request to the conversation beside the page - this screen's, where the card tool is in front. */
39
+ private askFor;
40
+ private make;
41
+ private openLibrary;
42
+ private placeOf;
43
+ private arrange;
44
+ private onCardAction;
45
+ }
46
+ export {};
@@ -0,0 +1,376 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ /*
3
+ * 나의 대시보드 - the cards a person placed, drawn from the data as them (ADR-0160 decision 8).
4
+ *
5
+ * Cards are made in the AI conversation beside the page (its card tool is in front here) and saved by pressing the
6
+ * card there; the library holds one's own cards and those shared with one. The page asks no model: each card asks
7
+ * the server to run its definition, each on its own, so a slow card waits in its place.
8
+ */
9
+ import '@material/web/icon/icon.js';
10
+ import '../components/dashboard-card.js';
11
+ import '../components/card-library.js';
12
+ import { css, html, nothing } from 'lit';
13
+ import { customElement, state } from 'lit/decorators.js';
14
+ import { i18next, localize } from '@operato/i18n';
15
+ import { notify, openPopup } from '@operato/layout';
16
+ import { PageView } from '@operato/shell';
17
+ import { DocumentPageStyles, ScrollbarStyles } from '@operato/styles';
18
+ import { askAssistant } from '@things-factory/ai-assistant/dist-client/index.js';
19
+ import { cardApi, DASHBOARD_CHANGED, dashboardChanged } from '../utils/card-api.js';
20
+ import { movedPlaces } from '../utils/card-words.js';
21
+ import { openCardAiPrompt, openCardRename, openCardShare, openCardVersions } from '../components/card-dialogs.js';
22
+ const t = (key, options = {}) => String(i18next.t(key, options));
23
+ /** The requests the empty dashboard offers - each sent to the conversation beside the page as it is. */
24
+ const EXAMPLES = ['ai-dashboard.example.receivables', 'ai-dashboard.example.cash-trend', 'ai-dashboard.example.month-count'];
25
+ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView) {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.places = [];
29
+ this.loaded = false;
30
+ this.editing = false;
31
+ this.onChanged = () => this.load();
32
+ }
33
+ static { this.styles = [
34
+ DocumentPageStyles,
35
+ ScrollbarStyles,
36
+ css `
37
+ .page {
38
+ gap: var(--spacing-large, 16px);
39
+ }
40
+
41
+ .lead {
42
+ display: flex;
43
+ flex-wrap: wrap;
44
+ align-items: center;
45
+ gap: 8px 16px;
46
+ }
47
+
48
+ .lead p {
49
+ flex: 1;
50
+ min-width: 240px;
51
+ margin: 0;
52
+ color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
53
+ }
54
+
55
+ .chip {
56
+ display: inline-flex;
57
+ align-items: center;
58
+ gap: 6px;
59
+ padding: 4px 10px;
60
+ border-radius: 999px;
61
+ background: var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent));
62
+ color: var(--ui-accent, var(--md-sys-color-primary));
63
+ font-size: var(--ui-t-small, 12px);
64
+ font-weight: 600;
65
+ --md-icon-size: 16px;
66
+ }
67
+
68
+ .board {
69
+ container-type: inline-size;
70
+ }
71
+
72
+ .grid {
73
+ display: grid;
74
+ grid-template-columns: repeat(4, minmax(0, 1fr));
75
+ grid-auto-rows: minmax(250px, auto);
76
+ grid-auto-flow: dense;
77
+ gap: 16px;
78
+ }
79
+
80
+ .grid > * {
81
+ grid-column: span var(--w, 2);
82
+ grid-row: span var(--h, 1);
83
+ }
84
+
85
+ @container (max-width: 1100px) {
86
+ .grid {
87
+ grid-template-columns: repeat(2, minmax(0, 1fr));
88
+ }
89
+
90
+ .grid > .w3,
91
+ .grid > .w4 {
92
+ --w: 2;
93
+ }
94
+ }
95
+
96
+ @container (max-width: 640px) {
97
+ .grid {
98
+ grid-template-columns: minmax(0, 1fr);
99
+ }
100
+
101
+ .grid > * {
102
+ --w: 1 !important;
103
+ }
104
+ }
105
+
106
+ .empty {
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: center;
110
+ gap: 14px;
111
+ max-width: 640px;
112
+ margin: 6vh auto 0;
113
+ padding: 36px 28px;
114
+ border: 1px dashed var(--ui-line, var(--md-sys-color-outline-variant));
115
+ border-radius: 16px;
116
+ background: radial-gradient(120% 100% at 50% 0%, var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 10%, transparent)) 0%, transparent 70%);
117
+ text-align: center;
118
+ }
119
+
120
+ .empty .mark {
121
+ display: grid;
122
+ place-items: center;
123
+ width: 56px;
124
+ height: 56px;
125
+ border-radius: 16px;
126
+ background: var(--ui-accent, var(--md-sys-color-primary));
127
+ color: var(--ui-on-accent, var(--md-sys-color-on-primary));
128
+ --md-icon-size: 30px;
129
+ box-shadow: 0 10px 24px -12px var(--ui-accent, var(--md-sys-color-primary));
130
+ }
131
+
132
+ .empty h2 {
133
+ margin: 4px 0 0;
134
+ font-size: var(--ui-t-page, 18px);
135
+ font-weight: 650;
136
+ }
137
+
138
+ .empty p {
139
+ margin: 0;
140
+ color: var(--ui-muted, var(--md-sys-color-on-surface-variant));
141
+ }
142
+
143
+ .examples {
144
+ display: flex;
145
+ flex-direction: column;
146
+ gap: 8px;
147
+ width: 100%;
148
+ margin-top: 6px;
149
+ }
150
+
151
+ .examples button,
152
+ .empty .library {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: 10px;
156
+ padding: 10px 14px;
157
+ border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));
158
+ border-radius: 10px;
159
+ background: var(--ui-panel, var(--md-sys-color-surface-container-lowest));
160
+ color: var(--ui-ink, var(--md-sys-color-on-surface));
161
+ font: inherit;
162
+ text-align: start;
163
+ cursor: pointer;
164
+ transition:
165
+ border-color 0.15s ease,
166
+ transform 0.15s ease;
167
+ --md-icon-size: 18px;
168
+ }
169
+
170
+ .examples button md-icon {
171
+ color: var(--ui-accent, var(--md-sys-color-primary));
172
+ }
173
+
174
+ .examples button:hover,
175
+ .examples button:focus-visible,
176
+ .empty .library:hover {
177
+ border-color: var(--ui-accent, var(--md-sys-color-primary));
178
+ transform: translateY(-1px);
179
+ outline: none;
180
+ }
181
+
182
+ .empty .library {
183
+ justify-content: center;
184
+ border-style: dashed;
185
+ background: transparent;
186
+ }
187
+
188
+ .notice {
189
+ margin: 0;
190
+ padding: 12px 14px;
191
+ border-radius: 10px;
192
+ background: color-mix(in srgb, var(--ui-crit, #c62828) 8%, transparent);
193
+ }
194
+
195
+ .note {
196
+ margin: 0;
197
+ font-size: var(--ui-t-small, 12px);
198
+ color: var(--ui-faint, var(--md-sys-color-on-surface-variant));
199
+ }
200
+ `
201
+ ]; }
202
+ get context() {
203
+ return {
204
+ title: t('ai-dashboard.title'),
205
+ frame: 'document',
206
+ actions: [
207
+ { title: t(this.editing ? 'ai-dashboard.button.done' : 'ai-dashboard.button.arrange'), action: () => (this.editing = !this.editing), icon: this.editing ? 'check' : 'dashboard_customize' },
208
+ { title: t('ai-dashboard.button.library'), action: () => this.openLibrary(), icon: 'collections_bookmark' },
209
+ { title: t('ai-dashboard.button.make'), action: () => this.make(), icon: 'auto_awesome', emphasis: { raised: true } }
210
+ ]
211
+ };
212
+ }
213
+ connectedCallback() {
214
+ super.connectedCallback();
215
+ window.addEventListener(DASHBOARD_CHANGED, this.onChanged);
216
+ }
217
+ disconnectedCallback() {
218
+ window.removeEventListener(DASHBOARD_CHANGED, this.onChanged);
219
+ super.disconnectedCallback();
220
+ }
221
+ updated(changes) {
222
+ /* The action bar follows the mode - its words say what pressing it does now. */
223
+ if (changes.has('editing'))
224
+ this.updateContext();
225
+ }
226
+ /* Not awaited: the shell sets the tab's title only after this returns. */
227
+ async pageUpdated(changes) {
228
+ if (this.active && changes.active)
229
+ this.load();
230
+ }
231
+ async load() {
232
+ try {
233
+ this.places = await cardApi.myDashboard();
234
+ this.error = undefined;
235
+ }
236
+ catch (error) {
237
+ this.error = error?.message ?? String(error);
238
+ }
239
+ finally {
240
+ this.loaded = true;
241
+ }
242
+ }
243
+ render() {
244
+ return html `<div class="page">
245
+ ${this.error
246
+ ? html `<p class="notice">${this.error}</p>`
247
+ : this.loaded && !this.places.length
248
+ ? this.renderEmpty()
249
+ : this.places.length
250
+ ? this.renderBoard()
251
+ : nothing}
252
+ </div>`;
253
+ }
254
+ renderBoard() {
255
+ const sorted = [...this.places].sort((a, b) => a.order - b.order);
256
+ return html `<div class="lead">
257
+ <p>${t('ai-dashboard.page.lead')}</p>
258
+ ${this.editing ? html `<span class="chip"><md-icon>dashboard_customize</md-icon>${t('ai-dashboard.page.arranging')}</span>` : nothing}
259
+ </div>
260
+ <div class="board">
261
+ <div class="grid" @card-action=${(event) => this.onCardAction(event)}>
262
+ ${sorted.map((place, i) => html `<ai-dashboard-card
263
+ class="w${place.width} h${place.height}"
264
+ style="--w: ${place.width}; --h: ${place.height}"
265
+ data-place=${place.id}
266
+ .card=${place.card}
267
+ .width=${place.width}
268
+ .height=${place.height}
269
+ ?editing=${this.editing}
270
+ ?first=${i === 0}
271
+ ?last=${i === sorted.length - 1}
272
+ ></ai-dashboard-card>`)}
273
+ </div>
274
+ </div>
275
+ <p class="note">${t('ai-dashboard.page.no-tokens')}</p>`;
276
+ }
277
+ renderEmpty() {
278
+ return html `<div class="empty">
279
+ <span class="mark"><md-icon>auto_awesome</md-icon></span>
280
+ <h2>${t('ai-dashboard.page.empty-title')}</h2>
281
+ <p>${t('ai-dashboard.page.empty-text')}</p>
282
+ <div class="examples">
283
+ ${EXAMPLES.map(key => html `<button @click=${() => this.askFor(t(key))}><md-icon>chat_bubble</md-icon><span>${t(key)}</span></button>`)}
284
+ </div>
285
+ <button class="library" @click=${() => this.openLibrary()}><md-icon>collections_bookmark</md-icon>${t('ai-dashboard.page.from-library')}</button>
286
+ <p class="note">${t('ai-dashboard.page.no-tokens')}</p>
287
+ </div>`;
288
+ }
289
+ /** Sends a request to the conversation beside the page - this screen's, where the card tool is in front. */
290
+ async askFor(ask) {
291
+ await askAssistant({ ask, continueCurrent: true });
292
+ }
293
+ make() {
294
+ askAssistant({ draft: t('ai-dashboard.page.make-draft'), continueCurrent: true });
295
+ }
296
+ openLibrary() {
297
+ openPopup(html `<ai-dashboard-card-library></ai-dashboard-card-library>`, { backdrop: true, size: 'large', title: t('ai-dashboard.library.title') });
298
+ }
299
+ placeOf(card) {
300
+ return this.places.find(one => one.card.id === card.id);
301
+ }
302
+ async arrange(next) {
303
+ const before = this.places;
304
+ this.places = next;
305
+ try {
306
+ await cardApi.arrange(next.map(({ id, order, width, height }) => ({ id, order, width, height })));
307
+ }
308
+ catch (error) {
309
+ this.places = before;
310
+ notify({ level: 'error', message: error?.message ?? String(error) });
311
+ }
312
+ }
313
+ async onCardAction(event) {
314
+ const { action, card } = event.detail;
315
+ const place = this.placeOf(card);
316
+ try {
317
+ switch (action) {
318
+ case 'ai':
319
+ return openCardAiPrompt(card);
320
+ case 'rename':
321
+ return openCardRename(card);
322
+ case 'share':
323
+ return openCardShare(card);
324
+ case 'versions':
325
+ return openCardVersions(card);
326
+ case 'copy':
327
+ await cardApi.copy(card.id);
328
+ notify({ level: 'info', message: t('ai-dashboard.text.copied', { name: card.name }) });
329
+ return dashboardChanged();
330
+ case 'unplace':
331
+ if (!place)
332
+ return;
333
+ await cardApi.unplace(place.id);
334
+ notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) });
335
+ return this.load();
336
+ case 'left':
337
+ case 'right':
338
+ return place && this.arrange(movedPlaces(this.places, place.id, action === 'left' ? -1 : 1));
339
+ case 'wider':
340
+ case 'narrower':
341
+ case 'taller':
342
+ case 'shorter': {
343
+ if (!place)
344
+ return;
345
+ const width = Math.min(4, Math.max(1, place.width + (action === 'wider' ? 1 : action === 'narrower' ? -1 : 0)));
346
+ const height = Math.min(2, Math.max(1, place.height + (action === 'taller' ? 1 : action === 'shorter' ? -1 : 0)));
347
+ return this.arrange(this.places.map(one => (one.id === place.id ? { ...one, width, height } : one)));
348
+ }
349
+ }
350
+ }
351
+ catch (error) {
352
+ notify({ level: 'error', message: error?.message ?? String(error) });
353
+ }
354
+ }
355
+ };
356
+ __decorate([
357
+ state(),
358
+ __metadata("design:type", Array)
359
+ ], MyDashboardPage.prototype, "places", void 0);
360
+ __decorate([
361
+ state(),
362
+ __metadata("design:type", Object)
363
+ ], MyDashboardPage.prototype, "loaded", void 0);
364
+ __decorate([
365
+ state(),
366
+ __metadata("design:type", String)
367
+ ], MyDashboardPage.prototype, "error", void 0);
368
+ __decorate([
369
+ state(),
370
+ __metadata("design:type", Object)
371
+ ], MyDashboardPage.prototype, "editing", void 0);
372
+ MyDashboardPage = __decorate([
373
+ customElement('my-dashboard-page')
374
+ ], MyDashboardPage);
375
+ export { MyDashboardPage };
376
+ //# sourceMappingURL=my-dashboard-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"my-dashboard-page.js","sourceRoot":"","sources":["../../client/pages/my-dashboard-page.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;AACH,OAAO,4BAA4B,CAAA;AACnC,OAAO,iCAAiC,CAAA;AACxC,OAAO,+BAA+B,CAAA;AAEtC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,mDAAmD,CAAA;AAEhF,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAiC,MAAM,sBAAsB,CAAA;AAClH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAGjH,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,UAAmC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;AAEjG,wGAAwG;AACxG,MAAM,QAAQ,GAAG,CAAC,kCAAkC,EAAE,iCAAiC,EAAE,kCAAkC,CAAC,CAAA;AAGrH,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IAAzD;;QA2KY,WAAM,GAAgB,EAAE,CAAA;QACxB,WAAM,GAAG,KAAK,CAAA;QAEd,YAAO,GAAG,KAAK,CAAA;QAExB,cAAS,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IAmKvC,CAAC;aAlVQ,WAAM,GAAG;QACd,kBAAkB;QAClB,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoKF;KACF,AAxKY,CAwKZ;IASD,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,CAAC,CAAC,oBAAoB,CAAC;YAC9B,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,6BAA6B,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,EAAE;gBAC3L,EAAE,KAAK,EAAE,CAAC,CAAC,6BAA6B,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE;gBAC3G,EAAE,KAAK,EAAE,CAAC,CAAC,0BAA0B,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;aACtH;SACF,CAAA;IACH,CAAC;IAED,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,MAAM,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;IAC5D,CAAC;IAED,oBAAoB;QAClB,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7D,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IAED,OAAO,CAAC,OAA6B;QACnC,gFAAgF;QAChF,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,IAAI,CAAC,aAAa,EAAE,CAAA;IAClD,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,WAAW,CAAC,OAAY;QAC5B,IAAK,IAAY,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;IACzD,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAA;YACzC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAA;QACxB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,GAAG,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QACpB,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,KAAK;YACV,CAAC,CAAC,IAAI,CAAA,qBAAqB,IAAI,CAAC,KAAK,MAAM;YAC3C,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;gBAClC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE;gBACpB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;oBAClB,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE;oBACpB,CAAC,CAAC,OAAO;WACV,CAAA;IACT,CAAC;IAEO,WAAW;QACjB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACjE,OAAO,IAAI,CAAA;aACF,CAAC,CAAC,wBAAwB,CAAC;UAC9B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,4DAA4D,CAAC,CAAC,6BAA6B,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;;;yCAGnG,CAAC,KAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAC7E,MAAM,CAAC,GAAG,CACV,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;wBACN,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM;4BACxB,KAAK,CAAC,KAAK,UAAU,KAAK,CAAC,MAAM;2BAClC,KAAK,CAAC,EAAE;sBACb,KAAK,CAAC,IAAI;uBACT,KAAK,CAAC,KAAK;wBACV,KAAK,CAAC,MAAM;yBACX,IAAI,CAAC,OAAO;uBACd,CAAC,KAAK,CAAC;sBACR,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC;kCACX,CACvB;;;wBAGa,CAAC,CAAC,6BAA6B,CAAC,MAAM,CAAA;IAC5D,CAAC;IAEO,WAAW;QACjB,OAAO,IAAI,CAAA;;YAEH,CAAC,CAAC,+BAA+B,CAAC;WACnC,CAAC,CAAC,8BAA8B,CAAC;;UAElC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,kBAAkB,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC;;uCAEvG,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,2CAA2C,CAAC,CAAC,gCAAgC,CAAC;wBACrH,CAAC,CAAC,6BAA6B,CAAC;WAC7C,CAAA;IACT,CAAC;IAED,4GAA4G;IACpG,KAAK,CAAC,MAAM,CAAC,GAAW;QAC9B,MAAM,YAAY,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;IACpD,CAAC;IAEO,IAAI;QACV,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,8BAA8B,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;IACnF,CAAC;IAEO,WAAW;QACjB,SAAS,CAAC,IAAI,CAAA,yDAAyD,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,4BAA4B,CAAC,EAAE,CAAC,CAAA;IACrJ,CAAC;IAEO,OAAO,CAAC,IAAc;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAA;IACzD,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAiB;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;QACnG,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;YACpB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAkB;QAC3C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,MAAgD,CAAA;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC;YACH,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,IAAI;oBACP,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAA;gBAC/B,KAAK,QAAQ;oBACX,OAAO,cAAc,CAAC,IAAI,CAAC,CAAA;gBAC7B,KAAK,OAAO;oBACV,OAAO,aAAa,CAAC,IAAI,CAAC,CAAA;gBAC5B,KAAK,UAAU;oBACb,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAA;gBAC/B,KAAK,MAAM;oBACT,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;oBAC3B,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;oBACtF,OAAO,gBAAgB,EAAE,CAAA;gBAC3B,KAAK,SAAS;oBACZ,IAAI,CAAC,KAAK;wBAAE,OAAM;oBAClB,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;oBAC/B,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,4BAA4B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;oBACxF,OAAO,IAAI,CAAC,IAAI,EAAE,CAAA;gBACpB,KAAK,MAAM,CAAC;gBACZ,KAAK,OAAO;oBACV,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;gBAC9F,KAAK,OAAO,CAAC;gBACb,KAAK,UAAU,CAAC;gBAChB,KAAK,QAAQ,CAAC;gBACd,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,IAAI,CAAC,KAAK;wBAAE,OAAM;oBAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;oBAC/G,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;oBACjH,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gBACtG,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;;AAvKgB;IAAhB,KAAK,EAAE;;+CAAiC;AACxB;IAAhB,KAAK,EAAE;;+CAAuB;AACd;IAAhB,KAAK,EAAE;;8CAAuB;AACd;IAAhB,KAAK,EAAE;;gDAAwB;AA9KrB,eAAe;IAD3B,aAAa,CAAC,mBAAmB,CAAC;GACtB,eAAe,CAmV3B","sourcesContent":["/*\n * 나의 대시보드 - the cards a person placed, drawn from the data as them (ADR-0160 decision 8).\n *\n * Cards are made in the AI conversation beside the page (its card tool is in front here) and saved by pressing the\n * card there; the library holds one's own cards and those shared with one. The page asks no model: each card asks\n * the server to run its definition, each on its own, so a slow card waits in its place.\n */\nimport '@material/web/icon/icon.js'\nimport '../components/dashboard-card.js'\nimport '../components/card-library.js'\n\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\nimport { askAssistant } from '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { cardApi, DASHBOARD_CHANGED, dashboardChanged, type CardItem, type PlaceItem } from '../utils/card-api.js'\nimport { movedPlaces } from '../utils/card-words.js'\nimport { openCardAiPrompt, openCardRename, openCardShare, openCardVersions } from '../components/card-dialogs.js'\nimport type { CardAction } from '../components/dashboard-card.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n/** The requests the empty dashboard offers - each sent to the conversation beside the page as it is. */\nconst EXAMPLES = ['ai-dashboard.example.receivables', 'ai-dashboard.example.cash-trend', 'ai-dashboard.example.month-count']\n\n@customElement('my-dashboard-page')\nexport class MyDashboardPage extends localize(i18next)(PageView) {\n static styles = [\n DocumentPageStyles,\n ScrollbarStyles,\n css`\n .page {\n gap: var(--spacing-large, 16px);\n }\n\n .lead {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 16px;\n }\n\n .lead p {\n flex: 1;\n min-width: 240px;\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: 999px;\n background: var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent));\n color: var(--ui-accent, var(--md-sys-color-primary));\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n --md-icon-size: 16px;\n }\n\n .board {\n container-type: inline-size;\n }\n\n .grid {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n grid-auto-rows: minmax(250px, auto);\n grid-auto-flow: dense;\n gap: 16px;\n }\n\n .grid > * {\n grid-column: span var(--w, 2);\n grid-row: span var(--h, 1);\n }\n\n @container (max-width: 1100px) {\n .grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .grid > .w3,\n .grid > .w4 {\n --w: 2;\n }\n }\n\n @container (max-width: 640px) {\n .grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .grid > * {\n --w: 1 !important;\n }\n }\n\n .empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n max-width: 640px;\n margin: 6vh auto 0;\n padding: 36px 28px;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 16px;\n background: radial-gradient(120% 100% at 50% 0%, var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 10%, transparent)) 0%, transparent 70%);\n text-align: center;\n }\n\n .empty .mark {\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n border-radius: 16px;\n background: var(--ui-accent, var(--md-sys-color-primary));\n color: var(--ui-on-accent, var(--md-sys-color-on-primary));\n --md-icon-size: 30px;\n box-shadow: 0 10px 24px -12px var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .empty h2 {\n margin: 4px 0 0;\n font-size: var(--ui-t-page, 18px);\n font-weight: 650;\n }\n\n .empty p {\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .examples {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n margin-top: 6px;\n }\n\n .examples button,\n .empty .library {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 10px;\n background: var(--ui-panel, var(--md-sys-color-surface-container-lowest));\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n font: inherit;\n text-align: start;\n cursor: pointer;\n transition:\n border-color 0.15s ease,\n transform 0.15s ease;\n --md-icon-size: 18px;\n }\n\n .examples button md-icon {\n color: var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .examples button:hover,\n .examples button:focus-visible,\n .empty .library:hover {\n border-color: var(--ui-accent, var(--md-sys-color-primary));\n transform: translateY(-1px);\n outline: none;\n }\n\n .empty .library {\n justify-content: center;\n border-style: dashed;\n background: transparent;\n }\n\n .notice {\n margin: 0;\n padding: 12px 14px;\n border-radius: 10px;\n background: color-mix(in srgb, var(--ui-crit, #c62828) 8%, transparent);\n }\n\n .note {\n margin: 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-faint, var(--md-sys-color-on-surface-variant));\n }\n `\n ]\n\n @state() private places: PlaceItem[] = []\n @state() private loaded = false\n @state() private error?: string\n @state() private editing = false\n\n private onChanged = () => this.load()\n\n get context() {\n return {\n title: t('ai-dashboard.title'),\n frame: 'document',\n actions: [\n { title: t(this.editing ? 'ai-dashboard.button.done' : 'ai-dashboard.button.arrange'), action: () => (this.editing = !this.editing), icon: this.editing ? 'check' : 'dashboard_customize' },\n { title: t('ai-dashboard.button.library'), action: () => this.openLibrary(), icon: 'collections_bookmark' },\n { title: t('ai-dashboard.button.make'), action: () => this.make(), icon: 'auto_awesome', emphasis: { raised: true } }\n ]\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener(DASHBOARD_CHANGED, this.onChanged)\n }\n\n disconnectedCallback() {\n window.removeEventListener(DASHBOARD_CHANGED, this.onChanged)\n super.disconnectedCallback()\n }\n\n updated(changes: Map<string, unknown>) {\n /* The action bar follows the mode - its words say what pressing it does now. */\n if (changes.has('editing')) this.updateContext()\n }\n\n /* Not awaited: the shell sets the tab's title only after this returns. */\n async pageUpdated(changes: any) {\n if ((this as any).active && changes.active) this.load()\n }\n\n private async load() {\n try {\n this.places = await cardApi.myDashboard()\n this.error = undefined\n } catch (error: any) {\n this.error = error?.message ?? String(error)\n } finally {\n this.loaded = true\n }\n }\n\n render() {\n return html`<div class=\"page\">\n ${this.error\n ? html`<p class=\"notice\">${this.error}</p>`\n : this.loaded && !this.places.length\n ? this.renderEmpty()\n : this.places.length\n ? this.renderBoard()\n : nothing}\n </div>`\n }\n\n private renderBoard() {\n const sorted = [...this.places].sort((a, b) => a.order - b.order)\n return html`<div class=\"lead\">\n <p>${t('ai-dashboard.page.lead')}</p>\n ${this.editing ? html`<span class=\"chip\"><md-icon>dashboard_customize</md-icon>${t('ai-dashboard.page.arranging')}</span>` : nothing}\n </div>\n <div class=\"board\">\n <div class=\"grid\" @card-action=${(event: CustomEvent) => this.onCardAction(event)}>\n ${sorted.map(\n (place, i) => html`<ai-dashboard-card\n class=\"w${place.width} h${place.height}\"\n style=\"--w: ${place.width}; --h: ${place.height}\"\n data-place=${place.id}\n .card=${place.card}\n .width=${place.width}\n .height=${place.height}\n ?editing=${this.editing}\n ?first=${i === 0}\n ?last=${i === sorted.length - 1}\n ></ai-dashboard-card>`\n )}\n </div>\n </div>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>`\n }\n\n private renderEmpty() {\n return html`<div class=\"empty\">\n <span class=\"mark\"><md-icon>auto_awesome</md-icon></span>\n <h2>${t('ai-dashboard.page.empty-title')}</h2>\n <p>${t('ai-dashboard.page.empty-text')}</p>\n <div class=\"examples\">\n ${EXAMPLES.map(key => html`<button @click=${() => this.askFor(t(key))}><md-icon>chat_bubble</md-icon><span>${t(key)}</span></button>`)}\n </div>\n <button class=\"library\" @click=${() => this.openLibrary()}><md-icon>collections_bookmark</md-icon>${t('ai-dashboard.page.from-library')}</button>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>\n </div>`\n }\n\n /** Sends a request to the conversation beside the page - this screen's, where the card tool is in front. */\n private async askFor(ask: string) {\n await askAssistant({ ask, continueCurrent: true })\n }\n\n private make() {\n askAssistant({ draft: t('ai-dashboard.page.make-draft'), continueCurrent: true })\n }\n\n private openLibrary() {\n openPopup(html`<ai-dashboard-card-library></ai-dashboard-card-library>`, { backdrop: true, size: 'large', title: t('ai-dashboard.library.title') })\n }\n\n private placeOf(card: CardItem) {\n return this.places.find(one => one.card.id === card.id)\n }\n\n private async arrange(next: PlaceItem[]) {\n const before = this.places\n this.places = next\n try {\n await cardApi.arrange(next.map(({ id, order, width, height }) => ({ id, order, width, height })))\n } catch (error: any) {\n this.places = before\n notify({ level: 'error', message: error?.message ?? String(error) })\n }\n }\n\n private async onCardAction(event: CustomEvent) {\n const { action, card } = event.detail as { action: CardAction; card: CardItem }\n const place = this.placeOf(card)\n try {\n switch (action) {\n case 'ai':\n return openCardAiPrompt(card)\n case 'rename':\n return openCardRename(card)\n case 'share':\n return openCardShare(card)\n case 'versions':\n return openCardVersions(card)\n case 'copy':\n await cardApi.copy(card.id)\n notify({ level: 'info', message: t('ai-dashboard.text.copied', { name: card.name }) })\n return dashboardChanged()\n case 'unplace':\n if (!place) return\n await cardApi.unplace(place.id)\n notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) })\n return this.load()\n case 'left':\n case 'right':\n return place && this.arrange(movedPlaces(this.places, place.id, action === 'left' ? -1 : 1))\n case 'wider':\n case 'narrower':\n case 'taller':\n case 'shorter': {\n if (!place) return\n const width = Math.min(4, Math.max(1, place.width + (action === 'wider' ? 1 : action === 'narrower' ? -1 : 0)))\n const height = Math.min(2, Math.max(1, place.height + (action === 'taller' ? 1 : action === 'shorter' ? -1 : 0)))\n return this.arrange(this.places.map(one => (one.id === place.id ? { ...one, width, height } : one)))\n }\n }\n } catch (error: any) {\n notify({ level: 'error', message: error?.message ?? String(error) })\n }\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export default function route(page: string): "my-dashboard" | undefined;
@@ -0,0 +1,9 @@
1
+ /* The page this module brings to an application that puts it in its menu (ADR-0160 decision 10). */
2
+ export default function route(page) {
3
+ switch (page) {
4
+ case 'my-dashboard':
5
+ import('./pages/my-dashboard-page.js');
6
+ return page;
7
+ }
8
+ }
9
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAY;IACxC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc;YACjB,MAAM,CAAC,8BAA8B,CAAC,CAAA;YACtC,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["/* The page this module brings to an application that puts it in its menu (ADR-0160 decision 10). */\nexport default function route(page: string) {\n switch (page) {\n case 'my-dashboard':\n import('./pages/my-dashboard-page.js')\n return page\n }\n}\n"]}