@almadar/ui 4.22.4 → 4.24.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.
@@ -4,7 +4,7 @@ import * as React110 from 'react';
4
4
  import React110__default, { useContext, useMemo, useRef, useEffect, useCallback, createContext, useState, Suspense, lazy, useSyncExternalStore, useLayoutEffect, useId } from 'react';
5
5
  import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
6
6
  import * as LucideIcons from 'lucide-react';
7
- import { Loader2, X, AlertTriangle, Info, AlertCircle, CheckCircle, ChevronDown, List, Printer, ChevronRight, ChevronLeft, XCircle, Wrench, RotateCcw, Send, Code, FileText, WrapText, Check, Copy, Zap, Sword, Move, Heart, Shield, Trash2, Settings, Menu as Menu$1, Search, Bell, LogOut, ChevronUp, MoreHorizontal, Bug, ZoomOut, ZoomIn, Download, Pause, Play, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ArrowRight, ArrowLeft, Eraser, SkipForward, TrendingUp, TrendingDown, Minus, ArrowUp, ArrowDown, MoreVertical, Circle, Clock, CheckCircle2, HelpCircle, FileQuestion, Inbox, Plus, User, Filter, Star, FileWarning, Tag, DollarSign, Sun, Moon } from 'lucide-react';
7
+ import { Loader2, X, AlertTriangle, Info, AlertCircle, CheckCircle, ChevronDown, List, Printer, ChevronRight, ChevronLeft, XCircle, Wrench, RotateCcw, Send, Code, FileText, WrapText, Check, Copy, Zap, Sword, Move, Heart, Shield, Trash2, Menu as Menu$1, Search, Bell, LogOut, ChevronUp, MoreHorizontal, Bug, ZoomOut, ZoomIn, Download, Pause, Play, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ArrowRight, ArrowLeft, Eraser, SkipForward, TrendingUp, TrendingDown, Minus, ArrowUp, ArrowDown, MoreVertical, Circle, Clock, CheckCircle2, HelpCircle, FileQuestion, Inbox, Plus, User, Filter, Star, FileWarning, Tag, DollarSign, Sun, Moon } from 'lucide-react';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
9
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
10
10
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
@@ -16996,6 +16996,7 @@ var init_DashboardLayout = __esm({
16996
16996
  init_Typography();
16997
16997
  init_Icon();
16998
16998
  init_useAuthContext();
16999
+ init_useEventBus();
16999
17000
  init_useTranslate();
17000
17001
  DashboardLayout = ({
17001
17002
  appName = "{{APP_TITLE}}",
@@ -17003,11 +17004,29 @@ var init_DashboardLayout = __esm({
17003
17004
  navItems = [],
17004
17005
  user: userProp,
17005
17006
  headerActions,
17006
- showSearch = true,
17007
+ showSearch = false,
17008
+ searchEvent,
17009
+ onSearchSubmit,
17010
+ notifications,
17011
+ notificationClickEvent,
17012
+ onNotificationClick,
17013
+ showThemeToggle = true,
17007
17014
  sidebarFooter,
17008
17015
  onSignOut: onSignOutProp,
17009
17016
  children
17010
17017
  }) => {
17018
+ const eventBus = useEventBus();
17019
+ const searchEnabled = showSearch || Boolean(searchEvent) || Boolean(onSearchSubmit);
17020
+ const notificationsEnabled = Array.isArray(notifications);
17021
+ const unreadCount = notificationsEnabled ? notifications.filter((n) => n.read !== true).length : 0;
17022
+ const handleSearchSubmit = (value) => {
17023
+ if (searchEvent) eventBus.emit(`UI:${searchEvent}`, { value });
17024
+ if (onSearchSubmit) onSearchSubmit(value);
17025
+ };
17026
+ const handleNotificationClick = () => {
17027
+ if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
17028
+ if (onNotificationClick) onNotificationClick();
17029
+ };
17011
17030
  const [sidebarOpen, setSidebarOpen] = useState(false);
17012
17031
  const [userMenuOpen, setUserMenuOpen] = useState(false);
17013
17032
  const location = useLocation();
@@ -17092,17 +17111,7 @@ var init_DashboardLayout = __esm({
17092
17111
  ))
17093
17112
  }
17094
17113
  ),
17095
- sidebarFooter || /* @__PURE__ */ jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: /* @__PURE__ */ jsxs(
17096
- Link,
17097
- {
17098
- to: "/settings",
17099
- className: "flex items-center gap-3 px-3 py-2 text-sm text-muted-foreground dark:text-muted-foreground rounded-lg hover:bg-muted dark:hover:bg-muted",
17100
- children: [
17101
- /* @__PURE__ */ jsx(Settings, { className: "h-5 w-5" }),
17102
- t("common.settings")
17103
- ]
17104
- }
17105
- ) })
17114
+ sidebarFooter && /* @__PURE__ */ jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: sidebarFooter })
17106
17115
  ]
