@iloveagents/foundry-web-ui 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @iloveagents/foundry-web-ui
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Patch Changes
6
+
7
+ - @iloveagents/foundry-agent@0.3.0
8
+ - @iloveagents/foundry-web-primitives@0.3.0
9
+
3
10
  ## 0.2.2
4
11
 
5
12
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-web-ui",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "type": "module",
6
6
  "types": "./src/index.ts",
@@ -46,8 +46,8 @@
46
46
  "react-markdown": "^10.0.0",
47
47
  "remark-gfm": "^4.0.0",
48
48
  "shiki": "^4.0.0",
49
- "@iloveagents/foundry-agent": "0.2.2",
50
- "@iloveagents/foundry-web-primitives": "0.2.2"
49
+ "@iloveagents/foundry-agent": "0.3.0",
50
+ "@iloveagents/foundry-web-primitives": "0.3.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "typescript": "~5.9.3",
@@ -1407,6 +1407,7 @@ function SidebarContent({ collapsed }: { collapsed: boolean }) {
1407
1407
  const toggle = useSidebarStore((s) => s.toggle);
1408
1408
  const handleNewConversation = useNewConversation();
1409
1409
  const rawNavConfig = useNavStore((s) => s.config);
1410
+ const navLoading = useNavStore((s) => s.navLoading);
1410
1411
  // Sort by `priority` descending so feature hooks can declare slot
1411
1412
  // intent (e.g. "Recents above Tasks") instead of relying on the
1412
1413
  // order in which addGroup() happened to be called. Stable sort: ties
@@ -1420,6 +1421,12 @@ function SidebarContent({ collapsed }: { collapsed: boolean }) {
1420
1421
  .map(({ g }) => g),
1421
1422
  [rawNavConfig],
1422
1423
  );
1424
+ // Show skeleton rows during the cold nav fetch — but only until the
1425
+ // integrator's primary dynamic group ("Workspaces") has been published.
1426
+ // Once it exists, real rows render even if a later phase (status dots) is
1427
+ // still resolving, so the skeleton never flashes over a populated tree.
1428
+ const hasWorkspacesGroup = navConfig.some((group) => group.label === "Workspaces");
1429
+ const showNavSkeleton = navLoading && !hasWorkspacesGroup;
1423
1430
  const currentPage = useAppStore((s) => s.currentPage);
1424
1431
  const navContext = useAppStore((s) => s.navContext);
1425
1432
 
@@ -1546,6 +1553,16 @@ function SidebarContent({ collapsed }: { collapsed: boolean }) {
1546
1553
  {navConfig.map((group) => (
1547
1554
  <NavGroupSection key={group.label} group={group} />
1548
1555
  ))}
1556
+ {showNavSkeleton && (
1557
+ <div className="space-y-1 px-1 pt-2" aria-hidden="true">
1558
+ {Array.from({ length: 6 }).map((_, index) => (
1559
+ <div
1560
+ key={index}
1561
+ className="h-7 mx-1 rounded-lg animate-pulse bg-sidebar-accent/40"
1562
+ />
1563
+ ))}
1564
+ </div>
1565
+ )}
1549
1566
  </nav>
1550
1567
 
1551
1568
  {/* Footer actions — registered by feature modules */}
@@ -24,8 +24,18 @@ export interface NavFooterAction {
24
24
  interface NavStoreState {
25
25
  config: NavGroup[];
26
26
  footerActions: NavFooterAction[];
27
+ /**
28
+ * True while an integrator's nav sync is loading its first batch of
29
+ * groups. Optional/defaulted (starts ``false``) so existing consumers
30
+ * that never set it are unaffected. The sidebar reads it to render
31
+ * skeleton rows instead of an empty list during the cold fetch —
32
+ * avoids the "empty sidebar for N seconds" gap on a slow nav sync.
33
+ */
34
+ navLoading: boolean;
27
35
  /** Replace the entire config */
28
36
  setConfig: (config: NavGroup[]) => void;
37
+ /** Toggle the cold-load skeleton state. */
38
+ setNavLoading: (loading: boolean) => void;
29
39
  /** Add a group (replaces existing group with the same label) */
30
40
  addGroup: (group: NavGroup) => void;
31
41
  /** Remove a group by label */
@@ -39,9 +49,12 @@ interface NavStoreState {
39
49
  export const useNavStore = create<NavStoreState>((set, get) => ({
40
50
  config: DEFAULT_NAV_CONFIG,
41
51
  footerActions: [],
52
+ navLoading: false,
42
53
 
43
54
  setConfig: (config) => set({ config }),
44
55
 
56
+ setNavLoading: (navLoading) => set({ navLoading }),
57
+
45
58
  addGroup: (group) => {
46
59
  const config = get().config;
47
60
  const idx = config.findIndex((g) => g.label === group.label);