@alfakit/react 0.1.1 → 0.1.6
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 +16 -0
- package/dist/components/actions/action-button.d.ts.map +1 -1
- package/dist/components/actions/action-button.js +5 -4
- package/dist/components/actions/action-button.js.map +1 -1
- package/dist/components/actions/action-modals.d.ts.map +1 -1
- package/dist/components/actions/action-modals.js +6 -5
- package/dist/components/actions/action-modals.js.map +1 -1
- package/dist/components/ai/copilot.d.ts +3 -1
- package/dist/components/ai/copilot.d.ts.map +1 -1
- package/dist/components/ai/copilot.js +4 -1
- package/dist/components/ai/copilot.js.map +1 -1
- package/dist/components/cms/live-preview.js +3 -2
- package/dist/components/cms/live-preview.js.map +1 -1
- package/dist/components/cms/page.js +1 -1
- package/dist/components/fields/builder.js +15 -6
- package/dist/components/fields/builder.js.map +1 -1
- package/dist/components/fields/color-picker.js +1 -0
- package/dist/components/fields/color-picker.js.map +1 -1
- package/dist/components/fields/file-upload.js +11 -10
- package/dist/components/fields/file-upload.js.map +1 -1
- package/dist/components/fields/image-editor-dialog.js +4 -2
- package/dist/components/fields/image-editor-dialog.js.map +1 -1
- package/dist/components/fields/item-actions.js +10 -10
- package/dist/components/fields/item-actions.js.map +1 -1
- package/dist/components/fields/key-value.d.ts.map +1 -1
- package/dist/components/fields/key-value.js +3 -3
- package/dist/components/fields/key-value.js.map +1 -1
- package/dist/components/fields/modal-table-select.js +6 -5
- package/dist/components/fields/modal-table-select.js.map +1 -1
- package/dist/components/fields/one-time-code-input.js +1 -1
- package/dist/components/fields/one-time-code-input.js.map +1 -1
- package/dist/components/fields/repeater-table.js +12 -1
- package/dist/components/fields/repeater-table.js.map +1 -1
- package/dist/components/fields/repeater.js +2 -2
- package/dist/components/fields/repeater.js.map +1 -1
- package/dist/components/fields/rich-editor.js +2 -1
- package/dist/components/fields/rich-editor.js.map +1 -1
- package/dist/components/fields/select.js +3 -3
- package/dist/components/fields/select.js.map +1 -1
- package/dist/components/file-manager/file-manager.js +1 -1
- package/dist/components/file-manager/file-manager.js.map +1 -1
- package/dist/components/form/form-block.d.ts.map +1 -1
- package/dist/components/form/form-block.js +14 -2
- package/dist/components/form/form-block.js.map +1 -1
- package/dist/components/form/form-context.js +7 -3
- package/dist/components/form/form-context.js.map +1 -1
- package/dist/components/kanban/kanban.js +4 -3
- package/dist/components/kanban/kanban.js.map +1 -1
- package/dist/components/layout/fused-group.js +1 -0
- package/dist/components/layout/fused-group.js.map +1 -1
- package/dist/components/layout/section.js +2 -2
- package/dist/components/layout/section.js.map +1 -1
- package/dist/components/layout/tabs.d.ts.map +1 -1
- package/dist/components/layout/tabs.js +54 -15
- package/dist/components/layout/tabs.js.map +1 -1
- package/dist/components/panel/app-sidebar.d.ts +2 -3
- package/dist/components/panel/app-sidebar.d.ts.map +1 -1
- package/dist/components/panel/app-sidebar.js +1 -24
- package/dist/components/panel/app-sidebar.js.map +1 -1
- package/dist/components/panel/brand.d.ts +10 -0
- package/dist/components/panel/brand.d.ts.map +1 -0
- package/dist/components/panel/brand.js +37 -0
- package/dist/components/panel/brand.js.map +1 -0
- package/dist/components/panel/global-search.js +1 -0
- package/dist/components/panel/global-search.js.map +1 -1
- package/dist/components/panel/index.d.ts +2 -1
- package/dist/components/panel/shortcut-keys.js +1 -0
- package/dist/components/panel/shortcut-keys.js.map +1 -1
- package/dist/components/panel/tenant-menu.js +2 -2
- package/dist/components/panel/tenant-menu.js.map +1 -1
- package/dist/components/panel/topbar.js +1 -1
- package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
- package/dist/components/realtime/live-records-pill.js +6 -3
- package/dist/components/realtime/live-records-pill.js.map +1 -1
- package/dist/components/table/cells.d.ts +6 -0
- package/dist/components/table/cells.d.ts.map +1 -1
- package/dist/components/table/cells.js +15 -3
- package/dist/components/table/cells.js.map +1 -1
- package/dist/components/table/column-manager.js +8 -7
- package/dist/components/table/column-manager.js.map +1 -1
- package/dist/components/table/content-layout.js +2 -1
- package/dist/components/table/content-layout.js.map +1 -1
- package/dist/components/table/grouping.js +11 -1
- package/dist/components/table/grouping.js.map +1 -1
- package/dist/components/table/pagination.js +16 -13
- package/dist/components/table/pagination.js.map +1 -1
- package/dist/components/table/table-block.js +14 -4
- package/dist/components/table/table-block.js.map +1 -1
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog.js +3 -1
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/popover.js +3 -1
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet.js +3 -1
- package/dist/components/ui/sheet.js.map +1 -1
- package/dist/components/ui/tooltip.js +3 -1
- package/dist/components/ui/tooltip.js.map +1 -1
- package/dist/components.css +347 -0
- package/dist/context.d.ts +5 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +5 -1
- package/dist/context.js.map +1 -1
- package/dist/create-alfakit.d.ts.map +1 -1
- package/dist/create-alfakit.js +8 -5
- package/dist/create-alfakit.js.map +1 -1
- package/dist/eject-manifest.json +16 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +24 -21
- package/dist/layouts/app-layout.d.ts.map +1 -1
- package/dist/layouts/app-layout.js +2 -29
- package/dist/layouts/app-layout.js.map +1 -1
- package/dist/layouts/auth-layout.js +2 -2
- package/dist/layouts/auth-layout.js.map +1 -1
- package/dist/layouts/fullscreen-layout.js +1 -1
- package/dist/layouts/fullscreen-layout.js.map +1 -1
- package/dist/layouts/lazy-layouts.js +15 -0
- package/dist/layouts/lazy-layouts.js.map +1 -0
- package/dist/layouts/max-widths.js +34 -0
- package/dist/layouts/max-widths.js.map +1 -0
- package/dist/layouts/panel-layouts.d.ts +10 -0
- package/dist/layouts/panel-layouts.d.ts.map +1 -0
- package/dist/layouts/panel-layouts.js +20 -0
- package/dist/layouts/panel-layouts.js.map +1 -0
- package/dist/layouts/top-nav-layout.js +2 -2
- package/dist/layouts/top-nav-layout.js.map +1 -1
- package/dist/pages/page.d.ts.map +1 -1
- package/dist/pages/page.js +12 -7
- package/dist/pages/page.js.map +1 -1
- package/dist/standalone/alfakit-component.js +11 -6
- package/dist/standalone/alfakit-component.js.map +1 -1
- package/dist/standalone/alfakit-toaster.d.ts.map +1 -1
- package/dist/standalone/alfakit-toaster.js +8 -1
- package/dist/standalone/alfakit-toaster.js.map +1 -1
- package/dist/standalone.css +54 -0
- package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
- package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
- package/dist/starter-kit/dashboard-widgets.js +53 -0
- package/dist/starter-kit/dashboard-widgets.js.map +1 -0
- package/dist/starter-kit/impersonation-banner.js +34 -0
- package/dist/starter-kit/impersonation-banner.js.map +1 -0
- package/dist/starter-kit/index.d.ts +3 -2
- package/dist/starter-kit/index.js +3 -2
- package/dist/starter-kit/starter-kit.d.ts +6 -0
- package/dist/starter-kit/starter-kit.d.ts.map +1 -1
- package/dist/starter-kit/starter-kit.js +18 -7
- package/dist/starter-kit/starter-kit.js.map +1 -1
- package/dist/starter-kit/widgets-loaded.js +21 -5
- package/dist/starter-kit/widgets-loaded.js.map +1 -1
- package/dist/starter-kit/widgets-triggers.js +35 -3
- package/dist/starter-kit/widgets-triggers.js.map +1 -1
- package/dist/starter-kit/widgets.d.ts +13 -5
- package/dist/starter-kit/widgets.d.ts.map +1 -1
- package/dist/starter-kit/widgets.js +56 -18
- package/dist/starter-kit/widgets.js.map +1 -1
- package/dist/styles.css +15 -2
- package/dist/themes.css +8 -335
- package/package.json +2 -2
- package/src/components/actions/action-button.tsx +7 -4
- package/src/components/actions/action-modals.tsx +13 -1
- package/src/components/ai/copilot.tsx +14 -1
- package/src/components/cms/live-preview.tsx +5 -2
- package/src/components/fields/builder.tsx +14 -5
- package/src/components/fields/color-picker.tsx +1 -0
- package/src/components/fields/file-upload.tsx +21 -10
- package/src/components/fields/image-editor-dialog.tsx +7 -2
- package/src/components/fields/item-actions.tsx +32 -9
- package/src/components/fields/key-value.tsx +3 -2
- package/src/components/fields/modal-table-select.tsx +8 -3
- package/src/components/fields/one-time-code-input.tsx +1 -1
- package/src/components/fields/repeater-table.tsx +12 -1
- package/src/components/fields/repeater.tsx +2 -3
- package/src/components/fields/rich-editor.tsx +3 -0
- package/src/components/fields/select.tsx +7 -3
- package/src/components/file-manager/file-manager.tsx +1 -1
- package/src/components/form/form-block.tsx +26 -1
- package/src/components/form/form-context.tsx +3 -6
- package/src/components/kanban/kanban.tsx +16 -3
- package/src/components/layout/fused-group.tsx +5 -1
- package/src/components/layout/section.tsx +2 -2
- package/src/components/layout/tabs.tsx +72 -17
- package/src/components/panel/app-sidebar.tsx +2 -38
- package/src/components/panel/brand.tsx +46 -0
- package/src/components/panel/global-search.tsx +1 -1
- package/src/components/panel/shortcut-keys.tsx +4 -1
- package/src/components/panel/tenant-menu.tsx +2 -2
- package/src/components/realtime/live-records-pill.tsx +4 -3
- package/src/components/table/cells.tsx +27 -5
- package/src/components/table/column-manager.tsx +12 -10
- package/src/components/table/content-layout.tsx +5 -1
- package/src/components/table/grouping.tsx +15 -1
- package/src/components/table/pagination.tsx +16 -9
- package/src/components/table/table-block.tsx +25 -12
- package/src/components/ui/dialog.tsx +5 -1
- package/src/components/ui/popover.tsx +5 -1
- package/src/components/ui/sheet.tsx +5 -1
- package/src/components/ui/tooltip.tsx +5 -1
- package/src/context.tsx +10 -0
- package/src/create-alfakit.tsx +11 -2
- package/src/index.ts +2 -0
- package/src/layouts/app-layout.tsx +4 -28
- package/src/layouts/auth-layout.tsx +2 -2
- package/src/layouts/fullscreen-layout.tsx +1 -1
- package/src/layouts/lazy-layouts.ts +14 -0
- package/src/layouts/max-widths.ts +29 -0
- package/src/layouts/panel-layouts.ts +17 -0
- package/src/layouts/top-nav-layout.tsx +2 -2
- package/src/pages/page.tsx +21 -12
- package/src/standalone/alfakit-component.tsx +18 -7
- package/src/standalone/alfakit-toaster.tsx +21 -2
- package/src/starter-kit/dashboard-widgets.tsx +78 -0
- package/src/starter-kit/impersonation-banner.tsx +48 -0
- package/src/starter-kit/index.ts +2 -0
- package/src/starter-kit/starter-kit.tsx +31 -4
- package/src/starter-kit/widgets-loaded.tsx +23 -1
- package/src/starter-kit/widgets-triggers.tsx +37 -2
- package/src/starter-kit/widgets.tsx +95 -20
- package/src/styles.css +15 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","names":[],"sources":["../../../src/components/layout/tabs.tsx"],"sourcesContent":["import type { TabSchema, TabsSchema } from '@alfakit/core'\nimport {
|
|
1
|
+
{"version":3,"file":"tabs.js","names":[],"sources":["../../../src/components/layout/tabs.tsx"],"sourcesContent":["import type { TabSchema, TabsSchema } from '@alfakit/core'\nimport {\n componentHasErrors,\n readPersisted,\n schemaGapClass,\n tabFromQuery,\n tabQueryValue,\n tabToReveal,\n writePersisted,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\nimport { useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { useStoreSelector } from '../../hooks/use-store'\nimport { extraProps } from '../../lib/attributes'\nimport { badgeColorClasses, colorClass } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useOptionalFormStore } from '../form/form-context'\nimport { SchemaRenderer } from '../schema/schema-renderer'\nimport { Badge } from '../ui/badge'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs'\nimport { DeferredSchema, useDeferredBadge } from './deferred'\n\n// Used when tabs render outside a form. Module-level so the snapshot stays stable.\nconst NO_ERRORS: Record<string, string[]> = {}\nconst NO_FORM_STORE = {\n get: () => ({ errors: NO_ERRORS }),\n subscribe: () => () => {},\n}\n\nconst TAB_INVALID_CLASSES =\n 'text-destructive data-[state=active]:text-destructive dark:text-destructive dark:data-[state=active]:text-destructive'\n\nexport function TabsComponent({ component }: { component: TabsSchema }) {\n const tabs = component.schema ?? []\n // The page URL (not `window.location`) so the server renders the same tab as the browser.\n const url = usePage().url\n // The tab's readable value (`?tab=billing-address`), or its key in links from older versions.\n const fromQuery = component.queryStringKey\n ? tabFromQuery(\n tabs,\n new URL(url, 'http://localhost').searchParams.get(component.queryStringKey),\n )\n : null\n const [initial] = useState<string>(\n () => fromQuery ?? tabs[Math.max(0, component.activeTab - 1)]?.key ?? tabs[0]?.key ?? '',\n )\n\n const persist = component.persistTab\n const hydrated = useHydrated()\n const [chosen, setChosen] = useState<string | null>(null)\n // `persistTab()`: read only after hydration (the server can't see browser storage); a\n // tab named in the query string wins.\n const stored =\n hydrated && persist && !fromQuery ? readPersisted(persist.key, persist.storage) : null\n const active = chosen ?? (stored && tabs.some((tab) => tab.key === stored) ? stored : initial)\n\n // Tabs holding a field with a validation error are marked, and when a submit brings new\n // errors while the open tab has none, the first tab with an error opens.\n const t = useT()\n const store = useOptionalFormStore()\n const errors = useStoreSelector(store?.store ?? NO_FORM_STORE, (state) => state.errors)\n const [seenErrors, setSeenErrors] = useState<Record<string, string[]>>({})\n\n if (seenErrors !== errors) {\n setSeenErrors(errors)\n\n const reveal = tabToReveal(tabs, active, seenErrors, errors)\n\n if (reveal !== null) setChosen(reveal)\n }\n\n const changeTab = (value: string) => {\n setChosen(value)\n\n if (persist) writePersisted(persist.key, value, persist.storage)\n }\n\n useEffect(() => {\n if (!component.queryStringKey || typeof window === 'undefined') return\n\n const tab = tabs.find((item) => item.key === active)\n const url = new URL(window.location.href)\n url.searchParams.set(component.queryStringKey, tab ? tabQueryValue(tab) : active)\n window.history.replaceState(window.history.state, '', url)\n }, [active, component.queryStringKey, tabs])\n\n return (\n <Tabs\n data-surface={component.contained ? 'tabs' : undefined}\n value={active}\n onValueChange={changeTab}\n orientation={component.vertical ? 'vertical' : 'horizontal'}\n\n {...extraProps(\n component.extraAttributes,\n cn(\n component.contained && 'bg-card rounded-xl border shadow-xs',\n component.vertical && 'flex-row',\n ),\n )}\n >\n <TabsList\n data-scrollable={component.scrollable === false ? 'false' : undefined}\n className={cn(\n component.contained && 'm-2',\n component.vertical\n ? 'self-start'\n : component.scrollable === false\n ? 'h-auto max-w-full flex-wrap justify-start'\n : 'relative max-w-full overflow-x-auto',\n )}\n >\n {tabs.map((tab) => {\n const invalid = componentHasErrors(tab, errors)\n\n return (\n <TabsTrigger\n key={tab.key}\n value={tab.key}\n data-invalid={invalid || undefined}\n className={invalid ? TAB_INVALID_CLASSES : undefined}\n >\n {tab.icon && tab.iconPosition !== 'after' && <Icon name={tab.icon} />}\n {tab.label}\n {tab.icon && tab.iconPosition === 'after' && <Icon name={tab.icon} />}\n <TabBadge tab={tab} />\n {invalid && (\n <>\n <span\n aria-hidden=\"true\"\n className=\"bg-destructive size-1.5 shrink-0 rounded-full\"\n />\n <span className=\"sr-only\">({t('translatable.has_errors')})</span>\n </>\n )}\n </TabsTrigger>\n )\n })}\n </TabsList>\n {tabs.map((tab) => (\n <TabsContent\n key={tab.key}\n value={tab.key}\n forceMount\n className={cn('data-[state=inactive]:hidden', component.contained ? 'p-6 pt-4' : 'pt-4')}\n >\n <DeferredSchema component={tab}>\n {(loaded) => (\n <SchemaRenderer\n components={loaded.schema ?? []}\n columns={loaded.columns}\n attributes={loaded.extraAttributes}\n className={schemaGapClass(loaded) || undefined}\n />\n )}\n </DeferredSchema>\n </TabsContent>\n ))}\n </Tabs>\n )\n}\n\n/** A tab's badge; `deferBadge()` badges appear once loaded. */\nfunction TabBadge({ tab }: { tab: TabSchema }) {\n const { badge, badgeColor, badgeTooltip } = useDeferredBadge(tab)\n\n if (badge === undefined || badge === null) return null\n\n return (\n <Badge\n variant=\"outline\"\n title={badgeTooltip ?? undefined}\n className={cn(\n 'ms-1 px-1.5 py-0',\n colorClass(badgeColorClasses, badgeColor ?? undefined, 'gray'),\n )}\n >\n {badge}\n </Badge>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { Brand } from "./brand.js";
|
|
1
2
|
//#region src/components/panel/app-sidebar.d.ts
|
|
2
|
-
export declare function Brand({ className }: {
|
|
3
|
-
className?: string;
|
|
4
|
-
}): import("react").JSX.Element;
|
|
5
3
|
export declare function AppSidebar(): import("react").JSX.Element;
|
|
6
4
|
//#endregion
|
|
5
|
+
export { Brand };
|
|
7
6
|
//# sourceMappingURL=app-sidebar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-sidebar.d.ts","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-sidebar.d.ts","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"mappings":";;wBAgUgB,8BAAU,IAAA"}
|
|
@@ -11,6 +11,7 @@ import { NavLabel } from "./nav-label.js";
|
|
|
11
11
|
import { NewTabHint } from "../../lib/new-tab-hint.js";
|
|
12
12
|
import { NotificationsMenu } from "../notifications/notifications-menu.js";
|
|
13
13
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarRail } from "../ui/sidebar.js";
|
|
14
|
+
import { Brand } from "./brand.js";
|
|
14
15
|
import { GlobalSearch } from "./global-search.js";
|
|
15
16
|
import { TenantMenu } from "./tenant-menu.js";
|
|
16
17
|
import { UserMenu } from "./user-menu.js";
|
|
@@ -19,30 +20,6 @@ import { Link } from "@inertiajs/react";
|
|
|
19
20
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
20
21
|
import { ChevronRightIcon } from "lucide-react";
|
|
21
22
|
//#region src/components/panel/app-sidebar.tsx
|
|
22
|
-
function Brand({ className }) {
|
|
23
|
-
const panel = usePanel();
|
|
24
|
-
return /* @__PURE__ */ jsx(Link, {
|
|
25
|
-
href: panel.url ?? "/",
|
|
26
|
-
className: cn("flex items-center gap-2 overflow-hidden", className),
|
|
27
|
-
children: panel.brandLogo ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("img", {
|
|
28
|
-
src: panel.brandLogo,
|
|
29
|
-
alt: panel.brandName,
|
|
30
|
-
style: { height: panel.brandLogoHeight ?? "1.75rem" },
|
|
31
|
-
className: cn("max-w-full object-contain", panel.darkModeBrandLogo && "dark:hidden")
|
|
32
|
-
}), panel.darkModeBrandLogo && /* @__PURE__ */ jsx("img", {
|
|
33
|
-
src: panel.darkModeBrandLogo,
|
|
34
|
-
alt: panel.brandName,
|
|
35
|
-
style: { height: panel.brandLogoHeight ?? "1.75rem" },
|
|
36
|
-
className: "hidden max-w-full object-contain dark:block"
|
|
37
|
-
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
38
|
-
className: "bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold",
|
|
39
|
-
children: panel.brandName.charAt(0)
|
|
40
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
41
|
-
className: "truncate text-sm font-semibold group-data-[collapsible=icon]:hidden",
|
|
42
|
-
children: panel.brandName
|
|
43
|
-
})] })
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
23
|
function NavBadge({ item }) {
|
|
47
24
|
const t = useT();
|
|
48
25
|
if (item.badgePending) return /* @__PURE__ */ jsx("span", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-sidebar.js","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n flattenNavigationItems,\n hasActiveNavigationItem,\n navigationItemText,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronRightIcon } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { badgeColorClasses, colorClass } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { NewTabHint } from '../../lib/new-tab-hint'\nimport { cn } from '../../lib/utils'\nimport { NotificationsMenu } from '../notifications/notifications-menu'\nimport { Badge } from '../ui/badge'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n} from '../ui/sidebar'\nimport { GlobalSearch } from './global-search'\nimport { NavLabel } from './nav-label'\nimport { Slot } from './slot'\nimport { TenantMenu } from './tenant-menu'\nimport { UserMenu } from './user-menu'\n\nexport function Brand({ className }: { className?: string }) {\n const panel = usePanel()\n\n return (\n <Link\n href={panel.url ?? '/'}\n className={cn('flex items-center gap-2 overflow-hidden', className)}\n >\n {panel.brandLogo ? (\n <>\n <img\n src={panel.brandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className={cn('max-w-full object-contain', panel.darkModeBrandLogo && 'dark:hidden')}\n />\n {panel.darkModeBrandLogo && (\n <img\n src={panel.darkModeBrandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className=\"hidden max-w-full object-contain dark:block\"\n />\n )}\n </>\n ) : (\n <>\n <span className=\"bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold\">\n {panel.brandName.charAt(0)}\n </span>\n <span className=\"truncate text-sm font-semibold group-data-[collapsible=icon]:hidden\">\n {panel.brandName}\n </span>\n </>\n )}\n </Link>\n )\n}\n\nfunction NavBadge({ item }: { item: NavigationItemSchema }) {\n const t = useT()\n\n // `deferNavigationBadges()`: a placeholder until the deferred badges arrive.\n if (item.badgePending) {\n return (\n <span\n data-slot=\"badge\"\n aria-busy=\"true\"\n aria-label={t('loading', {}, 'Loading')}\n className=\"bg-muted-foreground/20 ms-auto inline-block h-4 w-5 animate-pulse rounded-md\"\n />\n )\n }\n\n if (item.badge === undefined || item.badge === null) return null\n\n return (\n <Badge\n variant=\"outline\"\n className={cn('ms-auto px-1.5 py-0', colorClass(badgeColorClasses, item.badgeColor, 'gray'))}\n title={item.badgeTooltip}\n >\n {item.badge}\n </Badge>\n )\n}\n\n/**\n * A navigation link: an Inertia link, or a plain anchor for `openUrlInNewTab()`. Used as an\n * `asChild` target, so it must pass on the classes, data attributes and handlers it receives.\n */\nfunction NavLink({\n item,\n children,\n ...props\n}: { item: NavigationItemSchema; children: ReactNode } & Omit<\n ComponentProps<'a'>,\n 'href' | 'children'\n>) {\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n const attributes = {\n ...props,\n ...extraProps(item.extraAttributes, props.className),\n } as ComponentProps<'a'>\n\n return item.openInNewTab ? (\n <a {...attributes} href={item.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n <NewTabHint />\n </a>\n ) : (\n // Slot passes DOM props; Inertia's Link redefines a few event names, so pass them through untyped.\n <Link\n {...(attributes as Record<string, unknown>)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n >\n {children}\n </Link>\n )\n}\n\n/** Child items (any depth) with their own badges, new-tab links and nested children. */\nfunction NavSubItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <SidebarMenuSubItem>\n <Collapsible defaultOpen={item.active} className=\"group/nav-sub\">\n <CollapsibleTrigger asChild>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <button type=\"button\" {...extraProps(item.extraAttributes, 'w-full')}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/nav-sub:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-sub:rotate-90\" />\n </button>\n </SidebarMenuSubButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </Collapsible>\n </SidebarMenuSubItem>\n )\n }\n\n return (\n <SidebarMenuSubItem>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n}\n\nfunction NavItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen={item.active} className=\"group/collapsible\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton\n tooltip={navigationItemText(item)}\n isActive={item.active}\n {...extraProps(item.extraAttributes)}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem>\n <SidebarMenuButton asChild isActive={item.active} tooltip={navigationItemText(item)}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\n}\n\n/** A group's items in its flyout menu, children indented under their parent. */\nfunction FlyoutItems({ items }: { items: NavigationItemSchema[] }) {\n return flattenNavigationItems(items).map(({ item, depth }, index) => (\n <DropdownMenuItem\n key={`${depth}-${item.label}-${index}`}\n asChild\n data-active={item.active ? 'true' : undefined}\n >\n <NavLink\n item={item}\n aria-current={item.active ? 'page' : undefined}\n className={cn(\n 'data-[active=true]:bg-accent data-[active=true]:font-medium',\n depth === 1 && 'ps-6',\n depth > 1 && 'ps-9',\n )}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} className=\"truncate\" />\n <NavBadge item={item} />\n </NavLink>\n </DropdownMenuItem>\n ))\n}\n\n/**\n * In the icon-only (collapsed) sidebar, a group with an icon is one button that opens its\n * items in a flyout menu, like Filament. Hidden while the sidebar is expanded.\n */\nfunction NavGroupFlyout({ group }: { group: NavigationGroupSchema }) {\n const direction = useDirection()\n const active = hasActiveNavigationItem(group.items)\n\n return (\n <SidebarMenu className=\"hidden group-data-[collapsible=icon]:flex\" data-nav-flyout=\"\">\n <SidebarMenuItem>\n <DropdownMenu dir={direction}>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton isActive={active}>\n <Icon name={group.icon!} />\n <span>{group.label}</span>\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={direction === 'rtl' ? 'left' : 'right'}\n align=\"start\"\n className=\"min-w-56\"\n >\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n <FlyoutItems items={group.items} />\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction NavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraSidebarAttributes()`; `class` is merged with the group's own.\n const attributes = extraProps(group.extraSidebarAttributes)\n // A labelled group with an icon collapses into a flyout in the icon-only sidebar.\n const flyout = Boolean(group.label && group.icon)\n const content = (\n <SidebarGroupContent className={cn(flyout && 'group-data-[collapsible=icon]:hidden')}>\n <SidebarMenu>\n {group.items.map((item) => (\n <NavItem key={item.label} item={item} />\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n )\n const flyoutMenu = flyout ? <NavGroupFlyout group={group} /> : null\n\n if (!group.label) {\n return <SidebarGroup {...attributes}>{content}</SidebarGroup>\n }\n\n if (!group.collapsible) {\n return (\n <SidebarGroup {...attributes}>\n <SidebarGroupLabel>\n {group.icon && <Icon name={group.icon} className=\"me-1.5\" />}\n {group.label}\n </SidebarGroupLabel>\n {content}\n {flyoutMenu}\n </SidebarGroup>\n )\n }\n\n return (\n <Collapsible\n defaultOpen={!group.collapsed || group.items.some((item) => item.active)}\n className=\"group/nav-group\"\n >\n <SidebarGroup {...attributes}>\n <CollapsibleTrigger asChild>\n <SidebarGroupLabel\n asChild\n className=\"hover:bg-sidebar-accent w-full cursor-pointer justify-between\"\n >\n <button type=\"button\">\n <span className=\"flex items-center gap-1.5\">\n {group.icon && <Icon name={group.icon} />}\n {group.label}\n </span>\n <Icon\n name=\"alfakit::panels.sidebar.group.collapse-button\"\n fallback={ChevronRightIcon}\n className=\"size-3.5 transition-transform group-data-[state=open]/nav-group:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-group:rotate-90\"\n />\n </button>\n </SidebarGroupLabel>\n </CollapsibleTrigger>\n <CollapsibleContent>{content}</CollapsibleContent>\n {flyoutMenu}\n </SidebarGroup>\n </Collapsible>\n )\n}\n\nexport function AppSidebar() {\n const panel = usePanel()\n const direction = useDirection()\n const t = useT()\n\n return (\n <Sidebar\n side={direction === 'rtl' ? 'right' : 'left'}\n collapsible={\n panel.theme?.design?.layout === 'rail'\n ? 'icon'\n : panel.sidebarFullyCollapsibleOnDesktop\n ? 'offcanvas'\n : panel.sidebarCollapsibleOnDesktop\n ? 'icon'\n : 'none'\n }\n variant={panel.theme?.sidebar === 'flush' ? 'sidebar' : (panel.theme?.sidebar ?? 'inset')}\n >\n <SidebarHeader>\n <Slot name=\"sidebar.start\" />\n <Slot name=\"sidebar.logo.before\" />\n <SidebarMenu>\n <SidebarMenuItem>\n {panel.tenancy?.current ? (\n <>\n <Slot name=\"tenant-menu.before\" />\n <TenantMenu />\n <Slot name=\"tenant-menu.after\" />\n </>\n ) : (\n <SidebarMenuButton size=\"lg\" asChild>\n <div>\n <Brand />\n </div>\n </SidebarMenuButton>\n )}\n </SidebarMenuItem>\n </SidebarMenu>\n <Slot name=\"sidebar.logo.after\" />\n {/* `databaseNotifications(position: 'sidebar')` or `topbar(false)`. */}\n {panel.databaseNotifications?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <NotificationsMenu variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n {/* `globalSearch(position: GlobalSearchPosition::Sidebar)` or `topbar(false)`. */}\n {panel.globalSearch?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <GlobalSearch variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.header\" />\n </SidebarHeader>\n <SidebarContent>\n <Slot name=\"sidebar.nav.start\" />\n <nav aria-label={t('sidebar', {}, 'Sidebar')} className=\"contents\">\n {panel.navigation.map((group, index) => (\n <NavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"sidebar.nav.end\" />\n </SidebarContent>\n <SidebarFooter>\n <Slot name=\"sidebar.footer\" />\n {/* `userMenu(position: UserMenuPosition::Topbar)` shows it in the top bar instead. */}\n {panel.userMenu?.position !== 'topbar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <UserMenu />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.end\" />\n </SidebarFooter>\n <SidebarRail />\n </Sidebar>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,MAAM,EAAE,aAAqC;CAC3D,MAAM,QAAQ,SAAS;CAEvB,OACE,oBAAC,MAAD;EACE,MAAM,MAAM,OAAO;EACnB,WAAW,GAAG,2CAA2C,SAAS;EAEjE,UAAA,MAAM,YACL,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAW,GAAG,6BAA6B,MAAM,qBAAqB,aAAa;EACpF,CAAA,GACA,MAAM,qBACL,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAU;EACX,CAAA,CAEH,EAAA,CAAA,IAEF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,UAAU,OAAO,CAAC;EACrB,CAAA,GACN,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM;EACH,CAAA,CACN,EAAA,CAAA;CAEA,CAAA;AAEV;AAEA,SAAS,SAAS,EAAE,QAAwC;CAC1D,MAAM,IAAI,KAAK;CAGf,IAAI,KAAK,cACP,OACE,oBAAC,QAAD;EACE,aAAU;EACV,aAAU;EACV,cAAY,EAAE,WAAW,CAAC,GAAG,SAAS;EACtC,WAAU;CACX,CAAA;CAIL,IAAI,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU,MAAM,OAAO;CAE5D,OACE,oBAAC,OAAD;EACE,SAAQ;EACR,WAAW,GAAG,uBAAuB,WAAW,mBAAmB,KAAK,YAAY,MAAM,CAAC;EAC3F,OAAO,KAAK;EAEX,UAAA,KAAK;CACD,CAAA;AAEX;;;;;AAMA,SAAS,QAAQ,EACf,MACA,UACA,GAAG,SAIF;CAED,MAAM,aAAa;EACjB,GAAG;EACH,GAAG,WAAW,KAAK,iBAAiB,MAAM,SAAS;CACrD;CAEA,OAAO,KAAK,eACV,qBAAC,KAAD;EAAG,GAAI;EAAY,MAAM,KAAK;EAAK,QAAO;EAAS,KAAI;EAAvD,UAAA,CACG,UACD,oBAAC,YAAD,CAAa,CAAA,CACZ;CAGH,CAAA,IAAA,oBAAC,MAAD;EACE,GAAK;EACL,MAAM,KAAK,OAAO;EAClB,UAAA;EACA,UAAU;EAET;CACG,CAAA;AAEV;;AAGA,SAAS,WAAW,EAAE,QAAwC;CAC5D,IAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAC1C,OACE,oBAAC,oBAAD,EAAA,UACE,qBAAC,aAAD;EAAa,aAAa,KAAK;EAAQ,WAAU;EAAjD,UAAA,CACE,oBAAC,oBAAD;GAAoB,SAAA;GAClB,UAAA,oBAAC,sBAAD;IAAsB,SAAA;IAAQ,UAAU,KAAK;IAC3C,UAAA,qBAAC,UAAD;KAAQ,MAAK;KAAS,GAAI,WAAW,KAAK,iBAAiB,QAAQ;KAAnE,UAAA;MACG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA;MACtC,oBAAC,UAAD,EAAgB,KAAO,CAAA;MACvB,oBAAC,UAAD,EAAgB,KAAO,CAAA;MACvB,oBAAC,kBAAD,EAAkB,WAAU,mJAAoJ,CAAA;KAC1K;;GACY,CAAA;EACJ,CAAA,GACpB,oBAAC,oBAAD,EAAA,UACE,oBAAC,gBAAD,EAAA,UACG,KAAK,SAAS,KAAK,UAClB,oBAAC,YAAD,EAA8B,MAAM,MAAQ,GAA3B,MAAM,KAAqB,CAC7C,EACa,CAAA,EACE,CAAA,CACT;CACK,CAAA,EAAA,CAAA;CAIxB,OACE,oBAAC,oBAAD,EAAA,UACE,oBAAC,sBAAD;EAAsB,SAAA;EAAQ,UAAU,KAAK;EAC3C,UAAA,qBAAC,SAAD;GAAe;GAAf,UAAA;IACG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA;IACtC,oBAAC,UAAD,EAAgB,KAAO,CAAA;IACvB,oBAAC,UAAD,EAAgB,KAAO,CAAA;GAChB;;CACW,CAAA,EACJ,CAAA;AAExB;AAEA,SAAS,QAAQ,EAAE,QAAwC;CACzD,IAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAC1C,OACE,oBAAC,aAAD;EAAa,SAAA;EAAQ,aAAa,KAAK;EAAQ,WAAU;EACvD,UAAA,qBAAC,iBAAD,EAAA,UAAA,CACE,oBAAC,oBAAD;GAAoB,SAAA;GAClB,UAAA,qBAAC,mBAAD;IACE,SAAS,mBAAmB,IAAI;IAChC,UAAU,KAAK;IACf,GAAI,WAAW,KAAK,eAAe;IAHrC,UAAA;KAKG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA;KACtC,oBAAC,UAAD,EAAgB,KAAO,CAAA;KACvB,oBAAC,UAAD,EAAgB,KAAO,CAAA;KACvB,oBAAC,kBAAD,EAAkB,WAAU,2JAA4J,CAAA;IACvK;;EACD,CAAA,GACpB,oBAAC,oBAAD,EAAA,UACE,oBAAC,gBAAD,EAAA,UACG,KAAK,SAAS,KAAK,UAClB,oBAAC,YAAD,EAA8B,MAAM,MAAQ,GAA3B,MAAM,KAAqB,CAC7C,EACa,CAAA,EACE,CAAA,CACL,EAAA,CAAA;CACN,CAAA;CAIjB,OACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,mBAAD;EAAmB,SAAA;EAAQ,UAAU,KAAK;EAAQ,SAAS,mBAAmB,IAAI;EAChF,UAAA,qBAAC,SAAD;GAAe;GAAf,UAAA;IACG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA;IACtC,oBAAC,UAAD,EAAgB,KAAO,CAAA;IACvB,oBAAC,UAAD,EAAgB,KAAO,CAAA;GAChB;;CACQ,CAAA,EACJ,CAAA;AAErB;;AAGA,SAAS,YAAY,EAAE,SAA4C;CACjE,OAAO,uBAAuB,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,SAAS,UACzD,oBAAC,kBAAD;EAEE,SAAA;EACA,eAAa,KAAK,SAAS,SAAS,KAAA;EAEpC,UAAA,qBAAC,SAAD;GACQ;GACN,gBAAc,KAAK,SAAS,SAAS,KAAA;GACrC,WAAW,GACT,+DACA,UAAU,KAAK,QACf,QAAQ,KAAK,MACf;GAPF,UAAA;IASG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA;IACtC,oBAAC,UAAD;KAAgB;KAAM,WAAU;IAAY,CAAA;IAC5C,oBAAC,UAAD,EAAgB,KAAO,CAAA;GAChB;;CACO,GAjBX,GAAG,MAAM,GAAG,KAAK,MAAM,GAAG,OAiBf,CACnB;AACH;;;;;AAMA,SAAS,eAAe,EAAE,SAA2C;CACnE,MAAM,YAAY,aAAa;CAC/B,MAAM,SAAS,wBAAwB,MAAM,KAAK;CAElD,OACE,oBAAC,aAAD;EAAa,WAAU;EAA4C,mBAAgB;EACjF,UAAA,oBAAC,iBAAD,EAAA,UACE,qBAAC,cAAD;GAAc,KAAK;GAAnB,UAAA,CACE,oBAAC,qBAAD;IAAqB,SAAA;IACnB,UAAA,qBAAC,mBAAD;KAAmB,UAAU;KAA7B,UAAA,CACE,oBAAC,MAAD,EAAM,MAAM,MAAM,KAAQ,CAAA,GAC1B,oBAAC,QAAD,EAAA,UAAO,MAAM,MAAY,CAAA,CACR;;GACA,CAAA,GACrB,qBAAC,qBAAD;IACE,MAAM,cAAc,QAAQ,SAAS;IACrC,OAAM;IACN,WAAU;IAHZ,UAAA,CAKE,oBAAC,mBAAD,EAAA,UAAoB,MAAM,MAAyB,CAAA,GACnD,oBAAC,aAAD,EAAa,OAAO,MAAM,MAAQ,CAAA,CACf;GACT,CAAA,CAAA;EACC,CAAA,EAAA,CAAA;CACN,CAAA;AAEjB;AAEA,SAAS,SAAS,EAAE,SAA2C;CAE7D,MAAM,aAAa,WAAW,MAAM,sBAAsB;CAE1D,MAAM,SAAS,QAAQ,MAAM,SAAS,MAAM,IAAI;CAChD,MAAM,UACJ,oBAAC,qBAAD;EAAqB,WAAW,GAAG,UAAU,sCAAsC;EACjF,UAAA,oBAAC,aAAD,EAAA,UACG,MAAM,MAAM,KAAK,SAChB,oBAAC,SAAD,EAAgC,KAAO,GAAzB,KAAK,KAAoB,CACxC,EACU,CAAA;CACM,CAAA;CAEvB,MAAM,aAAa,SAAS,oBAAC,gBAAD,EAAuB,MAAQ,CAAA,IAAI;CAE/D,IAAI,CAAC,MAAM,OACT,OAAO,oBAAC,cAAD;EAAc,GAAI;EAAa,UAAA;CAAsB,CAAA;CAG9D,IAAI,CAAC,MAAM,aACT,OACE,qBAAC,cAAD;EAAc,GAAI;EAAlB,UAAA;GACE,qBAAC,mBAAD,EAAA,UAAA,CACG,MAAM,QAAQ,oBAAC,MAAD;IAAM,MAAM,MAAM;IAAM,WAAU;GAAU,CAAA,GAC1D,MAAM,KACU,EAAA,CAAA;GAClB;GACA;EACW;;CAIlB,OACE,oBAAC,aAAD;EACE,aAAa,CAAC,MAAM,aAAa,MAAM,MAAM,MAAM,SAAS,KAAK,MAAM;EACvE,WAAU;EAEV,UAAA,qBAAC,cAAD;GAAc,GAAI;GAAlB,UAAA;IACE,oBAAC,oBAAD;KAAoB,SAAA;KAClB,UAAA,oBAAC,mBAAD;MACE,SAAA;MACA,WAAU;MAEV,UAAA,qBAAC,UAAD;OAAQ,MAAK;OAAb,UAAA,CACE,qBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA,CACG,MAAM,QAAQ,oBAAC,MAAD,EAAM,MAAM,MAAM,KAAO,CAAA,GACvC,MAAM,KACH;OACN,CAAA,GAAA,oBAAC,MAAD;QACE,MAAK;QACL,UAAU;QACV,WAAU;OACX,CAAA,CACK;;KACS,CAAA;IACD,CAAA;IACpB,oBAAC,oBAAD,EAAA,UAAqB,QAA4B,CAAA;IAChD;GACW;;CACH,CAAA;AAEjB;AAEA,SAAgB,aAAa;CAC3B,MAAM,QAAQ,SAAS;CACvB,MAAM,YAAY,aAAa;CAC/B,MAAM,IAAI,KAAK;CAEf,OACE,qBAAC,SAAD;EACE,MAAM,cAAc,QAAQ,UAAU;EACtC,aACE,MAAM,OAAO,QAAQ,WAAW,SAC5B,SACA,MAAM,mCACJ,cACA,MAAM,8BACJ,SACA;EAEV,SAAS,MAAM,OAAO,YAAY,UAAU,YAAa,MAAM,OAAO,WAAW;EAXnF,UAAA;GAaE,qBAAC,eAAD,EAAA,UAAA;IACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;IAC5B,oBAAC,MAAD,EAAM,MAAK,sBAAuB,CAAA;IAClC,oBAAC,aAAD,EAAA,UACE,oBAAC,iBAAD,EAAA,UACG,MAAM,SAAS,UACd,qBAAA,UAAA,EAAA,UAAA;KACE,oBAAC,MAAD,EAAM,MAAK,qBAAsB,CAAA;KACjC,oBAAC,YAAD,CAAa,CAAA;KACb,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;IAChC,EAAA,CAAA,IAEF,oBAAC,mBAAD;KAAmB,MAAK;KAAK,SAAA;KAC3B,UAAA,oBAAC,OAAD,EAAA,UACE,oBAAC,OAAD,CAAQ,CAAA,EACL,CAAA;IACY,CAAA,EAEN,CAAA,EACN,CAAA;IACb,oBAAC,MAAD,EAAM,MAAK,qBAAsB,CAAA;IAEhC,MAAM,uBAAuB,aAAa,aACzC,oBAAC,aAAD,EAAA,UACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,mBAAD,EAAmB,SAAQ,UAAW,CAAA,EACvB,CAAA,EACN,CAAA;IAGd,MAAM,cAAc,aAAa,aAChC,oBAAC,aAAD,EAAA,UACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,cAAD,EAAc,SAAQ,UAAW,CAAA,EAClB,CAAA,EACN,CAAA;IAEf,oBAAC,MAAD,EAAM,MAAK,iBAAkB,CAAA;GAChB,EAAA,CAAA;GACf,qBAAC,gBAAD,EAAA,UAAA;IACE,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;IAChC,oBAAC,OAAD;KAAK,cAAY,EAAE,WAAW,CAAC,GAAG,SAAS;KAAG,WAAU;KACrD,UAAA,MAAM,WAAW,KAAK,OAAO,UAC5B,oBAAC,UAAD,EAAuD,MAAQ,GAAhD,MAAM,SAAS,SAAS,OAAwB,CAChE;IACE,CAAA;IACL,oBAAC,MAAD,EAAM,MAAK,kBAAmB,CAAA;GAChB,EAAA,CAAA;GAChB,qBAAC,eAAD,EAAA,UAAA;IACE,oBAAC,MAAD,EAAM,MAAK,iBAAkB,CAAA;IAE5B,MAAM,UAAU,aAAa,YAC5B,oBAAC,aAAD,EAAA,UACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,UAAD,CAAW,CAAA,EACI,CAAA,EACN,CAAA;IAEf,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;GACb,EAAA,CAAA;GACf,oBAAC,aAAD,CAAc,CAAA;EACP;;AAEb"}
|
|
1
|
+
{"version":3,"file":"app-sidebar.js","names":[],"sources":["../../../src/components/panel/app-sidebar.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n flattenNavigationItems,\n hasActiveNavigationItem,\n navigationItemText,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronRightIcon } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { badgeColorClasses, colorClass } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { NewTabHint } from '../../lib/new-tab-hint'\nimport { cn } from '../../lib/utils'\nimport { NotificationsMenu } from '../notifications/notifications-menu'\nimport { Badge } from '../ui/badge'\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n} from '../ui/sidebar'\nimport { Brand } from './brand'\nimport { GlobalSearch } from './global-search'\nimport { NavLabel } from './nav-label'\nimport { Slot } from './slot'\nimport { TenantMenu } from './tenant-menu'\nimport { UserMenu } from './user-menu'\n\nexport { Brand } from './brand'\n\nfunction NavBadge({ item }: { item: NavigationItemSchema }) {\n const t = useT()\n\n // `deferNavigationBadges()`: a placeholder until the deferred badges arrive.\n if (item.badgePending) {\n return (\n <span\n data-slot=\"badge\"\n aria-busy=\"true\"\n aria-label={t('loading', {}, 'Loading')}\n className=\"bg-muted-foreground/20 ms-auto inline-block h-4 w-5 animate-pulse rounded-md\"\n />\n )\n }\n\n if (item.badge === undefined || item.badge === null) return null\n\n return (\n <Badge\n variant=\"outline\"\n className={cn('ms-auto px-1.5 py-0', colorClass(badgeColorClasses, item.badgeColor, 'gray'))}\n title={item.badgeTooltip}\n >\n {item.badge}\n </Badge>\n )\n}\n\n/**\n * A navigation link: an Inertia link, or a plain anchor for `openUrlInNewTab()`. Used as an\n * `asChild` target, so it must pass on the classes, data attributes and handlers it receives.\n */\nfunction NavLink({\n item,\n children,\n ...props\n}: { item: NavigationItemSchema; children: ReactNode } & Omit<\n ComponentProps<'a'>,\n 'href' | 'children'\n>) {\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n const attributes = {\n ...props,\n ...extraProps(item.extraAttributes, props.className),\n } as ComponentProps<'a'>\n\n return item.openInNewTab ? (\n <a {...attributes} href={item.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n <NewTabHint />\n </a>\n ) : (\n // Slot passes DOM props; Inertia's Link redefines a few event names, so pass them through untyped.\n <Link\n {...(attributes as Record<string, unknown>)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n >\n {children}\n </Link>\n )\n}\n\n/** Child items (any depth) with their own badges, new-tab links and nested children. */\nfunction NavSubItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <SidebarMenuSubItem>\n <Collapsible defaultOpen={item.active} className=\"group/nav-sub\">\n <CollapsibleTrigger asChild>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <button type=\"button\" {...extraProps(item.extraAttributes, 'w-full')}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/nav-sub:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-sub:rotate-90\" />\n </button>\n </SidebarMenuSubButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </Collapsible>\n </SidebarMenuSubItem>\n )\n }\n\n return (\n <SidebarMenuSubItem>\n <SidebarMenuSubButton asChild isActive={item.active}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n}\n\nfunction NavItem({ item }: { item: NavigationItemSchema }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen={item.active} className=\"group/collapsible\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton\n tooltip={navigationItemText(item)}\n isActive={item.active}\n {...extraProps(item.extraAttributes)}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <NavSubItem key={child.label} item={child} />\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem>\n <SidebarMenuButton asChild isActive={item.active} tooltip={navigationItemText(item)}>\n <NavLink item={item}>\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NavBadge item={item} />\n </NavLink>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\n}\n\n/** A group's items in its flyout menu, children indented under their parent. */\nfunction FlyoutItems({ items }: { items: NavigationItemSchema[] }) {\n return flattenNavigationItems(items).map(({ item, depth }, index) => (\n <DropdownMenuItem\n key={`${depth}-${item.label}-${index}`}\n asChild\n data-active={item.active ? 'true' : undefined}\n >\n <NavLink\n item={item}\n aria-current={item.active ? 'page' : undefined}\n className={cn(\n 'data-[active=true]:bg-accent data-[active=true]:font-medium',\n depth === 1 && 'ps-6',\n depth > 1 && 'ps-9',\n )}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} className=\"truncate\" />\n <NavBadge item={item} />\n </NavLink>\n </DropdownMenuItem>\n ))\n}\n\n/**\n * In the icon-only (collapsed) sidebar, a group with an icon is one button that opens its\n * items in a flyout menu, like Filament. Hidden while the sidebar is expanded.\n */\nfunction NavGroupFlyout({ group }: { group: NavigationGroupSchema }) {\n const direction = useDirection()\n const active = hasActiveNavigationItem(group.items)\n\n return (\n <SidebarMenu className=\"hidden group-data-[collapsible=icon]:flex\" data-nav-flyout=\"\">\n <SidebarMenuItem>\n <DropdownMenu dir={direction}>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton isActive={active}>\n <Icon name={group.icon!} />\n <span>{group.label}</span>\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={direction === 'rtl' ? 'left' : 'right'}\n align=\"start\"\n className=\"min-w-56\"\n >\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n <FlyoutItems items={group.items} />\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction NavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraSidebarAttributes()`; `class` is merged with the group's own.\n const attributes = extraProps(group.extraSidebarAttributes)\n // A labelled group with an icon collapses into a flyout in the icon-only sidebar.\n const flyout = Boolean(group.label && group.icon)\n const content = (\n <SidebarGroupContent className={cn(flyout && 'group-data-[collapsible=icon]:hidden')}>\n <SidebarMenu>\n {group.items.map((item) => (\n <NavItem key={item.label} item={item} />\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n )\n const flyoutMenu = flyout ? <NavGroupFlyout group={group} /> : null\n\n if (!group.label) {\n return <SidebarGroup {...attributes}>{content}</SidebarGroup>\n }\n\n if (!group.collapsible) {\n return (\n <SidebarGroup {...attributes}>\n <SidebarGroupLabel>\n {group.icon && <Icon name={group.icon} className=\"me-1.5\" />}\n {group.label}\n </SidebarGroupLabel>\n {content}\n {flyoutMenu}\n </SidebarGroup>\n )\n }\n\n return (\n <Collapsible\n defaultOpen={!group.collapsed || group.items.some((item) => item.active)}\n className=\"group/nav-group\"\n >\n <SidebarGroup {...attributes}>\n <CollapsibleTrigger asChild>\n <SidebarGroupLabel\n asChild\n className=\"hover:bg-sidebar-accent w-full cursor-pointer justify-between\"\n >\n <button type=\"button\">\n <span className=\"flex items-center gap-1.5\">\n {group.icon && <Icon name={group.icon} />}\n {group.label}\n </span>\n <Icon\n name=\"alfakit::panels.sidebar.group.collapse-button\"\n fallback={ChevronRightIcon}\n className=\"size-3.5 transition-transform group-data-[state=open]/nav-group:rotate-90 rtl:rotate-180 rtl:group-data-[state=open]/nav-group:rotate-90\"\n />\n </button>\n </SidebarGroupLabel>\n </CollapsibleTrigger>\n <CollapsibleContent>{content}</CollapsibleContent>\n {flyoutMenu}\n </SidebarGroup>\n </Collapsible>\n )\n}\n\nexport function AppSidebar() {\n const panel = usePanel()\n const direction = useDirection()\n const t = useT()\n\n return (\n <Sidebar\n side={direction === 'rtl' ? 'right' : 'left'}\n collapsible={\n panel.theme?.design?.layout === 'rail'\n ? 'icon'\n : panel.sidebarFullyCollapsibleOnDesktop\n ? 'offcanvas'\n : panel.sidebarCollapsibleOnDesktop\n ? 'icon'\n : 'none'\n }\n variant={panel.theme?.sidebar === 'flush' ? 'sidebar' : (panel.theme?.sidebar ?? 'inset')}\n >\n <SidebarHeader>\n <Slot name=\"sidebar.start\" />\n <Slot name=\"sidebar.logo.before\" />\n <SidebarMenu>\n <SidebarMenuItem>\n {panel.tenancy?.current ? (\n <>\n <Slot name=\"tenant-menu.before\" />\n <TenantMenu />\n <Slot name=\"tenant-menu.after\" />\n </>\n ) : (\n <SidebarMenuButton size=\"lg\" asChild>\n <div>\n <Brand />\n </div>\n </SidebarMenuButton>\n )}\n </SidebarMenuItem>\n </SidebarMenu>\n <Slot name=\"sidebar.logo.after\" />\n {/* `databaseNotifications(position: 'sidebar')` or `topbar(false)`. */}\n {panel.databaseNotifications?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <NotificationsMenu variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n {/* `globalSearch(position: GlobalSearchPosition::Sidebar)` or `topbar(false)`. */}\n {panel.globalSearch?.position === 'sidebar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <GlobalSearch variant=\"sidebar\" />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.header\" />\n </SidebarHeader>\n <SidebarContent>\n <Slot name=\"sidebar.nav.start\" />\n <nav aria-label={t('sidebar', {}, 'Sidebar')} className=\"contents\">\n {panel.navigation.map((group, index) => (\n <NavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"sidebar.nav.end\" />\n </SidebarContent>\n <SidebarFooter>\n <Slot name=\"sidebar.footer\" />\n {/* `userMenu(position: UserMenuPosition::Topbar)` shows it in the top bar instead. */}\n {panel.userMenu?.position !== 'topbar' && (\n <SidebarMenu>\n <SidebarMenuItem>\n <UserMenu />\n </SidebarMenuItem>\n </SidebarMenu>\n )}\n <Slot name=\"sidebar.end\" />\n </SidebarFooter>\n <SidebarRail />\n </Sidebar>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/components/panel/brand.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The panel's logo (or initial) and name, linking to the panel home. Its own module, so the
|
|
4
|
+
* auth layout doesn't import the sidebar.
|
|
5
|
+
*/
|
|
6
|
+
export declare function Brand({ className }: {
|
|
7
|
+
className?: string;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
//#endregion
|
|
10
|
+
//# sourceMappingURL=brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","names":[],"sources":["../../../src/components/panel/brand.tsx"],"mappings":";;;;;wBAQgB,QAAQ;EAAe;oBAAoB,IAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { usePanel } from "../../context.js";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { Link } from "@inertiajs/react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/panel/brand.tsx
|
|
6
|
+
/**
|
|
7
|
+
* The panel's logo (or initial) and name, linking to the panel home. Its own module, so the
|
|
8
|
+
* auth layout doesn't import the sidebar.
|
|
9
|
+
*/
|
|
10
|
+
function Brand({ className }) {
|
|
11
|
+
const panel = usePanel();
|
|
12
|
+
return /* @__PURE__ */ jsx(Link, {
|
|
13
|
+
href: panel.url ?? "/",
|
|
14
|
+
className: cn("flex items-center gap-2 overflow-hidden", className),
|
|
15
|
+
children: panel.brandLogo ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("img", {
|
|
16
|
+
src: panel.brandLogo,
|
|
17
|
+
alt: panel.brandName,
|
|
18
|
+
style: { height: panel.brandLogoHeight ?? "1.75rem" },
|
|
19
|
+
className: cn("max-w-full object-contain", panel.darkModeBrandLogo && "dark:hidden")
|
|
20
|
+
}), panel.darkModeBrandLogo && /* @__PURE__ */ jsx("img", {
|
|
21
|
+
src: panel.darkModeBrandLogo,
|
|
22
|
+
alt: panel.brandName,
|
|
23
|
+
style: { height: panel.brandLogoHeight ?? "1.75rem" },
|
|
24
|
+
className: "hidden max-w-full object-contain dark:block"
|
|
25
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
26
|
+
className: "bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold",
|
|
27
|
+
children: panel.brandName.charAt(0)
|
|
28
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
29
|
+
className: "truncate text-sm font-semibold group-data-[collapsible=icon]:hidden",
|
|
30
|
+
children: panel.brandName
|
|
31
|
+
})] })
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Brand };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","names":[],"sources":["../../../src/components/panel/brand.tsx"],"sourcesContent":["import { Link } from '@inertiajs/react'\nimport { usePanel } from '../../context'\nimport { cn } from '../../lib/utils'\n\n/**\n * The panel's logo (or initial) and name, linking to the panel home. Its own module, so the\n * auth layout doesn't import the sidebar.\n */\nexport function Brand({ className }: { className?: string }) {\n const panel = usePanel()\n\n return (\n <Link\n href={panel.url ?? '/'}\n className={cn('flex items-center gap-2 overflow-hidden', className)}\n >\n {panel.brandLogo ? (\n <>\n <img\n src={panel.brandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className={cn('max-w-full object-contain', panel.darkModeBrandLogo && 'dark:hidden')}\n />\n {panel.darkModeBrandLogo && (\n <img\n src={panel.darkModeBrandLogo}\n alt={panel.brandName}\n style={{ height: panel.brandLogoHeight ?? '1.75rem' }}\n className=\"hidden max-w-full object-contain dark:block\"\n />\n )}\n </>\n ) : (\n <>\n <span className=\"bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-lg text-sm font-bold\">\n {panel.brandName.charAt(0)}\n </span>\n <span className=\"truncate text-sm font-semibold group-data-[collapsible=icon]:hidden\">\n {panel.brandName}\n </span>\n </>\n )}\n </Link>\n )\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,MAAM,EAAE,aAAqC;CAC3D,MAAM,QAAQ,SAAS;CAEvB,OACE,oBAAC,MAAD;EACE,MAAM,MAAM,OAAO;EACnB,WAAW,GAAG,2CAA2C,SAAS;EAEjE,UAAA,MAAM,YACL,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAW,GAAG,6BAA6B,MAAM,qBAAqB,aAAa;EACpF,CAAA,GACA,MAAM,qBACL,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM;GACX,OAAO,EAAE,QAAQ,MAAM,mBAAmB,UAAU;GACpD,WAAU;EACX,CAAA,CAEH,EAAA,CAAA,IAEF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,UAAU,OAAO,CAAC;EACrB,CAAA,GACN,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM;EACH,CAAA,CACN,EAAA,CAAA;CAEA,CAAA;AAEV"}
|
|
@@ -96,6 +96,7 @@ function GlobalSearch({ variant = "topbar" }) {
|
|
|
96
96
|
children: suffix.text
|
|
97
97
|
}),
|
|
98
98
|
hydrated && suffix?.type === "keyBinding" && /* @__PURE__ */ jsx("kbd", {
|
|
99
|
+
dir: "ltr",
|
|
99
100
|
className: "bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline",
|
|
100
101
|
children: formatKeyBinding(suffix.keyBinding)
|
|
101
102
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global-search.js","names":[],"sources":["../../../src/components/panel/global-search.tsx"],"sourcesContent":["import { formatKeyBinding, globalSearchSuffix, SHORTCUT_IDS, shortcuts } from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { SearchIcon } from 'lucide-react'\nimport { useEffect, useState, type ComponentType } from 'react'\nimport { usePanel, useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { Icon } from '../../lib/icons'\nimport { Button } from '../ui/button'\nimport { Slot } from './slot'\n\ntype PaletteComponent = ComponentType<{ open: boolean; onOpenChange: (open: boolean) => void }>\n\nlet loadedPalette: PaletteComponent | undefined\nlet loadingPalette: Promise<PaletteComponent> | undefined\n\n/** The palette's code: loaded the first time it opens (or ahead, on hover and focus). */\nfunction loadPalette(): Promise<PaletteComponent> {\n loadingPalette ??= import('./global-search-palette').then(\n (module) => (loadedPalette = module.GlobalSearchPalette),\n (error: unknown) => {\n loadingPalette = undefined\n throw error\n },\n )\n\n return loadingPalette\n}\n\nconst preloadPalette = () => void loadPalette().catch(() => undefined)\n\n/**\n * The search field and its command palette (`GlobalSearchPalette`, loaded on first open):\n * global search results plus (with `alfakit.commandPalette`) the page's header actions,\n * panel commands, navigation, \"create\" links, recent records, theme switching and the\n * shortcuts overlay. `variant=\"sidebar\"` is the full-width field in the sidebar header\n * (`globalSearch(position: GlobalSearchPosition::Sidebar)`).\n */\nexport function GlobalSearch({ variant = 'topbar' }: { variant?: 'topbar' | 'sidebar' }) {\n const t = useT()\n const panel = usePanel()\n const hydrated = useHydrated()\n const [open, setOpen] = useState(false)\n // Undefined on the server and during hydration (nothing loads there), so the markup matches.\n const [Palette, setPalette] = useState<PaletteComponent | undefined>(() => loadedPalette)\n const config = panel.globalSearch\n const palette = panel.commandPalette\n const endpoint = config ? panel.endpoints.globalSearch : undefined\n const placeholder =\n config?.placeholder ??\n palette?.placeholder ??\n t('palette.placeholder', {}, 'Type a command or search…')\n // Without global search the palette still opens with ⌘K / Ctrl+K.\n const suffix = globalSearchSuffix(\n config ?? (palette ? { keyBindings: ['mod+k'], placeholder } : undefined),\n )\n const keys = JSON.stringify(config?.keyBindings ?? ['mod+k'])\n const label = t('shortcuts.open_palette', {}, 'Open the command palette')\n\n // The palette's key bindings (`globalSearchKeyBindings()`): essential, so they keep working\n // with `keyboardShortcuts(false)`; users may change them in the shortcuts overlay.\n useEffect(() => {\n if (!config && !palette) return\n\n return shortcuts.register({\n id: SHORTCUT_IDS.palette,\n keys: JSON.parse(keys) as string[],\n label,\n group: 'general',\n essential: true,\n handler: () => setOpen(true),\n })\n }, [config, palette, keys, label])\n\n // Opening before the code has arrived (a click or `mod+k` right after the page loads)\n // keeps `open` set; the palette mounts open once it has loaded.\n useEffect(() => {\n if (!open || Palette) return\n\n let active = true\n\n loadPalette().then(\n (component) => active && setPalette(() => component),\n () => active && setOpen(false),\n )\n\n return () => {\n active = false\n }\n }, [open, Palette])\n\n // A palette opened while its code was still loading closes when the page changes.\n useEffect(() => router.on('navigate', () => setOpen(false)), [])\n\n if ((!config || !endpoint) && !palette) {\n return null\n }\n\n return (\n <>\n <Slot name=\"global-search.before\" />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n data-variant={variant}\n className={\n variant === 'sidebar'\n ? 'text-muted-foreground w-full justify-start gap-2 px-2.5 font-normal group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0'\n : 'text-muted-foreground size-8 justify-center gap-2 px-0 font-normal sm:w-56 sm:justify-start sm:px-2.5'\n }\n onClick={() => setOpen(true)}\n onPointerEnter={preloadPalette}\n onFocus={preloadPalette}\n >\n <Icon name=\"alfakit::panels.global-search.field\" fallback={SearchIcon} className=\"size-4\" />\n <span\n className={\n variant === 'sidebar'\n ? 'flex-1 truncate text-start group-data-[collapsible=icon]:sr-only'\n : 'sr-only sm:not-sr-only sm:flex-1 sm:text-start'\n }\n >\n {placeholder}\n </span>\n {/* `globalSearchFieldSuffix()`, or the first key binding: it depends on the visitor's\n platform (⌘ or Ctrl), so it renders after hydration. */}\n {suffix?.type === 'text' && (\n <span\n data-slot=\"global-search-suffix\"\n className=\"text-muted-foreground hidden text-[10px] sm:inline\"\n >\n {suffix.text}\n </span>\n )}\n {hydrated && suffix?.type === 'keyBinding' && (\n <kbd className=\"bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline\">\n {formatKeyBinding(suffix.keyBinding)}\n </kbd>\n )}\n </Button>\n <Slot name=\"global-search.after\" />\n {/* The dialog's code loads on first open (click or shortcut); hovering or focusing the\n field fetches it ahead. Not rendered on the server, like the closed dialog before it. */}\n {Palette && <Palette open={open} onOpenChange={setOpen} />}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAI;AACJ,IAAI;;AAGJ,SAAS,cAAyC;CAChD,mBAAmB,OAAO,6BAA0B,CAAC,MAClD,WAAY,gBAAgB,OAAO,sBACnC,UAAmB;EAClB,iBAAiB,KAAA;EACjB,MAAM;CACR,CACF;CAEA,OAAO;AACT;AAEA,MAAM,uBAAuB,KAAK,YAAY,CAAC,CAAC,YAAY,KAAA,CAAS;;;;;;;;AASrE,SAAgB,aAAa,EAAE,UAAU,YAAgD;CACvF,MAAM,IAAI,KAAK;CACf,MAAM,QAAQ,SAAS;CACvB,MAAM,WAAW,YAAY;CAC7B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,CAAC,SAAS,cAAc,eAA6C,aAAa;CACxF,MAAM,SAAS,MAAM;CACrB,MAAM,UAAU,MAAM;CACtB,MAAM,WAAW,SAAS,MAAM,UAAU,eAAe,KAAA;CACzD,MAAM,cACJ,QAAQ,eACR,SAAS,eACT,EAAE,uBAAuB,CAAC,GAAG,2BAA2B;CAE1D,MAAM,SAAS,mBACb,WAAW,UAAU;EAAE,aAAa,CAAC,OAAO;EAAG;CAAY,IAAI,KAAA,EACjE;CACA,MAAM,OAAO,KAAK,UAAU,QAAQ,eAAe,CAAC,OAAO,CAAC;CAC5D,MAAM,QAAQ,EAAE,0BAA0B,CAAC,GAAG,0BAA0B;CAIxE,gBAAgB;EACd,IAAI,CAAC,UAAU,CAAC,SAAS;EAEzB,OAAO,UAAU,SAAS;GACxB,IAAI,aAAa;GACjB,MAAM,KAAK,MAAM,IAAI;GACrB;GACA,OAAO;GACP,WAAW;GACX,eAAe,QAAQ,IAAI;EAC7B,CAAC;CACH,GAAG;EAAC;EAAQ;EAAS;EAAM;CAAK,CAAC;CAIjC,gBAAgB;EACd,IAAI,CAAC,QAAQ,SAAS;EAEtB,IAAI,SAAS;EAEb,YAAY,CAAC,CAAC,MACX,cAAc,UAAU,iBAAiB,SAAS,SAC7C,UAAU,QAAQ,KAAK,CAC/B;EAEA,aAAa;GACX,SAAS;EACX;CACF,GAAG,CAAC,MAAM,OAAO,CAAC;CAGlB,gBAAgB,OAAO,GAAG,kBAAkB,QAAQ,KAAK,CAAC,GAAG,CAAC,CAAC;CAE/D,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,SAC7B,OAAO;CAGT,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,MAAD,EAAM,MAAK,uBAAwB,CAAA;EACnC,qBAAC,QAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,gBAAc;GACd,WACE,YAAY,YACR,6LACA;GAEN,eAAe,QAAQ,IAAI;GAC3B,gBAAgB;GAChB,SAAS;GAZX,UAAA;IAcE,oBAAC,MAAD;KAAM,MAAK;KAAsC,UAAU;KAAY,WAAU;IAAU,CAAA;IAC3F,oBAAC,QAAD;KACE,WACE,YAAY,YACR,qEACA;KAGL,UAAA;IACG,CAAA;IAGL,QAAQ,SAAS,UAChB,oBAAC,QAAD;KACE,aAAU;KACV,WAAU;KAET,UAAA,OAAO;IACJ,CAAA;IAEP,YAAY,QAAQ,SAAS,gBAC5B,oBAAC,OAAD;KAAK,WAAU;
|
|
1
|
+
{"version":3,"file":"global-search.js","names":[],"sources":["../../../src/components/panel/global-search.tsx"],"sourcesContent":["import { formatKeyBinding, globalSearchSuffix, SHORTCUT_IDS, shortcuts } from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { SearchIcon } from 'lucide-react'\nimport { useEffect, useState, type ComponentType } from 'react'\nimport { usePanel, useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { Icon } from '../../lib/icons'\nimport { Button } from '../ui/button'\nimport { Slot } from './slot'\n\ntype PaletteComponent = ComponentType<{ open: boolean; onOpenChange: (open: boolean) => void }>\n\nlet loadedPalette: PaletteComponent | undefined\nlet loadingPalette: Promise<PaletteComponent> | undefined\n\n/** The palette's code: loaded the first time it opens (or ahead, on hover and focus). */\nfunction loadPalette(): Promise<PaletteComponent> {\n loadingPalette ??= import('./global-search-palette').then(\n (module) => (loadedPalette = module.GlobalSearchPalette),\n (error: unknown) => {\n loadingPalette = undefined\n throw error\n },\n )\n\n return loadingPalette\n}\n\nconst preloadPalette = () => void loadPalette().catch(() => undefined)\n\n/**\n * The search field and its command palette (`GlobalSearchPalette`, loaded on first open):\n * global search results plus (with `alfakit.commandPalette`) the page's header actions,\n * panel commands, navigation, \"create\" links, recent records, theme switching and the\n * shortcuts overlay. `variant=\"sidebar\"` is the full-width field in the sidebar header\n * (`globalSearch(position: GlobalSearchPosition::Sidebar)`).\n */\nexport function GlobalSearch({ variant = 'topbar' }: { variant?: 'topbar' | 'sidebar' }) {\n const t = useT()\n const panel = usePanel()\n const hydrated = useHydrated()\n const [open, setOpen] = useState(false)\n // Undefined on the server and during hydration (nothing loads there), so the markup matches.\n const [Palette, setPalette] = useState<PaletteComponent | undefined>(() => loadedPalette)\n const config = panel.globalSearch\n const palette = panel.commandPalette\n const endpoint = config ? panel.endpoints.globalSearch : undefined\n const placeholder =\n config?.placeholder ??\n palette?.placeholder ??\n t('palette.placeholder', {}, 'Type a command or search…')\n // Without global search the palette still opens with ⌘K / Ctrl+K.\n const suffix = globalSearchSuffix(\n config ?? (palette ? { keyBindings: ['mod+k'], placeholder } : undefined),\n )\n const keys = JSON.stringify(config?.keyBindings ?? ['mod+k'])\n const label = t('shortcuts.open_palette', {}, 'Open the command palette')\n\n // The palette's key bindings (`globalSearchKeyBindings()`): essential, so they keep working\n // with `keyboardShortcuts(false)`; users may change them in the shortcuts overlay.\n useEffect(() => {\n if (!config && !palette) return\n\n return shortcuts.register({\n id: SHORTCUT_IDS.palette,\n keys: JSON.parse(keys) as string[],\n label,\n group: 'general',\n essential: true,\n handler: () => setOpen(true),\n })\n }, [config, palette, keys, label])\n\n // Opening before the code has arrived (a click or `mod+k` right after the page loads)\n // keeps `open` set; the palette mounts open once it has loaded.\n useEffect(() => {\n if (!open || Palette) return\n\n let active = true\n\n loadPalette().then(\n (component) => active && setPalette(() => component),\n () => active && setOpen(false),\n )\n\n return () => {\n active = false\n }\n }, [open, Palette])\n\n // A palette opened while its code was still loading closes when the page changes.\n useEffect(() => router.on('navigate', () => setOpen(false)), [])\n\n if ((!config || !endpoint) && !palette) {\n return null\n }\n\n return (\n <>\n <Slot name=\"global-search.before\" />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n data-variant={variant}\n className={\n variant === 'sidebar'\n ? 'text-muted-foreground w-full justify-start gap-2 px-2.5 font-normal group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0'\n : 'text-muted-foreground size-8 justify-center gap-2 px-0 font-normal sm:w-56 sm:justify-start sm:px-2.5'\n }\n onClick={() => setOpen(true)}\n onPointerEnter={preloadPalette}\n onFocus={preloadPalette}\n >\n <Icon name=\"alfakit::panels.global-search.field\" fallback={SearchIcon} className=\"size-4\" />\n <span\n className={\n variant === 'sidebar'\n ? 'flex-1 truncate text-start group-data-[collapsible=icon]:sr-only'\n : 'sr-only sm:not-sr-only sm:flex-1 sm:text-start'\n }\n >\n {placeholder}\n </span>\n {/* `globalSearchFieldSuffix()`, or the first key binding: it depends on the visitor's\n platform (⌘ or Ctrl), so it renders after hydration. */}\n {suffix?.type === 'text' && (\n <span\n data-slot=\"global-search-suffix\"\n className=\"text-muted-foreground hidden text-[10px] sm:inline\"\n >\n {suffix.text}\n </span>\n )}\n {hydrated && suffix?.type === 'keyBinding' && (\n <kbd dir=\"ltr\" className=\"bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline\">\n {formatKeyBinding(suffix.keyBinding)}\n </kbd>\n )}\n </Button>\n <Slot name=\"global-search.after\" />\n {/* The dialog's code loads on first open (click or shortcut); hovering or focusing the\n field fetches it ahead. Not rendered on the server, like the closed dialog before it. */}\n {Palette && <Palette open={open} onOpenChange={setOpen} />}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAI;AACJ,IAAI;;AAGJ,SAAS,cAAyC;CAChD,mBAAmB,OAAO,6BAA0B,CAAC,MAClD,WAAY,gBAAgB,OAAO,sBACnC,UAAmB;EAClB,iBAAiB,KAAA;EACjB,MAAM;CACR,CACF;CAEA,OAAO;AACT;AAEA,MAAM,uBAAuB,KAAK,YAAY,CAAC,CAAC,YAAY,KAAA,CAAS;;;;;;;;AASrE,SAAgB,aAAa,EAAE,UAAU,YAAgD;CACvF,MAAM,IAAI,KAAK;CACf,MAAM,QAAQ,SAAS;CACvB,MAAM,WAAW,YAAY;CAC7B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,CAAC,SAAS,cAAc,eAA6C,aAAa;CACxF,MAAM,SAAS,MAAM;CACrB,MAAM,UAAU,MAAM;CACtB,MAAM,WAAW,SAAS,MAAM,UAAU,eAAe,KAAA;CACzD,MAAM,cACJ,QAAQ,eACR,SAAS,eACT,EAAE,uBAAuB,CAAC,GAAG,2BAA2B;CAE1D,MAAM,SAAS,mBACb,WAAW,UAAU;EAAE,aAAa,CAAC,OAAO;EAAG;CAAY,IAAI,KAAA,EACjE;CACA,MAAM,OAAO,KAAK,UAAU,QAAQ,eAAe,CAAC,OAAO,CAAC;CAC5D,MAAM,QAAQ,EAAE,0BAA0B,CAAC,GAAG,0BAA0B;CAIxE,gBAAgB;EACd,IAAI,CAAC,UAAU,CAAC,SAAS;EAEzB,OAAO,UAAU,SAAS;GACxB,IAAI,aAAa;GACjB,MAAM,KAAK,MAAM,IAAI;GACrB;GACA,OAAO;GACP,WAAW;GACX,eAAe,QAAQ,IAAI;EAC7B,CAAC;CACH,GAAG;EAAC;EAAQ;EAAS;EAAM;CAAK,CAAC;CAIjC,gBAAgB;EACd,IAAI,CAAC,QAAQ,SAAS;EAEtB,IAAI,SAAS;EAEb,YAAY,CAAC,CAAC,MACX,cAAc,UAAU,iBAAiB,SAAS,SAC7C,UAAU,QAAQ,KAAK,CAC/B;EAEA,aAAa;GACX,SAAS;EACX;CACF,GAAG,CAAC,MAAM,OAAO,CAAC;CAGlB,gBAAgB,OAAO,GAAG,kBAAkB,QAAQ,KAAK,CAAC,GAAG,CAAC,CAAC;CAE/D,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,SAC7B,OAAO;CAGT,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,MAAD,EAAM,MAAK,uBAAwB,CAAA;EACnC,qBAAC,QAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,gBAAc;GACd,WACE,YAAY,YACR,6LACA;GAEN,eAAe,QAAQ,IAAI;GAC3B,gBAAgB;GAChB,SAAS;GAZX,UAAA;IAcE,oBAAC,MAAD;KAAM,MAAK;KAAsC,UAAU;KAAY,WAAU;IAAU,CAAA;IAC3F,oBAAC,QAAD;KACE,WACE,YAAY,YACR,qEACA;KAGL,UAAA;IACG,CAAA;IAGL,QAAQ,SAAS,UAChB,oBAAC,QAAD;KACE,aAAU;KACV,WAAU;KAET,UAAA,OAAO;IACJ,CAAA;IAEP,YAAY,QAAQ,SAAS,gBAC5B,oBAAC,OAAD;KAAK,KAAI;KAAM,WAAU;KACtB,UAAA,iBAAiB,OAAO,UAAU;IAChC,CAAA;GAED;;EACR,oBAAC,MAAD,EAAM,MAAK,sBAAuB,CAAA;EAGjC,WAAW,oBAAC,SAAD;GAAe;GAAM,cAAc;EAAU,CAAA;CACzD,EAAA,CAAA;AAEN"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Brand } from "./brand.js";
|
|
2
|
+
import { AppSidebar } from "./app-sidebar.js";
|
|
2
3
|
import { BottomNav } from "./bottom-nav.js";
|
|
3
4
|
import { DebugPanelSlot } from "./debug-panel-slot.js";
|
|
4
5
|
import { DebugPanel, DebugTreeNode } from "./debug-panel.js";
|
|
@@ -21,6 +21,7 @@ function ShortcutKeys({ binding, className }) {
|
|
|
21
21
|
className: "text-muted-foreground text-[10px]",
|
|
22
22
|
children: t("shortcuts.then", {}, "then")
|
|
23
23
|
}), /* @__PURE__ */ jsx("kbd", {
|
|
24
|
+
dir: "ltr",
|
|
24
25
|
className: "bg-muted text-muted-foreground rounded border px-1.5 font-mono text-[10px] leading-5",
|
|
25
26
|
children: step
|
|
26
27
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shortcut-keys.js","names":[],"sources":["../../../src/components/panel/shortcut-keys.tsx"],"sourcesContent":["import { shortcutSteps } from '@alfakit/core'\nimport { useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { cn } from '../../lib/utils'\n\n/**\n * A key binding as `<kbd>` keys (`G` then `D`, `⌘K`). The keys depend on the visitor's\n * platform (⌘ or Ctrl), so they render after hydration.\n */\nexport function ShortcutKeys({ binding, className }: { binding: string; className?: string }) {\n const t = useT()\n const hydrated = useHydrated()\n\n if (!hydrated) return null\n\n const steps = shortcutSteps(binding)\n\n return (\n <span data-slot=\"shortcut-keys\" className={cn('inline-flex items-center gap-1', className)}>\n {steps.map((step, index) => (\n <span key={index} className=\"inline-flex items-center gap-1\">\n {index > 0 && (\n <span className=\"text-muted-foreground text-[10px]\">\n {t('shortcuts.then', {}, 'then')}\n </span>\n )}\n <kbd
|
|
1
|
+
{"version":3,"file":"shortcut-keys.js","names":[],"sources":["../../../src/components/panel/shortcut-keys.tsx"],"sourcesContent":["import { shortcutSteps } from '@alfakit/core'\nimport { useT } from '../../context'\nimport { useHydrated } from '../../hooks/use-hydrated'\nimport { cn } from '../../lib/utils'\n\n/**\n * A key binding as `<kbd>` keys (`G` then `D`, `⌘K`). The keys depend on the visitor's\n * platform (⌘ or Ctrl), so they render after hydration.\n */\nexport function ShortcutKeys({ binding, className }: { binding: string; className?: string }) {\n const t = useT()\n const hydrated = useHydrated()\n\n if (!hydrated) return null\n\n const steps = shortcutSteps(binding)\n\n return (\n <span data-slot=\"shortcut-keys\" className={cn('inline-flex items-center gap-1', className)}>\n {steps.map((step, index) => (\n <span key={index} className=\"inline-flex items-center gap-1\">\n {index > 0 && (\n <span className=\"text-muted-foreground text-[10px]\">\n {t('shortcuts.then', {}, 'then')}\n </span>\n )}\n <kbd\n dir=\"ltr\"\n className=\"bg-muted text-muted-foreground rounded border px-1.5 font-mono text-[10px] leading-5\"\n >\n {step}\n </kbd>\n </span>\n ))}\n </span>\n )\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,aAAa,EAAE,SAAS,aAAsD;CAC5F,MAAM,IAAI,KAAK;CAGf,IAAI,CAFa,YAEL,GAAG,OAAO;CAEtB,MAAM,QAAQ,cAAc,OAAO;CAEnC,OACE,oBAAC,QAAD;EAAM,aAAU;EAAgB,WAAW,GAAG,kCAAkC,SAAS;EACtF,UAAA,MAAM,KAAK,MAAM,UAChB,qBAAC,QAAD;GAAkB,WAAU;GAA5B,UAAA,CACG,QAAQ,KACP,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA,EAAE,kBAAkB,CAAC,GAAG,MAAM;GAC3B,CAAA,GAER,oBAAC,OAAD;IACE,KAAI;IACJ,WAAU;IAET,UAAA;GACE,CAAA,CACD;EAZK,GAAA,KAYL,CACP;CACG,CAAA;AAEV"}
|
|
@@ -161,7 +161,7 @@ function TenantMenu({ variant = "sidebar" }) {
|
|
|
161
161
|
fallback: SettingsIcon
|
|
162
162
|
}),
|
|
163
163
|
" ",
|
|
164
|
-
t("tenancy.profile", {}, "Settings")
|
|
164
|
+
tenancy.profileLabel ?? t("tenancy.profile", {}, "Settings")
|
|
165
165
|
]
|
|
166
166
|
})
|
|
167
167
|
}),
|
|
@@ -183,7 +183,7 @@ function TenantMenu({ variant = "sidebar" }) {
|
|
|
183
183
|
fallback: PlusIcon
|
|
184
184
|
}),
|
|
185
185
|
" ",
|
|
186
|
-
t("tenancy.register", {}, "New")
|
|
186
|
+
tenancy.registrationLabel ?? t("tenancy.register", {}, "New")
|
|
187
187
|
]
|
|
188
188
|
})
|
|
189
189
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-menu.js","names":[],"sources":["../../../src/components/panel/tenant-menu.tsx"],"sourcesContent":["import { filterTenants, initials, tenantNameText } from '@alfakit/core'\nimport { Link, router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon, PlusIcon, SearchIcon, SettingsIcon } from 'lucide-react'\nimport { useState } from 'react'\nimport { usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { SidebarMenuButton } from '../ui/sidebar'\nimport { MenuItemEntries, MenuItemEntry } from './menu-item'\nimport { TenantName } from './nav-label'\n\n/**\n * The tenant switcher: a sidebar header button, or a compact button in the top bar of the\n * `topbar` layout (`variant=\"topbar\"`), where the store name shows from `lg` up.\n */\nexport function TenantMenu({ variant = 'sidebar' }: { variant?: 'sidebar' | 'topbar' }) {\n const t = useT()\n const { tenancy, brandName } = usePanel()\n const [search, setSearch] = useState('')\n\n if (!tenancy || !tenancy.current) {\n return null\n }\n\n const current = tenancy.current\n // `tenantSwitcher(false)` sends no tenants; `searchableTenantMenu()` adds a search field.\n const tenants = tenancy.searchable ? filterTenants(tenancy.tenants, search) : tenancy.tenants\n const hasSwitcher = tenancy.switcher !== false && tenancy.tenants.length > 0\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n {variant === 'topbar' ? (\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n className=\"hover:bg-accent data-[state=open]:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <Avatar className=\"size-6 rounded-md\">\n {current.avatar && <AvatarImage src={current.avatar} alt=\"\" />}\n <AvatarFallback className=\"rounded-md text-[10px]\">\n {initials(tenantNameText(current))}\n </AvatarFallback>\n </Avatar>\n <span className=\"sr-only min-w-0 truncate lg:not-sr-only lg:grid lg:text-start lg:leading-tight\">\n {current.label && (\n <span data-slot=\"tenant-menu-label\" className=\"text-muted-foreground text-[10px]\">\n {current.label}{' '}\n </span>\n )}\n <TenantName tenant={current} className=\"truncate\" />\n </span>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"text-muted-foreground size-4 shrink-0\"\n />\n </button>\n ) : (\n <SidebarMenuButton size=\"lg\" className=\"data-[state=open]:bg-sidebar-accent\">\n <Avatar className=\"size-8 rounded-lg\">\n {current.avatar && <AvatarImage src={current.avatar} alt={tenantNameText(current)} />}\n <AvatarFallback className=\"rounded-lg\">\n {initials(tenantNameText(current))}\n </AvatarFallback>\n </Avatar>\n <div className=\"grid flex-1 text-start text-sm leading-tight\">\n {/* `HasCurrentTenantLabel`: a caption above the name instead of the brand. */}\n {current.label && (\n <span\n data-slot=\"tenant-menu-label\"\n className=\"text-muted-foreground truncate text-xs\"\n >\n {current.label}\n </span>\n )}\n <TenantName tenant={current} className=\"truncate font-medium\" />\n {!current.label && (\n <span className=\"text-muted-foreground truncate text-xs\">{brandName}</span>\n )}\n </div>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"ms-auto size-4\"\n />\n </SidebarMenuButton>\n )}\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"min-w-56 rounded-lg\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n >\n {hasSwitcher && (\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n {t('tenancy.switch', {}, 'Switch')}\n </DropdownMenuLabel>\n )}\n {hasSwitcher && tenancy.searchable && (\n <div data-slot=\"tenant-menu-search\" className=\"relative px-1 pb-1\">\n <SearchIcon\n className=\"text-muted-foreground pointer-events-none absolute start-3 top-1/2 size-3.5 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n // Keep the menu's type-ahead from taking the keys.\n onKeyDown={(event) => event.stopPropagation()}\n placeholder={t('tenancy.search', {}, 'Search')}\n aria-label={t('tenancy.search', {}, 'Search')}\n className=\"border-input focus-visible:ring-ring/50 h-8 w-full rounded-md border bg-transparent ps-7 pe-2 text-sm outline-none focus-visible:ring-[3px]\"\n />\n </div>\n )}\n {hasSwitcher && tenancy.searchable && tenants.length === 0 && (\n <p className=\"text-muted-foreground px-2 py-1.5 text-sm\">\n {t('no_results', {}, 'No results.')}\n </p>\n )}\n {tenants.map((tenant) => (\n <DropdownMenuItem key={String(tenant.id)} onSelect={() => router.visit(tenant.url)}>\n <Avatar className=\"size-6 rounded-sm\">\n {tenant.avatar && <AvatarImage src={tenant.avatar} alt={tenantNameText(tenant)} />}\n <AvatarFallback className=\"rounded-sm text-[10px]\">\n {initials(tenantNameText(tenant))}\n </AvatarFallback>\n </Avatar>\n <TenantName tenant={tenant} className=\"flex-1 truncate\" />\n {String(tenant.id) === String(current.id) && <CheckIcon className=\"size-4\" />}\n </DropdownMenuItem>\n ))}\n {hasSwitcher && (tenancy.registrationUrl || tenancy.profileUrl || tenancy.menu?.length) && (\n <DropdownMenuSeparator />\n )}\n {tenancy.profile ? (\n <MenuItemEntry item={tenancy.profile} menu=\"tenantMenu\" />\n ) : (\n tenancy.profileUrl && (\n <DropdownMenuItem asChild>\n <Link href={tenancy.profileUrl} className=\"w-full\">\n <Icon name=\"alfakit::panels.tenant-menu.profile-button\" fallback={SettingsIcon} />{' '}\n {t('tenancy.profile', {}, 'Settings')}\n </Link>\n </DropdownMenuItem>\n )\n )}\n {tenancy.menu && <MenuItemEntries items={tenancy.menu} menu=\"tenantMenu\" />}\n {tenancy.registration ? (\n <MenuItemEntry item={tenancy.registration} menu=\"tenantMenu\" />\n ) : (\n tenancy.registrationUrl && (\n <DropdownMenuItem asChild>\n <Link href={tenancy.registrationUrl} className=\"w-full\">\n <Icon name=\"alfakit::panels.tenant-menu.registration-button\" fallback={PlusIcon} />{' '}\n {t('tenancy.register', {}, 'New')}\n </Link>\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tenant-menu.js","names":[],"sources":["../../../src/components/panel/tenant-menu.tsx"],"sourcesContent":["import { filterTenants, initials, tenantNameText } from '@alfakit/core'\nimport { Link, router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon, PlusIcon, SearchIcon, SettingsIcon } from 'lucide-react'\nimport { useState } from 'react'\nimport { usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/dropdown-menu'\nimport { SidebarMenuButton } from '../ui/sidebar'\nimport { MenuItemEntries, MenuItemEntry } from './menu-item'\nimport { TenantName } from './nav-label'\n\n/**\n * The tenant switcher: a sidebar header button, or a compact button in the top bar of the\n * `topbar` layout (`variant=\"topbar\"`), where the store name shows from `lg` up.\n */\nexport function TenantMenu({ variant = 'sidebar' }: { variant?: 'sidebar' | 'topbar' }) {\n const t = useT()\n const { tenancy, brandName } = usePanel()\n const [search, setSearch] = useState('')\n\n if (!tenancy || !tenancy.current) {\n return null\n }\n\n const current = tenancy.current\n // `tenantSwitcher(false)` sends no tenants; `searchableTenantMenu()` adds a search field.\n const tenants = tenancy.searchable ? filterTenants(tenancy.tenants, search) : tenancy.tenants\n const hasSwitcher = tenancy.switcher !== false && tenancy.tenants.length > 0\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n {variant === 'topbar' ? (\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n className=\"hover:bg-accent data-[state=open]:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <Avatar className=\"size-6 rounded-md\">\n {current.avatar && <AvatarImage src={current.avatar} alt=\"\" />}\n <AvatarFallback className=\"rounded-md text-[10px]\">\n {initials(tenantNameText(current))}\n </AvatarFallback>\n </Avatar>\n <span className=\"sr-only min-w-0 truncate lg:not-sr-only lg:grid lg:text-start lg:leading-tight\">\n {current.label && (\n <span data-slot=\"tenant-menu-label\" className=\"text-muted-foreground text-[10px]\">\n {current.label}{' '}\n </span>\n )}\n <TenantName tenant={current} className=\"truncate\" />\n </span>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"text-muted-foreground size-4 shrink-0\"\n />\n </button>\n ) : (\n <SidebarMenuButton size=\"lg\" className=\"data-[state=open]:bg-sidebar-accent\">\n <Avatar className=\"size-8 rounded-lg\">\n {current.avatar && <AvatarImage src={current.avatar} alt={tenantNameText(current)} />}\n <AvatarFallback className=\"rounded-lg\">\n {initials(tenantNameText(current))}\n </AvatarFallback>\n </Avatar>\n <div className=\"grid flex-1 text-start text-sm leading-tight\">\n {/* `HasCurrentTenantLabel`: a caption above the name instead of the brand. */}\n {current.label && (\n <span\n data-slot=\"tenant-menu-label\"\n className=\"text-muted-foreground truncate text-xs\"\n >\n {current.label}\n </span>\n )}\n <TenantName tenant={current} className=\"truncate font-medium\" />\n {!current.label && (\n <span className=\"text-muted-foreground truncate text-xs\">{brandName}</span>\n )}\n </div>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"ms-auto size-4\"\n />\n </SidebarMenuButton>\n )}\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"min-w-56 rounded-lg\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n >\n {hasSwitcher && (\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n {t('tenancy.switch', {}, 'Switch')}\n </DropdownMenuLabel>\n )}\n {hasSwitcher && tenancy.searchable && (\n <div data-slot=\"tenant-menu-search\" className=\"relative px-1 pb-1\">\n <SearchIcon\n className=\"text-muted-foreground pointer-events-none absolute start-3 top-1/2 size-3.5 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n // Keep the menu's type-ahead from taking the keys.\n onKeyDown={(event) => event.stopPropagation()}\n placeholder={t('tenancy.search', {}, 'Search')}\n aria-label={t('tenancy.search', {}, 'Search')}\n className=\"border-input focus-visible:ring-ring/50 h-8 w-full rounded-md border bg-transparent ps-7 pe-2 text-sm outline-none focus-visible:ring-[3px]\"\n />\n </div>\n )}\n {hasSwitcher && tenancy.searchable && tenants.length === 0 && (\n <p className=\"text-muted-foreground px-2 py-1.5 text-sm\">\n {t('no_results', {}, 'No results.')}\n </p>\n )}\n {tenants.map((tenant) => (\n <DropdownMenuItem key={String(tenant.id)} onSelect={() => router.visit(tenant.url)}>\n <Avatar className=\"size-6 rounded-sm\">\n {tenant.avatar && <AvatarImage src={tenant.avatar} alt={tenantNameText(tenant)} />}\n <AvatarFallback className=\"rounded-sm text-[10px]\">\n {initials(tenantNameText(tenant))}\n </AvatarFallback>\n </Avatar>\n <TenantName tenant={tenant} className=\"flex-1 truncate\" />\n {String(tenant.id) === String(current.id) && <CheckIcon className=\"size-4\" />}\n </DropdownMenuItem>\n ))}\n {hasSwitcher && (tenancy.registrationUrl || tenancy.profileUrl || tenancy.menu?.length) && (\n <DropdownMenuSeparator />\n )}\n {tenancy.profile ? (\n <MenuItemEntry item={tenancy.profile} menu=\"tenantMenu\" />\n ) : (\n tenancy.profileUrl && (\n <DropdownMenuItem asChild>\n <Link href={tenancy.profileUrl} className=\"w-full\">\n <Icon name=\"alfakit::panels.tenant-menu.profile-button\" fallback={SettingsIcon} />{' '}\n {tenancy.profileLabel ?? t('tenancy.profile', {}, 'Settings')}\n </Link>\n </DropdownMenuItem>\n )\n )}\n {tenancy.menu && <MenuItemEntries items={tenancy.menu} menu=\"tenantMenu\" />}\n {tenancy.registration ? (\n <MenuItemEntry item={tenancy.registration} menu=\"tenantMenu\" />\n ) : (\n tenancy.registrationUrl && (\n <DropdownMenuItem asChild>\n <Link href={tenancy.registrationUrl} className=\"w-full\">\n <Icon name=\"alfakit::panels.tenant-menu.registration-button\" fallback={PlusIcon} />{' '}\n {tenancy.registrationLabel ?? t('tenancy.register', {}, 'New')}\n </Link>\n </DropdownMenuItem>\n )\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuBA,SAAgB,WAAW,EAAE,UAAU,aAAiD;CACtF,MAAM,IAAI,KAAK;CACf,MAAM,EAAE,SAAS,cAAc,SAAS;CACxC,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CAEvC,IAAI,CAAC,WAAW,CAAC,QAAQ,SACvB,OAAO;CAGT,MAAM,UAAU,QAAQ;CAExB,MAAM,UAAU,QAAQ,aAAa,cAAc,QAAQ,SAAS,MAAM,IAAI,QAAQ;CACtF,MAAM,cAAc,QAAQ,aAAa,SAAS,QAAQ,QAAQ,SAAS;CAE3E,OACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,qBAAD;EAAqB,SAAA;EAClB,UAAA,YAAY,WACX,qBAAC,UAAD;GACE,MAAK;GACL,aAAU;GACV,WAAU;GAHZ,UAAA;IAKE,qBAAC,QAAD;KAAQ,WAAU;KAAlB,UAAA,CACG,QAAQ,UAAU,oBAAC,aAAD;MAAa,KAAK,QAAQ;MAAQ,KAAI;KAAI,CAAA,GAC7D,oBAAC,gBAAD;MAAgB,WAAU;MACvB,UAAA,SAAS,eAAe,OAAO,CAAC;KACnB,CAAA,CACV;;IACR,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACG,QAAQ,SACP,qBAAC,QAAD;MAAM,aAAU;MAAoB,WAAU;MAA9C,UAAA,CACG,QAAQ,OAAO,GACZ;KAER,CAAA,GAAA,oBAAC,YAAD;MAAY,QAAQ;MAAS,WAAU;KAAY,CAAA,CAC/C;;IACN,oBAAC,MAAD;KACE,MAAK;KACL,UAAU;KACV,WAAU;IACX,CAAA;GACK;EAER,CAAA,IAAA,qBAAC,mBAAD;GAAmB,MAAK;GAAK,WAAU;GAAvC,UAAA;IACE,qBAAC,QAAD;KAAQ,WAAU;KAAlB,UAAA,CACG,QAAQ,UAAU,oBAAC,aAAD;MAAa,KAAK,QAAQ;MAAQ,KAAK,eAAe,OAAO;KAAI,CAAA,GACpF,oBAAC,gBAAD;MAAgB,WAAU;MACvB,UAAA,SAAS,eAAe,OAAO,CAAC;KACnB,CAAA,CACV;;IACR,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MAEG,QAAQ,SACP,oBAAC,QAAD;OACE,aAAU;OACV,WAAU;OAET,UAAA,QAAQ;MACL,CAAA;MAER,oBAAC,YAAD;OAAY,QAAQ;OAAS,WAAU;MAAwB,CAAA;MAC9D,CAAC,QAAQ,SACR,oBAAC,QAAD;OAAM,WAAU;OAA0C,UAAA;MAAgB,CAAA;KAEzE;;IACL,oBAAC,MAAD;KACE,MAAK;KACL,UAAU;KACV,WAAU;IACX,CAAA;GACgB;;CAEF,CAAA,GACrB,qBAAC,qBAAD;EACE,WAAU;EACV,MAAK;EACL,OAAM;EACN,YAAY;EAJd,UAAA;GAMG,eACC,oBAAC,mBAAD;IAAmB,WAAU;IAC1B,UAAA,EAAE,kBAAkB,CAAC,GAAG,QAAQ;GAChB,CAAA;GAEpB,eAAe,QAAQ,cACtB,qBAAC,OAAD;IAAK,aAAU;IAAqB,WAAU;IAA9C,UAAA,CACE,oBAAC,YAAD;KACE,WAAU;KACV,eAAY;IACb,CAAA,GACD,oBAAC,SAAD;KACE,MAAK;KACL,OAAO;KACP,WAAW,UAAU,UAAU,MAAM,OAAO,KAAK;KAEjD,YAAY,UAAU,MAAM,gBAAgB;KAC5C,aAAa,EAAE,kBAAkB,CAAC,GAAG,QAAQ;KAC7C,cAAY,EAAE,kBAAkB,CAAC,GAAG,QAAQ;KAC5C,WAAU;IACX,CAAA,CACE;;GAEN,eAAe,QAAQ,cAAc,QAAQ,WAAW,KACvD,oBAAC,KAAD;IAAG,WAAU;IACV,UAAA,EAAE,cAAc,CAAC,GAAG,aAAa;GACjC,CAAA;GAEJ,QAAQ,KAAK,WACZ,qBAAC,kBAAD;IAA0C,gBAAgB,OAAO,MAAM,OAAO,GAAG;IAAjF,UAAA;KACE,qBAAC,QAAD;MAAQ,WAAU;MAAlB,UAAA,CACG,OAAO,UAAU,oBAAC,aAAD;OAAa,KAAK,OAAO;OAAQ,KAAK,eAAe,MAAM;MAAI,CAAA,GACjF,oBAAC,gBAAD;OAAgB,WAAU;OACvB,UAAA,SAAS,eAAe,MAAM,CAAC;MAClB,CAAA,CACV;;KACR,oBAAC,YAAD;MAAoB;MAAQ,WAAU;KAAmB,CAAA;KACxD,OAAO,OAAO,EAAE,MAAM,OAAO,QAAQ,EAAE,KAAK,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA;IAC5D;GATK,GAAA,OAAO,OAAO,EAAE,CASrB,CACnB;GACA,gBAAgB,QAAQ,mBAAmB,QAAQ,cAAc,QAAQ,MAAM,WAC9E,oBAAC,uBAAD,CAAwB,CAAA;GAEzB,QAAQ,UACP,oBAAC,eAAD;IAAe,MAAM,QAAQ;IAAS,MAAK;GAAc,CAAA,IAEzD,QAAQ,cACN,oBAAC,kBAAD;IAAkB,SAAA;IAChB,UAAA,qBAAC,MAAD;KAAM,MAAM,QAAQ;KAAY,WAAU;KAA1C,UAAA;MACE,oBAAC,MAAD;OAAM,MAAK;OAA6C,UAAU;MAAe,CAAA;MAAE;MAClF,QAAQ,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,UAAU;KACxD;;GACU,CAAA;GAGrB,QAAQ,QAAQ,oBAAC,iBAAD;IAAiB,OAAO,QAAQ;IAAM,MAAK;GAAc,CAAA;GACzE,QAAQ,eACP,oBAAC,eAAD;IAAe,MAAM,QAAQ;IAAc,MAAK;GAAc,CAAA,IAE9D,QAAQ,mBACN,oBAAC,kBAAD;IAAkB,SAAA;IAChB,UAAA,qBAAC,MAAD;KAAM,MAAM,QAAQ;KAAiB,WAAU;KAA/C,UAAA;MACE,oBAAC,MAAD;OAAM,MAAK;OAAkD,UAAU;MAAW,CAAA;MAAE;MACnF,QAAQ,qBAAqB,EAAE,oBAAoB,CAAC,GAAG,KAAK;KACzD;;GACU,CAAA;EAGH;CACT,CAAA,CAAA,EAAA,CAAA;AAElB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { usePanel, useT } from "../../context.js";
|
|
2
2
|
import { Slot } from "./slot.js";
|
|
3
|
+
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
|
|
3
4
|
import { NotificationsMenu } from "../notifications/notifications-menu.js";
|
|
4
5
|
import { Separator } from "../ui/separator.js";
|
|
5
6
|
import { SidebarTrigger } from "../ui/sidebar.js";
|
|
6
7
|
import { GlobalSearch } from "./global-search.js";
|
|
7
8
|
import { TopbarLocaleSwitcher } from "./locale-switcher.js";
|
|
8
9
|
import { UserMenu } from "./user-menu.js";
|
|
9
|
-
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
|
|
10
10
|
import { DebugPanelSlot } from "./debug-panel-slot.js";
|
|
11
11
|
import { ThemeToggle } from "./theme-toggle.js";
|
|
12
12
|
import { Link } from "@inertiajs/react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-records-pill.d.ts","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"mappings":";;;;;;;wBAYgB,eACd,MAAM,+BACN,gBACA;EAAW;EAAmB,UAAU;IAAgB,MAAM;;IAC7D;;
|
|
1
|
+
{"version":3,"file":"live-records-pill.d.ts","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"mappings":";;;;;;;wBAYgB,eACd,MAAM,+BACN,gBACA;EAAW;EAAmB,UAAU;IAAgB,MAAM;;IAC7D;;wBAyBa,kBAAkB;EAAU,MAAM;oBAAa,IAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useChoice, usePollComponent } from "../../context.js";
|
|
1
|
+
import { useChoice, usePollComponent, useRefreshComponents } from "../../context.js";
|
|
2
2
|
import { Button } from "../ui/button.js";
|
|
3
3
|
import { useStore } from "../../hooks/use-store.js";
|
|
4
4
|
import { LiveUpdates, shownRecordKeys } from "@alfakit/core";
|
|
@@ -13,6 +13,7 @@ import { ArrowUpIcon } from "lucide-react";
|
|
|
13
13
|
*/
|
|
14
14
|
function useLiveUpdates(live, target, options = {}) {
|
|
15
15
|
const poll = usePollComponent();
|
|
16
|
+
const refresh = useRefreshComponents();
|
|
16
17
|
const key = live ? JSON.stringify(live) : "";
|
|
17
18
|
const polling = options.polling;
|
|
18
19
|
const records = options.records;
|
|
@@ -20,12 +21,14 @@ function useLiveUpdates(live, target, options = {}) {
|
|
|
20
21
|
live,
|
|
21
22
|
target,
|
|
22
23
|
polling,
|
|
23
|
-
poll
|
|
24
|
+
poll,
|
|
25
|
+
refresh
|
|
24
26
|
}) : null, [
|
|
25
27
|
key,
|
|
26
28
|
target,
|
|
27
29
|
polling,
|
|
28
|
-
poll
|
|
30
|
+
poll,
|
|
31
|
+
refresh
|
|
29
32
|
]);
|
|
30
33
|
useEffect(() => {
|
|
31
34
|
controller?.setShownKeys(records === void 0 ? null : shownRecordKeys(records));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-records-pill.js","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"sourcesContent":["import { LiveUpdates, shownRecordKeys, type LiveUpdatesSchema, type RecordKey } from '@alfakit/core'\nimport { ArrowUpIcon } from 'lucide-react'\nimport { useEffect, useMemo } from 'react'\nimport { useChoice, usePollComponent } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { Button } from '../ui/button'\n\n/**\n * Follow `live()` updates of a table or widget: refresh it in place when its records\n * change, polling instead without Echo. Returns the controller (its store counts created\n * records for `<LiveRecordsPill>`), or null without `live()`.\n */\nexport function useLiveUpdates(\n live: LiveUpdatesSchema | undefined,\n target: string,\n options: { polling?: boolean; records?: ReadonlyArray<{ key?: RecordKey }> | null } = {},\n): LiveUpdates | null {\n const poll = usePollComponent()\n const key = live ? JSON.stringify(live) : ''\n const polling = options.polling\n const records = options.records\n\n const controller = useMemo(\n () => (live ? new LiveUpdates({ live, target, polling, poll }) : null),\n // `live` is compared by value (`key`): a reload brings a new object with the same settings.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [key, target, polling, poll],\n )\n\n // Updates of records on other pages don't refresh the table.\n useEffect(() => {\n controller?.setShownKeys(records === undefined ? null : shownRecordKeys(records))\n }, [controller, records])\n\n useEffect(() => controller?.start(), [controller])\n\n return controller\n}\n\n/** \"3 new records — show\": created records the table doesn't show yet. */\nexport function LiveRecordsPill({ live }: { live: LiveUpdates }) {\n const choice = useChoice()\n const { pending } = useStore(live.store)\n\n return (\n <div data-slot=\"live-records\" aria-live=\"polite\" className=\"flex justify-center\">\n {pending > 0 && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"rounded-full shadow-sm\"\n onClick={() => void live.showPending()}\n >\n <ArrowUpIcon aria-hidden=\"true\" />\n {choice(\n 'realtime.new_records',\n pending,\n {},\n '{1} :count new record — show|[2,*] :count new records — show',\n )}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eACd,MACA,QACA,UAAsF,CAAC,GACnE;CACpB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;CAC1C,MAAM,UAAU,QAAQ;CACxB,MAAM,UAAU,QAAQ;CAExB,MAAM,aAAa,cACV,OAAO,IAAI,YAAY;EAAE;EAAM;EAAQ;EAAS;
|
|
1
|
+
{"version":3,"file":"live-records-pill.js","names":[],"sources":["../../../src/components/realtime/live-records-pill.tsx"],"sourcesContent":["import { LiveUpdates, shownRecordKeys, type LiveUpdatesSchema, type RecordKey } from '@alfakit/core'\nimport { ArrowUpIcon } from 'lucide-react'\nimport { useEffect, useMemo } from 'react'\nimport { useChoice, usePollComponent, useRefreshComponents } from '../../context'\nimport { useStore } from '../../hooks/use-store'\nimport { Button } from '../ui/button'\n\n/**\n * Follow `live()` updates of a table or widget: refresh it in place when its records\n * change, polling instead without Echo. Returns the controller (its store counts created\n * records for `<LiveRecordsPill>`), or null without `live()`.\n */\nexport function useLiveUpdates(\n live: LiveUpdatesSchema | undefined,\n target: string,\n options: { polling?: boolean; records?: ReadonlyArray<{ key?: RecordKey }> | null } = {},\n): LiveUpdates | null {\n const poll = usePollComponent()\n const refresh = useRefreshComponents()\n const key = live ? JSON.stringify(live) : ''\n const polling = options.polling\n const records = options.records\n\n const controller = useMemo(\n () => (live ? new LiveUpdates({ live, target, polling, poll, refresh }) : null),\n // `live` is compared by value (`key`): a reload brings a new object with the same settings.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [key, target, polling, poll, refresh],\n )\n\n // Updates of records on other pages don't refresh the table.\n useEffect(() => {\n controller?.setShownKeys(records === undefined ? null : shownRecordKeys(records))\n }, [controller, records])\n\n useEffect(() => controller?.start(), [controller])\n\n return controller\n}\n\n/** \"3 new records — show\": created records the table doesn't show yet. */\nexport function LiveRecordsPill({ live }: { live: LiveUpdates }) {\n const choice = useChoice()\n const { pending } = useStore(live.store)\n\n return (\n <div data-slot=\"live-records\" aria-live=\"polite\" className=\"flex justify-center\">\n {pending > 0 && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n className=\"rounded-full shadow-sm\"\n onClick={() => void live.showPending()}\n >\n <ArrowUpIcon aria-hidden=\"true\" />\n {choice(\n 'realtime.new_records',\n pending,\n {},\n '{1} :count new record — show|[2,*] :count new records — show',\n )}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eACd,MACA,QACA,UAAsF,CAAC,GACnE;CACpB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,UAAU,qBAAqB;CACrC,MAAM,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;CAC1C,MAAM,UAAU,QAAQ;CACxB,MAAM,UAAU,QAAQ;CAExB,MAAM,aAAa,cACV,OAAO,IAAI,YAAY;EAAE;EAAM;EAAQ;EAAS;EAAM;CAAQ,CAAC,IAAI,MAG1E;EAAC;EAAK;EAAQ;EAAS;EAAM;CAAO,CACtC;CAGA,gBAAgB;EACd,YAAY,aAAa,YAAY,KAAA,IAAY,OAAO,gBAAgB,OAAO,CAAC;CAClF,GAAG,CAAC,YAAY,OAAO,CAAC;CAExB,gBAAgB,YAAY,MAAM,GAAG,CAAC,UAAU,CAAC;CAEjD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,EAAE,QAA+B;CAC/D,MAAM,SAAS,UAAU;CACzB,MAAM,EAAE,YAAY,SAAS,KAAK,KAAK;CAEvC,OACE,oBAAC,OAAD;EAAK,aAAU;EAAe,aAAU;EAAS,WAAU;EACxD,UAAA,UAAU,KACT,qBAAC,QAAD;GACE,MAAK;GACL,MAAK;GACL,SAAQ;GACR,WAAU;GACV,eAAe,KAAK,KAAK,YAAY;GALvC,UAAA,CAOE,oBAAC,aAAD,EAAa,eAAY,OAAQ,CAAA,GAChC,OACC,wBACA,SACA,CAAC,GACD,8DACF,CACM;;CAEP,CAAA;AAET"}
|
|
@@ -6,6 +6,12 @@ export interface CellProps {
|
|
|
6
6
|
recordKey: RecordKey;
|
|
7
7
|
token: string;
|
|
8
8
|
component: string;
|
|
9
|
+
/**
|
|
10
|
+
* Set when this renderer was picked from the registry (`column:<type>`): it then renders
|
|
11
|
+
* the built-in cell instead of looking itself up again, so an ejected `TableCellContent`
|
|
12
|
+
* registered for a column type doesn't render itself forever.
|
|
13
|
+
*/
|
|
14
|
+
fromRegistry?: boolean;
|
|
9
15
|
}
|
|
10
16
|
export declare function TableCellContent(props: CellProps): import("react").JSX.Element;
|
|
11
17
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cells.d.ts","names":[],"sources":["../../../src/components/table/cells.tsx"],"mappings":";;iBAwDiB;EACf,QAAQ;EACR,MAAM;EACN,WAAW;EACX;EACA;;wBAGc,iBAAiB,OAAO,4BAAS,IAAA"}
|
|
1
|
+
{"version":3,"file":"cells.d.ts","names":[],"sources":["../../../src/components/table/cells.tsx"],"mappings":";;iBAwDiB;EACf,QAAQ;EACR,MAAM;EACN,WAAW;EACX;EACA;;;;;;EAMA;;wBAGc,iBAAiB,OAAO,4BAAS,IAAA"}
|
|
@@ -13,14 +13,18 @@ import { Switch } from "../ui/switch.js";
|
|
|
13
13
|
import { FormattedText } from "../entries/text-entry.js";
|
|
14
14
|
import { columnRegistryKey, filterSelectColumnOptions, isOptionGroup, optionText, remainingTextSizeClass, resolvePartialProps, searchTableColumnOptions, selectColumnEmptyMessage, stackedImageStyle, updateTableCell, usesDefaultImageStack } from "@alfakit/core";
|
|
15
15
|
import { router } from "@inertiajs/react";
|
|
16
|
-
import { createElement, useEffect, useRef, useState } from "react";
|
|
16
|
+
import { createElement, useEffect, useId, useRef, useState } from "react";
|
|
17
17
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
18
|
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
|
|
19
19
|
//#region src/components/table/cells.tsx
|
|
20
20
|
function TableCellContent(props) {
|
|
21
21
|
const { column } = props;
|
|
22
|
-
const
|
|
23
|
-
|
|
22
|
+
const registry = useRegistry();
|
|
23
|
+
const Custom = props.fromRegistry ? void 0 : registry.resolve(columnRegistryKey(column));
|
|
24
|
+
if (Custom) return createElement(Custom, {
|
|
25
|
+
...props,
|
|
26
|
+
fromRegistry: true
|
|
27
|
+
});
|
|
24
28
|
switch (column.type) {
|
|
25
29
|
case "IconColumn": return /* @__PURE__ */ jsx(IconCell, { ...props });
|
|
26
30
|
case "ImageColumn": return /* @__PURE__ */ jsx(ImageCell, { ...props });
|
|
@@ -374,6 +378,7 @@ function NativeSelectCell(props) {
|
|
|
374
378
|
const schema = column;
|
|
375
379
|
const { update, saving, error } = useCellUpdate(props);
|
|
376
380
|
const [value, setValue] = useState(cell.state === null || cell.state === void 0 ? "" : String(cell.state));
|
|
381
|
+
const errorId = useId();
|
|
377
382
|
return /* @__PURE__ */ jsxs("span", {
|
|
378
383
|
onClick: (event) => event.stopPropagation(),
|
|
379
384
|
children: [/* @__PURE__ */ jsxs("select", {
|
|
@@ -383,7 +388,9 @@ function NativeSelectCell(props) {
|
|
|
383
388
|
setValue(event.target.value);
|
|
384
389
|
update(event.target.value === "" ? null : event.target.value);
|
|
385
390
|
},
|
|
391
|
+
"aria-label": column.label || column.name,
|
|
386
392
|
"aria-invalid": error ? true : void 0,
|
|
393
|
+
"aria-describedby": error ? errorId : void 0,
|
|
387
394
|
className: cn("border-input dark:bg-input/30 focus-visible:ring-ring/50 h-8 min-w-32 rounded-md border bg-transparent px-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]", error && "border-destructive"),
|
|
388
395
|
children: [schema.selectablePlaceholder && /* @__PURE__ */ jsx("option", {
|
|
389
396
|
value: "",
|
|
@@ -394,6 +401,7 @@ function NativeSelectCell(props) {
|
|
|
394
401
|
children: option.label
|
|
395
402
|
}, option.value))]
|
|
396
403
|
}), error && /* @__PURE__ */ jsx("span", {
|
|
404
|
+
id: errorId,
|
|
397
405
|
className: "text-destructive block text-xs",
|
|
398
406
|
children: error
|
|
399
407
|
})]
|
|
@@ -406,6 +414,7 @@ function TextInputCell(props) {
|
|
|
406
414
|
const [value, setValue] = useState(cell.state === null || cell.state === void 0 ? "" : String(cell.state));
|
|
407
415
|
const initial = cell.state === null || cell.state === void 0 ? "" : String(cell.state);
|
|
408
416
|
const grouped = Boolean(cell.prefix || cell.suffix);
|
|
417
|
+
const errorId = useId();
|
|
409
418
|
const field = /* @__PURE__ */ jsxs("span", {
|
|
410
419
|
className: cn("relative block", grouped && "min-w-0 flex-1"),
|
|
411
420
|
children: [
|
|
@@ -425,7 +434,9 @@ function TextInputCell(props) {
|
|
|
425
434
|
step: schema.step,
|
|
426
435
|
inputMode: schema.inputMode,
|
|
427
436
|
disabled: Boolean(cell.disabled) || saving,
|
|
437
|
+
"aria-label": column.label || column.name,
|
|
428
438
|
"aria-invalid": error ? true : void 0,
|
|
439
|
+
"aria-describedby": error ? errorId : void 0,
|
|
429
440
|
className: cn("h-8 min-w-32", schema.prefixIcon && "ps-8", schema.suffixIcon && "pe-8", grouped && "h-full rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent"),
|
|
430
441
|
onChange: (event) => setValue(event.target.value),
|
|
431
442
|
onBlur: () => value !== initial && void update(value),
|
|
@@ -461,6 +472,7 @@ function TextInputCell(props) {
|
|
|
461
472
|
})
|
|
462
473
|
]
|
|
463
474
|
}) : field, error && /* @__PURE__ */ jsx("span", {
|
|
475
|
+
id: errorId,
|
|
464
476
|
className: "text-destructive block text-xs",
|
|
465
477
|
children: error
|
|
466
478
|
})]
|