17107
17116
  }
17108
17117
  ),
@@ -17129,32 +17138,40 @@ var init_DashboardLayout = __esm({
17129
17138
  children: /* @__PURE__ */ jsx(Menu$1, { className: "h-5 w-5" })
17130
17139
  }
17131
17140
  ),
17132
- showSearch && /* @__PURE__ */ jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
17141
+ searchEnabled && /* @__PURE__ */ jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
17133
17142
  /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground dark:text-muted-foreground" }),
17134
17143
  /* @__PURE__ */ jsx(
17135
17144
  Input,
17136
17145
  {
17137
17146
  type: "search",
17138
17147
  placeholder: t("common.search"),
17139
- className: "pl-10 w-full"
17148
+ className: "pl-10 w-full",
17149
+ onKeyDown: (e) => {
17150
+ if (e.key === "Enter") {
17151
+ handleSearchSubmit(e.target.value);
17152
+ }
17153
+ }
17140
17154
  }
17141
17155
  )
17142
17156
  ] }) }),
17143
17157
  /* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
17144
17158
  headerActions,
17145
- /* @__PURE__ */ jsx(ThemeToggle, {}),
17146
- /* @__PURE__ */ jsxs(
17159
+ showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
17160
+ notificationsEnabled && /* @__PURE__ */ jsxs(
17147
17161
  Button,
17148
17162
  {
17149
17163
  variant: "ghost",
17150
17164
  className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
17165
+ onClick: handleNotificationClick,
17166
+ "aria-label": t("common.notifications"),
17151
17167
  children: [
17152
17168
  /* @__PURE__ */ jsx(Bell, { className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
17153
- /* @__PURE__ */ jsx(
17169
+ unreadCount > 0 && /* @__PURE__ */ jsx(
17154
17170
  Box,
17155
17171
  {
17156
17172
  as: "span",
17157
- className: "absolute top-1 right-1 w-2 h-2 bg-error rounded-full"
17173
+ className: "absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 bg-error rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
17174
+ children: unreadCount > 99 ? "99+" : unreadCount
17158
17175
  }
17159
17176
  )
17160
17177
  ]
@@ -17219,17 +17236,6 @@ var init_DashboardLayout = __esm({
17219
17236
  }
17220
17237
  )
17221
17238
  ] }),
17222
- /* @__PURE__ */ jsxs(
17223
- Link,
17224
- {
17225
- to: "/settings",
17226
- className: "flex items-center gap-2 px-4 py-2 text-sm text-foreground dark:text-foreground hover:bg-muted dark:hover:bg-muted",
17227
- children: [
17228
- /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
17229
- t("common.settings")
17230
- ]
17231
- }
17232
- ),
17233
17239
  /* @__PURE__ */ jsxs(
17234
17240
  Button,
17235
17241
  {
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { LucideIcon } from "lucide-react";
3
+ import type { EventEmit } from "@almadar/core";
3
4
  export interface NavItem {
4
5
  label: string;
5
6
  href: string;
@@ -8,12 +9,24 @@ export interface NavItem {
8
9
  badge?: string | number;
9
10
  children?: NavItem[];
10
11
  }
12
+ export interface NotificationItem {
13
+ id: string;
14
+ /** Short label shown in the dropdown row. */
15
+ message: string;
16
+ /** Optional secondary text. */
17
+ description?: string;
18
+ /** Optional ISO timestamp string. */
19
+ createdAt?: string;
20
+ /** Optional flag — bell badge counts items where read !== true. */
21
+ read?: boolean;
22
+ }
11
23
  export interface DashboardLayoutProps {
12
24
  /** App name shown in sidebar */
13
25
  appName?: string;
14
26
  /** Logo component or URL */
15
27
  logo?: React.ReactNode;
16
- /** Navigation items */
28
+ /** Navigation items. Apps that need a Settings page should add it
29
+ * as a navItems entry, not depend on baked-in chrome. */
17
30
  navItems?: NavItem[];
18
31
  /** Current user info (optional - auto-populated from auth context if not provided) */
19
32
  user?: {
@@ -21,11 +34,34 @@ export interface DashboardLayoutProps {
21
34
  email: string;
22
35
  avatar?: string;
23
36
  };
24
- /** Header actions (notifications, etc.) */
37
+ /** Header actions (extra slots beyond bell/search/theme). */
25
38
  headerActions?: React.ReactNode;
26
- /** Show search in header */
39
+ /** Show the top-bar search box. Default `false` — opt in by setting
40
+ * `searchEvent` (any truthy value implies showSearch) or this flag. */
27
41
  showSearch?: boolean;
28
- /** Custom sidebar footer */
42
+ /** Declarative search event — fires `UI:{searchEvent}` on the bus
43
+ * when the user submits the search box (Enter key). Setting this
44
+ * implies `showSearch=true`. Use `onSearchSubmit` for direct React
45
+ * usage instead. */
46
+ searchEvent?: EventEmit<{
47
+ value: string;
48
+ }>;
49
+ /** React-side search submit callback. Used when the host wires the
50
+ * layout directly (not via render-ui pattern resolution). */
51
+ onSearchSubmit?: (value: string) => void;
52
+ /** Notification list. Pass an empty array to show the bell with no
53
+ * badge; omit / pass null to hide the bell entirely. */
54
+ notifications?: NotificationItem[] | null;
55
+ /** Declarative bell click event — fires `UI:{notificationClickEvent}`
56
+ * on the bus with an empty payload when the user clicks the bell. */
57
+ notificationClickEvent?: EventEmit<Record<string, never>>;
58
+ /** React-side bell click callback. */
59
+ onNotificationClick?: () => void;
60
+ /** Show the theme toggle button in the header. Default `true` —
61
+ * universally useful for a11y / dark mode. */
62
+ showThemeToggle?: boolean;
63
+ /** Custom sidebar footer (optional). When omitted, the sidebar has
64
+ * no footer — apps that need Settings/etc. add them via navItems. */
29
65
  sidebarFooter?: React.ReactNode;
30
66
  /** Callback when user clicks sign out (optional - uses auth context signOut if not provided) */
31
67
  onSignOut?: () => void;
@@ -18368,6 +18368,7 @@ var init_DashboardLayout = __esm({
18368
18368
  init_Typography();
18369
18369
  init_Icon();
18370
18370
  init_useAuthContext();
18371
+ init_useEventBus();
18371
18372
  init_useTranslate();
18372
18373
  DashboardLayout = ({
18373
18374
  appName = "{{APP_TITLE}}",
@@ -18375,11 +18376,29 @@ var init_DashboardLayout = __esm({
18375
18376
  navItems = [],
18376
18377
  user: userProp,
18377
18378
  headerActions,
18378
- showSearch = true,
18379
+ showSearch = false,
18380
+ searchEvent,
18381
+ onSearchSubmit,
18382
+ notifications,
18383
+ notificationClickEvent,
18384
+ onNotificationClick,
18385
+ showThemeToggle = true,
18379
18386
  sidebarFooter,
18380
18387
  onSignOut: onSignOutProp,
18381
18388
  children
18382
18389
  }) => {
18390
+ const eventBus = useEventBus();
18391
+ const searchEnabled = showSearch || Boolean(searchEvent) || Boolean(onSearchSubmit);
18392
+ const notificationsEnabled = Array.isArray(notifications);
18393
+ const unreadCount = notificationsEnabled ? notifications.filter((n) => n.read !== true).length : 0;
18394
+ const handleSearchSubmit = (value) => {
18395
+ if (searchEvent) eventBus.emit(`UI:${searchEvent}`, { value });
18396
+ if (onSearchSubmit) onSearchSubmit(value);
18397
+ };
18398
+ const handleNotificationClick = () => {
18399
+ if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
18400
+ if (onNotificationClick) onNotificationClick();
18401
+ };
18383
18402
  const [sidebarOpen, setSidebarOpen] = React115.useState(false);
18384
18403
  const [userMenuOpen, setUserMenuOpen] = React115.useState(false);
18385
18404
  const location = reactRouterDom.useLocation();
@@ -18460,17 +18479,7 @@ var init_DashboardLayout = __esm({
18460
18479
  ))
18461
18480
  }
18462
18481
  ),
18463
- sidebarFooter || /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(
18464
- reactRouterDom.Link,
18465
- {
18466
- to: "/settings",
18467
- className: "flex items-center gap-3 px-3 py-2 text-sm text-muted-foreground dark:text-muted-foreground rounded-lg hover:bg-muted dark:hover:bg-muted",
18468
- children: [
18469
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Settings, { className: "h-5 w-5" }),
18470
- t("common.settings")
18471
- ]
18472
- }
18473
- ) })
18482
+ sidebarFooter && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: sidebarFooter })
18474
18483
  ]
18475
18484
  }
18476
18485
  ),
@@ -18497,32 +18506,40 @@ var init_DashboardLayout = __esm({
18497
18506
  children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Menu, { className: "h-5 w-5" })
18498
18507
  }
18499
18508
  ),
18500
- showSearch && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
18509
+ searchEnabled && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
18501
18510
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground dark:text-muted-foreground" }),
18502
18511
  /* @__PURE__ */ jsxRuntime.jsx(
18503
18512
  Input,
18504
18513
  {
18505
18514
  type: "search",
18506
18515
  placeholder: t("common.search"),
18507
- className: "pl-10 w-full"
18516
+ className: "pl-10 w-full",
18517
+ onKeyDown: (e) => {
18518
+ if (e.key === "Enter") {
18519
+ handleSearchSubmit(e.target.value);
18520
+ }
18521
+ }
18508
18522
  }
18509
18523
  )
18510
18524
  ] }) }),
