@lateralus-ai/shipping-ui 2.0.0-dev.20 → 2.0.0-dev.4

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 (38) hide show
  1. package/dist/components/Entry.d.ts +7 -27
  2. package/dist/components/Tabs.d.ts +5 -5
  3. package/dist/components/index.d.ts +2 -4
  4. package/dist/index.cjs +25 -25
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.esm.js +3374 -3584
  7. package/dist/patterns/Search/ResultRow.d.ts +5 -11
  8. package/dist/patterns/Sidebar/sidebar-styles.d.ts +1 -2
  9. package/dist/primitives/Badge.d.ts +4 -7
  10. package/dist/primitives/index.d.ts +1 -1
  11. package/dist/tailwind-theme.d.ts +0 -4
  12. package/dist/{theme-entry-tLBc6zGT.mjs → theme-entry-BUK3MJUJ.mjs} +4 -8
  13. package/dist/theme-entry-ygTpGaNC.js +1 -0
  14. package/dist/theme.cjs +1 -1
  15. package/dist/theme.esm.js +1 -1
  16. package/package.json +128 -128
  17. package/src/components/Entry.tsx +45 -119
  18. package/src/components/Tabs.tsx +27 -33
  19. package/src/components/index.ts +1 -15
  20. package/src/index.ts +0 -11
  21. package/src/patterns/Search/ResultRow.tsx +38 -24
  22. package/src/patterns/Search/SearchModal.tsx +1 -7
  23. package/src/patterns/Sidebar/CollapsibleNavGroup.tsx +1 -1
  24. package/src/patterns/Sidebar/SidebarAction.tsx +17 -26
  25. package/src/patterns/Sidebar/SidebarEntry.tsx +39 -54
  26. package/src/patterns/Sidebar/SidebarLink.tsx +20 -30
  27. package/src/patterns/Sidebar/sidebar-styles.ts +1 -2
  28. package/src/primitives/Badge.tsx +10 -20
  29. package/src/primitives/Button.tsx +11 -16
  30. package/src/primitives/index.ts +1 -1
  31. package/src/stories/canvases/ContentCanvas.tsx +14 -253
  32. package/src/tailwind-theme.ts +182 -186
  33. package/src/utils/cn.ts +1 -28
  34. package/dist/components/PageHeader.d.ts +0 -41
  35. package/dist/components/ScrollableList.d.ts +0 -22
  36. package/dist/theme-entry-Dwr2mV7_.js +0 -1
  37. package/src/components/PageHeader.tsx +0 -132
  38. package/src/components/ScrollableList.tsx +0 -61
@@ -11,37 +11,26 @@ import { cn } from "../utils/cn";
11
11
 
12
12
  export type TabsType = "tabs" | "pills";
13
13
 
14
- /** Soft = search filters (filled idle, light accent active). Solid = list filters (grey-100 idle, blue-600 active). */
15
- export type TabsAppearance = "soft" | "solid";
16
-
17
14
  type TabsContextValue = {
18
15
  type: TabsType;
19
- appearance: TabsAppearance;
20
16
  };
21
17
 
22
- const TabsContext = createContext<TabsContextValue>({
23
- type: "tabs",
24
- appearance: "soft",
25
- });
18
+ const TabsContext = createContext<TabsContextValue>({ type: "tabs" });
26
19
 
27
20
  export type TabsProps = ComponentPropsWithoutRef<typeof TabsPrimitive.Root> & {
28
21
  type?: TabsType;
29
- /** Only applies when `type="pills"`. Defaults to `soft`. */
30
- appearance?: TabsAppearance;
31
22
  };
32
23
 
