@kodffe/ui 0.0.0-stage → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/accordion/accordion.d.ts +44 -0
- package/dist/accordion/accordion.js +84 -0
- package/dist/accordion/accordion.js.map +1 -0
- package/dist/alert/alert.d.ts +17 -0
- package/dist/alert/alert.js +59 -0
- package/dist/alert/alert.js.map +1 -0
- package/dist/app-shell/app-footer.d.ts +29 -0
- package/dist/app-shell/app-footer.js +39 -0
- package/dist/app-shell/app-footer.js.map +1 -0
- package/dist/app-shell/app-shell-context.d.ts +10 -0
- package/dist/app-shell/app-shell-context.js +12 -0
- package/dist/app-shell/app-shell-context.js.map +1 -0
- package/dist/app-shell/app-shell.d.ts +42 -0
- package/dist/app-shell/app-shell.js +191 -0
- package/dist/app-shell/app-shell.js.map +1 -0
- package/dist/app-shell/floating-actions.d.ts +19 -0
- package/dist/app-shell/floating-actions.js +59 -0
- package/dist/app-shell/floating-actions.js.map +1 -0
- package/dist/app-shell/workspace-switcher.d.ts +25 -0
- package/dist/app-shell/workspace-switcher.js +82 -0
- package/dist/app-shell/workspace-switcher.js.map +1 -0
- package/dist/badge/badge.d.ts +19 -0
- package/dist/badge/badge.js +59 -0
- package/dist/badge/badge.js.map +1 -0
- package/dist/banner/banner.d.ts +22 -0
- package/dist/banner/banner.js +80 -0
- package/dist/banner/banner.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbs.d.ts +18 -0
- package/dist/breadcrumbs/breadcrumbs.js +45 -0
- package/dist/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/button/button.d.ts +38 -0
- package/dist/button/button.js +83 -0
- package/dist/button/button.js.map +1 -0
- package/dist/card/card.d.ts +159 -0
- package/dist/card/card.js +390 -0
- package/dist/card/card.js.map +1 -0
- package/dist/card/insight-card.d.ts +19 -0
- package/dist/card/insight-card.js +51 -0
- package/dist/card/insight-card.js.map +1 -0
- package/dist/card/integration-card.d.ts +19 -0
- package/dist/card/integration-card.js +70 -0
- package/dist/card/integration-card.js.map +1 -0
- package/dist/charts/charts.d.ts +75 -0
- package/dist/charts/charts.js +453 -0
- package/dist/charts/charts.js.map +1 -0
- package/dist/choice/choice.d.ts +39 -0
- package/dist/choice/choice.js +143 -0
- package/dist/choice/choice.js.map +1 -0
- package/dist/combobox/combobox.d.ts +46 -0
- package/dist/combobox/combobox.js +196 -0
- package/dist/combobox/combobox.js.map +1 -0
- package/dist/command-palette/command-palette.d.ts +35 -0
- package/dist/command-palette/command-palette.js +164 -0
- package/dist/command-palette/command-palette.js.map +1 -0
- package/dist/confirm-dialog/confirm-dialog.d.ts +37 -0
- package/dist/confirm-dialog/confirm-dialog.js +106 -0
- package/dist/confirm-dialog/confirm-dialog.js.map +1 -0
- package/dist/content/assistant.d.ts +86 -0
- package/dist/content/assistant.js +213 -0
- package/dist/content/assistant.js.map +1 -0
- package/dist/content/content.d.ts +45 -0
- package/dist/content/content.js +136 -0
- package/dist/content/content.js.map +1 -0
- package/dist/data-display/avatar-sizes.d.ts +8 -0
- package/dist/data-display/avatar-sizes.js +12 -0
- package/dist/data-display/avatar-sizes.js.map +1 -0
- package/dist/data-display/avatar.d.ts +21 -0
- package/dist/data-display/avatar.js +53 -0
- package/dist/data-display/avatar.js.map +1 -0
- package/dist/data-display/chip.d.ts +20 -0
- package/dist/data-display/chip.js +64 -0
- package/dist/data-display/chip.js.map +1 -0
- package/dist/data-display/code-block.d.ts +14 -0
- package/dist/data-display/code-block.js +50 -0
- package/dist/data-display/code-block.js.map +1 -0
- package/dist/data-display/data-display.d.ts +73 -0
- package/dist/data-display/data-display.js +227 -0
- package/dist/data-display/data-display.js.map +1 -0
- package/dist/data-display/insights.d.ts +120 -0
- package/dist/data-display/insights.js +220 -0
- package/dist/data-display/insights.js.map +1 -0
- package/dist/data-table/cells.d.ts +86 -0
- package/dist/data-table/cells.js +163 -0
- package/dist/data-table/cells.js.map +1 -0
- package/dist/data-table/data-table.d.ts +112 -0
- package/dist/data-table/data-table.js +558 -0
- package/dist/data-table/data-table.js.map +1 -0
- package/dist/date-picker/date-picker.d.ts +61 -0
- package/dist/date-picker/date-picker.js +309 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/drawer/drawer.d.ts +32 -0
- package/dist/drawer/drawer.js +72 -0
- package/dist/drawer/drawer.js.map +1 -0
- package/dist/empty-state/empty-state.d.ts +25 -0
- package/dist/empty-state/empty-state.js +78 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/error-state/error-state.d.ts +19 -0
- package/dist/error-state/error-state.js +56 -0
- package/dist/error-state/error-state.js.map +1 -0
- package/dist/event-calendar/calendar-logic.test.d.ts +1 -0
- package/dist/event-calendar/dates.d.ts +35 -0
- package/dist/event-calendar/dates.js +55 -0
- package/dist/event-calendar/dates.js.map +1 -0
- package/dist/event-calendar/event-calendar.d.ts +125 -0
- package/dist/event-calendar/event-calendar.js +795 -0
- package/dist/event-calendar/event-calendar.js.map +1 -0
- package/dist/event-calendar/event-details.d.ts +50 -0
- package/dist/event-calendar/event-details.js +124 -0
- package/dist/event-calendar/event-details.js.map +1 -0
- package/dist/event-calendar/layout.d.ts +48 -0
- package/dist/event-calendar/layout.js +55 -0
- package/dist/event-calendar/layout.js.map +1 -0
- package/dist/file-upload/file-upload.d.ts +70 -0
- package/dist/file-upload/file-upload.js +307 -0
- package/dist/file-upload/file-upload.js.map +1 -0
- package/dist/filters/filters.d.ts +48 -0
- package/dist/filters/filters.js +103 -0
- package/dist/filters/filters.js.map +1 -0
- package/dist/form-field/form-field.d.ts +39 -0
- package/dist/form-field/form-field.js +88 -0
- package/dist/form-field/form-field.js.map +1 -0
- package/dist/hover-card/hover-card.d.ts +15 -0
- package/dist/hover-card/hover-card.js +27 -0
- package/dist/hover-card/hover-card.js.map +1 -0
- package/dist/hover-card/person-hover-card.d.ts +26 -0
- package/dist/hover-card/person-hover-card.js +85 -0
- package/dist/hover-card/person-hover-card.js.map +1 -0
- package/dist/icon/icon-tile.d.ts +20 -0
- package/dist/icon/icon-tile.js +55 -0
- package/dist/icon/icon-tile.js.map +1 -0
- package/dist/icon/icon.d.ts +14 -0
- package/dist/icon/icon.js +28 -0
- package/dist/icon/icon.js.map +1 -0
- package/dist/icon/icons.generated.d.ts +358 -0
- package/dist/icon/icons.generated.js +362 -0
- package/dist/icon/icons.generated.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +88 -0
- package/dist/input/extra-inputs.d.ts +122 -0
- package/dist/input/extra-inputs.js +351 -0
- package/dist/input/extra-inputs.js.map +1 -0
- package/dist/input/field-styles.d.ts +5 -0
- package/dist/input/field-styles.js +14 -0
- package/dist/input/field-styles.js.map +1 -0
- package/dist/input/input.d.ts +50 -0
- package/dist/input/input.js +107 -0
- package/dist/input/input.js.map +1 -0
- package/dist/layout/layout.d.ts +41 -0
- package/dist/layout/layout.js +90 -0
- package/dist/layout/layout.js.map +1 -0
- package/dist/lib/control-styles.d.ts +9 -0
- package/dist/lib/control-styles.js +16 -0
- package/dist/lib/control-styles.js.map +1 -0
- package/dist/lib/cx.d.ts +2 -0
- package/dist/lib/cx.js +8 -0
- package/dist/lib/cx.js.map +1 -0
- package/dist/lib/glyphs.d.ts +13 -0
- package/dist/lib/glyphs.js +67 -0
- package/dist/lib/glyphs.js.map +1 -0
- package/dist/lib/segmented-styles.d.ts +8 -0
- package/dist/lib/segmented-styles.js +12 -0
- package/dist/lib/segmented-styles.js.map +1 -0
- package/dist/lib/select-on-arrow.d.ts +7 -0
- package/dist/lib/select-on-arrow.js +21 -0
- package/dist/lib/select-on-arrow.js.map +1 -0
- package/dist/lib/skip-link.d.ts +5 -0
- package/dist/lib/skip-link.js +13 -0
- package/dist/lib/skip-link.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +4 -0
- package/dist/lib/use-media-query.js +15 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lists/lists.d.ts +76 -0
- package/dist/lists/lists.js +133 -0
- package/dist/lists/lists.js.map +1 -0
- package/dist/locale-switch/locale-switch.d.ts +29 -0
- package/dist/locale-switch/locale-switch.js +62 -0
- package/dist/locale-switch/locale-switch.js.map +1 -0
- package/dist/logo/logo.d.ts +31 -0
- package/dist/logo/logo.js +157 -0
- package/dist/logo/logo.js.map +1 -0
- package/dist/logo/product-logo.d.ts +19 -0
- package/dist/logo/product-logo.js +46 -0
- package/dist/logo/product-logo.js.map +1 -0
- package/dist/marketing/marketing.d.ts +176 -0
- package/dist/marketing/marketing.js +451 -0
- package/dist/marketing/marketing.js.map +1 -0
- package/dist/marketing/newsletter-form.d.ts +21 -0
- package/dist/marketing/newsletter-form.js +100 -0
- package/dist/marketing/newsletter-form.js.map +1 -0
- package/dist/mascot/mascot.d.ts +28 -0
- package/dist/mascot/mascot.js +28 -0
- package/dist/mascot/mascot.js.map +1 -0
- package/dist/mascot/mascots.generated.d.ts +284 -0
- package/dist/mascot/mascots.generated.js +287 -0
- package/dist/mascot/mascots.generated.js.map +1 -0
- package/dist/master-detail/master-detail.d.ts +30 -0
- package/dist/master-detail/master-detail.js +71 -0
- package/dist/master-detail/master-detail.js.map +1 -0
- package/dist/menu/account-menu.d.ts +44 -0
- package/dist/menu/account-menu.js +78 -0
- package/dist/menu/account-menu.js.map +1 -0
- package/dist/menu/context-menu.d.ts +31 -0
- package/dist/menu/context-menu.js +111 -0
- package/dist/menu/context-menu.js.map +1 -0
- package/dist/menu/dropdown-menu.d.ts +49 -0
- package/dist/menu/dropdown-menu.js +152 -0
- package/dist/menu/dropdown-menu.js.map +1 -0
- package/dist/menu/menu-styles.d.ts +8 -0
- package/dist/menu/menu-styles.js +6 -0
- package/dist/menu/menu-styles.js.map +1 -0
- package/dist/menu/menubar.d.ts +31 -0
- package/dist/menu/menubar.js +125 -0
- package/dist/menu/menubar.js.map +1 -0
- package/dist/modal/modal.d.ts +34 -0
- package/dist/modal/modal.js +58 -0
- package/dist/modal/modal.js.map +1 -0
- package/dist/notification-center/notification-center.d.ts +51 -0
- package/dist/notification-center/notification-center.js +244 -0
- package/dist/notification-center/notification-center.js.map +1 -0
- package/dist/otp-input/otp-input.d.ts +23 -0
- package/dist/otp-input/otp-input.js +61 -0
- package/dist/otp-input/otp-input.js.map +1 -0
- package/dist/overlay/overlay.d.ts +53 -0
- package/dist/overlay/overlay.js +103 -0
- package/dist/overlay/overlay.js.map +1 -0
- package/dist/page-header/page-header.d.ts +55 -0
- package/dist/page-header/page-header.js +114 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/page-header/record-headers.d.ts +51 -0
- package/dist/page-header/record-headers.js +134 -0
- package/dist/page-header/record-headers.js.map +1 -0
- package/dist/page-header/section-header.d.ts +21 -0
- package/dist/page-header/section-header.js +44 -0
- package/dist/page-header/section-header.js.map +1 -0
- package/dist/page-navigation/page-navigation.d.ts +59 -0
- package/dist/page-navigation/page-navigation.js +136 -0
- package/dist/page-navigation/page-navigation.js.map +1 -0
- package/dist/pagination/pagination.d.ts +28 -0
- package/dist/pagination/pagination.js +102 -0
- package/dist/pagination/pagination.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +34 -0
- package/dist/phone-input/phone-input.js +171 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/popover.d.ts +23 -0
- package/dist/popover/popover.js +40 -0
- package/dist/popover/popover.js.map +1 -0
- package/dist/progress/progress.d.ts +21 -0
- package/dist/progress/progress.js +49 -0
- package/dist/progress/progress.js.map +1 -0
- package/dist/segmented-control/segmented-control.d.ts +32 -0
- package/dist/segmented-control/segmented-control.js +29 -0
- package/dist/segmented-control/segmented-control.js.map +1 -0
- package/dist/select/select.d.ts +48 -0
- package/dist/select/select.js +136 -0
- package/dist/select/select.js.map +1 -0
- package/dist/settings/permission-matrix.d.ts +29 -0
- package/dist/settings/permission-matrix.js +101 -0
- package/dist/settings/permission-matrix.js.map +1 -0
- package/dist/settings/settings-row.d.ts +32 -0
- package/dist/settings/settings-row.js +63 -0
- package/dist/settings/settings-row.js.map +1 -0
- package/dist/side-nav/side-nav.d.ts +36 -0
- package/dist/side-nav/side-nav.js +123 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/site-header/site-header.d.ts +32 -0
- package/dist/site-header/site-header.js +99 -0
- package/dist/site-header/site-header.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +16 -0
- package/dist/skeleton/skeleton.js +19 -0
- package/dist/skeleton/skeleton.js.map +1 -0
- package/dist/slider/slider.d.ts +15 -0
- package/dist/slider/slider.js +48 -0
- package/dist/slider/slider.js.map +1 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +42 -0
- package/dist/spinner/spinner.js.map +1 -0
- package/dist/stepper/step-dots.d.ts +16 -0
- package/dist/stepper/step-dots.js +26 -0
- package/dist/stepper/step-dots.js.map +1 -0
- package/dist/stepper/stepper.d.ts +26 -0
- package/dist/stepper/stepper.js +113 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/tabs/tabs.d.ts +31 -0
- package/dist/tabs/tabs.js +66 -0
- package/dist/tabs/tabs.js.map +1 -0
- package/dist/templates/app-templates.d.ts +126 -0
- package/dist/templates/app-templates.js +153 -0
- package/dist/templates/app-templates.js.map +1 -0
- package/dist/templates/site-templates.d.ts +49 -0
- package/dist/templates/site-templates.js +110 -0
- package/dist/templates/site-templates.js.map +1 -0
- package/dist/toast/toast-store.d.ts +54 -0
- package/dist/toast/toast-store.js +49 -0
- package/dist/toast/toast-store.js.map +1 -0
- package/dist/toast/toaster.d.ts +15 -0
- package/dist/toast/toaster.js +124 -0
- package/dist/toast/toaster.js.map +1 -0
- package/dist/tooltip/tooltip.d.ts +29 -0
- package/dist/tooltip/tooltip.js +54 -0
- package/dist/tooltip/tooltip.js.map +1 -0
- package/package.json +88 -3
- package/styles.css +521 -0
- package/README.md +0 -3
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var e = Object.defineProperty, t = (t, n) => {
|
|
3
|
+
let r = {};
|
|
4
|
+
for (var i in t) e(r, i, {
|
|
5
|
+
get: t[i],
|
|
6
|
+
enumerable: !0
|
|
7
|
+
});
|
|
8
|
+
return n || e(r, Symbol.toStringTag, { value: "Module" }), r;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as __exportAll };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as RadixAccordion from '@radix-ui/react-accordion';
|
|
2
|
+
import * as RadixCollapsible from '@radix-ui/react-collapsible';
|
|
3
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Stacked sections that expand and collapse: FAQs, filter groups, settings. Use `type="single"`
|
|
6
|
+
* (with `collapsible`) when only one section should be open, `type="multiple"` otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export type AccordionAppearance = 'divided' | 'card';
|
|
9
|
+
export type AccordionProps = ComponentPropsWithoutRef<typeof RadixAccordion.Root> & {
|
|
10
|
+
/** `divided` (default): rows split by lines (FAQs, filters). `card`: each section is a card (long edit forms). */
|
|
11
|
+
appearance?: AccordionAppearance;
|
|
12
|
+
};
|
|
13
|
+
export declare function Accordion({ appearance, className, ...rest }: AccordionProps): import("react").JSX.Element;
|
|
14
|
+
export declare function AccordionItem({ className, ...rest }: ComponentPropsWithoutRef<typeof RadixAccordion.Item>): import("react").JSX.Element;
|
|
15
|
+
export interface AccordionTriggerProps extends ComponentPropsWithoutRef<typeof RadixAccordion.Trigger> {
|
|
16
|
+
/** Heading level wrapping the trigger, to fit the page outline. */
|
|
17
|
+
headingLevel?: 2 | 3 | 4;
|
|
18
|
+
/** `md` (15px, settings and filters) or `lg` (17px, FAQs). Use this instead of a text size in `className`. */
|
|
19
|
+
size?: 'md' | 'lg';
|
|
20
|
+
/** A line under the title ("Name, photo and contact details"). */
|
|
21
|
+
description?: ReactNode;
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare function AccordionTrigger({ headingLevel, size, description, className, children, ...rest }: AccordionTriggerProps): import("react").JSX.Element;
|
|
25
|
+
/**
|
|
26
|
+
* With `forceMount`, closed content stays in the DOM (hidden with `display: none`), so it is in the
|
|
27
|
+
* server HTML for search engines and in-page find. It opens with the animation and closes instantly.
|
|
28
|
+
*/
|
|
29
|
+
export declare function AccordionContent({ size, className, children, ...rest }: ComponentPropsWithoutRef<typeof RadixAccordion.Content> & {
|
|
30
|
+
size?: 'md' | 'lg';
|
|
31
|
+
}): import("react").JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* Per-section actions at the end of an `AccordionContent` in a card accordion (Undo / Save).
|
|
34
|
+
* Spans the card's width with a top border; stacks full-width on mobile like dialog footers.
|
|
35
|
+
*/
|
|
36
|
+
export declare function AccordionFooter({ className, children }: {
|
|
37
|
+
className?: string;
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
}): import("react").JSX.Element;
|
|
40
|
+
/** A single show/hide region ("Show advanced settings"). */
|
|
41
|
+
export declare const Collapsible: import("react").ForwardRefExoticComponent<RadixCollapsible.CollapsibleProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
42
|
+
/** Use `asChild` with a Button; it gets `aria-expanded` automatically. */
|
|
43
|
+
export declare const CollapsibleTrigger: import("react").ForwardRefExoticComponent<RadixCollapsible.CollapsibleTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
44
|
+
export declare function CollapsibleContent({ className, ...rest }: ComponentPropsWithoutRef<typeof RadixCollapsible.Content>): import("react").JSX.Element;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Glyph as t } from "../lib/glyphs.js";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
import { createContext as i, useContext as a } from "react";
|
|
6
|
+
import * as o from "@radix-ui/react-accordion";
|
|
7
|
+
import * as s from "@radix-ui/react-collapsible";
|
|
8
|
+
//#region src/accordion/accordion.tsx
|
|
9
|
+
var c = i("divided");
|
|
10
|
+
function l({ appearance: t = "divided", className: r, ...i }) {
|
|
11
|
+
return /* @__PURE__ */ n(c.Provider, {
|
|
12
|
+
value: t,
|
|
13
|
+
children: /* @__PURE__ */ n(o.Root, {
|
|
14
|
+
className: e("font-sans", t === "card" && "grid gap-3", r),
|
|
15
|
+
...i
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function u({ className: t, ...r }) {
|
|
20
|
+
let i = a(c) === "card";
|
|
21
|
+
return /* @__PURE__ */ n(o.Item, {
|
|
22
|
+
className: e(i ? "overflow-hidden rounded-lg border border-border bg-surface" : "border-b border-border", t),
|
|
23
|
+
...r
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
var d = {
|
|
27
|
+
md: "text-[15px]",
|
|
28
|
+
lg: "text-[17px]"
|
|
29
|
+
}, f = {
|
|
30
|
+
md: "text-[15px]",
|
|
31
|
+
lg: "text-base"
|
|
32
|
+
};
|
|
33
|
+
function p({ headingLevel: i = 3, size: s = "md", description: l, className: u, children: f, ...p }) {
|
|
34
|
+
let m = `h${i}`, h = a(c) === "card";
|
|
35
|
+
return /* @__PURE__ */ n(o.Header, {
|
|
36
|
+
asChild: !0,
|
|
37
|
+
children: /* @__PURE__ */ n(m, {
|
|
38
|
+
className: "m-0 flex",
|
|
39
|
+
children: /* @__PURE__ */ r(o.Trigger, {
|
|
40
|
+
className: e("group flex flex-1 cursor-pointer items-center justify-between gap-4 border-0 bg-transparent py-4 text-left font-sans font-semibold text-fg", d[s], h && "px-5 hover:bg-surface-muted/60", "hover:text-link focus-visible:outline-3 focus-visible:outline-focus", h ? "focus-visible:-outline-offset-3" : "focus-visible:outline-offset-2", u),
|
|
41
|
+
...p,
|
|
42
|
+
children: [l ? /* @__PURE__ */ r("span", {
|
|
43
|
+
className: "grid gap-0.5",
|
|
44
|
+
children: [f, /* @__PURE__ */ n("span", {
|
|
45
|
+
className: "text-sm font-normal text-fg-muted",
|
|
46
|
+
children: l
|
|
47
|
+
})]
|
|
48
|
+
}) : f, /* @__PURE__ */ n(t, {
|
|
49
|
+
name: "chevron-down",
|
|
50
|
+
size: 18,
|
|
51
|
+
className: "shrink-0 text-fg-muted transition-transform duration-200 ease-standard group-data-[state=open]:rotate-180 motion-reduce:transition-none"
|
|
52
|
+
})]
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function m({ size: t = "md", className: r, children: i, ...s }) {
|
|
58
|
+
let l = a(c) === "card";
|
|
59
|
+
return /* @__PURE__ */ n(o.Content, {
|
|
60
|
+
className: e("kf-collapse overflow-hidden", s.forceMount && "data-[state=closed]:hidden"),
|
|
61
|
+
...s,
|
|
62
|
+
children: /* @__PURE__ */ n("div", {
|
|
63
|
+
className: e("pb-5 text-fg-muted", l && "border-t border-border px-5 pt-5", f[t], r),
|
|
64
|
+
children: i
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function h({ className: t, children: r }) {
|
|
69
|
+
return /* @__PURE__ */ n("div", {
|
|
70
|
+
className: e("-mx-5 mt-5 -mb-5 flex flex-col-reverse gap-2 border-t border-border px-5 py-3 *:w-full sm:flex-row sm:justify-end sm:*:w-auto", t),
|
|
71
|
+
children: r
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
var g = s.Root, _ = s.Trigger;
|
|
75
|
+
function v({ className: t, ...r }) {
|
|
76
|
+
return /* @__PURE__ */ n(s.Content, {
|
|
77
|
+
className: e("kf-collapse overflow-hidden", t),
|
|
78
|
+
...r
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { l as Accordion, m as AccordionContent, h as AccordionFooter, u as AccordionItem, p as AccordionTrigger, g as Collapsible, v as CollapsibleContent, _ as CollapsibleTrigger };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=accordion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accordion.js","names":["RadixAccordion","RadixCollapsible","AppearanceContext","createContext","Accordion","rest","appearance","cx","className","AccordionItem","card","useContext","TRIGGER_SIZE","CONTENT_SIZE","AccordionTrigger","H","headingLevel","size","description","children","Glyph","AccordionContent","AccordionFooter","Collapsible","CollapsibleTrigger","CollapsibleContent"],"sources":["../../src/accordion/accordion.tsx"],"sourcesContent":["'use client';\n\nimport * as RadixAccordion from '@radix-ui/react-accordion';\nimport * as RadixCollapsible from '@radix-ui/react-collapsible';\nimport { createContext, useContext, type ComponentPropsWithoutRef, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Glyph } from '../lib/glyphs';\n\n/**\n * Stacked sections that expand and collapse: FAQs, filter groups, settings. Use `type=\"single\"`\n * (with `collapsible`) when only one section should be open, `type=\"multiple\"` otherwise.\n */\nexport type AccordionAppearance = 'divided' | 'card';\nconst AppearanceContext = createContext<AccordionAppearance>('divided');\n\nexport type AccordionProps = ComponentPropsWithoutRef<typeof RadixAccordion.Root> & {\n /** `divided` (default): rows split by lines (FAQs, filters). `card`: each section is a card (long edit forms). */\n appearance?: AccordionAppearance;\n};\n\nexport function Accordion({ appearance = 'divided', className, ...rest }: AccordionProps) {\n return (\n <AppearanceContext.Provider value={appearance}>\n <RadixAccordion.Root className={cx('font-sans', appearance === 'card' && 'grid gap-3', className)} {...rest} />\n </AppearanceContext.Provider>\n );\n}\n\nexport function AccordionItem({ className, ...rest }: ComponentPropsWithoutRef<typeof RadixAccordion.Item>) {\n const card = useContext(AppearanceContext) === 'card';\n return (\n <RadixAccordion.Item\n className={cx(card ? 'overflow-hidden rounded-lg border border-border bg-surface' : 'border-b border-border', className)}\n {...rest}\n />\n );\n}\n\nexport interface AccordionTriggerProps extends ComponentPropsWithoutRef<typeof RadixAccordion.Trigger> {\n /** Heading level wrapping the trigger, to fit the page outline. */\n headingLevel?: 2 | 3 | 4;\n /** `md` (15px, settings and filters) or `lg` (17px, FAQs). Use this instead of a text size in `className`. */\n size?: 'md' | 'lg';\n /** A line under the title (\"Name, photo and contact details\"). */\n description?: ReactNode;\n children: ReactNode;\n}\n\n/*\n * `cx` only joins classes, it doesn't resolve Tailwind conflicts: a `text-[17px]` in `className` next to\n * the default `text-[15px]` wins or loses by stylesheet order. Sizes are props so there is never a clash.\n */\nconst TRIGGER_SIZE = { md: 'text-[15px]', lg: 'text-[17px]' };\nconst CONTENT_SIZE = { md: 'text-[15px]', lg: 'text-base' };\n\nexport function AccordionTrigger({\n headingLevel = 3,\n size = 'md',\n description,\n className,\n children,\n ...rest\n}: AccordionTriggerProps) {\n const H = `h${headingLevel}` as const;\n const card = useContext(AppearanceContext) === 'card';\n return (\n <RadixAccordion.Header asChild>\n <H className=\"m-0 flex\">\n <RadixAccordion.Trigger\n className={cx(\n 'group flex flex-1 cursor-pointer items-center justify-between gap-4 border-0 bg-transparent py-4 text-left font-sans font-semibold text-fg',\n TRIGGER_SIZE[size],\n card && 'px-5 hover:bg-surface-muted/60',\n 'hover:text-link focus-visible:outline-3 focus-visible:outline-focus',\n // Inside a card (overflow hidden) the ring is drawn inward, or it would be clipped.\n card ? 'focus-visible:-outline-offset-3' : 'focus-visible:outline-offset-2',\n className,\n )}\n {...rest}\n >\n {description ? (\n <span className=\"grid gap-0.5\">\n {children}\n <span className=\"text-sm font-normal text-fg-muted\">{description}</span>\n </span>\n ) : (\n children\n )}\n <Glyph\n name=\"chevron-down\"\n size={18}\n className=\"shrink-0 text-fg-muted transition-transform duration-200 ease-standard group-data-[state=open]:rotate-180 motion-reduce:transition-none\"\n />\n </RadixAccordion.Trigger>\n </H>\n </RadixAccordion.Header>\n );\n}\n\n/**\n * With `forceMount`, closed content stays in the DOM (hidden with `display: none`), so it is in the\n * server HTML for search engines and in-page find. It opens with the animation and closes instantly.\n */\nexport function AccordionContent({\n size = 'md',\n className,\n children,\n ...rest\n}: ComponentPropsWithoutRef<typeof RadixAccordion.Content> & { size?: 'md' | 'lg' }) {\n const card = useContext(AppearanceContext) === 'card';\n return (\n <RadixAccordion.Content\n className={cx('kf-collapse overflow-hidden', rest.forceMount && 'data-[state=closed]:hidden')}\n {...rest}\n >\n <div className={cx('pb-5 text-fg-muted', card && 'border-t border-border px-5 pt-5', CONTENT_SIZE[size], className)}>\n {children}\n </div>\n </RadixAccordion.Content>\n );\n}\n\n/**\n * Per-section actions at the end of an `AccordionContent` in a card accordion (Undo / Save).\n * Spans the card's width with a top border; stacks full-width on mobile like dialog footers.\n */\nexport function AccordionFooter({ className, children }: { className?: string; children: ReactNode }) {\n return (\n <div\n className={cx(\n '-mx-5 mt-5 -mb-5 flex flex-col-reverse gap-2 border-t border-border px-5 py-3 *:w-full sm:flex-row sm:justify-end sm:*:w-auto',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n/** A single show/hide region (\"Show advanced settings\"). */\nexport const Collapsible = RadixCollapsible.Root;\n/** Use `asChild` with a Button; it gets `aria-expanded` automatically. */\nexport const CollapsibleTrigger = RadixCollapsible.Trigger;\n\nexport function CollapsibleContent({ className, ...rest }: ComponentPropsWithoutRef<typeof RadixCollapsible.Content>) {\n return <RadixCollapsible.Content className={cx('kf-collapse overflow-hidden', className)} {...rest} />;\n}\n"],"mappings":";;;;;;;;AAaA,IAAME,IAAoBC,EAAmC,SAAS;AAOtE,SAAgBC,EAAU,EAAE,gBAAa,WAAW,cAAW,GAAGC,KAAwB;CACxF,OACE,kBAACH,EAAkB,UAAnB;EAA4B,OAAOI;EACjC,UAAA,kBAACN,EAAe,MAAhB;GAAqB,WAAWO,EAAG,aAAaD,MAAe,UAAU,cAAcE,CAAS;GAAG,GAAIH;EAAO,CAAA;CACpF,CAAA;AAEhC;AAEA,SAAgBI,EAAc,EAAE,cAAW,GAAGJ,KAA8D;CAC1G,IAAMK,IAAOC,EAAWT,CAAiB,MAAM;CAC/C,OACE,kBAACF,EAAe,MAAhB;EACE,WAAWO,EAAGG,IAAO,+DAA+D,0BAA0BF,CAAS;EACvH,GAAIH;CACL,CAAA;AAEL;AAgBA,IAAMO,IAAe;CAAE,IAAI;CAAe,IAAI;AAAc,GACtDC,IAAe;CAAE,IAAI;CAAe,IAAI;AAAY;AAE1D,SAAgBC,EAAiB,EAC/B,kBAAe,GACf,UAAO,MACP,gBACA,cACA,aACA,GAAGT,KACqB;CACxB,IAAMU,IAAI,IAAIC,KACRN,IAAOC,EAAWT,CAAiB,MAAM;CAC/C,OACE,kBAACF,EAAe,QAAhB;EAAuB,SAAA;EACrB,UAAA,kBAACe,GAAD;GAAG,WAAU;GACX,UAAA,kBAACf,EAAe,SAAhB;IACE,WAAWO,EACT,8IACAK,EAAaK,IACbP,KAAQ,kCACR,uEAEAA,IAAO,oCAAoC,kCAC3CF,CACF;IACA,GAAIH;IAVN,UAAA,CAYGa,IACC,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACGC,GACD,kBAAC,QAAD;MAAM,WAAU;MAAqC,UAAAD;KAAkB,CAAA,CACnE;IAEN,CAAA,IAAAC,GAEF,kBAACC,GAAD;KACE,MAAK;KACL,MAAM;KACN,WAAU;IACX,CAAA,CACqB;;EACvB,CAAA;CACkB,CAAA;AAE3B;AAMA,SAAgBC,EAAiB,EAC/B,UAAO,MACP,cACA,aACA,GAAGhB,KACgF;CACnF,IAAMK,IAAOC,EAAWT,CAAiB,MAAM;CAC/C,OACE,kBAACF,EAAe,SAAhB;EACE,WAAWO,EAAG,+BAA+BF,EAAK,cAAc,4BAA4B;EAC5F,GAAIA;EAEJ,UAAA,kBAAC,OAAD;GAAK,WAAWE,EAAG,sBAAsBG,KAAQ,oCAAoCG,EAAaI,IAAOT,CAAS;GAC/G;EACE,CAAA;CACiB,CAAA;AAE5B;AAMA,SAAgBc,EAAgB,EAAE,cAAW,eAAyD;CACpG,OACE,kBAAC,OAAD;EACE,WAAWf,EACT,iIACAC,CACF;EAEC;CACE,CAAA;AAET;AAGA,IAAae,IAActB,EAAiB,MAE/BuB,IAAqBvB,EAAiB;AAEnD,SAAgBwB,EAAmB,EAAE,cAAW,GAAGpB,KAAmE;CACpH,OAAO,kBAACJ,EAAiB,SAAlB;EAA0B,WAAWM,EAAG,+BAA+BC,CAAS;EAAG,GAAIH;CAAO,CAAA;AACvG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type AlertVariant = 'success' | 'warning' | 'danger' | 'info';
|
|
3
|
+
export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
4
|
+
variant?: AlertVariant;
|
|
5
|
+
/** Optional for `callout`, where one line of text is often enough. */
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
/** `box` (default): a bordered message. `callout`: a lighter note with a left bar, for hints inside pages. */
|
|
8
|
+
appearance?: 'box' | 'callout';
|
|
9
|
+
/** Optional action area (e.g. a Button) shown at the end. */
|
|
10
|
+
action?: ReactNode;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Inline feedback message. `danger` is announced immediately (`role="alert"`);
|
|
15
|
+
* the others politely (`role="status"`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function Alert({ variant, title, action, appearance, className, children, ...rest }: AlertProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Icon as t } from "../icon/icon.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/alert/alert.tsx
|
|
5
|
+
var i = {
|
|
6
|
+
success: {
|
|
7
|
+
className: "bg-success-surface border-success-border text-success-fg",
|
|
8
|
+
icon: "accept",
|
|
9
|
+
iconClass: "text-success-icon"
|
|
10
|
+
},
|
|
11
|
+
warning: {
|
|
12
|
+
className: "bg-warning-surface border-warning-border text-warning-fg",
|
|
13
|
+
icon: "warning",
|
|
14
|
+
iconClass: "text-warning-icon"
|
|
15
|
+
},
|
|
16
|
+
danger: {
|
|
17
|
+
className: "bg-danger-surface border-danger-border text-danger-fg",
|
|
18
|
+
icon: "error",
|
|
19
|
+
iconClass: "text-danger-icon"
|
|
20
|
+
},
|
|
21
|
+
info: {
|
|
22
|
+
className: "bg-info-surface border-info-border text-info-fg",
|
|
23
|
+
icon: "info",
|
|
24
|
+
iconClass: "text-info-icon"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function a({ variant: a = "info", title: o, action: s, appearance: c = "box", className: l, children: u, ...d }) {
|
|
28
|
+
let f = i[a], p = c === "callout";
|
|
29
|
+
return /* @__PURE__ */ r("div", {
|
|
30
|
+
role: a === "danger" ? "alert" : "status",
|
|
31
|
+
className: e("flex flex-wrap items-start font-sans", p ? "gap-3 rounded-sm border-l-4 px-4 py-3 [&_a]:font-semibold [&_a]:underline" : "gap-4 rounded-md border px-5 py-4", f.className, l),
|
|
32
|
+
...d,
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ n(t, {
|
|
35
|
+
name: f.icon,
|
|
36
|
+
size: p ? 20 : 28,
|
|
37
|
+
className: e("shrink-0", p ? "mt-px" : "mt-0.5", f.iconClass)
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ r("div", {
|
|
40
|
+
className: "min-w-[min(100%,12rem)] flex-1",
|
|
41
|
+
children: [o && /* @__PURE__ */ n("p", {
|
|
42
|
+
className: e("m-0 font-semibold", p && "text-sm"),
|
|
43
|
+
children: o
|
|
44
|
+
}), u && /* @__PURE__ */ n("div", {
|
|
45
|
+
className: e("text-sm", o ? "mt-0.5" : void 0),
|
|
46
|
+
children: u
|
|
47
|
+
})]
|
|
48
|
+
}),
|
|
49
|
+
s && /* @__PURE__ */ n("div", {
|
|
50
|
+
className: "shrink-0 self-center",
|
|
51
|
+
children: s
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { a as Alert };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert.js","names":["VARIANTS","Alert","rest","v","variant","callout","appearance","cx","className","Icon","title","children","action"],"sources":["../../src/alert/alert.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Icon, type IconName } from '../icon/icon';\n\nexport type AlertVariant = 'success' | 'warning' | 'danger' | 'info';\n\nconst VARIANTS: Record<AlertVariant, { className: string; icon: IconName; iconClass: string }> = {\n success: { className: 'bg-success-surface border-success-border text-success-fg', icon: 'accept', iconClass: 'text-success-icon' },\n warning: { className: 'bg-warning-surface border-warning-border text-warning-fg', icon: 'warning', iconClass: 'text-warning-icon' },\n danger: { className: 'bg-danger-surface border-danger-border text-danger-fg', icon: 'error', iconClass: 'text-danger-icon' },\n info: { className: 'bg-info-surface border-info-border text-info-fg', icon: 'info', iconClass: 'text-info-icon' },\n};\n\nexport interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n variant?: AlertVariant;\n /** Optional for `callout`, where one line of text is often enough. */\n title?: ReactNode;\n /** `box` (default): a bordered message. `callout`: a lighter note with a left bar, for hints inside pages. */\n appearance?: 'box' | 'callout';\n /** Optional action area (e.g. a Button) shown at the end. */\n action?: ReactNode;\n children?: ReactNode;\n}\n\n/**\n * Inline feedback message. `danger` is announced immediately (`role=\"alert\"`);\n * the others politely (`role=\"status\"`).\n */\nexport function Alert({ variant = 'info', title, action, appearance = 'box', className, children, ...rest }: AlertProps) {\n const v = VARIANTS[variant];\n const callout = appearance === 'callout';\n return (\n <div\n role={variant === 'danger' ? 'alert' : 'status'}\n className={cx(\n 'flex flex-wrap items-start font-sans',\n callout ? 'gap-3 rounded-sm border-l-4 px-4 py-3 [&_a]:font-semibold [&_a]:underline' : 'gap-4 rounded-md border px-5 py-4',\n v.className,\n className,\n )}\n {...rest}\n >\n <Icon name={v.icon} size={callout ? 20 : 28} className={cx('shrink-0', callout ? 'mt-px' : 'mt-0.5', v.iconClass)} />\n <div className=\"min-w-[min(100%,12rem)] flex-1\">\n {title && <p className={cx('m-0 font-semibold', callout && 'text-sm')}>{title}</p>}\n {children && <div className={cx('text-sm', title ? 'mt-0.5' : undefined)}>{children}</div>}\n </div>\n {action && <div className=\"shrink-0 self-center\">{action}</div>}\n </div>\n );\n}\n"],"mappings":";;;;AAMA,IAAMA,IAA2F;CAC/F,SAAS;EAAE,WAAW;EAA4D,MAAM;EAAU,WAAW;CAAoB;CACjI,SAAS;EAAE,WAAW;EAA4D,MAAM;EAAW,WAAW;CAAoB;CAClI,QAAQ;EAAE,WAAW;EAAyD,MAAM;EAAS,WAAW;CAAmB;CAC3H,MAAM;EAAE,WAAW;EAAmD,MAAM;EAAQ,WAAW;CAAiB;AAClH;AAiBA,SAAgBC,EAAM,EAAE,aAAU,QAAQ,UAAO,WAAQ,gBAAa,OAAO,cAAW,aAAU,GAAGC,KAAoB;CACvH,IAAMC,IAAIH,EAASI,IACbC,IAAUC,MAAe;CAC/B,OACE,kBAAC,OAAD;EACE,MAAMF,MAAY,WAAW,UAAU;EACvC,WAAWG,EACT,wCACAF,IAAU,8EAA8E,qCACxFF,EAAE,WACFK,CACF;EACA,GAAIN;EARN,UAAA;GAUE,kBAACO,GAAD;IAAM,MAAMN,EAAE;IAAM,MAAME,IAAU,KAAK;IAAI,WAAWE,EAAG,YAAYF,IAAU,UAAU,UAAUF,EAAE,SAAS;GAAI,CAAA;GACpH,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACGO,KAAS,kBAAC,KAAD;KAAG,WAAWH,EAAG,qBAAqBF,KAAW,SAAS;KAAI,UAAAK;IAAS,CAAA,GAChFC,KAAY,kBAAC,OAAD;KAAK,WAAWJ,EAAG,WAAWG,IAAQ,WAAW,KAAA,CAAS;KAAI;IAAc,CAAA,CACtF;;GACJE,KAAU,kBAAC,OAAD;IAAK,WAAU;IAAwB,UAAAA;GAAY,CAAA;EAC3D;;AAET"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface KodffeAttributionProps {
|
|
3
|
+
/** `logo` (recommended in footers): "By" + the Kodffe logo. `text`: "By Kodffe". */
|
|
4
|
+
variant?: 'logo' | 'text';
|
|
5
|
+
href?: string;
|
|
6
|
+
/** The word before the name ("By", "Por"). */
|
|
7
|
+
label?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
/** "By Kodffe" for the footers of Kodffe's products, as text or with the logo; inherits the text color. */
|
|
11
|
+
export declare function KodffeAttribution({ variant, href, label, className, }: KodffeAttributionProps): import("react").JSX.Element;
|
|
12
|
+
export interface AppFooterProps {
|
|
13
|
+
/** Product name ("Kudibot"). */
|
|
14
|
+
product: ReactNode;
|
|
15
|
+
/** Short line after the product ("People and recognition"). */
|
|
16
|
+
tagline?: ReactNode;
|
|
17
|
+
/** Small links in the middle (Help, Status, Terms). */
|
|
18
|
+
links?: {
|
|
19
|
+
label: string;
|
|
20
|
+
href: string;
|
|
21
|
+
}[];
|
|
22
|
+
attribution?: KodffeAttributionProps['variant'] | false;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The slim footer of admin pages: product · tagline on the left, "By Kodffe" on the right. Pass it to
|
|
27
|
+
* `AppShell`'s `footer` (which provides the `<footer>` landmark and the centred container).
|
|
28
|
+
*/
|
|
29
|
+
export declare function AppFooter({ product, tagline, links, attribution, className }: AppFooterProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Logo as t } from "../logo/logo.js";
|
|
3
|
+
import { Fragment as n, jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
4
|
+
//#region src/app-shell/app-footer.tsx
|
|
5
|
+
function a({ variant: n = "logo", href: a = "https://kodffe.com", label: o = "By", className: s }) {
|
|
6
|
+
return /* @__PURE__ */ i("a", {
|
|
7
|
+
href: a,
|
|
8
|
+
className: e("inline-flex items-center gap-1.5 rounded-xs text-sm text-fg-muted no-underline hover:text-fg focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus", s),
|
|
9
|
+
children: [o, n === "logo" ? /* @__PURE__ */ r(t, { className: "text-[0.95rem] text-fg" }) : /* @__PURE__ */ r("span", {
|
|
10
|
+
className: "font-semibold text-fg",
|
|
11
|
+
children: "Kodffe"
|
|
12
|
+
})]
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function o({ product: t, tagline: o, links: s = [], attribution: c = "logo", className: l }) {
|
|
16
|
+
return /* @__PURE__ */ i("div", {
|
|
17
|
+
className: e("flex w-full flex-wrap items-center justify-between gap-x-6 gap-y-2 font-sans text-sm text-fg-muted", l),
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ i("span", { children: [/* @__PURE__ */ r("span", {
|
|
20
|
+
className: "font-semibold text-fg",
|
|
21
|
+
children: t
|
|
22
|
+
}), o && /* @__PURE__ */ i(n, { children: [" · ", o] })] }),
|
|
23
|
+
s.length > 0 && /* @__PURE__ */ r("nav", {
|
|
24
|
+
"aria-label": "Footer",
|
|
25
|
+
className: "flex flex-wrap gap-x-4 gap-y-1",
|
|
26
|
+
children: s.map((e) => /* @__PURE__ */ r("a", {
|
|
27
|
+
href: e.href,
|
|
28
|
+
className: "text-fg-muted no-underline hover:text-fg hover:underline",
|
|
29
|
+
children: e.label
|
|
30
|
+
}, e.href))
|
|
31
|
+
}),
|
|
32
|
+
c && /* @__PURE__ */ r(a, { variant: c })
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { o as AppFooter, a as KodffeAttribution };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=app-footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-footer.js","names":["_Fragment","KodffeAttribution","cx","className","label","variant","Logo","AppFooter","product","tagline","Fragment","links","l","attribution"],"sources":["../../src/app-shell/app-footer.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Logo } from '../logo/logo';\n\nexport interface KodffeAttributionProps {\n /** `logo` (recommended in footers): \"By\" + the Kodffe logo. `text`: \"By Kodffe\". */\n variant?: 'logo' | 'text';\n href?: string;\n /** The word before the name (\"By\", \"Por\"). */\n label?: string;\n className?: string;\n}\n\n/** \"By Kodffe\" for the footers of Kodffe's products, as text or with the logo; inherits the text color. */\nexport function KodffeAttribution({\n variant = 'logo',\n href = 'https://kodffe.com',\n label = 'By',\n className,\n}: KodffeAttributionProps) {\n return (\n <a\n href={href}\n className={cx(\n 'inline-flex items-center gap-1.5 rounded-xs text-sm text-fg-muted no-underline hover:text-fg focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus',\n className,\n )}\n >\n {label}\n {variant === 'logo' ? (\n <Logo className=\"text-[0.95rem] text-fg\" />\n ) : (\n <span className=\"font-semibold text-fg\">Kodffe</span>\n )}\n </a>\n );\n}\n\nexport interface AppFooterProps {\n /** Product name (\"Kudibot\"). */\n product: ReactNode;\n /** Short line after the product (\"People and recognition\"). */\n tagline?: ReactNode;\n /** Small links in the middle (Help, Status, Terms). */\n links?: { label: string; href: string }[];\n attribution?: KodffeAttributionProps['variant'] | false;\n className?: string;\n}\n\n/**\n * The slim footer of admin pages: product · tagline on the left, \"By Kodffe\" on the right. Pass it to\n * `AppShell`'s `footer` (which provides the `<footer>` landmark and the centred container).\n */\nexport function AppFooter({ product, tagline, links = [], attribution = 'logo', className }: AppFooterProps) {\n return (\n <div\n className={cx(\n 'flex w-full flex-wrap items-center justify-between gap-x-6 gap-y-2 font-sans text-sm text-fg-muted',\n className,\n )}\n >\n <span>\n <span className=\"font-semibold text-fg\">{product}</span>\n {tagline && <> · {tagline}</>}\n </span>\n {links.length > 0 && (\n <nav aria-label=\"Footer\" className=\"flex flex-wrap gap-x-4 gap-y-1\">\n {links.map((l) => (\n <a key={l.href} href={l.href} className=\"text-fg-muted no-underline hover:text-fg hover:underline\">\n {l.label}\n </a>\n ))}\n </nav>\n )}\n {attribution && <KodffeAttribution variant={attribution} />}\n </div>\n );\n}\n"],"mappings":";;;;AAcA,SAAgBC,EAAkB,EAChC,aAAU,QACV,UAAO,sBACP,WAAQ,MACR,gBACyB;CACzB,OACE,kBAAC,KAAD;EACQ;EACN,WAAWC,EACT,mLACAC,CACF;EALF,UAAA,CAOGC,GACAC,MAAY,SACX,kBAACC,GAAD,EAAM,WAAU,yBAA0B,CAAA,IAE1C,kBAAC,QAAD;GAAM,WAAU;GAAwB,UAAA;EAAY,CAAA,CAErD;;AAEP;AAiBA,SAAgBC,EAAU,EAAE,YAAS,YAAS,WAAQ,CAAC,GAAG,iBAAc,QAAQ,gBAA6B;CAC3G,OACE,kBAAC,OAAD;EACE,WAAWL,EACT,sGACAC,CACF;EAJF,UAAA;GAME,kBAAC,QAAD,EAAA,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAAyB,UAAAK;GAAc,CAAA,GACtDC,KAAW,kBAAAT,GAAA,EAAA,UAAA,CAAE,OAAIS,CAAU,EAAA,CAAA,CACxB,EAAA,CAAA;GACLE,EAAM,SAAS,KACd,kBAAC,OAAD;IAAK,cAAW;IAAS,WAAU;IAChC,UAAAA,EAAM,KAAK,MACV,kBAAC,KAAD;KAAgB,MAAMC,EAAE;KAAM,WAAU;KACrC,UAAAA,EAAE;IACF,GAFKA,EAAE,IAEP,CACJ;GACE,CAAA;GAENC,KAAe,kBAACZ,GAAD,EAAmB,SAASY,EAAc,CAAA;EACvD;;AAET"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface AppShellState {
|
|
2
|
+
/** Desktop sidebar shows icons only. */
|
|
3
|
+
collapsed: boolean;
|
|
4
|
+
/** Rendering inside the mobile drawer. */
|
|
5
|
+
inDrawer: boolean;
|
|
6
|
+
/** Closes the mobile drawer (call after navigating). */
|
|
7
|
+
closeDrawer: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const AppShellContext: import("react").Context<AppShellState>;
|
|
10
|
+
export declare const useAppShell: () => AppShellState;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext as e, useContext as t } from "react";
|
|
3
|
+
//#region src/app-shell/app-shell-context.ts
|
|
4
|
+
var n = e({
|
|
5
|
+
collapsed: !1,
|
|
6
|
+
inDrawer: !1,
|
|
7
|
+
closeDrawer: () => {}
|
|
8
|
+
}), r = () => t(n);
|
|
9
|
+
//#endregion
|
|
10
|
+
export { n as AppShellContext, r as useAppShell };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=app-shell-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell-context.js","names":["AppShellContext","createContext","useAppShell","useContext"],"sources":["../../src/app-shell/app-shell-context.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\nexport interface AppShellState {\n /** Desktop sidebar shows icons only. */\n collapsed: boolean;\n /** Rendering inside the mobile drawer. */\n inDrawer: boolean;\n /** Closes the mobile drawer (call after navigating). */\n closeDrawer: () => void;\n}\n\nexport const AppShellContext = createContext<AppShellState>({\n collapsed: false,\n inDrawer: false,\n closeDrawer: () => {},\n});\n\nexport const useAppShell = () => useContext(AppShellContext);\n"],"mappings":";;;AAaA,IAAaA,IAAkBC,EAA6B;CAC1D,WAAW;CACX,UAAU;CACV,mBAAmB,CAAC;AACtB,CAAC,GAEYC,UAAoBC,EAAWH,CAAe"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface AppShellProps {
|
|
3
|
+
/** Brand at the top of the sidebar and in the mobile top bar (e.g. `<Logo />` in a link). */
|
|
4
|
+
brand: ReactNode;
|
|
5
|
+
/** Brand for the collapsed 72px rail (e.g. `<Logo variant="mark" />` in a link). Defaults to `brand`. */
|
|
6
|
+
brandCompact?: ReactNode;
|
|
7
|
+
/** Navigation (usually `<SideNav />`). Rendered in the sidebar and in the mobile drawer. */
|
|
8
|
+
nav?: ReactNode;
|
|
9
|
+
/** Bottom of the sidebar: workspace switcher, user menu, help. Hidden in the collapsed rail. */
|
|
10
|
+
navFooter?: ReactNode;
|
|
11
|
+
/** Top-bar content: page title, search, notifications, user menu. */
|
|
12
|
+
header?: ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* `sidebar` (default): full-height collapsible sidebar beside the top bar. `topbar`: a full-width top bar
|
|
15
|
+
* (brand, header content), then the sidebar and the content side by side in a centred container, and a slim
|
|
16
|
+
* `footer` (admin dashboards).
|
|
17
|
+
*/
|
|
18
|
+
layout?: 'sidebar' | 'topbar';
|
|
19
|
+
/** `topbar` only: slim footer under the content ("By Kodffe", version, links). */
|
|
20
|
+
footer?: ReactNode;
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/** Controlled collapsed state of the desktop sidebar. */
|
|
23
|
+
collapsed?: boolean;
|
|
24
|
+
defaultCollapsed?: boolean;
|
|
25
|
+
onCollapsedChange?: (collapsed: boolean) => void;
|
|
26
|
+
labels?: Partial<typeof LABELS>;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const LABELS: {
|
|
30
|
+
skip: string;
|
|
31
|
+
openMenu: string;
|
|
32
|
+
menu: string;
|
|
33
|
+
collapse: string;
|
|
34
|
+
expand: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Product layout. `sidebar`: collapsible sidebar + top bar + content. `topbar`: full-width top bar, then
|
|
38
|
+
* sidebar and content in a centred container, and a slim footer. Below 960px the sidebar becomes a
|
|
39
|
+
* drawer opened from the top bar's menu button. Includes a skip link to the main content.
|
|
40
|
+
*/
|
|
41
|
+
export declare function AppShell({ brand, brandCompact, nav, navFooter, header, layout, footer, children, collapsed: collapsedProp, defaultCollapsed, onCollapsedChange, labels: overrides, className, }: AppShellProps): import("react").JSX.Element;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Drawer as t, DrawerContent as n, DrawerTrigger as r } from "../drawer/drawer.js";
|
|
4
|
+
import { Tooltip as i } from "../tooltip/tooltip.js";
|
|
5
|
+
import { Glyph as a } from "../lib/glyphs.js";
|
|
6
|
+
import { AppShellContext as o } from "./app-shell-context.js";
|
|
7
|
+
import { SkipLink as s } from "../lib/skip-link.js";
|
|
8
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
9
|
+
import { useState as u } from "react";
|
|
10
|
+
//#region src/app-shell/app-shell.tsx
|
|
11
|
+
var d = {
|
|
12
|
+
skip: "Skip to content",
|
|
13
|
+
openMenu: "Open menu",
|
|
14
|
+
menu: "Menu",
|
|
15
|
+
collapse: "Collapse sidebar",
|
|
16
|
+
expand: "Expand sidebar"
|
|
17
|
+
};
|
|
18
|
+
function f({ brand: f, brandCompact: p, nav: m, navFooter: h, header: g, layout: _ = "sidebar", footer: v, children: y, collapsed: b, defaultCollapsed: x = !1, onCollapsedChange: S, labels: C, className: w }) {
|
|
19
|
+
let T = {
|
|
20
|
+
...d,
|
|
21
|
+
...C
|
|
22
|
+
}, [E, D] = u(x), O = b ?? E, [k, A] = u(!1), j = () => {
|
|
23
|
+
b === void 0 && D(!O), S?.(!O);
|
|
24
|
+
}, M = () => A(!1), N = "grid size-10 shrink-0 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-fg hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-1 focus-visible:outline-focus", P = /* @__PURE__ */ c(s, { label: T.skip }), F = /* @__PURE__ */ l(t, {
|
|
25
|
+
open: k,
|
|
26
|
+
onOpenChange: A,
|
|
27
|
+
children: [/* @__PURE__ */ c(r, {
|
|
28
|
+
asChild: !0,
|
|
29
|
+
children: /* @__PURE__ */ c("button", {
|
|
30
|
+
type: "button",
|
|
31
|
+
"aria-label": T.openMenu,
|
|
32
|
+
className: e(N, "-ml-2 md:hidden"),
|
|
33
|
+
children: /* @__PURE__ */ c(a, {
|
|
34
|
+
name: "menu",
|
|
35
|
+
size: 22
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
}), /* @__PURE__ */ c(n, {
|
|
39
|
+
side: "left",
|
|
40
|
+
size: "sm",
|
|
41
|
+
title: T.menu,
|
|
42
|
+
hideTitle: !0,
|
|
43
|
+
bodyClassName: "px-3! flex flex-col gap-4",
|
|
44
|
+
children: /* @__PURE__ */ l(o.Provider, {
|
|
45
|
+
value: {
|
|
46
|
+
collapsed: !1,
|
|
47
|
+
inDrawer: !0,
|
|
48
|
+
closeDrawer: M
|
|
49
|
+
},
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ c("div", {
|
|
52
|
+
className: "px-3",
|
|
53
|
+
children: f
|
|
54
|
+
}),
|
|
55
|
+
m,
|
|
56
|
+
h && /* @__PURE__ */ c("div", {
|
|
57
|
+
className: "mt-auto border-t border-border pt-3",
|
|
58
|
+
children: h
|
|
59
|
+
})
|
|
60
|
+
]
|
|
61
|
+
})
|
|
62
|
+
})]
|
|
63
|
+
});
|
|
64
|
+
return _ === "topbar" ? /* @__PURE__ */ l("div", {
|
|
65
|
+
className: e("flex min-h-dvh flex-col bg-bg font-sans text-fg", w),
|
|
66
|
+
children: [
|
|
67
|
+
P,
|
|
68
|
+
/* @__PURE__ */ c("header", {
|
|
69
|
+
className: "sticky top-0 z-40 h-appbar shrink-0 border-b border-border bg-surface/90 backdrop-blur-md",
|
|
70
|
+
children: /* @__PURE__ */ l("div", {
|
|
71
|
+
className: "mx-auto flex h-full max-w-app items-center gap-3 px-gutter",
|
|
72
|
+
children: [
|
|
73
|
+
m ? F : null,
|
|
74
|
+
/* @__PURE__ */ c("div", {
|
|
75
|
+
className: "shrink-0",
|
|
76
|
+
children: f
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ c("div", {
|
|
79
|
+
className: "flex min-w-0 flex-1 items-center justify-end gap-2",
|
|
80
|
+
children: g
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
}),
|
|
85
|
+
/* @__PURE__ */ l("div", {
|
|
86
|
+
className: "mx-auto flex w-full max-w-app flex-1 gap-8 px-gutter py-6",
|
|
87
|
+
children: [m && /* @__PURE__ */ c(o.Provider, {
|
|
88
|
+
value: {
|
|
89
|
+
collapsed: !1,
|
|
90
|
+
inDrawer: !1,
|
|
91
|
+
closeDrawer: M
|
|
92
|
+
},
|
|
93
|
+
children: /* @__PURE__ */ c("aside", {
|
|
94
|
+
className: "hidden w-sidebar shrink-0 md:block",
|
|
95
|
+
children: /* @__PURE__ */ l("div", {
|
|
96
|
+
className: "sticky top-[calc(var(--spacing-appbar)+1.5rem)] grid max-h-[calc(100dvh-var(--spacing-appbar)-3rem)] gap-4 overflow-y-auto",
|
|
97
|
+
children: [m, h && /* @__PURE__ */ c("div", {
|
|
98
|
+
className: "border-t border-border pt-3",
|
|
99
|
+
children: h
|
|
100
|
+
})]
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
}), /* @__PURE__ */ c("main", {
|
|
104
|
+
id: "kf-main",
|
|
105
|
+
tabIndex: -1,
|
|
106
|
+
className: "min-w-0 flex-1 focus:outline-none",
|
|
107
|
+
children: y
|
|
108
|
+
})]
|
|
109
|
+
}),
|
|
110
|
+
v && /* @__PURE__ */ c("footer", {
|
|
111
|
+
className: "border-t border-border",
|
|
112
|
+
children: /* @__PURE__ */ c("div", {
|
|
113
|
+
className: "mx-auto flex max-w-app flex-wrap items-center justify-between gap-x-6 gap-y-2 px-gutter py-4 text-sm text-fg-muted",
|
|
114
|
+
children: v
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
]
|
|
118
|
+
}) : /* @__PURE__ */ l("div", {
|
|
119
|
+
className: e("flex min-h-dvh bg-bg font-sans text-fg", w),
|
|
120
|
+
children: [
|
|
121
|
+
P,
|
|
122
|
+
/* @__PURE__ */ c(o.Provider, {
|
|
123
|
+
value: {
|
|
124
|
+
collapsed: O,
|
|
125
|
+
inDrawer: !1,
|
|
126
|
+
closeDrawer: M
|
|
127
|
+
},
|
|
128
|
+
children: /* @__PURE__ */ l("aside", {
|
|
129
|
+
className: e("sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border bg-surface transition-[width] duration-200 ease-standard motion-reduce:transition-none md:flex", O ? "w-[4.5rem]" : "w-64"),
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ c("div", {
|
|
132
|
+
className: e("flex h-16 shrink-0 items-center overflow-hidden", O ? "justify-center px-2" : "px-5"),
|
|
133
|
+
children: O ? p ?? f : f
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ c("div", {
|
|
136
|
+
className: "min-h-0 flex-1 overflow-x-hidden overflow-y-auto px-3 py-2",
|
|
137
|
+
children: m
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ l("div", {
|
|
140
|
+
className: e("flex shrink-0 items-center gap-2 border-t border-border p-3", O && "flex-col"),
|
|
141
|
+
children: [h && !O && /* @__PURE__ */ c("div", {
|
|
142
|
+
className: "min-w-0 flex-1",
|
|
143
|
+
children: h
|
|
144
|
+
}), /* @__PURE__ */ c(i, {
|
|
145
|
+
content: O ? T.expand : T.collapse,
|
|
146
|
+
side: "right",
|
|
147
|
+
children: /* @__PURE__ */ c("button", {
|
|
148
|
+
type: "button",
|
|
149
|
+
"aria-label": O ? T.expand : T.collapse,
|
|
150
|
+
"aria-expanded": !O,
|
|
151
|
+
onClick: j,
|
|
152
|
+
className: e(N, "text-fg-muted"),
|
|
153
|
+
children: /* @__PURE__ */ c(a, {
|
|
154
|
+
name: "sidebar",
|
|
155
|
+
size: 20
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
})]
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ l("div", {
|
|
164
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
165
|
+
children: [/* @__PURE__ */ l("header", {
|
|
166
|
+
className: "sticky top-0 z-40 flex h-16 shrink-0 items-center gap-3 border-b border-border bg-bg/85 px-4 backdrop-blur-md sm:px-6",
|
|
167
|
+
children: [
|
|
168
|
+
F,
|
|
169
|
+
/* @__PURE__ */ c("div", {
|
|
170
|
+
className: "md:hidden",
|
|
171
|
+
children: f
|
|
172
|
+
}),
|
|
173
|
+
/* @__PURE__ */ c("div", {
|
|
174
|
+
className: "flex min-w-0 flex-1 items-center justify-end gap-2 md:justify-between",
|
|
175
|
+
children: g
|
|
176
|
+
})
|
|
177
|
+
]
|
|
178
|
+
}), /* @__PURE__ */ c("main", {
|
|
179
|
+
id: "kf-main",
|
|
180
|
+
tabIndex: -1,
|
|
181
|
+
className: "min-w-0 flex-1 focus:outline-none",
|
|
182
|
+
children: y
|
|
183
|
+
})]
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { f as AppShell };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=app-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell.js","names":["LABELS","AppShell","collapsedProp","overrides","labels","uncontrolled","setUncontrolled","useState","defaultCollapsed","collapsed","drawerOpen","setDrawerOpen","toggle","onCollapsedChange","closeDrawer","iconButton","skipLink","SkipLink","mobileMenu","Drawer","DrawerTrigger","cx","Glyph","DrawerContent","AppShellContext","brand","nav","navFooter","layout","className","header","footer","brandCompact","Tooltip"],"sources":["../../src/app-shell/app-shell.tsx"],"sourcesContent":["'use client';\n\nimport { useState, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { SkipLink } from '../lib/skip-link';\nimport { Glyph } from '../lib/glyphs';\nimport { Drawer, DrawerContent, DrawerTrigger } from '../drawer/drawer';\nimport { Tooltip } from '../tooltip/tooltip';\nimport { AppShellContext } from './app-shell-context';\n\nexport interface AppShellProps {\n /** Brand at the top of the sidebar and in the mobile top bar (e.g. `<Logo />` in a link). */\n brand: ReactNode;\n /** Brand for the collapsed 72px rail (e.g. `<Logo variant=\"mark\" />` in a link). Defaults to `brand`. */\n brandCompact?: ReactNode;\n /** Navigation (usually `<SideNav />`). Rendered in the sidebar and in the mobile drawer. */\n nav?: ReactNode;\n /** Bottom of the sidebar: workspace switcher, user menu, help. Hidden in the collapsed rail. */\n navFooter?: ReactNode;\n /** Top-bar content: page title, search, notifications, user menu. */\n header?: ReactNode;\n /**\n * `sidebar` (default): full-height collapsible sidebar beside the top bar. `topbar`: a full-width top bar\n * (brand, header content), then the sidebar and the content side by side in a centred container, and a slim\n * `footer` (admin dashboards).\n */\n layout?: 'sidebar' | 'topbar';\n /** `topbar` only: slim footer under the content (\"By Kodffe\", version, links). */\n footer?: ReactNode;\n children: ReactNode;\n /** Controlled collapsed state of the desktop sidebar. */\n collapsed?: boolean;\n defaultCollapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n labels?: Partial<typeof LABELS>;\n className?: string;\n}\n\nconst LABELS = {\n skip: 'Skip to content',\n openMenu: 'Open menu',\n menu: 'Menu',\n collapse: 'Collapse sidebar',\n expand: 'Expand sidebar',\n};\n\n/**\n * Product layout. `sidebar`: collapsible sidebar + top bar + content. `topbar`: full-width top bar, then\n * sidebar and content in a centred container, and a slim footer. Below 960px the sidebar becomes a\n * drawer opened from the top bar's menu button. Includes a skip link to the main content.\n */\nexport function AppShell({\n brand,\n brandCompact,\n nav,\n navFooter,\n header,\n layout = 'sidebar',\n footer,\n children,\n collapsed: collapsedProp,\n defaultCollapsed = false,\n onCollapsedChange,\n labels: overrides,\n className,\n}: AppShellProps) {\n const labels = { ...LABELS, ...overrides };\n const [uncontrolled, setUncontrolled] = useState(defaultCollapsed);\n const collapsed = collapsedProp ?? uncontrolled;\n const [drawerOpen, setDrawerOpen] = useState(false);\n const toggle = () => {\n if (collapsedProp === undefined) setUncontrolled(!collapsed);\n onCollapsedChange?.(!collapsed);\n };\n const closeDrawer = () => setDrawerOpen(false);\n const iconButton =\n 'grid size-10 shrink-0 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-fg hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-1 focus-visible:outline-focus';\n\n const skipLink = <SkipLink label={labels.skip} />;\n\n const mobileMenu = (\n <Drawer open={drawerOpen} onOpenChange={setDrawerOpen}>\n <DrawerTrigger asChild>\n <button type=\"button\" aria-label={labels.openMenu} className={cx(iconButton, '-ml-2 md:hidden')}>\n <Glyph name=\"menu\" size={22} />\n </button>\n </DrawerTrigger>\n <DrawerContent side=\"left\" size=\"sm\" title={labels.menu} hideTitle bodyClassName=\"px-3! flex flex-col gap-4\">\n <AppShellContext.Provider value={{ collapsed: false, inDrawer: true, closeDrawer }}>\n <div className=\"px-3\">{brand}</div>\n {nav}\n {navFooter && <div className=\"mt-auto border-t border-border pt-3\">{navFooter}</div>}\n </AppShellContext.Provider>\n </DrawerContent>\n </Drawer>\n );\n\n if (layout === 'topbar') {\n return (\n <div className={cx('flex min-h-dvh flex-col bg-bg font-sans text-fg', className)}>\n {skipLink}\n <header className=\"sticky top-0 z-40 h-appbar shrink-0 border-b border-border bg-surface/90 backdrop-blur-md\">\n <div className=\"mx-auto flex h-full max-w-app items-center gap-3 px-gutter\">\n {/* Pages without a sidebar (account settings) have no menu to open. */}\n {nav ? mobileMenu : null}\n <div className=\"shrink-0\">{brand}</div>\n <div className=\"flex min-w-0 flex-1 items-center justify-end gap-2\">{header}</div>\n </div>\n </header>\n <div className=\"mx-auto flex w-full max-w-app flex-1 gap-8 px-gutter py-6\">\n {nav && (\n <AppShellContext.Provider value={{ collapsed: false, inDrawer: false, closeDrawer }}>\n <aside className=\"hidden w-sidebar shrink-0 md:block\">\n {/* Sticks under the top bar; scrolls on its own when taller than the viewport. */}\n <div className=\"sticky top-[calc(var(--spacing-appbar)+1.5rem)] grid max-h-[calc(100dvh-var(--spacing-appbar)-3rem)] gap-4 overflow-y-auto\">\n {nav}\n {navFooter && <div className=\"border-t border-border pt-3\">{navFooter}</div>}\n </div>\n </aside>\n </AppShellContext.Provider>\n )}\n <main id=\"kf-main\" tabIndex={-1} className=\"min-w-0 flex-1 focus:outline-none\">\n {children}\n </main>\n </div>\n {footer && (\n <footer className=\"border-t border-border\">\n <div className=\"mx-auto flex max-w-app flex-wrap items-center justify-between gap-x-6 gap-y-2 px-gutter py-4 text-sm text-fg-muted\">\n {footer}\n </div>\n </footer>\n )}\n </div>\n );\n }\n\n return (\n <div className={cx('flex min-h-dvh bg-bg font-sans text-fg', className)}>\n {skipLink}\n\n <AppShellContext.Provider value={{ collapsed, inDrawer: false, closeDrawer }}>\n <aside\n className={cx(\n 'sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border bg-surface transition-[width] duration-200 ease-standard motion-reduce:transition-none md:flex',\n collapsed ? 'w-[4.5rem]' : 'w-64',\n )}\n >\n <div\n className={cx(\n 'flex h-16 shrink-0 items-center overflow-hidden',\n collapsed ? 'justify-center px-2' : 'px-5',\n )}\n >\n {collapsed ? (brandCompact ?? brand) : brand}\n </div>\n <div className=\"min-h-0 flex-1 overflow-x-hidden overflow-y-auto px-3 py-2\">{nav}</div>\n <div className={cx('flex shrink-0 items-center gap-2 border-t border-border p-3', collapsed && 'flex-col')}>\n {navFooter && !collapsed && <div className=\"min-w-0 flex-1\">{navFooter}</div>}\n <Tooltip content={collapsed ? labels.expand : labels.collapse} side=\"right\">\n <button\n type=\"button\"\n aria-label={collapsed ? labels.expand : labels.collapse}\n aria-expanded={!collapsed}\n onClick={toggle}\n className={cx(iconButton, 'text-fg-muted')}\n >\n <Glyph name=\"sidebar\" size={20} />\n </button>\n </Tooltip>\n </div>\n </aside>\n </AppShellContext.Provider>\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <header className=\"sticky top-0 z-40 flex h-16 shrink-0 items-center gap-3 border-b border-border bg-bg/85 px-4 backdrop-blur-md sm:px-6\">\n {mobileMenu}\n <div className=\"md:hidden\">{brand}</div>\n <div className=\"flex min-w-0 flex-1 items-center justify-end gap-2 md:justify-between\">{header}</div>\n </header>\n <main id=\"kf-main\" tabIndex={-1} className=\"min-w-0 flex-1 focus:outline-none\">\n {children}\n </main>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type IconName } from '../icon/icon';
|
|
2
|
+
export interface FloatingAction {
|
|
3
|
+
label: string;
|
|
4
|
+
icon: IconName;
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The bottom-right floating button (the assistant) with optional secondary round buttons, plus "Back to top" after
|
|
9
|
+
* scrolling. Respects the safe area on phones.
|
|
10
|
+
*/
|
|
11
|
+
export declare function FloatingActions({ primary, secondary, scrollTop, labels, className, }: {
|
|
12
|
+
primary: FloatingAction;
|
|
13
|
+
secondary?: FloatingAction[];
|
|
14
|
+
scrollTop?: boolean;
|
|
15
|
+
labels?: {
|
|
16
|
+
top?: string;
|
|
17
|
+
};
|
|
18
|
+
className?: string;
|
|
19
|
+
}): import("react").JSX.Element;
|