18511
18525
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "xs", children: [
18512
18526
  headerActions,
18513
- /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, {}),
18514
- /* @__PURE__ */ jsxRuntime.jsxs(
18527
+ showThemeToggle && /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, {}),
18528
+ notificationsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
18515
18529
  Button,
18516
18530
  {
18517
18531
  variant: "ghost",
18518
18532
  className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
18533
+ onClick: handleNotificationClick,
18534
+ "aria-label": t("common.notifications"),
18519
18535
  children: [
18520
18536
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Bell, { className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
18521
- /* @__PURE__ */ jsxRuntime.jsx(
18537
+ unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
18522
18538
  Box,
18523
18539
  {
18524
18540
  as: "span",
18525
- className: "absolute top-1 right-1 w-2 h-2 bg-error rounded-full"
18541
+ className: "absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 bg-error rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
18542
+ children: unreadCount > 99 ? "99+" : unreadCount
18526
18543
  }
18527
18544
  )
18528
18545
  ]
@@ -18587,17 +18604,6 @@ var init_DashboardLayout = __esm({
18587
18604
  }
18588
18605
  )
18589
18606
  ] }),
18590
- /* @__PURE__ */ jsxRuntime.jsxs(
18591
- reactRouterDom.Link,
18592
- {
18593
- to: "/settings",
18594
- className: "flex items-center gap-2 px-4 py-2 text-sm text-foreground dark:text-foreground hover:bg-muted dark:hover:bg-muted",
18595
- children: [
18596
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Settings, { className: "h-4 w-4" }),
18597
- t("common.settings")
18598
- ]
18599
- }
18600
- ),
18601
18607
  /* @__PURE__ */ jsxRuntime.jsxs(
18602
18608
  Button,
18603
18609
  {
@@ -5,7 +5,7 @@ import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import * as LucideIcons from 'lucide-react';
8
- import { X, AlertTriangle, Info, AlertCircle, CheckCircle, Loader2, List, Printer, ChevronRight, ChevronLeft, Check, Copy, Code, FileText, WrapText, Trash2, Settings, Menu as Menu$1, Search, Bell, ChevronDown, LogOut, ZoomOut, ZoomIn, Download, FileQuestion, Inbox, XCircle, Filter, Plus, Pause, Play, RotateCcw, Package, Calendar, Pencil, Eye, MoreHorizontal, Image as Image$1, Upload, Minus, ArrowLeft, HelpCircle, ChevronUp, Eraser, Star, TrendingUp, TrendingDown, ArrowUp, ArrowDown, MoreVertical, Sun, Moon, Circle, Clock, CheckCircle2, ArrowRight, FileWarning, SkipForward, Bug, Send, Wrench, User, Tag, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
8
+ import { X, AlertTriangle, Info, AlertCircle, CheckCircle, Loader2, List, Printer, ChevronRight, ChevronLeft, Check, Copy, Code, FileText, WrapText, Trash2, Menu as Menu$1, Search, Bell, ChevronDown, LogOut, ZoomOut, ZoomIn, Download, FileQuestion, Inbox, XCircle, Filter, Plus, Pause, Play, RotateCcw, Package, Calendar, Pencil, Eye, MoreHorizontal, Image as Image$1, Upload, Minus, ArrowLeft, HelpCircle, ChevronUp, Eraser, Star, TrendingUp, TrendingDown, ArrowUp, ArrowDown, MoreVertical, Sun, Moon, Circle, Clock, CheckCircle2, ArrowRight, FileWarning, SkipForward, Bug, Send, Wrench, User, Tag, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
9
9
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
10
10
  import { useUISlots } from '@almadar/ui/context';
11
11
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
@@ -18323,6 +18323,7 @@ var init_DashboardLayout = __esm({
18323
18323
  init_Typography();
18324
18324
  init_Icon();
18325
18325
  init_useAuthContext();
18326
+ init_useEventBus();
18326
18327
  init_useTranslate();
18327
18328
  DashboardLayout = ({
18328
18329
  appName = "{{APP_TITLE}}",
@@ -18330,11 +18331,29 @@ var init_DashboardLayout = __esm({
18330
18331
  navItems = [],
18331
18332
  user: userProp,
18332
18333
  headerActions,
18333
- showSearch = true,
18334
+ showSearch = false,
18335
+ searchEvent,
18336
+ onSearchSubmit,
18337
+ notifications,
18338
+ notificationClickEvent,
18339
+ onNotificationClick,
18340
+ showThemeToggle = true,
18334
18341
  sidebarFooter,
18335
18342
  onSignOut: onSignOutProp,
18336
18343
  children
18337
18344
  }) => {
18345
+ const eventBus = useEventBus();
18346
+ const searchEnabled = showSearch || Boolean(searchEvent) || Boolean(onSearchSubmit);
18347
+ const notificationsEnabled = Array.isArray(notifications);
18348
+ const unreadCount = notificationsEnabled ? notifications.filter((n) => n.read !== true).length : 0;
18349
+ const handleSearchSubmit = (value) => {
18350
+ if (searchEvent) eventBus.emit(`UI:${searchEvent}`, { value });
18351
+ if (onSearchSubmit) onSearchSubmit(value);
18352
+ };
18353
+ const handleNotificationClick = () => {
18354
+ if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
18355
+ if (onNotificationClick) onNotificationClick();
18356
+ };
18338
18357
  const [sidebarOpen, setSidebarOpen] = useState(false);
18339
18358
  const [userMenuOpen, setUserMenuOpen] = useState(false);
18340
18359
  const location = useLocation();
@@ -18415,17 +18434,7 @@ var init_DashboardLayout = __esm({
18415
18434
  ))
18416
18435
  }
18417
18436
  ),
18418
- sidebarFooter || /* @__PURE__ */ jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: /* @__PURE__ */ jsxs(
18419
- Link,
18420
- {
18421
- to: "/settings",
18422
- className: "flex items-center gap-3 px-3 py-2 text-sm text-muted-foreground dark:text-muted-foreground rounded-lg hover:bg-muted dark:hover:bg-muted",
18423
- children: [
18424
- /* @__PURE__ */ jsx(Settings, { className: "h-5 w-5" }),
18425
- t("common.settings")
18426
- ]
18427
- }
18428
- ) })
18437
+ sidebarFooter && /* @__PURE__ */ jsx(Box, { className: "p-4 border-t border-border dark:border-border", children: sidebarFooter })
18429
18438
  ]
18430
18439
  }
18431
18440
  ),
@@ -18452,32 +18461,40 @@ var init_DashboardLayout = __esm({
18452
18461
  children: /* @__PURE__ */ jsx(Menu$1, { className: "h-5 w-5" })
18453
18462
  }
18454
18463
  ),
18455
- showSearch && /* @__PURE__ */ jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
18464
+ searchEnabled && /* @__PURE__ */ jsx(Box, { className: "hidden sm:block flex-1 max-w-md", children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
18456
18465
  /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground dark:text-muted-foreground" }),
18457
18466
  /* @__PURE__ */ jsx(
18458
18467
  Input,
18459
18468
  {
18460
18469
  type: "search",
18461
18470
  placeholder: t("common.search"),
18462
- className: "pl-10 w-full"
18471
+ className: "pl-10 w-full",
18472
+ onKeyDown: (e) => {
18473
+ if (e.key === "Enter") {
18474
+ handleSearchSubmit(e.target.value);
18475
+ }
18476
+ }
18463
18477
  }
18464
18478
  )
18465
18479
  ] }) }),
