@exxatdesignux/ui 0.0.5 → 0.0.7
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/bin/init.mjs +29 -0
- package/package.json +7 -2
- package/template/.nvmrc +1 -0
- package/template/.prettierignore +7 -0
- package/template/.prettierrc +11 -0
- package/template/AGENTS.md +485 -0
- package/template/Logo/Exxat_Prism.svg +39 -0
- package/template/Logo/Exxat_one.svg +36 -0
- package/template/README.md +58 -0
- package/template/app/(app)/compliance/page.tsx +10 -0
- package/template/app/(app)/dashboard/loading.tsx +18 -0
- package/template/app/(app)/dashboard/page.tsx +36 -0
- package/template/app/(app)/data-list/[id]/page.tsx +28 -0
- package/template/app/(app)/data-list/new/page.tsx +31 -0
- package/template/app/(app)/data-list/page.tsx +10 -0
- package/template/app/(app)/error.tsx +43 -0
- package/template/app/(app)/help/page.tsx +34 -0
- package/template/app/(app)/layout.tsx +54 -0
- package/template/app/(app)/loading.tsx +18 -0
- package/template/app/(app)/question-bank/page.tsx +10 -0
- package/template/app/(app)/rotations/page.tsx +15 -0
- package/template/app/(app)/settings/page.tsx +17 -0
- package/template/app/(app)/sites/all/page.tsx +13 -0
- package/template/app/(app)/team/page.tsx +10 -0
- package/template/app/favicon.ico +0 -0
- package/template/app/globals.css +1811 -0
- package/template/app/layout.tsx +95 -0
- package/template/app/page.tsx +9 -0
- package/template/components/.gitkeep +0 -0
- package/template/components/app-sidebar-dynamic.tsx +15 -0
- package/template/components/app-sidebar.tsx +901 -0
- package/template/components/ask-leo-composer.tsx +216 -0
- package/template/components/ask-leo-sidebar.tsx +509 -0
- package/template/components/chart-area-interactive.tsx +293 -0
- package/template/components/charts-overview.tsx +2321 -0
- package/template/components/command-menu-01.tsx +133 -0
- package/template/components/command-menu-02.tsx +386 -0
- package/template/components/command-menu.tsx +182 -0
- package/template/components/compliance-board-view.tsx +134 -0
- package/template/components/compliance-client.tsx +92 -0
- package/template/components/compliance-list-view.tsx +59 -0
- package/template/components/compliance-page-header.tsx +89 -0
- package/template/components/compliance-table.tsx +525 -0
- package/template/components/dashboard-onboarding-gallery.tsx +13 -0
- package/template/components/dashboard-onboarding.tsx +21 -0
- package/template/components/dashboard-promo-banner.tsx +67 -0
- package/template/components/dashboard-quota-progress-card.tsx +369 -0
- package/template/components/dashboard-report-charts.tsx +69 -0
- package/template/components/dashboard-section-heading.tsx +68 -0
- package/template/components/dashboard-tabs.tsx +598 -0
- package/template/components/data-list-client.tsx +239 -0
- package/template/components/data-list-table-cells.test.tsx +22 -0
- package/template/components/data-list-table-cells.tsx +173 -0
- package/template/components/data-list-table.tsx +879 -0
- package/template/components/data-table/filter-date-calendar.tsx +38 -0
- package/template/components/data-table/filter-text-value-input.tsx +77 -0
- package/template/components/data-table/index.tsx +1612 -0
- package/template/components/data-table/pagination.tsx +256 -0
- package/template/components/data-table/types.ts +91 -0
- package/template/components/data-table/use-table-state.ts +566 -0
- package/template/components/data-view-dashboard-charts-compliance.tsx +960 -0
- package/template/components/data-view-dashboard-charts-team.tsx +968 -0
- package/template/components/data-view-dashboard-charts.tsx +1668 -0
- package/template/components/data-views/board-card-primitives.tsx +93 -0
- package/template/components/data-views/index.ts +41 -0
- package/template/components/data-views/list-page-board-card.tsx +192 -0
- package/template/components/data-views/list-page-board-template.tsx +122 -0
- package/template/components/data-views/placement-board-card.tsx +262 -0
- package/template/components/export-drawer.tsx +375 -0
- package/template/components/exxat-product-logo.tsx +453 -0
- package/template/components/form-layout-01.tsx +131 -0
- package/template/components/getting-started.tsx +625 -0
- package/template/components/key-metrics.tsx +920 -0
- package/template/components/leo-insight-indicator.tsx +364 -0
- package/template/components/leo-typing-dots.tsx +121 -0
- package/template/components/list-hub-status-badge.tsx +51 -0
- package/template/components/list-page-dashboard-charts.tsx +18 -0
- package/template/components/nav-documents.tsx +89 -0
- package/template/components/nav-main.tsx +58 -0
- package/template/components/nav-secondary.tsx +64 -0
- package/template/components/nav-user.tsx +190 -0
- package/template/components/new-placement-back-btn.tsx +28 -0
- package/template/components/new-placement-form.tsx +1066 -0
- package/template/components/onboarding/index.ts +4 -0
- package/template/components/onboarding/onboarding-01.tsx +7 -0
- package/template/components/onboarding/onboarding-02.tsx +7 -0
- package/template/components/onboarding/onboarding-03.tsx +7 -0
- package/template/components/onboarding/onboarding-04.tsx +7 -0
- package/template/components/page-header.tsx +57 -0
- package/template/components/placement-detail.tsx +438 -0
- package/template/components/placements-board-view.tsx +404 -0
- package/template/components/placements-list-view.tsx +285 -0
- package/template/components/placements-page-header.tsx +160 -0
- package/template/components/placements-table-columns.tsx +639 -0
- package/template/components/product-switcher.tsx +116 -0
- package/template/components/question-bank-board-view.tsx +205 -0
- package/template/components/question-bank-client.tsx +77 -0
- package/template/components/question-bank-list-view.tsx +59 -0
- package/template/components/question-bank-page-header.tsx +89 -0
- package/template/components/question-bank-table.tsx +586 -0
- package/template/components/rotations-empty-state.tsx +47 -0
- package/template/components/rotations-panel-activator.tsx +8 -0
- package/template/components/secondary-nav.tsx +394 -0
- package/template/components/secondary-panel.tsx +239 -0
- package/template/components/section-cards.tsx +106 -0
- package/template/components/settings-appearance-card.tsx +424 -0
- package/template/components/settings-client.tsx +537 -0
- package/template/components/settings-form-row.tsx +42 -0
- package/template/components/sidebar-auto-collapse.tsx +23 -0
- package/template/components/sidebar-auto-open.tsx +18 -0
- package/template/components/sidebar-shell.tsx +37 -0
- package/template/components/site-header.tsx +93 -0
- package/template/components/sites-all-client.tsx +154 -0
- package/template/components/sites-board-view.tsx +67 -0
- package/template/components/sites-list-view.tsx +47 -0
- package/template/components/sites-table.tsx +312 -0
- package/template/components/system-banner-slot.tsx +66 -0
- package/template/components/table-properties/column-row.tsx +90 -0
- package/template/components/table-properties/draggable-list.ts +49 -0
- package/template/components/table-properties/drawer-button.tsx +231 -0
- package/template/components/table-properties/drawer.tsx +1102 -0
- package/template/components/table-properties/filter-card.tsx +251 -0
- package/template/components/table-properties/index.ts +22 -0
- package/template/components/table-properties/sort-card.tsx +59 -0
- package/template/components/table-properties/types.ts +124 -0
- package/template/components/task-list-panel.tsx +98 -0
- package/template/components/task-priority-badge.tsx +28 -0
- package/template/components/team-board-view.tsx +114 -0
- package/template/components/team-client.tsx +93 -0
- package/template/components/team-list-view.tsx +62 -0
- package/template/components/team-page-header.tsx +92 -0
- package/template/components/team-table.tsx +525 -0
- package/template/components/templates/list-page.tsx +576 -0
- package/template/components/templates/primary-page-template.tsx +56 -0
- package/template/components/theme-color-sync.tsx +32 -0
- package/template/components/theme-provider.tsx +71 -0
- package/template/components/tinted-icon-disc.tsx +53 -0
- package/template/components/ui/ai-thinking-surface.tsx +121 -0
- package/template/components/ui/avatar.tsx +1 -0
- package/template/components/ui/badge.tsx +1 -0
- package/template/components/ui/banner.tsx +1 -0
- package/template/components/ui/breadcrumb.tsx +1 -0
- package/template/components/ui/button.tsx +1 -0
- package/template/components/ui/calendar.tsx +1 -0
- package/template/components/ui/card.tsx +1 -0
- package/template/components/ui/chart.tsx +1 -0
- package/template/components/ui/checkbox.tsx +1 -0
- package/template/components/ui/coach-mark.tsx +1 -0
- package/template/components/ui/collapsible.tsx +1 -0
- package/template/components/ui/command.tsx +1 -0
- package/template/components/ui/date-picker-field.tsx +1 -0
- package/template/components/ui/dialog.tsx +1 -0
- package/template/components/ui/dot-pattern.tsx +159 -0
- package/template/components/ui/drag-handle-grip.tsx +1 -0
- package/template/components/ui/drawer.tsx +1 -0
- package/template/components/ui/dropdown-menu.tsx +1 -0
- package/template/components/ui/field.tsx +1 -0
- package/template/components/ui/form.tsx +1 -0
- package/template/components/ui/input-group.tsx +1 -0
- package/template/components/ui/input-mask.tsx +1 -0
- package/template/components/ui/input.tsx +1 -0
- package/template/components/ui/kbd.tsx +1 -0
- package/template/components/ui/label.tsx +1 -0
- package/template/components/ui/leo-icon.tsx +726 -0
- package/template/components/ui/payment-card-fields.tsx +1 -0
- package/template/components/ui/popover.tsx +1 -0
- package/template/components/ui/radio-group.tsx +1 -0
- package/template/components/ui/select.tsx +1 -0
- package/template/components/ui/selection-tile-grid.tsx +1 -0
- package/template/components/ui/separator.tsx +1 -0
- package/template/components/ui/sheet.tsx +1 -0
- package/template/components/ui/sidebar.tsx +1 -0
- package/template/components/ui/skeleton.tsx +1 -0
- package/template/components/ui/sonner.tsx +1 -0
- package/template/components/ui/status-badge.tsx +1 -0
- package/template/components/ui/table.tsx +1 -0
- package/template/components/ui/tabs.tsx +1 -0
- package/template/components/ui/textarea.tsx +1 -0
- package/template/components/ui/tip.tsx +1 -0
- package/template/components/ui/toggle-group.tsx +1 -0
- package/template/components/ui/toggle-switch.tsx +1 -0
- package/template/components/ui/toggle.tsx +1 -0
- package/template/components/ui/tooltip.tsx +1 -0
- package/template/components/ui/view-segmented-control.tsx +1 -0
- package/template/components.json +27 -0
- package/template/contexts/chart-variant-context.tsx +35 -0
- package/template/contexts/command-menu-context.tsx +28 -0
- package/template/contexts/dashboard-view-context.tsx +35 -0
- package/template/contexts/product-context.tsx +38 -0
- package/template/contexts/system-banner-context.tsx +127 -0
- package/template/docs/command-menu-pattern.md +45 -0
- package/template/docs/data-views-pattern.md +160 -0
- package/template/ecosystem.config.cjs +20 -0
- package/template/eslint.config.mjs +18 -0
- package/template/fontawesome-subset.manifest.json +190 -0
- package/template/hooks/.gitkeep +0 -0
- package/template/hooks/use-app-theme.ts +1 -0
- package/template/hooks/use-coach-mark.ts +1 -0
- package/template/hooks/use-mobile.ts +1 -0
- package/template/hooks/use-mod-key-label.ts +1 -0
- package/template/lib/.gitkeep +0 -0
- package/template/lib/ask-leo-route-context.ts +133 -0
- package/template/lib/chart-keyboard-selection.test.ts +20 -0
- package/template/lib/chart-keyboard-selection.ts +17 -0
- package/template/lib/chart-line-dash.ts +16 -0
- package/template/lib/coach-mark-registry.ts +68 -0
- package/template/lib/command-menu-config.ts +127 -0
- package/template/lib/command-menu-search-data.ts +44 -0
- package/template/lib/conditional-rule-match.ts +32 -0
- package/template/lib/dashboard-customize-coach-mark.ts +18 -0
- package/template/lib/dashboard-layout-merge.ts +63 -0
- package/template/lib/data-list-display-options.ts +35 -0
- package/template/lib/data-list-persistence.ts +280 -0
- package/template/lib/data-list-view-surface.ts +58 -0
- package/template/lib/data-list-view.ts +29 -0
- package/template/lib/data-view-dashboard-storage.ts +101 -0
- package/template/lib/date-filter.ts +8 -0
- package/template/lib/dev-log.test.ts +28 -0
- package/template/lib/dev-log.ts +8 -0
- package/template/lib/editable-target.ts +10 -0
- package/template/lib/floating-sheet-panel.ts +72 -0
- package/template/lib/initials-from-name.ts +7 -0
- package/template/lib/list-page-table-properties.ts +52 -0
- package/template/lib/list-status-badges.ts +168 -0
- package/template/lib/logo-dev.ts +12 -0
- package/template/lib/mock/compliance-kpi.ts +61 -0
- package/template/lib/mock/compliance.ts +146 -0
- package/template/lib/mock/dashboard.ts +105 -0
- package/template/lib/mock/navigation.tsx +231 -0
- package/template/lib/mock/placements-kpi.ts +134 -0
- package/template/lib/mock/placements.ts +183 -0
- package/template/lib/mock/question-bank-kpi.ts +61 -0
- package/template/lib/mock/question-bank.ts +142 -0
- package/template/lib/mock/sites-directory.ts +16 -0
- package/template/lib/mock/sites-kpi.ts +25 -0
- package/template/lib/mock/team-kpi.ts +60 -0
- package/template/lib/mock/team.ts +118 -0
- package/template/lib/motion-ui.ts +17 -0
- package/template/lib/placement-board-card-layout.ts +79 -0
- package/template/lib/placement-lifecycle.ts +5 -0
- package/template/lib/row-height.ts +10 -0
- package/template/lib/stock-portrait.ts +11 -0
- package/template/lib/utils.test.ts +13 -0
- package/template/lib/utils.ts +1 -0
- package/template/next.config.mjs +15 -0
- package/template/package.json +83 -0
- package/template/postcss.config.mjs +8 -0
- package/template/public/.gitkeep +0 -0
- package/template/public/Illustration/Rotation.svg +74 -0
- package/template/public/avatars/user.svg +11 -0
- package/template/public/favicon/favicon.ico +0 -0
- package/template/public/favicon.ico +0 -0
- package/template/public/logos/exxat-one.svg +36 -0
- package/template/public/logos/exxat-prism.svg +39 -0
- package/template/public/mock-schools/emory.svg +4 -0
- package/template/public/mock-schools/rush.svg +4 -0
- package/template/scripts/fontawesome-subset-audit.mjs +190 -0
- package/template/scripts/pm2-startup-macos.sh +13 -0
- package/template/skills-lock.json +10 -0
- package/template/stores/app-store.ts +33 -0
- package/template/tests/setup.ts +1 -0
- package/template/tsconfig.json +35 -0
- package/template/types/react-payment-inputs.d.ts +19 -0
- package/template/vitest.config.ts +18 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ThemeProvider as NextThemesProvider, useTheme } from "next-themes"
|
|
5
|
+
|
|
6
|
+
function ThemeProvider({
|
|
7
|
+
children,
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof NextThemesProvider>) {
|
|
10
|
+
return (
|
|
11
|
+
<NextThemesProvider
|
|
12
|
+
attribute="class"
|
|
13
|
+
defaultTheme="system"
|
|
14
|
+
enableSystem
|
|
15
|
+
disableTransitionOnChange
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<ThemeHotkey />
|
|
19
|
+
{children}
|
|
20
|
+
</NextThemesProvider>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isTypingTarget(target: EventTarget | null) {
|
|
25
|
+
if (!(target instanceof HTMLElement)) {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
target.isContentEditable ||
|
|
31
|
+
target.tagName === "INPUT" ||
|
|
32
|
+
target.tagName === "TEXTAREA" ||
|
|
33
|
+
target.tagName === "SELECT"
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ThemeHotkey() {
|
|
38
|
+
const { resolvedTheme, setTheme } = useTheme()
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
42
|
+
if (event.defaultPrevented || event.repeat) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (event.metaKey || event.ctrlKey || event.altKey) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (event.key.toLowerCase() !== "d") {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (isTypingTarget(event.target)) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setTheme(resolvedTheme === "dark" ? "light" : "dark")
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
window.addEventListener("keydown", onKeyDown)
|
|
62
|
+
|
|
63
|
+
return () => {
|
|
64
|
+
window.removeEventListener("keydown", onKeyDown)
|
|
65
|
+
}
|
|
66
|
+
}, [resolvedTheme, setTheme])
|
|
67
|
+
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { ThemeProvider }
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dashboard / feed — decorative icon on a tinted disc. Colors come from `app/globals.css`
|
|
5
|
+
* `--icon-disc-*` tokens (WCAG 1.4.11-friendly pairings). Prefer this over ad-hoc `oklch(from …)`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as React from "react"
|
|
9
|
+
import { cn } from "@/lib/utils"
|
|
10
|
+
|
|
11
|
+
export type TintedIconDiscTone = "chart-2" | "chart-4" | "brand" | "destructive"
|
|
12
|
+
|
|
13
|
+
const TONE_CLASS: Record<TintedIconDiscTone, string> = {
|
|
14
|
+
"chart-2":
|
|
15
|
+
"bg-[var(--icon-disc-chart-2-bg)] text-[var(--icon-disc-chart-2-fg)]",
|
|
16
|
+
"chart-4":
|
|
17
|
+
"bg-[var(--icon-disc-chart-4-bg)] text-[var(--icon-disc-chart-4-fg)]",
|
|
18
|
+
brand: "bg-[var(--icon-disc-brand-bg)] text-[var(--icon-disc-brand-fg)]",
|
|
19
|
+
destructive:
|
|
20
|
+
"bg-[var(--icon-disc-danger-bg)] text-[var(--icon-disc-danger-fg)]",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TintedIconDiscProps {
|
|
24
|
+
/** Font Awesome icon class suffix, e.g. `fa-arrow-trend-up` (paired with `fa-light`). */
|
|
25
|
+
icon: string
|
|
26
|
+
tone: TintedIconDiscTone
|
|
27
|
+
size?: "sm" | "md" | "lg"
|
|
28
|
+
className?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function TintedIconDisc({
|
|
32
|
+
icon,
|
|
33
|
+
tone,
|
|
34
|
+
size = "md",
|
|
35
|
+
className,
|
|
36
|
+
}: TintedIconDiscProps) {
|
|
37
|
+
const sizeClass =
|
|
38
|
+
size === "sm" ? "h-6 w-6 text-xs" : size === "lg" ? "h-12 w-12 text-xl" : "h-7 w-7 text-xs"
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<span
|
|
42
|
+
className={cn(
|
|
43
|
+
"inline-flex shrink-0 items-center justify-center rounded-full hc:border hc:border-foreground forced-colors:border forced-colors:border-[CanvasText] forced-colors:bg-[Canvas] forced-colors:text-[CanvasText]",
|
|
44
|
+
sizeClass,
|
|
45
|
+
TONE_CLASS[tone],
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
aria-hidden="true"
|
|
49
|
+
>
|
|
50
|
+
<i className={cn("fa-light", icon)} />
|
|
51
|
+
</span>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AiThinkingOverlay / AiThinkingSurface — ambient "AI is thinking" indicator.
|
|
5
|
+
*
|
|
6
|
+
* Drops a soft, drifting dot cloud onto any surface to signal the assistant
|
|
7
|
+
* is working. Intentionally decorative — pair with a visible text/sr-only
|
|
8
|
+
* status so screen readers still hear "Leo is thinking" / "Generating…".
|
|
9
|
+
*
|
|
10
|
+
* Two ways to use:
|
|
11
|
+
*
|
|
12
|
+
* 1) **Overlay** — drop inside an existing `relative` container:
|
|
13
|
+
*
|
|
14
|
+
* <div className="relative rounded-xl border p-6">
|
|
15
|
+
* <AiThinkingOverlay active={isPending} />
|
|
16
|
+
* <YourContent />
|
|
17
|
+
* </div>
|
|
18
|
+
*
|
|
19
|
+
* 2) **Surface** — wraps children and handles positioning for you:
|
|
20
|
+
*
|
|
21
|
+
* <AiThinkingSurface active={isPending} className="rounded-xl border p-6">
|
|
22
|
+
* <YourContent />
|
|
23
|
+
* </AiThinkingSurface>
|
|
24
|
+
*
|
|
25
|
+
* Accessibility: the overlay is `aria-hidden` and `pointer-events-none`;
|
|
26
|
+
* always render a live status element next to it, e.g.
|
|
27
|
+
* <span role="status" aria-live="polite" className="sr-only">Generating…</span>
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import * as React from "react"
|
|
31
|
+
import { cn } from "@/lib/utils"
|
|
32
|
+
import { DotPattern } from "@/components/ui/dot-pattern"
|
|
33
|
+
|
|
34
|
+
export interface AiThinkingOverlayProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
35
|
+
/** When false (default), nothing renders. Flip to true while the AI is working. */
|
|
36
|
+
active?: boolean
|
|
37
|
+
/** Number of drifting soft clouds. Keep small (1–2) for most surfaces. */
|
|
38
|
+
cloudCount?: number
|
|
39
|
+
/** Radius of each cloud in px — scale up for large surfaces. */
|
|
40
|
+
cloudRadius?: number
|
|
41
|
+
/** Grid tile size (both width and height of the repeating dot tile). */
|
|
42
|
+
gridSize?: number
|
|
43
|
+
/** Per-dot radius. */
|
|
44
|
+
dotRadius?: number
|
|
45
|
+
/** Tailwind utility for the dot fill (e.g. `"fill-foreground/35"`). */
|
|
46
|
+
fillClassName?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Absolute overlay. The parent must be `position: relative` and should usually
|
|
51
|
+
* clip overflow (e.g. `rounded-xl overflow-hidden`) so the drifting clouds
|
|
52
|
+
* don't paint outside the surface.
|
|
53
|
+
*/
|
|
54
|
+
export function AiThinkingOverlay({
|
|
55
|
+
active = false,
|
|
56
|
+
cloudCount = 2,
|
|
57
|
+
cloudRadius = 260,
|
|
58
|
+
gridSize = 14,
|
|
59
|
+
dotRadius = 0.8,
|
|
60
|
+
fillClassName = "fill-foreground/35 dark:fill-foreground/45",
|
|
61
|
+
className,
|
|
62
|
+
...props
|
|
63
|
+
}: AiThinkingOverlayProps) {
|
|
64
|
+
if (!active) return null
|
|
65
|
+
return (
|
|
66
|
+
<div
|
|
67
|
+
aria-hidden
|
|
68
|
+
className={cn("pointer-events-none absolute inset-0 z-0 overflow-hidden", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
>
|
|
71
|
+
<DotPattern
|
|
72
|
+
glow
|
|
73
|
+
glowCount={cloudCount}
|
|
74
|
+
glowRadius={cloudRadius}
|
|
75
|
+
width={gridSize}
|
|
76
|
+
height={gridSize}
|
|
77
|
+
cr={dotRadius}
|
|
78
|
+
className={cn("absolute inset-0 h-full w-full", fillClassName)}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface AiThinkingSurfaceProps
|
|
85
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
86
|
+
Pick<AiThinkingOverlayProps, "active" | "cloudCount" | "cloudRadius" | "gridSize" | "dotRadius" | "fillClassName"> {
|
|
87
|
+
/** Optional className applied to the content wrapper (above the overlay). */
|
|
88
|
+
contentClassName?: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Wrapper that adds `relative overflow-hidden`, renders the overlay, and
|
|
93
|
+
* stacks children above it. Use when you'd otherwise have to manually wire
|
|
94
|
+
* positioning around `<AiThinkingOverlay>`.
|
|
95
|
+
*/
|
|
96
|
+
export function AiThinkingSurface({
|
|
97
|
+
active,
|
|
98
|
+
cloudCount,
|
|
99
|
+
cloudRadius,
|
|
100
|
+
gridSize,
|
|
101
|
+
dotRadius,
|
|
102
|
+
fillClassName,
|
|
103
|
+
className,
|
|
104
|
+
contentClassName,
|
|
105
|
+
children,
|
|
106
|
+
...props
|
|
107
|
+
}: AiThinkingSurfaceProps) {
|
|
108
|
+
return (
|
|
109
|
+
<div className={cn("relative overflow-hidden", className)} {...props}>
|
|
110
|
+
<AiThinkingOverlay
|
|
111
|
+
active={active}
|
|
112
|
+
cloudCount={cloudCount}
|
|
113
|
+
cloudRadius={cloudRadius}
|
|
114
|
+
gridSize={gridSize}
|
|
115
|
+
dotRadius={dotRadius}
|
|
116
|
+
fillClassName={fillClassName}
|
|
117
|
+
/>
|
|
118
|
+
<div className={cn("relative z-[1]", contentClassName)}>{children}</div>
|
|
119
|
+
</div>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/avatar"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/badge"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/banner"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/breadcrumb"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/button"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/calendar"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/card"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/chart"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/checkbox"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/coach-mark"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/collapsible"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/command"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/date-picker-field"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/dialog"
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DotPattern — dot grid revealed by a soft drifting "cloud" mask.
|
|
5
|
+
*
|
|
6
|
+
* Inspiration: Google/Apple AI loading states — a diffuse dot field that
|
|
7
|
+
* softly fades in, drifts diagonally across the surface, then fades out.
|
|
8
|
+
* No bright glow cores, no particles — just one or two large soft halos
|
|
9
|
+
* sliding across the grid so the dots appear as an ambient cloud.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as React from "react"
|
|
13
|
+
import { motion } from "motion/react"
|
|
14
|
+
import { cn } from "@/lib/utils"
|
|
15
|
+
|
|
16
|
+
interface DotPatternProps extends React.SVGProps<SVGSVGElement> {
|
|
17
|
+
width?: number
|
|
18
|
+
height?: number
|
|
19
|
+
x?: number
|
|
20
|
+
y?: number
|
|
21
|
+
cx?: number
|
|
22
|
+
cy?: number
|
|
23
|
+
cr?: number
|
|
24
|
+
className?: string
|
|
25
|
+
glow?: boolean
|
|
26
|
+
/** Number of drifting soft clouds (keep small: 1–2). */
|
|
27
|
+
glowCount?: number
|
|
28
|
+
/** Cloud radius — large values produce a wide, diffuse reveal. */
|
|
29
|
+
glowRadius?: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Cloud = {
|
|
33
|
+
key: number
|
|
34
|
+
xs: string[]
|
|
35
|
+
ys: string[]
|
|
36
|
+
duration: number
|
|
37
|
+
delay: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function rand(min: number, max: number) {
|
|
41
|
+
return min + Math.random() * (max - min)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function DotPattern({
|
|
45
|
+
width = 14,
|
|
46
|
+
height = 14,
|
|
47
|
+
x = 0,
|
|
48
|
+
y = 0,
|
|
49
|
+
cx = 1,
|
|
50
|
+
cy = 1,
|
|
51
|
+
cr = 0.8,
|
|
52
|
+
className,
|
|
53
|
+
glow = false,
|
|
54
|
+
glowCount = 2,
|
|
55
|
+
glowRadius = 240,
|
|
56
|
+
...props
|
|
57
|
+
}: DotPatternProps) {
|
|
58
|
+
const id = React.useId()
|
|
59
|
+
const maskId = `${id}-mask`
|
|
60
|
+
const gradId = `${id}-grad`
|
|
61
|
+
|
|
62
|
+
const clouds = React.useMemo<Cloud[]>(
|
|
63
|
+
() =>
|
|
64
|
+
Array.from({ length: glowCount }).map((_, i) => {
|
|
65
|
+
// Drift diagonally: bottom-right → top-left. Start/end partly off-canvas
|
|
66
|
+
// so the cloud enters and exits softly without a visible edge.
|
|
67
|
+
const startX = rand(85, 120)
|
|
68
|
+
const endX = rand(-20, 15)
|
|
69
|
+
const midX = (startX + endX) / 2 + rand(-6, 6)
|
|
70
|
+
|
|
71
|
+
const startY = rand(85, 115)
|
|
72
|
+
const endY = rand(-15, 10)
|
|
73
|
+
const midY = (startY + endY) / 2 + rand(-4, 4)
|
|
74
|
+
|
|
75
|
+
const duration = rand(8, 12)
|
|
76
|
+
// Offset clouds by half a cycle so one is arriving as the other leaves.
|
|
77
|
+
const delay = -(i / glowCount) * duration
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
key: i,
|
|
81
|
+
xs: [`${startX}%`, `${midX}%`, `${endX}%`],
|
|
82
|
+
ys: [`${startY}%`, `${midY}%`, `${endY}%`],
|
|
83
|
+
duration,
|
|
84
|
+
delay,
|
|
85
|
+
}
|
|
86
|
+
}),
|
|
87
|
+
[glowCount],
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<svg
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
className={cn(
|
|
94
|
+
"pointer-events-none absolute inset-0 h-full w-full fill-neutral-400/80",
|
|
95
|
+
className,
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
>
|
|
99
|
+
<defs>
|
|
100
|
+
<pattern
|
|
101
|
+
id={id}
|
|
102
|
+
width={width}
|
|
103
|
+
height={height}
|
|
104
|
+
patternUnits="userSpaceOnUse"
|
|
105
|
+
patternContentUnits="userSpaceOnUse"
|
|
106
|
+
x={x}
|
|
107
|
+
y={y}
|
|
108
|
+
>
|
|
109
|
+
<circle cx={cx} cy={cy} r={cr} />
|
|
110
|
+
</pattern>
|
|
111
|
+
|
|
112
|
+
{glow ? (
|
|
113
|
+
<>
|
|
114
|
+
{/* Very soft falloff — no visible ring edge, dots dissolve gradually. */}
|
|
115
|
+
<radialGradient id={gradId}>
|
|
116
|
+
<stop offset="0%" stopColor="white" stopOpacity="0.9" />
|
|
117
|
+
<stop offset="40%" stopColor="white" stopOpacity="0.55" />
|
|
118
|
+
<stop offset="75%" stopColor="white" stopOpacity="0.18" />
|
|
119
|
+
<stop offset="100%" stopColor="white" stopOpacity="0" />
|
|
120
|
+
</radialGradient>
|
|
121
|
+
|
|
122
|
+
<mask id={maskId}>
|
|
123
|
+
{clouds.map((c) => (
|
|
124
|
+
<motion.circle
|
|
125
|
+
key={`cloud-${c.key}`}
|
|
126
|
+
r={glowRadius}
|
|
127
|
+
fill={`url(#${gradId})`}
|
|
128
|
+
initial={{ cx: c.xs[0], cy: c.ys[0], opacity: 0 }}
|
|
129
|
+
animate={{
|
|
130
|
+
cx: c.xs,
|
|
131
|
+
cy: c.ys,
|
|
132
|
+
// Long hold with soft fade at both ends.
|
|
133
|
+
opacity: [0, 1, 1, 0],
|
|
134
|
+
}}
|
|
135
|
+
transition={{
|
|
136
|
+
duration: c.duration,
|
|
137
|
+
delay: c.delay,
|
|
138
|
+
repeat: Infinity,
|
|
139
|
+
ease: "linear",
|
|
140
|
+
times: [0, 0.3, 0.7, 1],
|
|
141
|
+
}}
|
|
142
|
+
/>
|
|
143
|
+
))}
|
|
144
|
+
</mask>
|
|
145
|
+
</>
|
|
146
|
+
) : null}
|
|
147
|
+
</defs>
|
|
148
|
+
|
|
149
|
+
{/* Dot grid — only visible inside the drifting soft clouds when glow is on. */}
|
|
150
|
+
<rect
|
|
151
|
+
width="100%"
|
|
152
|
+
height="100%"
|
|
153
|
+
strokeWidth={0}
|
|
154
|
+
fill={`url(#${id})`}
|
|
155
|
+
mask={glow ? `url(#${maskId})` : undefined}
|
|
156
|
+
/>
|
|
157
|
+
</svg>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/drag-handle-grip"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/drawer"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/dropdown-menu"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/field"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/form"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/input-group"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/input-mask"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/input"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/kbd"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../../../packages/ui/src/components/ui/label"
|