33
24
  export const Tabs = ({
34
25
  type = "tabs",
35
- appearance = "soft",
36
26
  className,
37
27
  children,
38
28
  ...props
39
29
  }: TabsProps) => (
40
- <TabsContext.Provider value={{ type, appearance }}>
30
+ <TabsContext.Provider value={{ type }}>
41
31
  <TabsPrimitive.Root
42
32
  className={cn("flex flex-col", className)}
43
33
  data-type={type}
44
- data-appearance={type === "pills" ? appearance : undefined}
45
34
  {...props}
46
35
  >
47
36
  {children}
@@ -62,7 +51,7 @@ export const TabsList = forwardRef<
62
51
  ref={ref}
63
52
  className={cn(
64
53
  "flex items-center",
65
- type === "tabs" && "gap-6 border-b border-divider-primary",
54
+ type === "tabs" && "gap-1 border-b border-divider-primary",
66
55
  type === "pills" && "gap-2",
67
56
  className,
68
57
  )}
@@ -75,48 +64,53 @@ TabsList.displayName = TabsPrimitive.List.displayName;
75
64
  export type TabsTriggerProps = ComponentPropsWithoutRef<
76
65
  typeof TabsPrimitive.Trigger
77
66
  > & {
67
+ /** Optional count badge (pill variant / search filters). */
68
+ count?: number;
78
69
  children: ReactNode;
79
70
  };
80
71
 
81
72
  export const TabsTrigger = forwardRef<
82
73
  ElementRef<typeof TabsPrimitive.Trigger>,
83
74
  TabsTriggerProps
84
- >(({ className, children, ...props }, ref) => {
85
- const { type, appearance } = useContext(TabsContext);
75
+ >(({ className, count, children, ...props }, ref) => {
76
+ const { type } = useContext(TabsContext);
86
77
 
87
78
  return (
88
79
  <TabsPrimitive.Trigger
89
80
  ref={ref}
90
81
  className={cn(
91
- "inline-flex items-center justify-center gap-2.5 transition-colors outline-none",
82
+ "inline-flex items-center justify-center transition-colors outline-none",
92
83
  "disabled:pointer-events-none disabled:opacity-50",
93
84
  type === "tabs" && [
94
- "relative h-12 gap-2 px-0 py-0 text-caption-2 text-display-on-light-secondary",
85
+ "relative px-3 py-2 text-caption-2 text-display-on-light-secondary",
95
86
  "hover:text-display-on-light-primary",
96
87
  "data-[state=active]:text-caption-2-em data-[state=active]:text-display-on-light-primary",
97
88
  "data-[state=active]:after:absolute data-[state=active]:after:inset-x-0 data-[state=active]:after:-bottom-px",
98
89
  "data-[state=active]:after:h-0.5 data-[state=active]:after:rounded-full data-[state=active]:after:bg-grey-900",
99
90
  ],
100
- type === "pills" &&
101
- appearance === "soft" && [
102
- "min-h-9 rounded-full px-3 py-1 text-caption-2-em",
103
- "bg-grey-100 text-display-on-light-secondary",
104
- "hover:bg-grey-200",
105
- "data-[state=active]:bg-accent-bg-light data-[state=active]:text-display-on-light-primary",
106
- ],
107
- type === "pills" &&
108
- appearance === "solid" && [
109
- "min-h-9 rounded-full px-3 py-1 text-caption-2-em",
110
- "bg-grey-100 text-display-on-light-tertiary",
111
- "hover:bg-grey-200 hover:text-display-on-light-primary",
112
- "data-[state=active]:bg-blue-600 data-[state=active]:text-white",
113
- "data-[state=active]:hover:bg-blue-600",
114
- ],
91
+ type === "pills" && [
92
+ "group min-h-9 gap-2.5 rounded-full px-3 py-1 text-caption-2-em",
93
+ "bg-grey-100 text-display-on-light-secondary",
94
+ "hover:bg-grey-200",
95
+ "data-[state=active]:bg-accent-bg-light data-[state=active]:text-display-on-light-primary",
96
+ ],
115
97
  className,
116
98
  )}
117
99
  {...props}
118
100
  >
119
101
  {children}
102
+ {typeof count === "number" && (
103
+ <span
104
+ className={cn(
105
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-full text-footnote-em",
106
+ "bg-accent-bg-light text-display-on-light-secondary",
107
+ "group-data-[state=active]:text-display-on-light-tertiary",
108
+ )}
109
+ aria-label={`Count: ${count}`}
110
+ >
111
+ {count > 99 ? "99+" : count}
112
+ </span>
113
+ )}
120
114
  </TabsPrimitive.Trigger>
121
115
  );
122
116
  });
@@ -15,23 +15,9 @@ export {
15
15
  type TabsContentProps,
16
16
  type TabsItem,
17
17
  type TabsType,
18
- type TabsAppearance,
19
18
  } from "./Tabs";
20
19
  export { Header, type HeaderProps, type HeaderVariant } from "./Header";
21
- export {
22
- PageHeader,
23
- type PageHeaderProps,
24
- type PageHeaderCrumb,
25
- type PageHeaderShellProps,
26
- type PageHeaderBodyProps,
27
- } from "./PageHeader";
28
- export {
29
- ScrollableList,
30
- type ScrollableListProps,
31
- type ScrollableListHeaderProps,
32
- type ScrollableListBodyProps,
33
- } from "./ScrollableList";
34
- export { Entry, type EntryProps, type EntryType, type EntryState, type EntryVariant } from "./Entry";
20
+ export { Entry, type EntryProps, type EntryType, type EntryState } from "./Entry";
35
21
  export { EmptyState, type EmptyStateProps } from "./EmptyState";
36
22
  export {
37
23
  Modal,
package/src/index.ts CHANGED
@@ -19,7 +19,6 @@ export {
19
19
  TabsTrigger,
20
20
  TabsContent,
21
21
  Header,
22
- PageHeader,
23
22
  Entry,
24
23
  EmptyState,
25
24
  Modal,
@@ -36,7 +35,6 @@ export {
36
35
  PdfViewer,
37
36
  ImageViewer,
38
37
  DocumentEditor,
39
- ScrollableList,
40
38
  } from "./components";
41
39
 
42
40
  export type {
@@ -58,20 +56,11 @@ export type {
58
56
  TabsContentProps,
59
57
  TabsItem,
60
58
  TabsType,
61
- TabsAppearance,
62
59
  HeaderProps,
63
60
  HeaderVariant,
64
- PageHeaderProps,
65
- PageHeaderCrumb,
66
- PageHeaderShellProps,
67
- PageHeaderBodyProps,
68
- ScrollableListProps,
69
- ScrollableListHeaderProps,
70
- ScrollableListBodyProps,
71
61
  EntryProps,
72
62
  EntryType,
73
63
  EntryState,
74
- EntryVariant,
75
64
  EmptyStateProps,
76
65
  ModalProps,
77
66
  ModalOverlayProps,
@@ -1,28 +1,26 @@
1
1
  import { type ReactNode } from "react";
2
- import {
3
- Entry,
4
- type EntryProps,
5
- type EntryState,
6
- type EntryVariant,
7
- } from "../../components/Entry";
2
+ import { ChatIcon, IssuesIcon, ReportIcon } from "../../icons";
3
+ import { cn } from "../../utils/cn";
8
4
 
9
- /** @deprecated Prefer `EntryVariant`. */
10
- export type ResultRowVariant = EntryVariant;
11
- /** @deprecated Prefer `EntryState`. */
12
- export type ResultRowState = EntryState;
5
+ export type ResultRowVariant = "report" | "chat" | "issue";
6
+ export type ResultRowState = "idle" | "active";
13
7
 
14
8
  export type ResultRowProps = {
15
- variant?: EntryVariant;
16
- state?: EntryState;
9
+ variant?: ResultRowVariant;
10
+ state?: ResultRowState;
17
11
  title?: ReactNode;
12
+ /** Secondary line — excerpt, metadata, or highlighted query match. */
18
13
  subtitle?: ReactNode;
19
14
  onClick?: () => void;
20
15
  className?: string;
21
16
  };
22
17
 
23
- /**
24
- * @deprecated Prefer `Entry` — ResultRow is a thin alias for search lists.
25
- */
18
+ const variantIcons: Record<ResultRowVariant, ReactNode> = {
19
+ report: <ReportIcon className="size-4" />,
20
+ chat: <ChatIcon className="size-4" />,
21
+ issue: <IssuesIcon className="size-4" />,
22
+ };
23
+
26
24
  export const ResultRow = ({
27
25
  variant = "report",
28
26
  state = "idle",
@@ -31,14 +29,30 @@ export const ResultRow = ({
31
29
  onClick,
32
30
  className,
33
31
  }: ResultRowProps) => (
34
- <Entry
35
- variant={variant}
36
- state={state}
37
- title={title}
38
- subtitle={subtitle}
32
+ <button
33
+ type="button"
34
+ className={cn(
35
+ "flex w-full items-center gap-4 rounded-control px-3 py-2.5 text-left transition-colors",
36
+ "hover:bg-[rgba(38,36,32,0.04)]",
37
+ state === "active" && "bg-[rgba(38,36,32,0.04)]",
38
+ className,
39
+ )}
40
+ data-variant={variant}
41
+ data-state={state}
39
42
  onClick={onClick}
40
- className={className}
41
- />
43
+ >
44
+ <span className="shrink-0 text-display-on-light-secondary">
45
+ {variantIcons[variant]}
46
+ </span>
47
+ <span className="min-w-0 flex-1">
48
+ <span className="block truncate text-caption-1-em text-display-on-light-primary">
49
+ {title}
50
+ </span>
51
+ {subtitle != null && subtitle !== false && (
52
+ <span className="mt-0.5 block truncate text-caption-2 text-display-on-light-secondary">
53
+ {subtitle}
54
+ </span>
55
+ )}
56
+ </span>
57
+ </button>
42
58
  );
43
-
44
- export type { EntryProps };
@@ -13,7 +13,6 @@ import {
13
13
  type ModalProps,
14
14
  } from "../../components/Modal";
15
15
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/Tabs";
16
- import { Badge } from "../../primitives/Badge";
17
16
  import { cn } from "../../utils/cn";
18
17
  import { ResultRow, type ResultRowProps } from "./ResultRow";
19
18
  import { SectionHeader } from "./SectionHeader";
@@ -177,13 +176,8 @@ export const SearchModalFilters = ({
177
176
  )}
178
177
  >
179
178
  {tabs.map((tab) => (
180
- <TabsTrigger key={tab.value} value={tab.value}>
179
+ <TabsTrigger key={tab.value} value={tab.value} count={tab.count}>
181
180
  {tab.label}
182
- {typeof tab.count === "number" && (
183
- <Badge color="blue">
184
- {tab.count > 99 ? "99+" : tab.count}
185
- </Badge>
186
- )}
187
181
  </TabsTrigger>
188
182
  ))}
189
183
  </TabsList>
@@ -45,6 +45,7 @@ export const CollapsibleNavGroup = ({
45
45
  href={href}
46
46
  label={label}
47
47
  icon={icon}
48
+ tall
48
49
  onNavigate={onNavigate}
49
50
  trailing={
50
51
  <IconButton
@@ -92,7 +93,6 @@ export const CollapsibleNavGroup = ({
92
93
  ) : undefined
93
94
  }
94
95
  menuItems={entryMenuItems}
95
- onNavigate={onNavigate}
96
96
  />
97
97
  ))}
98
98
  </div>
@@ -1,14 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { Tooltip } from "../../primitives";
3
3
  import { cn } from "../../utils/cn";
4
- import {
5
- sidebarLinkActive,
6
- sidebarLinkIdle,
7
- sidebarRowInteractiveHover,
8
- sidebarSectionIconClass,
9
- sidebarSectionShell,
10
- sidebarSectionShellCollapsed,
11
- } from "./sidebar-styles";
4
+ import { sidebarLinkActive, sidebarLinkIdle, sidebarRowClass, sidebarRowInteractiveHover, sidebarSectionAnchorClass } from "./sidebar-styles";
12
5
 
13
6
  export type SidebarActionProps = {
14
7
  label: string;
@@ -30,28 +23,26 @@ export const SidebarAction = ({
30
23
  className,
31
24
  }: SidebarActionProps) => {
32
25
  const row = (
33
- <button
34
- type="button"
35
- onClick={onClick}
36
- aria-label={label}
37
- className={cn(
38
- collapsed ? sidebarSectionShellCollapsed : sidebarSectionShell,
39
- "cursor-pointer text-left",
40
- active ? sidebarLinkActive : sidebarLinkIdle,
41
- !active && sidebarRowInteractiveHover,
42
- !collapsed && "gap-2",
43
- className,
26
+ <div
27
+ className={sidebarRowClass(
28
+ cn(
29
+ active ? sidebarLinkActive : sidebarLinkIdle,
30
+ !active && sidebarRowInteractiveHover,
31
+ className,
32
+ ),
44
33
  )}
45
34
  data-active={active}
46
35
  data-collapsed={collapsed}
47
36
  >
48
- {icon && <span className={sidebarSectionIconClass}>{icon}</span>}
49
- {!collapsed && (
50
- <span className="min-w-0 flex-1 truncate text-caption-2 tracking-[0.01em]">
51
- {label}
52
- </span>
53
- )}
54
- </button>
37
+ <button
38
+ type="button"
39
+ className={sidebarSectionAnchorClass(collapsed ? "justify-center" : undefined)}
40
+ onClick={onClick}
41
+ >
42
+ {icon && <span className="shrink-0 [&>svg]:size-5">{icon}</span>}
43
+ {!collapsed && <span className="truncate">{label}</span>}
44
+ </button>
45
+ </div>
55
46
  );
56
47
 
57
48
  if (!collapsed || !tooltip) return row;
@@ -3,6 +3,7 @@ import { DropdownMenu, DropdownMenuItem, IconButton } from "../../primitives";
3
3
  import { MoreIcon } from "../../icons";
4
4
  import { cn } from "../../utils/cn";
5
5
  import {
6
+ sidebarAnchorClass,
6
7
  sidebarEntryHover,
7
8
  sidebarEntryIdle,
8
9
  sidebarEntrySelected,
@@ -65,74 +66,58 @@ export const SidebarEntry = ({
65
66
  )}
66
67
  data-state={state}
67
68
  >
68
- {/* Stretch hit target over shell padding (hover was on the shell, link was content-only). */}
69
69
  <a
70
70
  href={href}
71
- className="absolute inset-0 z-0 rounded-control"
72
- aria-label={label}
71
+ className={sidebarAnchorClass("gap-1")}
73
72
  aria-current={state === "selected" ? "true" : undefined}
74
73
  onClick={onNavigate}
75
- />
76
-
77
- <div className="pointer-events-none relative z-10 flex min-w-0 flex-1 items-center gap-2 text-caption-2">
78
- {icon && <span className="shrink-0 [&>svg]:size-4">{icon}</span>}
74
+ >
75
+ {icon && <span className="shrink-0 px-1 py-0.5 [&>svg]:size-4">{icon}</span>}
79
76
  <span className="truncate">{label}</span>
80
- </div>
77
+ </a>
81
78
 
82
79
  {badge && !(showMenu && menuVisible) && (
83
80
  <span
84
- className={cn(
85
- "pointer-events-none relative z-10 shrink-0",
86
- showMenu && !forceMenuVisible && "group-hover/row:hidden",
87
- )}
81
+ className={cn("shrink-0", showMenu && !forceMenuVisible && "group-hover/row:hidden")}
88
82
  >
89
83
  {badge}
90
84
  </span>
91
85
  )}
92
86
 
93
87
  {showMenu && (
94
- <div className="relative z-10 shrink-0">
95
- <DropdownMenu
96
- open={menuOpen}
97
- onOpenChange={setMenuOpen}
98
- align="end"
99
- trigger={
100
- <IconButton
101
- hierarchy="quaternary"
102
- size="small"
103
- aria-label={`Actions for ${label}`}
104
- aria-haspopup="menu"
105
- aria-expanded={menuOpen}
106
- className={cn(
107
- "size-6 min-h-6 shrink-0 p-1",
108
- sidebarQuaternaryIconButton,
109
- !forceMenuVisible &&
110
- !menuOpen &&
111
- "hidden group-hover/row:inline-flex",
112
- (forceMenuVisible || menuOpen) && "inline-flex",
113
- )}
114
- >
115
- <MoreIcon size="small" />
116
- </IconButton>
117
- }
118
- >
119
- {menuItems?.map((item) => (
120
- <DropdownMenuItem
121
- key={item.id}
122
- className={cn(
123
- item.destructive &&
124
- "text-red-500 hover:bg-red-50 hover:text-red-700",
125
- )}
126
- onSelect={() => item.onSelect()}
127
- >
128
- {item.icon && (
129
- <span className="shrink-0 [&>svg]:size-4">{item.icon}</span>
130
- )}
131
- {item.label}
132
- </DropdownMenuItem>
133
- ))}
134
- </DropdownMenu>
135
- </div>
88
+ <DropdownMenu
89
+ open={menuOpen}
90
+ onOpenChange={setMenuOpen}
91
+ align="end"
92
+ trigger={
93
+ <IconButton
94
+ hierarchy="quaternary"
95
+ size="small"
96
+ aria-label={`Actions for ${label}`}
97
+ aria-haspopup="menu"
98
+ aria-expanded={menuOpen}
99
+ className={cn(
100
+ "size-6 min-h-6 shrink-0 p-1",
101
+ sidebarQuaternaryIconButton,
102
+ !forceMenuVisible && !menuOpen && "hidden group-hover/row:inline-flex",
103
+ (forceMenuVisible || menuOpen) && "inline-flex",
104
+ )}
105
+ >
106
+ <MoreIcon size="small" />
107
+ </IconButton>
108
+ }
109
+ >
110
+ {menuItems?.map((item) => (
111
+ <DropdownMenuItem
112
+ key={item.id}
113
+ className={cn(item.destructive && "text-red-500 hover:bg-red-50 hover:text-red-700")}
114
+ onSelect={() => item.onSelect()}
115
+ >
116
+ {item.icon && <span className="shrink-0 [&>svg]:size-4">{item.icon}</span>}
117
+ {item.label}
118
+ </DropdownMenuItem>
119
+ ))}
120
+ </DropdownMenu>
136
121
  )}
137
122
  </div>
138
123
  );
@@ -58,7 +58,6 @@ export const SidebarLink = ({
58
58
  const row = collapsed ? (
59
59
  <div
60
60
  className={cn(
61
- "relative",
62
61
  sidebarSectionShellCollapsed,
63
62
  stateStyles[state],
64
63
  state === "idle" && sidebarRowInteractiveHover,
@@ -69,24 +68,24 @@ export const SidebarLink = ({
69
68
  >
70
69
  <a
71
70
  href={href}
72
- className="absolute inset-0 z-0 rounded-control"
71
+ className="flex w-full items-center justify-center"
73
72
  aria-current={state === "active" ? "page" : undefined}
74
73
  aria-label={label}
75
74
  onClick={onNavigate}
76
- />
77
- <span className="pointer-events-none relative z-10 inline-flex shrink-0 items-center">
78
- {icon && <span className={sidebarSectionIconClass}>{icon}</span>}
79
- {unread && (
80
- <span aria-hidden className={sidebarUnreadOverlay}>
81
- <span className={sidebarUnreadDot} />
82
- </span>
83
- )}
84
- </span>
75
+ >
76
+ <span className="relative inline-flex shrink-0 items-center">
77
+ {icon && <span className={sidebarSectionIconClass}>{icon}</span>}
78
+ {unread && (
79
+ <span aria-hidden className={sidebarUnreadOverlay}>
80
+ <span className={sidebarUnreadDot} />
81
+ </span>
82
+ )}
83
+ </span>
84
+ </a>
85
85
  </div>
86
86
  ) : (
87
87
  <div
88
88
  className={cn(
89
- "relative",
90
89
  tall ? sidebarSectionShellTall : sidebarSectionShell,
91
90
  stateStyles[state],
92
91
  state === "idle" && sidebarRowInteractiveHover,
@@ -95,27 +94,18 @@ export const SidebarLink = ({
95
94
  data-state={state}
96
95
  data-collapsed={collapsed}
97
96
  >
98
- <a
99
- href={href}
100
- className="absolute inset-0 z-0 rounded-control"
101
- aria-current={state === "active" ? "page" : undefined}
102
- aria-label={label}
103
- onClick={onNavigate}
104
- />
105
- <div
106
- className={cn(
107
- sidebarSectionContent,
108
- "pointer-events-none relative z-10",
109
- )}
110
- >
111
- <span className="flex min-w-0 flex-1 items-center gap-2 truncate text-left">
97
+ <div className={sidebarSectionContent}>
98
+ <a
99
+ href={href}
100
+ className="flex min-w-0 flex-1 items-center gap-2 truncate text-left"
101
+ aria-current={state === "active" ? "page" : undefined}
102
+ onClick={onNavigate}
103
+ >
112
104
  {icon && <span className={sidebarSectionIconClass}>{icon}</span>}
113
105
  <span className={sidebarSectionLabelClass}>{label}</span>
114
106
  {badge}
115
- </span>
116
- {trailing != null && (
117
- <span className="pointer-events-auto shrink-0">{trailing}</span>
118
- )}
107
+ </a>
108
+ {trailing}
119
109
  </div>
120
110
  </div>
121
111
  );
@@ -30,8 +30,7 @@ export const sidebarUnreadOverlay =
30
30
  export const sidebarUnreadDot =
31
31
  "absolute right-0 top-0 size-1.5 rounded-full bg-[#802c20]";
32
32
 
33
- /** Icon + label row inside a section shell — no extra inset (shell already has p-2). */
34
- export const sidebarSectionContent = "flex w-full min-w-0 items-center gap-2";
33
+ export const sidebarSectionContent = "flex w-full min-w-0 items-center gap-2 pl-1";
35
34
 
36
35
  export const sidebarSectionIconClass = "shrink-0 [&>svg]:size-4";
37
36
 
@@ -1,40 +1,30 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { cn } from "../utils/cn";
3
3
 
4
- export type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
5
- export type BadgeType = "label" | "icon";
4
+ type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
5
+ type BadgeType = "label" | "icon";
6
6
 
7
7
  export type BadgeProps = {
8
8
  color: BadgeColor;
9
- /** `label` grows with content (pill). `icon` is a compact circle for a glyph/digit. */
10
9
  type?: BadgeType;
11
10
  children: ReactNode;
12
11
  className?: string;
13
12
  };
14
13
 
15
14
  const colorStyles: Record<BadgeColor, string> = {
16
- blue: "bg-meta-blue text-meta-onBlue",
17
- green: "bg-meta-green text-meta-onGreen",
18
- red: "bg-meta-red text-meta-onRed",
19
- orange: "bg-meta-orange text-meta-onOrange",
20
- purple: "bg-meta-purple text-meta-onPurple",
15
+ blue: "bg-meta-blue text-meta-on-blue",
16
+ green: "bg-meta-green text-meta-on-green",
17
+ red: "bg-meta-red text-meta-on-red",
18
+ orange: "bg-meta-orange text-meta-on-orange",
19
+ purple: "bg-meta-purple text-meta-on-purple",
21
20
  grey: "bg-grey-100 text-display-on-light-secondary",
22
21
  };
23
22
 
24
- /**
25
- * Figma Badge (4365:74363) — padding + rounded-full; no fixed width on labels.
26
- */
27
- export const Badge = ({
28
- color,
29
- type = "label",
30
- children,
31
- className,
32
- }: BadgeProps) => (
23
+ export const Badge = ({ color, type = "label", children, className }: BadgeProps) => (
33
24
  <span
34
25
  className={cn(
35
- "inline-flex shrink-0 items-center justify-center text-footnote-em leading-none",
36
- type === "label" && "rounded-full px-1.5 py-0.5",
37
- type === "icon" && "size-5 rounded-full [&>svg]:size-3",
26
+ "inline-flex shrink-0 items-center justify-center text-footnote-em",
27
+ type === "label" ? "rounded-control px-2 py-0.5" : "size-6 rounded-full",
38
28
  colorStyles[color],
39
29
  className,
40
30
  )}