18466
18480
  /* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
18467
18481
  headerActions,
18468
- /* @__PURE__ */ jsx(ThemeToggle, {}),
18469
- /* @__PURE__ */ jsxs(
18482
+ showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
18483
+ notificationsEnabled && /* @__PURE__ */ jsxs(
18470
18484
  Button,
18471
18485
  {
18472
18486
  variant: "ghost",
18473
18487
  className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
18488
+ onClick: handleNotificationClick,
18489
+ "aria-label": t("common.notifications"),
18474
18490
  children: [
18475
18491
  /* @__PURE__ */ jsx(Bell, { className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
18476
- /* @__PURE__ */ jsx(
18492
+ unreadCount > 0 && /* @__PURE__ */ jsx(
18477
18493
  Box,
18478
18494
  {
18479
18495
  as: "span",
18480
- className: "absolute top-1 right-1 w-2 h-2 bg-error rounded-full"
18496
+ className: "absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 bg-error rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
18497
+ children: unreadCount > 99 ? "99+" : unreadCount
18481
18498
  }
18482
18499
  )
18483
18500
  ]
@@ -18542,17 +18559,6 @@ var init_DashboardLayout = __esm({
18542
18559
  }
18543
18560
  )
18544
18561
  ] }),
18545
- /* @__PURE__ */ jsxs(
18546
- Link,
18547
- {
18548
- to: "/settings",
18549
- className: "flex items-center gap-2 px-4 py-2 text-sm text-foreground dark:text-foreground hover:bg-muted dark:hover:bg-muted",
18550
- children: [
18551
- /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
18552
- t("common.settings")
18553
- ]
18554
- }
18555
- ),
18556
18562
  /* @__PURE__ */ jsxs(
18557
18563
  Button,
18558
18564
  {