@agimon-ai/po-web-dashboard 0.0.0-alpha.83 → 0.0.0-alpha.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web/components/DashboardTileGrid.cjs +57 -39
- package/dist/web/components/DashboardTileGrid.cjs.map +1 -1
- package/dist/web/components/DashboardTileGrid.d.mts +2 -1
- package/dist/web/components/DashboardTileGrid.d.mts.map +1 -1
- package/dist/web/components/DashboardTileGrid.mjs +57 -39
- package/dist/web/components/DashboardTileGrid.mjs.map +1 -1
- package/dist/web/components/HomePage.cjs +2 -1
- package/dist/web/components/HomePage.cjs.map +1 -1
- package/dist/web/components/HomePage.mjs +2 -1
- package/dist/web/components/HomePage.mjs.map +1 -1
- package/dist/web/components/WorkspacePage.cjs +1 -0
- package/dist/web/components/WorkspacePage.cjs.map +1 -1
- package/dist/web/components/WorkspacePage.mjs +1 -0
- package/dist/web/components/WorkspacePage.mjs.map +1 -1
- package/dist/web/lib/pluginRegistry.cjs +1 -0
- package/dist/web/lib/pluginRegistry.cjs.map +1 -1
- package/dist/web/lib/pluginRegistry.d.mts.map +1 -1
- package/dist/web/lib/pluginRegistry.mjs +1 -0
- package/dist/web/lib/pluginRegistry.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -8,50 +8,68 @@ const spans = {
|
|
|
8
8
|
tall: "row-span-2",
|
|
9
9
|
large: "row-span-2 @min-[340px]:col-span-2"
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
11
|
+
/** Explicit columns stack independently; unpositioned fills retain their size-based grid. */
|
|
12
12
|
function DashboardTileGrid({ tiles }) {
|
|
13
|
+
const columns = tiles.some((tile) => tile.column !== void 0) ? [{
|
|
14
|
+
name: "main",
|
|
15
|
+
tiles: tiles.filter((tile) => tile.column !== "side")
|
|
16
|
+
}, {
|
|
17
|
+
name: "side",
|
|
18
|
+
tiles: tiles.filter((tile) => tile.column === "side")
|
|
19
|
+
}].filter((column) => column.tiles.length > 0) : void 0;
|
|
13
20
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14
21
|
className: "@container min-w-0",
|
|
15
22
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
16
23
|
"data-testid": "dashboard-tile-grid",
|
|
17
|
-
className: "grid
|
|
18
|
-
children:
|
|
19
|
-
"data-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
24
|
+
className: columns ? columns.length > 1 ? "grid grid-cols-1 items-start gap-4 @min-[768px]:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]" : "grid grid-cols-1 items-start gap-4" : "grid grid-cols-1 items-start gap-4 @min-[340px]:grid-cols-2 @min-[960px]:grid-cols-4",
|
|
25
|
+
children: columns ? columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
26
|
+
"data-dashboard-column": column.name,
|
|
27
|
+
className: "flex min-w-0 flex-col gap-4",
|
|
28
|
+
children: column.tiles.map((tile) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DashboardTile, { tile }, tile.id))
|
|
29
|
+
}, column.name)) : tiles.map((tile) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DashboardTile, {
|
|
30
|
+
tile,
|
|
31
|
+
span: true
|
|
32
|
+
}, tile.id))
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function DashboardTile({ tile, span = false }) {
|
|
37
|
+
const { id, size = "small", title, icon: Icon, body, onOpen, legacy = false } = tile;
|
|
38
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
39
|
+
"data-tile-id": id,
|
|
40
|
+
"data-tile-size": size,
|
|
41
|
+
className: `min-w-0 ${span ? spans[size] : ""}`,
|
|
42
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ToolRendererBoundary.ToolRendererBoundary, {
|
|
43
|
+
toolName: id,
|
|
44
|
+
children: (failed) => failed ? null : legacy ? body : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_agimon_ai_po_web_components.Panel, {
|
|
45
|
+
className: "flex min-w-0 flex-col",
|
|
46
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
47
|
+
className: "flex min-h-11 items-center gap-2 px-3 py-2",
|
|
48
|
+
children: [
|
|
49
|
+
Icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
50
|
+
"aria-hidden": true,
|
|
51
|
+
className: "size-4 shrink-0 text-po-dim"
|
|
52
|
+
}) : null,
|
|
53
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
54
|
+
className: "min-w-0 flex-1 break-words text-base font-semibold text-po-hi",
|
|
55
|
+
children: title
|
|
56
|
+
}),
|
|
57
|
+
onOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_agimon_ai_po_web_components.Button, {
|
|
58
|
+
variant: "ghost",
|
|
59
|
+
size: "icon-md",
|
|
60
|
+
"aria-label": `Open ${title}`,
|
|
61
|
+
onClick: onOpen,
|
|
62
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_agimon_ai_po_web_components.ChevronRightIcon, {
|
|
63
|
+
"aria-hidden": true,
|
|
64
|
+
className: "size-4"
|
|
65
|
+
})
|
|
66
|
+
}) : null
|
|
67
|
+
]
|
|
68
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
69
|
+
className: "min-w-0 border-t border-po-border-soft p-3",
|
|
70
|
+
children: body
|
|
71
|
+
})]
|
|
72
|
+
})
|
|
55
73
|
})
|
|
56
74
|
});
|
|
57
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardTileGrid.cjs","names":["ToolRendererBoundary","Panel","Button","ChevronRightIcon"],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"sourcesContent":["import type { DashboardTileData, DashboardTileSize } from '@agimon-ai/po-core/web';\nimport { Button, ChevronRightIcon, Panel } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport { ToolRendererBoundary } from '../lib/ToolRendererBoundary';\n\nexport interface DashboardTileView {\n id: string;\n size?: DashboardTileSize;\n body: ReactNode;\n title?: string;\n icon?: DashboardTileData['icon'];\n onOpen?: () => void;\n /** Existing full-card fills keep their own heading and natural content height. */\n legacy?: boolean;\n}\n\nconst spans: Record<DashboardTileSize, string> = {\n small: '',\n wide: '@min-[340px]:col-span-2',\n tall: 'row-span-2',\n large: 'row-span-2 @min-[340px]:col-span-2',\n};\n\n/**
|
|
1
|
+
{"version":3,"file":"DashboardTileGrid.cjs","names":["ToolRendererBoundary","Panel","Button","ChevronRightIcon"],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"sourcesContent":["import type { DashboardTileData, DashboardTileSize } from '@agimon-ai/po-core/web';\nimport { Button, ChevronRightIcon, Panel } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport { ToolRendererBoundary } from '../lib/ToolRendererBoundary';\n\nexport interface DashboardTileView {\n id: string;\n size?: DashboardTileSize;\n column?: DashboardTileData['column'];\n body: ReactNode;\n title?: string;\n icon?: DashboardTileData['icon'];\n onOpen?: () => void;\n /** Existing full-card fills keep their own heading and natural content height. */\n legacy?: boolean;\n}\n\nconst spans: Record<DashboardTileSize, string> = {\n small: '',\n wide: '@min-[340px]:col-span-2',\n tall: 'row-span-2',\n large: 'row-span-2 @min-[340px]:col-span-2',\n};\n\n/** Explicit columns stack independently; unpositioned fills retain their size-based grid. */\nexport function DashboardTileGrid({ tiles }: { tiles: readonly DashboardTileView[] }) {\n const columns = tiles.some((tile) => tile.column !== undefined)\n ? [\n { name: 'main', tiles: tiles.filter((tile) => tile.column !== 'side') },\n { name: 'side', tiles: tiles.filter((tile) => tile.column === 'side') },\n ].filter((column) => column.tiles.length > 0)\n : undefined;\n return (\n <div className=\"@container min-w-0\">\n <div\n data-testid=\"dashboard-tile-grid\"\n className={\n columns\n ? columns.length > 1\n ? 'grid grid-cols-1 items-start gap-4 @min-[768px]:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]'\n : 'grid grid-cols-1 items-start gap-4'\n : 'grid grid-cols-1 items-start gap-4 @min-[340px]:grid-cols-2 @min-[960px]:grid-cols-4'\n }\n >\n {columns\n ? columns.map((column) => (\n <div key={column.name} data-dashboard-column={column.name} className=\"flex min-w-0 flex-col gap-4\">\n {column.tiles.map((tile) => (\n <DashboardTile key={tile.id} tile={tile} />\n ))}\n </div>\n ))\n : tiles.map((tile) => <DashboardTile key={tile.id} tile={tile} span />)}\n </div>\n </div>\n );\n}\n\nfunction DashboardTile({ tile, span = false }: { tile: DashboardTileView; span?: boolean }) {\n const { id, size = 'small', title, icon: Icon, body, onOpen, legacy = false } = tile;\n return (\n <div data-tile-id={id} data-tile-size={size} className={`min-w-0 ${span ? spans[size] : ''}`}>\n <ToolRendererBoundary toolName={id}>\n {(failed) =>\n failed ? null : legacy ? (\n body\n ) : (\n <Panel className=\"flex min-w-0 flex-col\">\n <div className=\"flex min-h-11 items-center gap-2 px-3 py-2\">\n {Icon ? <Icon aria-hidden className=\"size-4 shrink-0 text-po-dim\" /> : null}\n <h2 className=\"min-w-0 flex-1 break-words text-base font-semibold text-po-hi\">{title}</h2>\n {onOpen ? (\n <Button variant=\"ghost\" size=\"icon-md\" aria-label={`Open ${title}`} onClick={onOpen}>\n <ChevronRightIcon aria-hidden className=\"size-4\" />\n </Button>\n ) : null}\n </div>\n <div className=\"min-w-0 border-t border-po-border-soft p-3\">{body}</div>\n </Panel>\n )\n }\n </ToolRendererBoundary>\n </div>\n );\n}\n"],"mappings":";;;;AAkBA,MAAM,QAA2C;CAC/C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;AACT;;AAGA,SAAgB,kBAAkB,EAAE,SAAkD;CACpF,MAAM,UAAU,MAAM,MAAM,SAAS,KAAK,WAAW,KAAA,CAAS,IAC1D,CACE;EAAE,MAAM;EAAQ,OAAO,MAAM,QAAQ,SAAS,KAAK,WAAW,MAAM;CAAE,GACtE;EAAE,MAAM;EAAQ,OAAO,MAAM,QAAQ,SAAS,KAAK,WAAW,MAAM;CAAE,CACxE,CAAC,CAAC,QAAQ,WAAW,OAAO,MAAM,SAAS,CAAC,IAC5C,KAAA;CACJ,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,WAAU;EACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GACE,eAAY;GACZ,WACE,UACI,QAAQ,SAAS,IACf,4FACA,uCACF;GAGL,UAAA,UACG,QAAQ,KAAK,WACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAuB,yBAAuB,OAAO;IAAM,WAAU;IAClE,UAAA,OAAO,MAAM,KAAK,SACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD,EAAmC,KAAO,GAAtB,KAAK,EAAiB,CAC3C;GACE,GAJK,OAAO,IAIZ,CACN,IACD,MAAM,KAAK,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;IAAmC;IAAM,MAAA;GAAM,GAA3B,KAAK,EAAsB,CAAC;EACrE,CAAA;CACF,CAAA;AAET;AAEA,SAAS,cAAc,EAAE,MAAM,OAAO,SAAsD;CAC1F,MAAM,EAAE,IAAI,OAAO,SAAS,OAAO,MAAM,MAAM,MAAM,QAAQ,SAAS,UAAU;CAChF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,gBAAc;EAAI,kBAAgB;EAAM,WAAW,WAAW,OAAO,MAAM,QAAQ;EACtF,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACA,6BAAAA,sBAAD;GAAsB,UAAU;GAC5B,WAAA,WACA,SAAS,OAAO,SACd,OAEA,iBAAA,GAAA,kBAAA,KAAA,CAACC,6BAAAA,OAAD;IAAO,WAAU;IAAjB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAM,eAAA;OAAY,WAAU;MAA+B,CAAA,IAAI;MACvE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;OAAI,WAAU;OAAiE,UAAA;MAAU,CAAA;MACxF,SACC,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,QAAD;OAAQ,SAAQ;OAAQ,MAAK;OAAU,cAAY,QAAQ;OAAS,SAAS;OAC3E,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,kBAAD;QAAkB,eAAA;QAAY,WAAU;OAAU,CAAA;MAC5C,CAAA,IACN;KACD;IACL,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KAA8C,UAAA;IAAU,CAAA,CAClE;;EAGS,CAAA;CACnB,CAAA;AAET"}
|
|
@@ -4,6 +4,7 @@ import { DashboardTileData, DashboardTileSize } from "@agimon-ai/po-core/web";
|
|
|
4
4
|
export interface DashboardTileView {
|
|
5
5
|
id: string;
|
|
6
6
|
size?: DashboardTileSize;
|
|
7
|
+
column?: DashboardTileData['column'];
|
|
7
8
|
body: ReactNode;
|
|
8
9
|
title?: string;
|
|
9
10
|
icon?: DashboardTileData['icon'];
|
|
@@ -11,7 +12,7 @@ export interface DashboardTileView {
|
|
|
11
12
|
/** Existing full-card fills keep their own heading and natural content height. */
|
|
12
13
|
legacy?: boolean;
|
|
13
14
|
}
|
|
14
|
-
/**
|
|
15
|
+
/** Explicit columns stack independently; unpositioned fills retain their size-based grid. */
|
|
15
16
|
export declare function DashboardTileGrid({ tiles }: {
|
|
16
17
|
tiles: readonly DashboardTileView[];
|
|
17
18
|
}): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardTileGrid.d.mts","names":[],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"mappings":";;;iBAMiB;EACf;EACA,OAAO;EACP,MAAM;EACN;EACA,OAAO;EACP;;EAEA;;;wBAWc,oBAAoB;EAAW,gBAAgB;oBAAqB,IAAA"}
|
|
1
|
+
{"version":3,"file":"DashboardTileGrid.d.mts","names":[],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"mappings":";;;iBAMiB;EACf;EACA,OAAO;EACP,SAAS;EACT,MAAM;EACN;EACA,OAAO;EACP;;EAEA;;;wBAWc,oBAAoB;EAAW,gBAAgB;oBAAqB,IAAA"}
|
|
@@ -8,50 +8,68 @@ const spans = {
|
|
|
8
8
|
tall: "row-span-2",
|
|
9
9
|
large: "row-span-2 @min-[340px]:col-span-2"
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
11
|
+
/** Explicit columns stack independently; unpositioned fills retain their size-based grid. */
|
|
12
12
|
function DashboardTileGrid({ tiles }) {
|
|
13
|
+
const columns = tiles.some((tile) => tile.column !== void 0) ? [{
|
|
14
|
+
name: "main",
|
|
15
|
+
tiles: tiles.filter((tile) => tile.column !== "side")
|
|
16
|
+
}, {
|
|
17
|
+
name: "side",
|
|
18
|
+
tiles: tiles.filter((tile) => tile.column === "side")
|
|
19
|
+
}].filter((column) => column.tiles.length > 0) : void 0;
|
|
13
20
|
return /* @__PURE__ */ jsx("div", {
|
|
14
21
|
className: "@container min-w-0",
|
|
15
22
|
children: /* @__PURE__ */ jsx("div", {
|
|
16
23
|
"data-testid": "dashboard-tile-grid",
|
|
17
|
-
className: "grid
|
|
18
|
-
children:
|
|
19
|
-
"data-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
24
|
+
className: columns ? columns.length > 1 ? "grid grid-cols-1 items-start gap-4 @min-[768px]:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]" : "grid grid-cols-1 items-start gap-4" : "grid grid-cols-1 items-start gap-4 @min-[340px]:grid-cols-2 @min-[960px]:grid-cols-4",
|
|
25
|
+
children: columns ? columns.map((column) => /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"data-dashboard-column": column.name,
|
|
27
|
+
className: "flex min-w-0 flex-col gap-4",
|
|
28
|
+
children: column.tiles.map((tile) => /* @__PURE__ */ jsx(DashboardTile, { tile }, tile.id))
|
|
29
|
+
}, column.name)) : tiles.map((tile) => /* @__PURE__ */ jsx(DashboardTile, {
|
|
30
|
+
tile,
|
|
31
|
+
span: true
|
|
32
|
+
}, tile.id))
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function DashboardTile({ tile, span = false }) {
|
|
37
|
+
const { id, size = "small", title, icon: Icon, body, onOpen, legacy = false } = tile;
|
|
38
|
+
return /* @__PURE__ */ jsx("div", {
|
|
39
|
+
"data-tile-id": id,
|
|
40
|
+
"data-tile-size": size,
|
|
41
|
+
className: `min-w-0 ${span ? spans[size] : ""}`,
|
|
42
|
+
children: /* @__PURE__ */ jsx(ToolRendererBoundary, {
|
|
43
|
+
toolName: id,
|
|
44
|
+
children: (failed) => failed ? null : legacy ? body : /* @__PURE__ */ jsxs(Panel, {
|
|
45
|
+
className: "flex min-w-0 flex-col",
|
|
46
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
47
|
+
className: "flex min-h-11 items-center gap-2 px-3 py-2",
|
|
48
|
+
children: [
|
|
49
|
+
Icon ? /* @__PURE__ */ jsx(Icon, {
|
|
50
|
+
"aria-hidden": true,
|
|
51
|
+
className: "size-4 shrink-0 text-po-dim"
|
|
52
|
+
}) : null,
|
|
53
|
+
/* @__PURE__ */ jsx("h2", {
|
|
54
|
+
className: "min-w-0 flex-1 break-words text-base font-semibold text-po-hi",
|
|
55
|
+
children: title
|
|
56
|
+
}),
|
|
57
|
+
onOpen ? /* @__PURE__ */ jsx(Button, {
|
|
58
|
+
variant: "ghost",
|
|
59
|
+
size: "icon-md",
|
|
60
|
+
"aria-label": `Open ${title}`,
|
|
61
|
+
onClick: onOpen,
|
|
62
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, {
|
|
63
|
+
"aria-hidden": true,
|
|
64
|
+
className: "size-4"
|
|
65
|
+
})
|
|
66
|
+
}) : null
|
|
67
|
+
]
|
|
68
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
69
|
+
className: "min-w-0 border-t border-po-border-soft p-3",
|
|
70
|
+
children: body
|
|
71
|
+
})]
|
|
72
|
+
})
|
|
55
73
|
})
|
|
56
74
|
});
|
|
57
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardTileGrid.mjs","names":[],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"sourcesContent":["import type { DashboardTileData, DashboardTileSize } from '@agimon-ai/po-core/web';\nimport { Button, ChevronRightIcon, Panel } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport { ToolRendererBoundary } from '../lib/ToolRendererBoundary';\n\nexport interface DashboardTileView {\n id: string;\n size?: DashboardTileSize;\n body: ReactNode;\n title?: string;\n icon?: DashboardTileData['icon'];\n onOpen?: () => void;\n /** Existing full-card fills keep their own heading and natural content height. */\n legacy?: boolean;\n}\n\nconst spans: Record<DashboardTileSize, string> = {\n small: '',\n wide: '@min-[340px]:col-span-2',\n tall: 'row-span-2',\n large: 'row-span-2 @min-[340px]:col-span-2',\n};\n\n/**
|
|
1
|
+
{"version":3,"file":"DashboardTileGrid.mjs","names":[],"sources":["../../../src/web/components/DashboardTileGrid.tsx"],"sourcesContent":["import type { DashboardTileData, DashboardTileSize } from '@agimon-ai/po-core/web';\nimport { Button, ChevronRightIcon, Panel } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport { ToolRendererBoundary } from '../lib/ToolRendererBoundary';\n\nexport interface DashboardTileView {\n id: string;\n size?: DashboardTileSize;\n column?: DashboardTileData['column'];\n body: ReactNode;\n title?: string;\n icon?: DashboardTileData['icon'];\n onOpen?: () => void;\n /** Existing full-card fills keep their own heading and natural content height. */\n legacy?: boolean;\n}\n\nconst spans: Record<DashboardTileSize, string> = {\n small: '',\n wide: '@min-[340px]:col-span-2',\n tall: 'row-span-2',\n large: 'row-span-2 @min-[340px]:col-span-2',\n};\n\n/** Explicit columns stack independently; unpositioned fills retain their size-based grid. */\nexport function DashboardTileGrid({ tiles }: { tiles: readonly DashboardTileView[] }) {\n const columns = tiles.some((tile) => tile.column !== undefined)\n ? [\n { name: 'main', tiles: tiles.filter((tile) => tile.column !== 'side') },\n { name: 'side', tiles: tiles.filter((tile) => tile.column === 'side') },\n ].filter((column) => column.tiles.length > 0)\n : undefined;\n return (\n <div className=\"@container min-w-0\">\n <div\n data-testid=\"dashboard-tile-grid\"\n className={\n columns\n ? columns.length > 1\n ? 'grid grid-cols-1 items-start gap-4 @min-[768px]:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]'\n : 'grid grid-cols-1 items-start gap-4'\n : 'grid grid-cols-1 items-start gap-4 @min-[340px]:grid-cols-2 @min-[960px]:grid-cols-4'\n }\n >\n {columns\n ? columns.map((column) => (\n <div key={column.name} data-dashboard-column={column.name} className=\"flex min-w-0 flex-col gap-4\">\n {column.tiles.map((tile) => (\n <DashboardTile key={tile.id} tile={tile} />\n ))}\n </div>\n ))\n : tiles.map((tile) => <DashboardTile key={tile.id} tile={tile} span />)}\n </div>\n </div>\n );\n}\n\nfunction DashboardTile({ tile, span = false }: { tile: DashboardTileView; span?: boolean }) {\n const { id, size = 'small', title, icon: Icon, body, onOpen, legacy = false } = tile;\n return (\n <div data-tile-id={id} data-tile-size={size} className={`min-w-0 ${span ? spans[size] : ''}`}>\n <ToolRendererBoundary toolName={id}>\n {(failed) =>\n failed ? null : legacy ? (\n body\n ) : (\n <Panel className=\"flex min-w-0 flex-col\">\n <div className=\"flex min-h-11 items-center gap-2 px-3 py-2\">\n {Icon ? <Icon aria-hidden className=\"size-4 shrink-0 text-po-dim\" /> : null}\n <h2 className=\"min-w-0 flex-1 break-words text-base font-semibold text-po-hi\">{title}</h2>\n {onOpen ? (\n <Button variant=\"ghost\" size=\"icon-md\" aria-label={`Open ${title}`} onClick={onOpen}>\n <ChevronRightIcon aria-hidden className=\"size-4\" />\n </Button>\n ) : null}\n </div>\n <div className=\"min-w-0 border-t border-po-border-soft p-3\">{body}</div>\n </Panel>\n )\n }\n </ToolRendererBoundary>\n </div>\n );\n}\n"],"mappings":";;;;AAkBA,MAAM,QAA2C;CAC/C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;AACT;;AAGA,SAAgB,kBAAkB,EAAE,SAAkD;CACpF,MAAM,UAAU,MAAM,MAAM,SAAS,KAAK,WAAW,KAAA,CAAS,IAC1D,CACE;EAAE,MAAM;EAAQ,OAAO,MAAM,QAAQ,SAAS,KAAK,WAAW,MAAM;CAAE,GACtE;EAAE,MAAM;EAAQ,OAAO,MAAM,QAAQ,SAAS,KAAK,WAAW,MAAM;CAAE,CACxE,CAAC,CAAC,QAAQ,WAAW,OAAO,MAAM,SAAS,CAAC,IAC5C,KAAA;CACJ,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,oBAAC,OAAD;GACE,eAAY;GACZ,WACE,UACI,QAAQ,SAAS,IACf,4FACA,uCACF;GAGL,UAAA,UACG,QAAQ,KAAK,WACX,oBAAC,OAAD;IAAuB,yBAAuB,OAAO;IAAM,WAAU;IAClE,UAAA,OAAO,MAAM,KAAK,SACjB,oBAAC,eAAD,EAAmC,KAAO,GAAtB,KAAK,EAAiB,CAC3C;GACE,GAJK,OAAO,IAIZ,CACN,IACD,MAAM,KAAK,SAAS,oBAAC,eAAD;IAAmC;IAAM,MAAA;GAAM,GAA3B,KAAK,EAAsB,CAAC;EACrE,CAAA;CACF,CAAA;AAET;AAEA,SAAS,cAAc,EAAE,MAAM,OAAO,SAAsD;CAC1F,MAAM,EAAE,IAAI,OAAO,SAAS,OAAO,MAAM,MAAM,MAAM,QAAQ,SAAS,UAAU;CAChF,OACE,oBAAC,OAAD;EAAK,gBAAc;EAAI,kBAAgB;EAAM,WAAW,WAAW,OAAO,MAAM,QAAQ;EACtF,UAAA,oBAAC,sBAAD;GAAsB,UAAU;GAC5B,WAAA,WACA,SAAS,OAAO,SACd,OAEA,qBAAC,OAAD;IAAO,WAAU;IAAjB,UAAA,CACE,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,OAAO,oBAAC,MAAD;OAAM,eAAA;OAAY,WAAU;MAA+B,CAAA,IAAI;MACvE,oBAAC,MAAD;OAAI,WAAU;OAAiE,UAAA;MAAU,CAAA;MACxF,SACC,oBAAC,QAAD;OAAQ,SAAQ;OAAQ,MAAK;OAAU,cAAY,QAAQ;OAAS,SAAS;OAC3E,UAAA,oBAAC,kBAAD;QAAkB,eAAA;QAAY,WAAU;OAAU,CAAA;MAC5C,CAAA,IACN;KACD;IACL,CAAA,GAAA,oBAAC,OAAD;KAAK,WAAU;KAA8C,UAAA;IAAU,CAAA,CAClE;;EAGS,CAAA;CACnB,CAAA;AAET"}
|
|
@@ -63,7 +63,8 @@ function HomePage({ onShowSessions, navigationToggle }) {
|
|
|
63
63
|
size: data === null ? fill.data?.column === "side" ? "small" : "wide" : data.size ?? "small",
|
|
64
64
|
...data === null ? { legacy: true } : {
|
|
65
65
|
title: data.title,
|
|
66
|
-
icon: data.icon
|
|
66
|
+
icon: data.icon,
|
|
67
|
+
column: data.column
|
|
67
68
|
},
|
|
68
69
|
...destination === void 0 || open === void 0 ? {} : { onOpen: () => open(destination.id) },
|
|
69
70
|
body: (0, react.createElement)(component, props)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.cjs","names":["Button","FolderIcon","EmptyState","DashboardTileGrid","usePluginSlotProps","dashboardTileFills","legacyHomeAppFills","parseDashboardTileData","createElement"],"sources":["../../../src/web/components/HomePage.tsx"],"sourcesContent":["import { Button, EmptyState, FolderIcon } from '@agimon-ai/po-web-components';\nimport { createElement, type ReactNode } from 'react';\n\nimport { dashboardTileFills, legacyHomeAppFills, parseDashboardTileData } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { DashboardTileGrid, type DashboardTileView } from './DashboardTileGrid';\n\nexport interface HomeViewProps {\n tiles?: readonly DashboardTileView[];\n /** Legacy callers may still supply full cards; new callers supply ordered tiles instead. */\n main?: readonly ReactNode[];\n side?: readonly ReactNode[];\n title?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The shared Home and Workspace frame, independent of plugins, navigation and data loading. */\nexport function HomeView({\n tiles,\n main = [],\n side = [],\n title = 'Home',\n emptyTitle = 'Nothing on Home yet',\n emptyDescription = 'Apps you add show up here.',\n onShowSessions,\n navigationToggle = 'mobile',\n}: HomeViewProps) {\n const entries = tiles ?? [\n ...main.map((body, index): DashboardTileView => ({ id: `main-${index}`, size: 'wide', body, legacy: true })),\n ...side.map((body, index): DashboardTileView => ({ id: `side-${index}`, size: 'small', body, legacy: true })),\n ];\n return (\n <section\n aria-label={title}\n data-testid=\"home-page\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto bg-po-bg font-sans text-base text-po-text\"\n >\n {onShowSessions ? (\n <div className={`shrink-0 px-3 pt-2 ${navigationToggle === 'mobile' ? 'md:hidden' : ''}`}>\n <Button\n variant=\"ghost\"\n size=\"icon-md\"\n data-testid=\"mobile-sessions-open\"\n title=\"Show sessions\"\n aria-label=\"Show sessions\"\n onClick={onShowSessions}\n className=\"text-po-dim\"\n >\n <FolderIcon className=\"size-4\" />\n </Button>\n </div>\n ) : null}\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6 px-4 py-6 md:px-8 md:py-8\">\n <h1 className=\"text-2xl font-semibold text-po-hi\">{title}</h1>\n {entries.length === 0 ? (\n <EmptyState title={emptyTitle} description={emptyDescription} />\n ) : (\n <DashboardTileGrid tiles={entries} />\n )}\n </div>\n </section>\n );\n}\n\n/** Home reads only global fills, regardless of the focused session or workspace. */\nexport function HomePage({\n onShowSessions,\n navigationToggle,\n}: {\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}) {\n const props = usePluginSlotProps(null);\n const fills = [...dashboardTileFills({ scope: 'global' }), ...legacyHomeAppFills()].sort(\n (left, right) =>\n left.order - right.order || left.pluginId.localeCompare(right.pluginId) || left.id.localeCompare(right.id),\n );\n const tiles: DashboardTileView[] = [];\n for (const fill of fills) {\n const component = fill.component;\n if (component === undefined) continue;\n const id = JSON.stringify([fill.pluginId, fill.id]);\n const data = parseDashboardTileData(fill.data);\n const destination = data?.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n tiles.push({\n id,\n size:\n data === null\n ? (fill.data as { column?: unknown } | undefined)?.column === 'side'\n ? 'small'\n : 'wide'\n : (data.size ?? 'small'),\n ...(data === null ? { legacy: true } : { title: data.title, icon: data.icon }),\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(component, props),\n });\n }\n return (\n <HomeView\n tiles={tiles}\n {...(onShowSessions === undefined ? {} : { onShowSessions })}\n {...(navigationToggle === undefined ? {} : { navigationToggle })}\n />\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,SAAS,EACvB,OACA,OAAO,CAAC,GACR,OAAO,CAAC,GACR,QAAQ,QACR,aAAa,uBACb,mBAAmB,8BACnB,gBACA,mBAAmB,YACH;CAChB,MAAM,UAAU,SAAS,CACvB,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAQ;EAAM,QAAQ;CAAK,EAAE,GAC3G,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAS;EAAM,QAAQ;CAAK,EAAE,CAC9G;CACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;EACE,cAAY;EACZ,eAAY;EACZ,WAAU;EAHZ,UAAA,CAKG,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAAK,WAAW,sBAAsB,qBAAqB,WAAW,cAAc;GAClF,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACA,6BAAAA,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAY;IACZ,OAAM;IACN,cAAW;IACX,SAAS;IACT,WAAU;IAEV,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,YAAD,EAAY,WAAU,SAAU,CAAA;GAC1B,CAAA;EACL,CAAA,IACH,MACJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;IAAI,WAAU;IAAqC,UAAA;GAAU,CAAA,GAC5D,QAAQ,WAAW,IAClB,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,YAAD;IAAY,OAAO;IAAY,aAAa;GAAmB,CAAA,IAE/D,iBAAA,GAAA,kBAAA,IAAA,CAACC,0BAAAA,mBAAD,EAAmB,OAAO,QAAU,CAAA,CAEnC;EACE,CAAA,CAAA;;AAEb;;AAGA,SAAgB,SAAS,EACvB,gBACA,oBAIC;CACD,MAAM,QAAQC,2BAAAA,mBAAmB,IAAI;CACrC,MAAM,QAAQ,CAAC,GAAGC,uBAAAA,mBAAmB,EAAE,OAAO,SAAS,CAAC,GAAG,GAAGC,uBAAAA,mBAAmB,CAAC,CAAC,CAAC,MACjF,MAAM,UACL,KAAK,QAAQ,MAAM,SAAS,KAAK,SAAS,cAAc,MAAM,QAAQ,KAAK,KAAK,GAAG,cAAc,MAAM,EAAE,CAC7G;CACA,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,KAAK,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;EAClD,MAAM,OAAOC,uBAAAA,uBAAuB,KAAK,IAAI;EAC7C,MAAM,cAAc,MAAM;EAC1B,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,MAAM,KAAK;GACT;GACA,MACE,SAAS,OACJ,KAAK,MAA2C,WAAW,SAC1D,UACA,SACD,KAAK,QAAQ;GACpB,GAAI,SAAS,OAAO,EAAE,QAAQ,KAAK,IAAI;IAAE,OAAO,KAAK;IAAO,MAAM,KAAK;
|
|
1
|
+
{"version":3,"file":"HomePage.cjs","names":["Button","FolderIcon","EmptyState","DashboardTileGrid","usePluginSlotProps","dashboardTileFills","legacyHomeAppFills","parseDashboardTileData","createElement"],"sources":["../../../src/web/components/HomePage.tsx"],"sourcesContent":["import { Button, EmptyState, FolderIcon } from '@agimon-ai/po-web-components';\nimport { createElement, type ReactNode } from 'react';\n\nimport { dashboardTileFills, legacyHomeAppFills, parseDashboardTileData } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { DashboardTileGrid, type DashboardTileView } from './DashboardTileGrid';\n\nexport interface HomeViewProps {\n tiles?: readonly DashboardTileView[];\n /** Legacy callers may still supply full cards; new callers supply ordered tiles instead. */\n main?: readonly ReactNode[];\n side?: readonly ReactNode[];\n title?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The shared Home and Workspace frame, independent of plugins, navigation and data loading. */\nexport function HomeView({\n tiles,\n main = [],\n side = [],\n title = 'Home',\n emptyTitle = 'Nothing on Home yet',\n emptyDescription = 'Apps you add show up here.',\n onShowSessions,\n navigationToggle = 'mobile',\n}: HomeViewProps) {\n const entries = tiles ?? [\n ...main.map((body, index): DashboardTileView => ({ id: `main-${index}`, size: 'wide', body, legacy: true })),\n ...side.map((body, index): DashboardTileView => ({ id: `side-${index}`, size: 'small', body, legacy: true })),\n ];\n return (\n <section\n aria-label={title}\n data-testid=\"home-page\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto bg-po-bg font-sans text-base text-po-text\"\n >\n {onShowSessions ? (\n <div className={`shrink-0 px-3 pt-2 ${navigationToggle === 'mobile' ? 'md:hidden' : ''}`}>\n <Button\n variant=\"ghost\"\n size=\"icon-md\"\n data-testid=\"mobile-sessions-open\"\n title=\"Show sessions\"\n aria-label=\"Show sessions\"\n onClick={onShowSessions}\n className=\"text-po-dim\"\n >\n <FolderIcon className=\"size-4\" />\n </Button>\n </div>\n ) : null}\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6 px-4 py-6 md:px-8 md:py-8\">\n <h1 className=\"text-2xl font-semibold text-po-hi\">{title}</h1>\n {entries.length === 0 ? (\n <EmptyState title={emptyTitle} description={emptyDescription} />\n ) : (\n <DashboardTileGrid tiles={entries} />\n )}\n </div>\n </section>\n );\n}\n\n/** Home reads only global fills, regardless of the focused session or workspace. */\nexport function HomePage({\n onShowSessions,\n navigationToggle,\n}: {\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}) {\n const props = usePluginSlotProps(null);\n const fills = [...dashboardTileFills({ scope: 'global' }), ...legacyHomeAppFills()].sort(\n (left, right) =>\n left.order - right.order || left.pluginId.localeCompare(right.pluginId) || left.id.localeCompare(right.id),\n );\n const tiles: DashboardTileView[] = [];\n for (const fill of fills) {\n const component = fill.component;\n if (component === undefined) continue;\n const id = JSON.stringify([fill.pluginId, fill.id]);\n const data = parseDashboardTileData(fill.data);\n const destination = data?.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n tiles.push({\n id,\n size:\n data === null\n ? (fill.data as { column?: unknown } | undefined)?.column === 'side'\n ? 'small'\n : 'wide'\n : (data.size ?? 'small'),\n ...(data === null ? { legacy: true } : { title: data.title, icon: data.icon, column: data.column }),\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(component, props),\n });\n }\n return (\n <HomeView\n tiles={tiles}\n {...(onShowSessions === undefined ? {} : { onShowSessions })}\n {...(navigationToggle === undefined ? {} : { navigationToggle })}\n />\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,SAAS,EACvB,OACA,OAAO,CAAC,GACR,OAAO,CAAC,GACR,QAAQ,QACR,aAAa,uBACb,mBAAmB,8BACnB,gBACA,mBAAmB,YACH;CAChB,MAAM,UAAU,SAAS,CACvB,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAQ;EAAM,QAAQ;CAAK,EAAE,GAC3G,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAS;EAAM,QAAQ;CAAK,EAAE,CAC9G;CACA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;EACE,cAAY;EACZ,eAAY;EACZ,WAAU;EAHZ,UAAA,CAKG,iBACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAAK,WAAW,sBAAsB,qBAAqB,WAAW,cAAc;GAClF,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACA,6BAAAA,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAY;IACZ,OAAM;IACN,cAAW;IACX,SAAS;IACT,WAAU;IAEV,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,YAAD,EAAY,WAAU,SAAU,CAAA;GAC1B,CAAA;EACL,CAAA,IACH,MACJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;IAAI,WAAU;IAAqC,UAAA;GAAU,CAAA,GAC5D,QAAQ,WAAW,IAClB,iBAAA,GAAA,kBAAA,IAAA,CAACC,6BAAAA,YAAD;IAAY,OAAO;IAAY,aAAa;GAAmB,CAAA,IAE/D,iBAAA,GAAA,kBAAA,IAAA,CAACC,0BAAAA,mBAAD,EAAmB,OAAO,QAAU,CAAA,CAEnC;EACE,CAAA,CAAA;;AAEb;;AAGA,SAAgB,SAAS,EACvB,gBACA,oBAIC;CACD,MAAM,QAAQC,2BAAAA,mBAAmB,IAAI;CACrC,MAAM,QAAQ,CAAC,GAAGC,uBAAAA,mBAAmB,EAAE,OAAO,SAAS,CAAC,GAAG,GAAGC,uBAAAA,mBAAmB,CAAC,CAAC,CAAC,MACjF,MAAM,UACL,KAAK,QAAQ,MAAM,SAAS,KAAK,SAAS,cAAc,MAAM,QAAQ,KAAK,KAAK,GAAG,cAAc,MAAM,EAAE,CAC7G;CACA,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,KAAK,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;EAClD,MAAM,OAAOC,uBAAAA,uBAAuB,KAAK,IAAI;EAC7C,MAAM,cAAc,MAAM;EAC1B,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,MAAM,KAAK;GACT;GACA,MACE,SAAS,OACJ,KAAK,MAA2C,WAAW,SAC1D,UACA,SACD,KAAK,QAAQ;GACpB,GAAI,SAAS,OAAO,EAAE,QAAQ,KAAK,IAAI;IAAE,OAAO,KAAK;IAAO,MAAM,KAAK;IAAM,QAAQ,KAAK;GAAO;GACjG,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,OAAA,GAAMC,MAAAA,cAAAA,CAAc,WAAW,KAAK;EACtC,CAAC;CACH;CACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;EACS;EACP,GAAK,mBAAmB,KAAA,IAAY,CAAC,IAAI,EAAE,eAAe;EAC1D,GAAK,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB;CAC/D,CAAA;AAEL"}
|
|
@@ -63,7 +63,8 @@ function HomePage({ onShowSessions, navigationToggle }) {
|
|
|
63
63
|
size: data === null ? fill.data?.column === "side" ? "small" : "wide" : data.size ?? "small",
|
|
64
64
|
...data === null ? { legacy: true } : {
|
|
65
65
|
title: data.title,
|
|
66
|
-
icon: data.icon
|
|
66
|
+
icon: data.icon,
|
|
67
|
+
column: data.column
|
|
67
68
|
},
|
|
68
69
|
...destination === void 0 || open === void 0 ? {} : { onOpen: () => open(destination.id) },
|
|
69
70
|
body: createElement(component, props)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.mjs","names":[],"sources":["../../../src/web/components/HomePage.tsx"],"sourcesContent":["import { Button, EmptyState, FolderIcon } from '@agimon-ai/po-web-components';\nimport { createElement, type ReactNode } from 'react';\n\nimport { dashboardTileFills, legacyHomeAppFills, parseDashboardTileData } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { DashboardTileGrid, type DashboardTileView } from './DashboardTileGrid';\n\nexport interface HomeViewProps {\n tiles?: readonly DashboardTileView[];\n /** Legacy callers may still supply full cards; new callers supply ordered tiles instead. */\n main?: readonly ReactNode[];\n side?: readonly ReactNode[];\n title?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The shared Home and Workspace frame, independent of plugins, navigation and data loading. */\nexport function HomeView({\n tiles,\n main = [],\n side = [],\n title = 'Home',\n emptyTitle = 'Nothing on Home yet',\n emptyDescription = 'Apps you add show up here.',\n onShowSessions,\n navigationToggle = 'mobile',\n}: HomeViewProps) {\n const entries = tiles ?? [\n ...main.map((body, index): DashboardTileView => ({ id: `main-${index}`, size: 'wide', body, legacy: true })),\n ...side.map((body, index): DashboardTileView => ({ id: `side-${index}`, size: 'small', body, legacy: true })),\n ];\n return (\n <section\n aria-label={title}\n data-testid=\"home-page\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto bg-po-bg font-sans text-base text-po-text\"\n >\n {onShowSessions ? (\n <div className={`shrink-0 px-3 pt-2 ${navigationToggle === 'mobile' ? 'md:hidden' : ''}`}>\n <Button\n variant=\"ghost\"\n size=\"icon-md\"\n data-testid=\"mobile-sessions-open\"\n title=\"Show sessions\"\n aria-label=\"Show sessions\"\n onClick={onShowSessions}\n className=\"text-po-dim\"\n >\n <FolderIcon className=\"size-4\" />\n </Button>\n </div>\n ) : null}\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6 px-4 py-6 md:px-8 md:py-8\">\n <h1 className=\"text-2xl font-semibold text-po-hi\">{title}</h1>\n {entries.length === 0 ? (\n <EmptyState title={emptyTitle} description={emptyDescription} />\n ) : (\n <DashboardTileGrid tiles={entries} />\n )}\n </div>\n </section>\n );\n}\n\n/** Home reads only global fills, regardless of the focused session or workspace. */\nexport function HomePage({\n onShowSessions,\n navigationToggle,\n}: {\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}) {\n const props = usePluginSlotProps(null);\n const fills = [...dashboardTileFills({ scope: 'global' }), ...legacyHomeAppFills()].sort(\n (left, right) =>\n left.order - right.order || left.pluginId.localeCompare(right.pluginId) || left.id.localeCompare(right.id),\n );\n const tiles: DashboardTileView[] = [];\n for (const fill of fills) {\n const component = fill.component;\n if (component === undefined) continue;\n const id = JSON.stringify([fill.pluginId, fill.id]);\n const data = parseDashboardTileData(fill.data);\n const destination = data?.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n tiles.push({\n id,\n size:\n data === null\n ? (fill.data as { column?: unknown } | undefined)?.column === 'side'\n ? 'small'\n : 'wide'\n : (data.size ?? 'small'),\n ...(data === null ? { legacy: true } : { title: data.title, icon: data.icon }),\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(component, props),\n });\n }\n return (\n <HomeView\n tiles={tiles}\n {...(onShowSessions === undefined ? {} : { onShowSessions })}\n {...(navigationToggle === undefined ? {} : { navigationToggle })}\n />\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,SAAS,EACvB,OACA,OAAO,CAAC,GACR,OAAO,CAAC,GACR,QAAQ,QACR,aAAa,uBACb,mBAAmB,8BACnB,gBACA,mBAAmB,YACH;CAChB,MAAM,UAAU,SAAS,CACvB,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAQ;EAAM,QAAQ;CAAK,EAAE,GAC3G,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAS;EAAM,QAAQ;CAAK,EAAE,CAC9G;CACA,OACE,qBAAC,WAAD;EACE,cAAY;EACZ,eAAY;EACZ,WAAU;EAHZ,UAAA,CAKG,iBACC,oBAAC,OAAD;GAAK,WAAW,sBAAsB,qBAAqB,WAAW,cAAc;GAClF,UAAA,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAY;IACZ,OAAM;IACN,cAAW;IACX,SAAS;IACT,WAAU;IAEV,UAAA,oBAAC,YAAD,EAAY,WAAU,SAAU,CAAA;GAC1B,CAAA;EACL,CAAA,IACH,MACJ,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,MAAD;IAAI,WAAU;IAAqC,UAAA;GAAU,CAAA,GAC5D,QAAQ,WAAW,IAClB,oBAAC,YAAD;IAAY,OAAO;IAAY,aAAa;GAAmB,CAAA,IAE/D,oBAAC,mBAAD,EAAmB,OAAO,QAAU,CAAA,CAEnC;EACE,CAAA,CAAA;;AAEb;;AAGA,SAAgB,SAAS,EACvB,gBACA,oBAIC;CACD,MAAM,QAAQ,mBAAmB,IAAI;CACrC,MAAM,QAAQ,CAAC,GAAG,mBAAmB,EAAE,OAAO,SAAS,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAC,CAAC,MACjF,MAAM,UACL,KAAK,QAAQ,MAAM,SAAS,KAAK,SAAS,cAAc,MAAM,QAAQ,KAAK,KAAK,GAAG,cAAc,MAAM,EAAE,CAC7G;CACA,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,KAAK,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;EAClD,MAAM,OAAO,uBAAuB,KAAK,IAAI;EAC7C,MAAM,cAAc,MAAM;EAC1B,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,MAAM,KAAK;GACT;GACA,MACE,SAAS,OACJ,KAAK,MAA2C,WAAW,SAC1D,UACA,SACD,KAAK,QAAQ;GACpB,GAAI,SAAS,OAAO,EAAE,QAAQ,KAAK,IAAI;IAAE,OAAO,KAAK;IAAO,MAAM,KAAK;
|
|
1
|
+
{"version":3,"file":"HomePage.mjs","names":[],"sources":["../../../src/web/components/HomePage.tsx"],"sourcesContent":["import { Button, EmptyState, FolderIcon } from '@agimon-ai/po-web-components';\nimport { createElement, type ReactNode } from 'react';\n\nimport { dashboardTileFills, legacyHomeAppFills, parseDashboardTileData } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { DashboardTileGrid, type DashboardTileView } from './DashboardTileGrid';\n\nexport interface HomeViewProps {\n tiles?: readonly DashboardTileView[];\n /** Legacy callers may still supply full cards; new callers supply ordered tiles instead. */\n main?: readonly ReactNode[];\n side?: readonly ReactNode[];\n title?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The shared Home and Workspace frame, independent of plugins, navigation and data loading. */\nexport function HomeView({\n tiles,\n main = [],\n side = [],\n title = 'Home',\n emptyTitle = 'Nothing on Home yet',\n emptyDescription = 'Apps you add show up here.',\n onShowSessions,\n navigationToggle = 'mobile',\n}: HomeViewProps) {\n const entries = tiles ?? [\n ...main.map((body, index): DashboardTileView => ({ id: `main-${index}`, size: 'wide', body, legacy: true })),\n ...side.map((body, index): DashboardTileView => ({ id: `side-${index}`, size: 'small', body, legacy: true })),\n ];\n return (\n <section\n aria-label={title}\n data-testid=\"home-page\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto bg-po-bg font-sans text-base text-po-text\"\n >\n {onShowSessions ? (\n <div className={`shrink-0 px-3 pt-2 ${navigationToggle === 'mobile' ? 'md:hidden' : ''}`}>\n <Button\n variant=\"ghost\"\n size=\"icon-md\"\n data-testid=\"mobile-sessions-open\"\n title=\"Show sessions\"\n aria-label=\"Show sessions\"\n onClick={onShowSessions}\n className=\"text-po-dim\"\n >\n <FolderIcon className=\"size-4\" />\n </Button>\n </div>\n ) : null}\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6 px-4 py-6 md:px-8 md:py-8\">\n <h1 className=\"text-2xl font-semibold text-po-hi\">{title}</h1>\n {entries.length === 0 ? (\n <EmptyState title={emptyTitle} description={emptyDescription} />\n ) : (\n <DashboardTileGrid tiles={entries} />\n )}\n </div>\n </section>\n );\n}\n\n/** Home reads only global fills, regardless of the focused session or workspace. */\nexport function HomePage({\n onShowSessions,\n navigationToggle,\n}: {\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}) {\n const props = usePluginSlotProps(null);\n const fills = [...dashboardTileFills({ scope: 'global' }), ...legacyHomeAppFills()].sort(\n (left, right) =>\n left.order - right.order || left.pluginId.localeCompare(right.pluginId) || left.id.localeCompare(right.id),\n );\n const tiles: DashboardTileView[] = [];\n for (const fill of fills) {\n const component = fill.component;\n if (component === undefined) continue;\n const id = JSON.stringify([fill.pluginId, fill.id]);\n const data = parseDashboardTileData(fill.data);\n const destination = data?.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n tiles.push({\n id,\n size:\n data === null\n ? (fill.data as { column?: unknown } | undefined)?.column === 'side'\n ? 'small'\n : 'wide'\n : (data.size ?? 'small'),\n ...(data === null ? { legacy: true } : { title: data.title, icon: data.icon, column: data.column }),\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(component, props),\n });\n }\n return (\n <HomeView\n tiles={tiles}\n {...(onShowSessions === undefined ? {} : { onShowSessions })}\n {...(navigationToggle === undefined ? {} : { navigationToggle })}\n />\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,SAAS,EACvB,OACA,OAAO,CAAC,GACR,OAAO,CAAC,GACR,QAAQ,QACR,aAAa,uBACb,mBAAmB,8BACnB,gBACA,mBAAmB,YACH;CAChB,MAAM,UAAU,SAAS,CACvB,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAQ;EAAM,QAAQ;CAAK,EAAE,GAC3G,GAAG,KAAK,KAAK,MAAM,WAA8B;EAAE,IAAI,QAAQ;EAAS,MAAM;EAAS;EAAM,QAAQ;CAAK,EAAE,CAC9G;CACA,OACE,qBAAC,WAAD;EACE,cAAY;EACZ,eAAY;EACZ,WAAU;EAHZ,UAAA,CAKG,iBACC,oBAAC,OAAD;GAAK,WAAW,sBAAsB,qBAAqB,WAAW,cAAc;GAClF,UAAA,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAY;IACZ,OAAM;IACN,cAAW;IACX,SAAS;IACT,WAAU;IAEV,UAAA,oBAAC,YAAD,EAAY,WAAU,SAAU,CAAA;GAC1B,CAAA;EACL,CAAA,IACH,MACJ,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,MAAD;IAAI,WAAU;IAAqC,UAAA;GAAU,CAAA,GAC5D,QAAQ,WAAW,IAClB,oBAAC,YAAD;IAAY,OAAO;IAAY,aAAa;GAAmB,CAAA,IAE/D,oBAAC,mBAAD,EAAmB,OAAO,QAAU,CAAA,CAEnC;EACE,CAAA,CAAA;;AAEb;;AAGA,SAAgB,SAAS,EACvB,gBACA,oBAIC;CACD,MAAM,QAAQ,mBAAmB,IAAI;CACrC,MAAM,QAAQ,CAAC,GAAG,mBAAmB,EAAE,OAAO,SAAS,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAC,CAAC,MACjF,MAAM,UACL,KAAK,QAAQ,MAAM,SAAS,KAAK,SAAS,cAAc,MAAM,QAAQ,KAAK,KAAK,GAAG,cAAc,MAAM,EAAE,CAC7G;CACA,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,KAAK,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;EAClD,MAAM,OAAO,uBAAuB,KAAK,IAAI;EAC7C,MAAM,cAAc,MAAM;EAC1B,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,MAAM,KAAK;GACT;GACA,MACE,SAAS,OACJ,KAAK,MAA2C,WAAW,SAC1D,UACA,SACD,KAAK,QAAQ;GACpB,GAAI,SAAS,OAAO,EAAE,QAAQ,KAAK,IAAI;IAAE,OAAO,KAAK;IAAO,MAAM,KAAK;IAAM,QAAQ,KAAK;GAAO;GACjG,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,MAAM,cAAc,WAAW,KAAK;EACtC,CAAC;CACH;CACA,OACE,oBAAC,UAAD;EACS;EACP,GAAK,mBAAmB,KAAA,IAAY,CAAC,IAAI,EAAE,eAAe;EAC1D,GAAK,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB;CAC/D,CAAA;AAEL"}
|
|
@@ -47,6 +47,7 @@ function WorkspacePage({ workspaceId, ...navigation }) {
|
|
|
47
47
|
title: data.title,
|
|
48
48
|
icon: data.icon,
|
|
49
49
|
size: data.size ?? "small",
|
|
50
|
+
column: data.column,
|
|
50
51
|
...destination === void 0 || open === void 0 ? {} : { onOpen: () => open(destination.id) },
|
|
51
52
|
body: (0, react.createElement)(fill.component, props)
|
|
52
53
|
}];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacePage.cjs","names":["HomeView","useStore","workspacesStore","webPluginCompositionStore","webPluginMountState","usePluginSlotProps","dashboardTileFills","createElement"],"sources":["../../../src/web/components/WorkspacePage.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store';\nimport { createElement } from 'react';\n\nimport { webPluginCompositionStore, webPluginMountState } from '../lib/pluginCompositions';\nimport { dashboardTileFills } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { useWebPluginRegistry } from '../stores/useWebPluginRegistry';\nimport { workspacesStore } from '../stores/workspacesStore';\nimport type { DashboardTileView } from './DashboardTileGrid';\nimport { HomeView } from './HomePage';\n\nexport interface WorkspaceViewProps {\n title: string;\n state?: 'ready' | 'loading' | 'missing' | 'unavailable' | 'error';\n error?: string;\n tiles?: readonly DashboardTileView[];\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The same tile surface as Home, with explicit workspace delivery states. */\nexport function WorkspaceView({ title, state = 'ready', error, tiles = [], ...navigation }: WorkspaceViewProps) {\n const messages = {\n ready: ['Nothing in this workspace yet', 'Apps for this workspace will show up here.'],\n loading: ['Loading workspace', 'Your workspace is getting ready.'],\n missing: ['Workspace not found', 'This workspace may have been removed. Choose another from the session list.'],\n unavailable: [\n 'Workspace unavailable',\n 'Po cannot open this workspace right now. Reconnect to its host and try again.',\n ],\n error: ['Workspace apps could not load', error ?? 'Reconnect to this host and try again.'],\n } as const;\n return (\n <HomeView\n {...navigation}\n title={title}\n tiles={state === 'ready' ? tiles : []}\n emptyTitle={messages[state][0]}\n emptyDescription={messages[state][1]}\n />\n );\n}\n\n/** Reads the explicit workspace mount, never the unrelated focused session. The host loads its composition. */\nexport function WorkspacePage({\n workspaceId,\n ...navigation\n}: { workspaceId: string } & Pick<WorkspaceViewProps, 'onShowSessions' | 'navigationToggle'>) {\n useWebPluginRegistry();\n const workspace = useStore(workspacesStore, (state) => state.byId[workspaceId]);\n const hydrated = useStore(workspacesStore, (state) => state.hydrated);\n const mount = { scope: 'workspace', workspaceId } as const;\n const composition = useStore(webPluginCompositionStore, (state) => state);\n const readiness = webPluginMountState(mount, composition);\n const props = usePluginSlotProps(null, undefined, undefined, workspaceId);\n const tiles: DashboardTileView[] = dashboardTileFills(mount).flatMap((fill) => {\n if (fill.component === undefined) return [];\n const data = fill.data;\n const destination = data.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n return [\n {\n id: JSON.stringify([fill.pluginId, fill.id]),\n title: data.title,\n icon: data.icon,\n size: data.size ?? 'small',\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(fill.component, props),\n },\n ];\n });\n const state = !hydrated\n ? 'loading'\n : workspace === undefined\n ? 'missing'\n : workspace.available === false\n ? 'unavailable'\n : readiness.phase === 'error'\n ? 'error'\n : readiness.phase !== 'ready'\n ? 'loading'\n : 'ready';\n return (\n <WorkspaceView\n {...navigation}\n title={workspace?.name ?? 'Workspace'}\n state={state}\n error={readiness.error}\n tiles={tiles}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAgB,cAAc,EAAE,OAAO,QAAQ,SAAS,OAAO,QAAQ,CAAC,GAAG,GAAG,cAAkC;CAC9G,MAAM,WAAW;EACf,OAAO,CAAC,iCAAiC,4CAA4C;EACrF,SAAS,CAAC,qBAAqB,kCAAkC;EACjE,SAAS,CAAC,uBAAuB,6EAA6E;EAC9G,aAAa,CACX,yBACA,+EACF;EACA,OAAO,CAAC,iCAAiC,SAAS,uCAAuC;CAC3F;CACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,iBAAAA,UAAD;EACE,GAAI;EACG;EACP,OAAO,UAAU,UAAU,QAAQ,CAAC;EACpC,YAAY,SAAS,MAAM,CAAC;EAC5B,kBAAkB,SAAS,MAAM,CAAC;CACnC,CAAA;AAEL;;AAGA,SAAgB,cAAc,EAC5B,aACA,GAAG,cACyF;CAC5F,6BAAA,qBAAqB;CACrB,MAAM,aAAA,GAAYC,sBAAAA,SAAAA,CAASC,wBAAAA,kBAAkB,UAAU,MAAM,KAAK,YAAY;CAC9E,MAAM,YAAA,GAAWD,sBAAAA,SAAAA,CAASC,wBAAAA,kBAAkB,UAAU,MAAM,QAAQ;CACpE,MAAM,QAAQ;EAAE,OAAO;EAAa;CAAY;CAChD,MAAM,eAAA,GAAcD,sBAAAA,SAAAA,CAASE,2BAAAA,4BAA4B,UAAU,KAAK;CACxE,MAAM,YAAYC,2BAAAA,oBAAoB,OAAO,WAAW;CACxD,MAAM,QAAQC,2BAAAA,mBAAmB,MAAM,KAAA,GAAW,KAAA,GAAW,WAAW;CACxE,MAAM,QAA6BC,uBAAAA,mBAAmB,KAAK,CAAC,CAAC,SAAS,SAAS;EAC7E,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO,CAAC;EAC1C,MAAM,OAAO,KAAK;EAClB,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,OAAO,CACL;GACE,IAAI,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;GAC3C,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,MAAM,KAAK,QAAQ;GACnB,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,OAAA,GAAMC,MAAAA,cAAAA,CAAc,KAAK,WAAW,KAAK;EAC3C,CACF;CACF,CAAC;CACD,MAAM,QAAQ,CAAC,WACX,YACA,cAAc,KAAA,IACZ,YACA,UAAU,cAAc,QACtB,gBACA,UAAU,UAAU,UAClB,UACA,UAAU,UAAU,UAClB,YACA;CACZ,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;EACE,GAAI;EACJ,OAAO,WAAW,QAAQ;EACnB;EACP,OAAO,UAAU;EACV;CACR,CAAA;AAEL"}
|
|
1
|
+
{"version":3,"file":"WorkspacePage.cjs","names":["HomeView","useStore","workspacesStore","webPluginCompositionStore","webPluginMountState","usePluginSlotProps","dashboardTileFills","createElement"],"sources":["../../../src/web/components/WorkspacePage.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store';\nimport { createElement } from 'react';\n\nimport { webPluginCompositionStore, webPluginMountState } from '../lib/pluginCompositions';\nimport { dashboardTileFills } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { useWebPluginRegistry } from '../stores/useWebPluginRegistry';\nimport { workspacesStore } from '../stores/workspacesStore';\nimport type { DashboardTileView } from './DashboardTileGrid';\nimport { HomeView } from './HomePage';\n\nexport interface WorkspaceViewProps {\n title: string;\n state?: 'ready' | 'loading' | 'missing' | 'unavailable' | 'error';\n error?: string;\n tiles?: readonly DashboardTileView[];\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The same tile surface as Home, with explicit workspace delivery states. */\nexport function WorkspaceView({ title, state = 'ready', error, tiles = [], ...navigation }: WorkspaceViewProps) {\n const messages = {\n ready: ['Nothing in this workspace yet', 'Apps for this workspace will show up here.'],\n loading: ['Loading workspace', 'Your workspace is getting ready.'],\n missing: ['Workspace not found', 'This workspace may have been removed. Choose another from the session list.'],\n unavailable: [\n 'Workspace unavailable',\n 'Po cannot open this workspace right now. Reconnect to its host and try again.',\n ],\n error: ['Workspace apps could not load', error ?? 'Reconnect to this host and try again.'],\n } as const;\n return (\n <HomeView\n {...navigation}\n title={title}\n tiles={state === 'ready' ? tiles : []}\n emptyTitle={messages[state][0]}\n emptyDescription={messages[state][1]}\n />\n );\n}\n\n/** Reads the explicit workspace mount, never the unrelated focused session. The host loads its composition. */\nexport function WorkspacePage({\n workspaceId,\n ...navigation\n}: { workspaceId: string } & Pick<WorkspaceViewProps, 'onShowSessions' | 'navigationToggle'>) {\n useWebPluginRegistry();\n const workspace = useStore(workspacesStore, (state) => state.byId[workspaceId]);\n const hydrated = useStore(workspacesStore, (state) => state.hydrated);\n const mount = { scope: 'workspace', workspaceId } as const;\n const composition = useStore(webPluginCompositionStore, (state) => state);\n const readiness = webPluginMountState(mount, composition);\n const props = usePluginSlotProps(null, undefined, undefined, workspaceId);\n const tiles: DashboardTileView[] = dashboardTileFills(mount).flatMap((fill) => {\n if (fill.component === undefined) return [];\n const data = fill.data;\n const destination = data.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n return [\n {\n id: JSON.stringify([fill.pluginId, fill.id]),\n title: data.title,\n icon: data.icon,\n size: data.size ?? 'small',\n column: data.column,\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(fill.component, props),\n },\n ];\n });\n const state = !hydrated\n ? 'loading'\n : workspace === undefined\n ? 'missing'\n : workspace.available === false\n ? 'unavailable'\n : readiness.phase === 'error'\n ? 'error'\n : readiness.phase !== 'ready'\n ? 'loading'\n : 'ready';\n return (\n <WorkspaceView\n {...navigation}\n title={workspace?.name ?? 'Workspace'}\n state={state}\n error={readiness.error}\n tiles={tiles}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAgB,cAAc,EAAE,OAAO,QAAQ,SAAS,OAAO,QAAQ,CAAC,GAAG,GAAG,cAAkC;CAC9G,MAAM,WAAW;EACf,OAAO,CAAC,iCAAiC,4CAA4C;EACrF,SAAS,CAAC,qBAAqB,kCAAkC;EACjE,SAAS,CAAC,uBAAuB,6EAA6E;EAC9G,aAAa,CACX,yBACA,+EACF;EACA,OAAO,CAAC,iCAAiC,SAAS,uCAAuC;CAC3F;CACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,iBAAAA,UAAD;EACE,GAAI;EACG;EACP,OAAO,UAAU,UAAU,QAAQ,CAAC;EACpC,YAAY,SAAS,MAAM,CAAC;EAC5B,kBAAkB,SAAS,MAAM,CAAC;CACnC,CAAA;AAEL;;AAGA,SAAgB,cAAc,EAC5B,aACA,GAAG,cACyF;CAC5F,6BAAA,qBAAqB;CACrB,MAAM,aAAA,GAAYC,sBAAAA,SAAAA,CAASC,wBAAAA,kBAAkB,UAAU,MAAM,KAAK,YAAY;CAC9E,MAAM,YAAA,GAAWD,sBAAAA,SAAAA,CAASC,wBAAAA,kBAAkB,UAAU,MAAM,QAAQ;CACpE,MAAM,QAAQ;EAAE,OAAO;EAAa;CAAY;CAChD,MAAM,eAAA,GAAcD,sBAAAA,SAAAA,CAASE,2BAAAA,4BAA4B,UAAU,KAAK;CACxE,MAAM,YAAYC,2BAAAA,oBAAoB,OAAO,WAAW;CACxD,MAAM,QAAQC,2BAAAA,mBAAmB,MAAM,KAAA,GAAW,KAAA,GAAW,WAAW;CACxE,MAAM,QAA6BC,uBAAAA,mBAAmB,KAAK,CAAC,CAAC,SAAS,SAAS;EAC7E,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO,CAAC;EAC1C,MAAM,OAAO,KAAK;EAClB,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,OAAO,CACL;GACE,IAAI,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;GAC3C,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,MAAM,KAAK,QAAQ;GACnB,QAAQ,KAAK;GACb,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,OAAA,GAAMC,MAAAA,cAAAA,CAAc,KAAK,WAAW,KAAK;EAC3C,CACF;CACF,CAAC;CACD,MAAM,QAAQ,CAAC,WACX,YACA,cAAc,KAAA,IACZ,YACA,UAAU,cAAc,QACtB,gBACA,UAAU,UAAU,UAClB,UACA,UAAU,UAAU,UAClB,YACA;CACZ,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAD;EACE,GAAI;EACJ,OAAO,WAAW,QAAQ;EACnB;EACP,OAAO,UAAU;EACV;CACR,CAAA;AAEL"}
|
|
@@ -47,6 +47,7 @@ function WorkspacePage({ workspaceId, ...navigation }) {
|
|
|
47
47
|
title: data.title,
|
|
48
48
|
icon: data.icon,
|
|
49
49
|
size: data.size ?? "small",
|
|
50
|
+
column: data.column,
|
|
50
51
|
...destination === void 0 || open === void 0 ? {} : { onOpen: () => open(destination.id) },
|
|
51
52
|
body: createElement(fill.component, props)
|
|
52
53
|
}];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacePage.mjs","names":[],"sources":["../../../src/web/components/WorkspacePage.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store';\nimport { createElement } from 'react';\n\nimport { webPluginCompositionStore, webPluginMountState } from '../lib/pluginCompositions';\nimport { dashboardTileFills } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { useWebPluginRegistry } from '../stores/useWebPluginRegistry';\nimport { workspacesStore } from '../stores/workspacesStore';\nimport type { DashboardTileView } from './DashboardTileGrid';\nimport { HomeView } from './HomePage';\n\nexport interface WorkspaceViewProps {\n title: string;\n state?: 'ready' | 'loading' | 'missing' | 'unavailable' | 'error';\n error?: string;\n tiles?: readonly DashboardTileView[];\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The same tile surface as Home, with explicit workspace delivery states. */\nexport function WorkspaceView({ title, state = 'ready', error, tiles = [], ...navigation }: WorkspaceViewProps) {\n const messages = {\n ready: ['Nothing in this workspace yet', 'Apps for this workspace will show up here.'],\n loading: ['Loading workspace', 'Your workspace is getting ready.'],\n missing: ['Workspace not found', 'This workspace may have been removed. Choose another from the session list.'],\n unavailable: [\n 'Workspace unavailable',\n 'Po cannot open this workspace right now. Reconnect to its host and try again.',\n ],\n error: ['Workspace apps could not load', error ?? 'Reconnect to this host and try again.'],\n } as const;\n return (\n <HomeView\n {...navigation}\n title={title}\n tiles={state === 'ready' ? tiles : []}\n emptyTitle={messages[state][0]}\n emptyDescription={messages[state][1]}\n />\n );\n}\n\n/** Reads the explicit workspace mount, never the unrelated focused session. The host loads its composition. */\nexport function WorkspacePage({\n workspaceId,\n ...navigation\n}: { workspaceId: string } & Pick<WorkspaceViewProps, 'onShowSessions' | 'navigationToggle'>) {\n useWebPluginRegistry();\n const workspace = useStore(workspacesStore, (state) => state.byId[workspaceId]);\n const hydrated = useStore(workspacesStore, (state) => state.hydrated);\n const mount = { scope: 'workspace', workspaceId } as const;\n const composition = useStore(webPluginCompositionStore, (state) => state);\n const readiness = webPluginMountState(mount, composition);\n const props = usePluginSlotProps(null, undefined, undefined, workspaceId);\n const tiles: DashboardTileView[] = dashboardTileFills(mount).flatMap((fill) => {\n if (fill.component === undefined) return [];\n const data = fill.data;\n const destination = data.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n return [\n {\n id: JSON.stringify([fill.pluginId, fill.id]),\n title: data.title,\n icon: data.icon,\n size: data.size ?? 'small',\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(fill.component, props),\n },\n ];\n });\n const state = !hydrated\n ? 'loading'\n : workspace === undefined\n ? 'missing'\n : workspace.available === false\n ? 'unavailable'\n : readiness.phase === 'error'\n ? 'error'\n : readiness.phase !== 'ready'\n ? 'loading'\n : 'ready';\n return (\n <WorkspaceView\n {...navigation}\n title={workspace?.name ?? 'Workspace'}\n state={state}\n error={readiness.error}\n tiles={tiles}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAgB,cAAc,EAAE,OAAO,QAAQ,SAAS,OAAO,QAAQ,CAAC,GAAG,GAAG,cAAkC;CAC9G,MAAM,WAAW;EACf,OAAO,CAAC,iCAAiC,4CAA4C;EACrF,SAAS,CAAC,qBAAqB,kCAAkC;EACjE,SAAS,CAAC,uBAAuB,6EAA6E;EAC9G,aAAa,CACX,yBACA,+EACF;EACA,OAAO,CAAC,iCAAiC,SAAS,uCAAuC;CAC3F;CACA,OACE,oBAAC,UAAD;EACE,GAAI;EACG;EACP,OAAO,UAAU,UAAU,QAAQ,CAAC;EACpC,YAAY,SAAS,MAAM,CAAC;EAC5B,kBAAkB,SAAS,MAAM,CAAC;CACnC,CAAA;AAEL;;AAGA,SAAgB,cAAc,EAC5B,aACA,GAAG,cACyF;CAC5F,qBAAqB;CACrB,MAAM,YAAY,SAAS,kBAAkB,UAAU,MAAM,KAAK,YAAY;CAC9E,MAAM,WAAW,SAAS,kBAAkB,UAAU,MAAM,QAAQ;CACpE,MAAM,QAAQ;EAAE,OAAO;EAAa;CAAY;CAChD,MAAM,cAAc,SAAS,4BAA4B,UAAU,KAAK;CACxE,MAAM,YAAY,oBAAoB,OAAO,WAAW;CACxD,MAAM,QAAQ,mBAAmB,MAAM,KAAA,GAAW,KAAA,GAAW,WAAW;CACxE,MAAM,QAA6B,mBAAmB,KAAK,CAAC,CAAC,SAAS,SAAS;EAC7E,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO,CAAC;EAC1C,MAAM,OAAO,KAAK;EAClB,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,OAAO,CACL;GACE,IAAI,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;GAC3C,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,MAAM,KAAK,QAAQ;GACnB,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,MAAM,cAAc,KAAK,WAAW,KAAK;EAC3C,CACF;CACF,CAAC;CACD,MAAM,QAAQ,CAAC,WACX,YACA,cAAc,KAAA,IACZ,YACA,UAAU,cAAc,QACtB,gBACA,UAAU,UAAU,UAClB,UACA,UAAU,UAAU,UAClB,YACA;CACZ,OACE,oBAAC,eAAD;EACE,GAAI;EACJ,OAAO,WAAW,QAAQ;EACnB;EACP,OAAO,UAAU;EACV;CACR,CAAA;AAEL"}
|
|
1
|
+
{"version":3,"file":"WorkspacePage.mjs","names":[],"sources":["../../../src/web/components/WorkspacePage.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store';\nimport { createElement } from 'react';\n\nimport { webPluginCompositionStore, webPluginMountState } from '../lib/pluginCompositions';\nimport { dashboardTileFills } from '../lib/pluginRegistry';\nimport { usePluginSlotProps } from '../stores/usePluginSlotProps';\nimport { useWebPluginRegistry } from '../stores/useWebPluginRegistry';\nimport { workspacesStore } from '../stores/workspacesStore';\nimport type { DashboardTileView } from './DashboardTileGrid';\nimport { HomeView } from './HomePage';\n\nexport interface WorkspaceViewProps {\n title: string;\n state?: 'ready' | 'loading' | 'missing' | 'unavailable' | 'error';\n error?: string;\n tiles?: readonly DashboardTileView[];\n onShowSessions?: () => void;\n navigationToggle?: 'mobile' | 'always';\n}\n\n/** The same tile surface as Home, with explicit workspace delivery states. */\nexport function WorkspaceView({ title, state = 'ready', error, tiles = [], ...navigation }: WorkspaceViewProps) {\n const messages = {\n ready: ['Nothing in this workspace yet', 'Apps for this workspace will show up here.'],\n loading: ['Loading workspace', 'Your workspace is getting ready.'],\n missing: ['Workspace not found', 'This workspace may have been removed. Choose another from the session list.'],\n unavailable: [\n 'Workspace unavailable',\n 'Po cannot open this workspace right now. Reconnect to its host and try again.',\n ],\n error: ['Workspace apps could not load', error ?? 'Reconnect to this host and try again.'],\n } as const;\n return (\n <HomeView\n {...navigation}\n title={title}\n tiles={state === 'ready' ? tiles : []}\n emptyTitle={messages[state][0]}\n emptyDescription={messages[state][1]}\n />\n );\n}\n\n/** Reads the explicit workspace mount, never the unrelated focused session. The host loads its composition. */\nexport function WorkspacePage({\n workspaceId,\n ...navigation\n}: { workspaceId: string } & Pick<WorkspaceViewProps, 'onShowSessions' | 'navigationToggle'>) {\n useWebPluginRegistry();\n const workspace = useStore(workspacesStore, (state) => state.byId[workspaceId]);\n const hydrated = useStore(workspacesStore, (state) => state.hydrated);\n const mount = { scope: 'workspace', workspaceId } as const;\n const composition = useStore(webPluginCompositionStore, (state) => state);\n const readiness = webPluginMountState(mount, composition);\n const props = usePluginSlotProps(null, undefined, undefined, workspaceId);\n const tiles: DashboardTileView[] = dashboardTileFills(mount).flatMap((fill) => {\n if (fill.component === undefined) return [];\n const data = fill.data;\n const destination = data.open;\n const open = destination?.kind === 'page' ? props.openPage : props.openSettings;\n return [\n {\n id: JSON.stringify([fill.pluginId, fill.id]),\n title: data.title,\n icon: data.icon,\n size: data.size ?? 'small',\n column: data.column,\n ...(destination === undefined || open === undefined ? {} : { onOpen: () => open(destination.id) }),\n body: createElement(fill.component, props),\n },\n ];\n });\n const state = !hydrated\n ? 'loading'\n : workspace === undefined\n ? 'missing'\n : workspace.available === false\n ? 'unavailable'\n : readiness.phase === 'error'\n ? 'error'\n : readiness.phase !== 'ready'\n ? 'loading'\n : 'ready';\n return (\n <WorkspaceView\n {...navigation}\n title={workspace?.name ?? 'Workspace'}\n state={state}\n error={readiness.error}\n tiles={tiles}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAgB,cAAc,EAAE,OAAO,QAAQ,SAAS,OAAO,QAAQ,CAAC,GAAG,GAAG,cAAkC;CAC9G,MAAM,WAAW;EACf,OAAO,CAAC,iCAAiC,4CAA4C;EACrF,SAAS,CAAC,qBAAqB,kCAAkC;EACjE,SAAS,CAAC,uBAAuB,6EAA6E;EAC9G,aAAa,CACX,yBACA,+EACF;EACA,OAAO,CAAC,iCAAiC,SAAS,uCAAuC;CAC3F;CACA,OACE,oBAAC,UAAD;EACE,GAAI;EACG;EACP,OAAO,UAAU,UAAU,QAAQ,CAAC;EACpC,YAAY,SAAS,MAAM,CAAC;EAC5B,kBAAkB,SAAS,MAAM,CAAC;CACnC,CAAA;AAEL;;AAGA,SAAgB,cAAc,EAC5B,aACA,GAAG,cACyF;CAC5F,qBAAqB;CACrB,MAAM,YAAY,SAAS,kBAAkB,UAAU,MAAM,KAAK,YAAY;CAC9E,MAAM,WAAW,SAAS,kBAAkB,UAAU,MAAM,QAAQ;CACpE,MAAM,QAAQ;EAAE,OAAO;EAAa;CAAY;CAChD,MAAM,cAAc,SAAS,4BAA4B,UAAU,KAAK;CACxE,MAAM,YAAY,oBAAoB,OAAO,WAAW;CACxD,MAAM,QAAQ,mBAAmB,MAAM,KAAA,GAAW,KAAA,GAAW,WAAW;CACxE,MAAM,QAA6B,mBAAmB,KAAK,CAAC,CAAC,SAAS,SAAS;EAC7E,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO,CAAC;EAC1C,MAAM,OAAO,KAAK;EAClB,MAAM,cAAc,KAAK;EACzB,MAAM,OAAO,aAAa,SAAS,SAAS,MAAM,WAAW,MAAM;EACnE,OAAO,CACL;GACE,IAAI,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,EAAE,CAAC;GAC3C,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,MAAM,KAAK,QAAQ;GACnB,QAAQ,KAAK;GACb,GAAI,gBAAgB,KAAA,KAAa,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,KAAK,YAAY,EAAE,EAAE;GAChG,MAAM,cAAc,KAAK,WAAW,KAAK;EAC3C,CACF;CACF,CAAC;CACD,MAAM,QAAQ,CAAC,WACX,YACA,cAAc,KAAA,IACZ,YACA,UAAU,cAAc,QACtB,gBACA,UAAU,UAAU,UAClB,UACA,UAAU,UAAU,UAClB,YACA;CACZ,OACE,oBAAC,eAAD;EACE,GAAI;EACJ,OAAO,WAAW,QAAQ;EACnB;EACP,OAAO,UAAU;EACV;CACR,CAAA;AAEL"}
|
|
@@ -16,6 +16,7 @@ function parseDashboardTileData(input) {
|
|
|
16
16
|
"tall",
|
|
17
17
|
"large"
|
|
18
18
|
].includes(data.size)) return null;
|
|
19
|
+
if (data.column !== void 0 && data.column !== "main" && data.column !== "side") return null;
|
|
19
20
|
if (data.icon !== void 0 && typeof data.icon !== "function" && (typeof data.icon !== "object" || data.icon === null)) return null;
|
|
20
21
|
if (data.combinesComputers !== void 0 && typeof data.combinesComputers !== "boolean") return null;
|
|
21
22
|
if (data.surfaces !== void 0 && (!Array.isArray(data.surfaces) || data.surfaces.some((surface) => surface !== "home" && surface !== "workspace"))) return null;
|