@trackany-device/components 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +185 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/map/arrows/map-arrow-blue.png +0 -0
- package/src/assets/map/arrows/map-arrow-green.png +0 -0
- package/src/assets/map/arrows/map-arrow-purple.png +0 -0
- package/src/assets/map/arrows/map-arrow-red.png +0 -0
- package/src/assets/map/flags/flag-blue.png +0 -0
- package/src/assets/map/flags/flag-green.png +0 -0
- package/src/assets/map/flags/flag-red.png +0 -0
- package/src/assets/map/flags/flag-yellow.png +0 -0
- package/src/assets/map/pins/map-pin-blue.png +0 -0
- package/src/assets/map/pins/map-pin-green.png +0 -0
- package/src/assets/map/pins/map-pin-purple.png +0 -0
- package/src/assets/map/pins/map-pin-red.png +0 -0
- package/src/components/Card.tsx +9 -0
- package/src/components/alert-error.tsx +24 -0
- package/src/components/app-content.tsx +22 -0
- package/src/components/app-header.tsx +153 -0
- package/src/components/app-logo-icon.tsx +13 -0
- package/src/components/app-logo.tsx +21 -0
- package/src/components/app-shell.tsx +19 -0
- package/src/components/app-sidebar-header.tsx +68 -0
- package/src/components/app-sidebar.tsx +106 -0
- package/src/components/appearance-tabs.tsx +46 -0
- package/src/components/breadcrumbs.tsx +50 -0
- package/src/components/cms/blurred-image.tsx +111 -0
- package/src/components/cms/section-bg.tsx +473 -0
- package/src/components/cms/section-button.tsx +127 -0
- package/src/components/cms/sections/banner-5050-section.tsx +135 -0
- package/src/components/cms/sections/blogs-listing-section.tsx +270 -0
- package/src/components/cms/sections/cards-grid-section.tsx +185 -0
- package/src/components/cms/sections/contact-form-section.tsx +157 -0
- package/src/components/cms/sections/cta-section.tsx +101 -0
- package/src/components/cms/sections/featured-blog-slider-section.tsx +256 -0
- package/src/components/cms/sections/featured-products-grid-section.tsx +173 -0
- package/src/components/cms/sections/featured-solutions-grid-section.tsx +183 -0
- package/src/components/cms/sections/hero-section.tsx +180 -0
- package/src/components/cms/sections/solutions-with-filter-section.tsx +234 -0
- package/src/components/cms/sections/text-section.tsx +77 -0
- package/src/components/cutout-image.tsx +228 -0
- package/src/components/devices/devices-mini-map.tsx +275 -0
- package/src/components/docs/docs-shell.tsx +280 -0
- package/src/components/fleet-hero-animated.tsx +383 -0
- package/src/components/input-error.tsx +17 -0
- package/src/components/keenicons/assets/duotone/Read Me.txt +7 -0
- package/src/components/keenicons/assets/duotone/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/duotone/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/duotone/demo.html +12424 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.svg +1109 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.ttf +0 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.woff +0 -0
- package/src/components/keenicons/assets/duotone/selection.json +17313 -0
- package/src/components/keenicons/assets/duotone/style.css +4931 -0
- package/src/components/keenicons/assets/filled/Read Me.txt +7 -0
- package/src/components/keenicons/assets/filled/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/filled/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/filled/demo.html +12370 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.svg +1082 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.ttf +0 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.woff +0 -0
- package/src/components/keenicons/assets/filled/selection.json +17096 -0
- package/src/components/keenicons/assets/filled/style.css +4769 -0
- package/src/components/keenicons/assets/outline/Read Me.txt +7 -0
- package/src/components/keenicons/assets/outline/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/outline/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/outline/demo.html +11356 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.svg +575 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.ttf +0 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.woff +0 -0
- package/src/components/keenicons/assets/outline/selection.json +13054 -0
- package/src/components/keenicons/assets/outline/style.css +1721 -0
- package/src/components/keenicons/assets/solid/Read Me.txt +7 -0
- package/src/components/keenicons/assets/solid/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/solid/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/solid/demo.html +11356 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.svg +575 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.ttf +0 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.woff +0 -0
- package/src/components/keenicons/assets/solid/selection.json +13048 -0
- package/src/components/keenicons/assets/solid/style.css +1721 -0
- package/src/components/keenicons/assets/styles.css +4 -0
- package/src/components/keenicons/index.ts +2 -0
- package/src/components/keenicons/keenicons.tsx +16 -0
- package/src/components/keenicons/types.ts +7 -0
- package/src/components/nav-footer.tsx +49 -0
- package/src/components/nav-main.tsx +53 -0
- package/src/components/nav-user.tsx +59 -0
- package/src/components/notification-bell.tsx +190 -0
- package/src/components/products/product-card.tsx +159 -0
- package/src/components/text-link.tsx +23 -0
- package/src/components/ui/accordion-menu.tsx +322 -0
- package/src/components/ui/accordion.tsx +133 -0
- package/src/components/ui/alert-dialog.tsx +82 -0
- package/src/components/ui/alert.tsx +63 -0
- package/src/components/ui/avatar-group.tsx +129 -0
- package/src/components/ui/avatar.tsx +67 -0
- package/src/components/ui/badge.tsx +230 -0
- package/src/components/ui/breadcrumb.tsx +88 -0
- package/src/components/ui/button.tsx +412 -0
- package/src/components/ui/calendar.tsx +56 -0
- package/src/components/ui/card.tsx +147 -0
- package/src/components/ui/chart.tsx +290 -0
- package/src/components/ui/checkbox.tsx +47 -0
- package/src/components/ui/code.tsx +45 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/command-palette.tsx +189 -0
- package/src/components/ui/command.tsx +138 -0
- package/src/components/ui/cookie-banner.tsx +220 -0
- package/src/components/ui/copy-button.tsx +60 -0
- package/src/components/ui/data-grid-column-filter.tsx +124 -0
- package/src/components/ui/data-grid-column-header.tsx +284 -0
- package/src/components/ui/data-grid-column-visibility.tsx +38 -0
- package/src/components/ui/data-grid-pagination.tsx +206 -0
- package/src/components/ui/data-grid-table-dnd-rows.tsx +147 -0
- package/src/components/ui/data-grid-table-dnd.tsx +175 -0
- package/src/components/ui/data-grid-table.tsx +500 -0
- package/src/components/ui/data-grid.tsx +193 -0
- package/src/components/ui/data-list.tsx +76 -0
- package/src/components/ui/datefield.tsx +91 -0
- package/src/components/ui/dialog.tsx +139 -0
- package/src/components/ui/divider.tsx +41 -0
- package/src/components/ui/drawer.tsx +59 -0
- package/src/components/ui/dropdown-menu.tsx +224 -0
- package/src/components/ui/empty-state.tsx +54 -0
- package/src/components/ui/file-upload.tsx +152 -0
- package/src/components/ui/form.tsx +88 -0
- package/src/components/ui/icon.tsx +14 -0
- package/src/components/ui/input-otp.tsx +71 -0
- package/src/components/ui/input.tsx +155 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +31 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/pagination.tsx +37 -0
- package/src/components/ui/placeholder-pattern.tsx +21 -0
- package/src/components/ui/popover.tsx +50 -0
- package/src/components/ui/progress.tsx +65 -0
- package/src/components/ui/radio-group.tsx +73 -0
- package/src/components/ui/resizable.tsx +39 -0
- package/src/components/ui/scroll-area.tsx +50 -0
- package/src/components/ui/select.tsx +234 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/sheet.tsx +147 -0
- package/src/components/ui/sidebar.tsx +721 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/slider.tsx +35 -0
- package/src/components/ui/sonner.tsx +28 -0
- package/src/components/ui/sortable.tsx +724 -0
- package/src/components/ui/spinner.tsx +17 -0
- package/src/components/ui/stat-card.tsx +82 -0
- package/src/components/ui/stepper.tsx +410 -0
- package/src/components/ui/switch.tsx +68 -0
- package/src/components/ui/table.tsx +42 -0
- package/src/components/ui/tabs.tsx +196 -0
- package/src/components/ui/timeline.tsx +90 -0
- package/src/components/ui/toggle-group.tsx +73 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/tooltip.tsx +55 -0
- package/src/components/user-info.tsx +33 -0
- package/src/components/user-menu-content.tsx +53 -0
- package/src/components/web/SiteFooter.tsx +154 -0
- package/src/components/web/SiteHeader.tsx +159 -0
- package/src/components/workflows/workflow-canvas.tsx +321 -0
- package/src/controls/Blockquote.tsx +25 -0
- package/src/controls/Button.tsx +101 -0
- package/src/controls/Checkbox.tsx +29 -0
- package/src/controls/DateField.tsx +37 -0
- package/src/controls/FormField.tsx +20 -0
- package/src/controls/Heading.tsx +28 -0
- package/src/controls/Input.tsx +21 -0
- package/src/controls/Label.tsx +18 -0
- package/src/controls/Paragraph.tsx +39 -0
- package/src/controls/PasswordInput.tsx +40 -0
- package/src/controls/RadioGroup.tsx +70 -0
- package/src/controls/Select.tsx +24 -0
- package/src/controls/Slider.tsx +33 -0
- package/src/controls/Switch.tsx +31 -0
- package/src/controls/Textarea.tsx +22 -0
- package/src/elements/ConfirmPasswordForm.tsx +43 -0
- package/src/elements/DeviceStatusBadge.tsx +38 -0
- package/src/elements/DriverCard.tsx +67 -0
- package/src/elements/ForgotPasswordForm.tsx +64 -0
- package/src/elements/IncidentCard.tsx +67 -0
- package/src/elements/LoginForm.tsx +100 -0
- package/src/elements/OtpForm.tsx +71 -0
- package/src/elements/RegisterForm.tsx +150 -0
- package/src/elements/ResetPasswordForm.tsx +72 -0
- package/src/elements/SmsChallengeForm.tsx +104 -0
- package/src/elements/VehicleCard.tsx +73 -0
- package/src/elements/VerifyEmailForm.tsx +39 -0
- package/src/hooks/use-appearance.tsx +117 -0
- package/src/hooks/use-applied-theme.ts +98 -0
- package/src/hooks/use-clipboard.ts +34 -0
- package/src/hooks/use-current-url.ts +83 -0
- package/src/hooks/use-dark-mode.ts +48 -0
- package/src/hooks/use-flash-toast.ts +29 -0
- package/src/hooks/use-initials.tsx +24 -0
- package/src/hooks/use-mobile-navigation.ts +12 -0
- package/src/hooks/use-mobile.tsx +38 -0
- package/src/index.ts +408 -0
- package/src/layouts/AppLayout.tsx +60 -0
- package/src/layouts/AuthLayout.tsx +32 -0
- package/src/layouts/SettingsLayout.tsx +21 -0
- package/src/layouts/app/AIChatLayout.tsx +73 -0
- package/src/layouts/app/AsideSidebarLayout.tsx +3 -0
- package/src/layouts/app/CalendarSidebarLayout.tsx +69 -0
- package/src/layouts/app/CommunitiesNavbarLayout.tsx +3 -0
- package/src/layouts/app/DualNavbarSidebarLayout.tsx +3 -0
- package/src/layouts/app/FocusSidebarLayout.tsx +75 -0
- package/src/layouts/app/MailLayout.tsx +69 -0
- package/src/layouts/app/MegaMenuHeaderLayout.tsx +3 -0
- package/src/layouts/app/MegaMenuLayout.tsx +81 -0
- package/src/layouts/app/MegaMenuNavbarLayout.tsx +88 -0
- package/src/layouts/app/MegaMenuSearchNavbarLayout.tsx +3 -0
- package/src/layouts/app/NavbarCollapsibleLayout.tsx +88 -0
- package/src/layouts/app/NavbarCollapsibleLinksLayout.tsx +3 -0
- package/src/layouts/app/NavbarMinimalLayout.tsx +3 -0
- package/src/layouts/app/NavbarMinimalSidebarLayout.tsx +3 -0
- package/src/layouts/app/NavbarSidebarDashboardLayout.tsx +3 -0
- package/src/layouts/app/NavbarSidebarLayout.tsx +92 -0
- package/src/layouts/app/NavbarSimpleSidebarLayout.tsx +3 -0
- package/src/layouts/app/NavbarTitledSidebarLayout.tsx +3 -0
- package/src/layouts/app/PanelSidebarLayout.tsx +3 -0
- package/src/layouts/app/SearchNavbarSidebarLayout.tsx +3 -0
- package/src/layouts/app/SidebarBreadcrumbLayout.tsx +3 -0
- package/src/layouts/app/SidebarCleanLayout.tsx +3 -0
- package/src/layouts/app/SidebarCommunitiesLayout.tsx +3 -0
- package/src/layouts/app/SidebarContentLayout.tsx +3 -0
- package/src/layouts/app/SidebarDualMenuLayout.tsx +104 -0
- package/src/layouts/app/SidebarFixedLayout.tsx +166 -0
- package/src/layouts/app/SidebarFooterNavbarLayout.tsx +3 -0
- package/src/layouts/app/SidebarHeaderMenuLayout.tsx +3 -0
- package/src/layouts/app/SidebarMegaMenuLayout.tsx +4 -0
- package/src/layouts/app/SidebarMinimalLayout.tsx +70 -0
- package/src/layouts/app/SidebarMobileSearchLayout.tsx +3 -0
- package/src/layouts/app/SidebarMultiPanelLayout.tsx +3 -0
- package/src/layouts/app/SidebarPrimarySecondaryLayout.tsx +3 -0
- package/src/layouts/app/SidebarSearchHeaderLayout.tsx +103 -0
- package/src/layouts/app/SidebarSearchToolbarLayout.tsx +3 -0
- package/src/layouts/app/SidebarTabsDualLayout.tsx +3 -0
- package/src/layouts/app/SidebarTabsLayout.tsx +98 -0
- package/src/layouts/app/SidebarTreeLayout.tsx +3 -0
- package/src/layouts/app/SplitNavbarLayout.tsx +3 -0
- package/src/layouts/app/SplitSidebarDashboardLayout.tsx +3 -0
- package/src/layouts/app/SplitSidebarLayout.tsx +99 -0
- package/src/layouts/app/TopNavLayout.tsx +105 -0
- package/src/layouts/app/TopNavLinksLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceBreadcrumbLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceCommunitiesLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceNavbarLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceSidebarLayout.tsx +98 -0
- package/src/layouts/app/WorkspaceSidebarTitleLayout.tsx +3 -0
- package/src/layouts/app/app-header-layout.tsx +45 -0
- package/src/layouts/app/app-sidebar-layout.tsx +56 -0
- package/src/layouts/app/layout-context.tsx +44 -0
- package/src/layouts/app/layout-types.ts +47 -0
- package/src/layouts/app/partials/Footer.tsx +35 -0
- package/src/layouts/app/partials/HeaderTopbar.tsx +96 -0
- package/src/layouts/app/partials/Navbar.tsx +85 -0
- package/src/layouts/app/partials/Toolbar.tsx +47 -0
- package/src/layouts/app-layout.tsx +29 -0
- package/src/layouts/auth/AuthBrandedLayout.tsx +58 -0
- package/src/layouts/auth/AuthCardLayout.tsx +31 -0
- package/src/layouts/auth/AuthCenteredLayout.tsx +41 -0
- package/src/layouts/auth/AuthClassicLayout.tsx +41 -0
- package/src/layouts/auth/AuthSimpleLayout.tsx +33 -0
- package/src/layouts/auth/AuthSplitLayout.tsx +89 -0
- package/src/layouts/web-app-layout.tsx +162 -0
- package/src/layouts/web-layout.tsx +23 -0
- package/src/lib/datetime.ts +188 -0
- package/src/lib/google-maps-loader.ts +99 -0
- package/src/lib/location.ts +127 -0
- package/src/lib/lucide-icon-map.ts +132 -0
- package/src/lib/map-markers.ts +124 -0
- package/src/lib/map-styles.ts +351 -0
- package/src/lib/utils.ts +11 -0
- package/src/platform/adapters/default.tsx +156 -0
- package/src/platform/adapters/inertia.tsx +88 -0
- package/src/platform/adapters/nextjs.ts +86 -0
- package/src/platform/context.tsx +106 -0
- package/src/platform/index.ts +27 -0
- package/src/platform/types.ts +105 -0
- package/src/styles/layouts/sidebar-fixed.css +161 -0
- package/src/styles/themes.css +583 -0
- package/src/types/assets.d.ts +5 -0
- package/src/types/auth.ts +25 -0
- package/src/types/global.d.ts +13 -0
- package/src/types/index.ts +9 -0
- package/src/types/navigation.ts +15 -0
- package/src/types/ui.ts +32 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, type ReactNode } from 'react';
|
|
4
|
+
import type { PlatformAdapter, PlatformLinkProps, PlatformForm, NavigateOptions } from './types';
|
|
5
|
+
import { defaultAdapter } from './adapters/default';
|
|
6
|
+
|
|
7
|
+
// ─── Context ─────────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
const PlatformContext = createContext<PlatformAdapter>(defaultAdapter);
|
|
10
|
+
|
|
11
|
+
// ─── Provider ────────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provide a platform adapter to the component tree.
|
|
15
|
+
*
|
|
16
|
+
* Place this at the root of each app:
|
|
17
|
+
* - core/ + login/ → wrap with createInertiaAdapter(...)
|
|
18
|
+
* - web/ → wrap with createNextjsAdapter(...)
|
|
19
|
+
* - Storybook → no provider needed (defaultAdapter kicks in)
|
|
20
|
+
*/
|
|
21
|
+
export function PlatformProvider({
|
|
22
|
+
adapter,
|
|
23
|
+
children,
|
|
24
|
+
}: {
|
|
25
|
+
adapter: PlatformAdapter;
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}) {
|
|
28
|
+
return (
|
|
29
|
+
<PlatformContext.Provider value={adapter}>
|
|
30
|
+
{children}
|
|
31
|
+
</PlatformContext.Provider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─── usePlatform ─────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/** Returns the full adapter. Use the fine-grained hooks below in most cases. */
|
|
38
|
+
export function usePlatform(): PlatformAdapter {
|
|
39
|
+
return useContext(PlatformContext);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── Fine-grained hooks ──────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Platform-agnostic Link component.
|
|
46
|
+
*
|
|
47
|
+
* Usage in components:
|
|
48
|
+
* const PlatformLink = usePlatformLink();
|
|
49
|
+
* return <PlatformLink href="/foo">Go</PlatformLink>;
|
|
50
|
+
*
|
|
51
|
+
* Or use the <PlatformLink> convenience component exported below.
|
|
52
|
+
*/
|
|
53
|
+
export function usePlatformLink() {
|
|
54
|
+
return useContext(PlatformContext).Link;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Programmatic navigation — platform's router.visit / router.push / window.location */
|
|
58
|
+
export function usePlatformNavigate() {
|
|
59
|
+
return useContext(PlatformContext).navigate;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Current URL (pathname + search). Reactive in SPA routers. */
|
|
63
|
+
export function usePlatformUrl(): string {
|
|
64
|
+
return useContext(PlatformContext).useCurrentUrl();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Shared page props injected by the server.
|
|
69
|
+
* In Inertia: all shared() props.
|
|
70
|
+
* In Next.js: whatever was passed to createNextjsAdapter({ pageProps }).
|
|
71
|
+
* In Storybook/default: empty object.
|
|
72
|
+
*/
|
|
73
|
+
export function usePlatformPageProps<T extends Record<string, unknown>>(): T {
|
|
74
|
+
return useContext(PlatformContext).usePageProps<T>();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Inertia-compatible form hook.
|
|
79
|
+
* In Inertia: Inertia's real useForm.
|
|
80
|
+
* Everywhere else: fetch-based implementation with the same interface.
|
|
81
|
+
*/
|
|
82
|
+
export function usePlatformForm<T extends Record<string, unknown>>(
|
|
83
|
+
initialData: T,
|
|
84
|
+
): PlatformForm<T> {
|
|
85
|
+
return useContext(PlatformContext).useForm<T>(initialData);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Document head component, or null if the platform manages head via other means. */
|
|
89
|
+
export function usePlatformHead() {
|
|
90
|
+
return useContext(PlatformContext).Head;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Convenience components ──────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Drop-in replacement for <a href> or Inertia's <Link>.
|
|
97
|
+
* Automatically uses the platform's router.
|
|
98
|
+
*
|
|
99
|
+
* Usage:
|
|
100
|
+
* import { PlatformLink } from '@trackany-device/components';
|
|
101
|
+
* <PlatformLink href="/dashboard">Dashboard</PlatformLink>
|
|
102
|
+
*/
|
|
103
|
+
export function PlatformLink(props: PlatformLinkProps) {
|
|
104
|
+
const Link = usePlatformLink();
|
|
105
|
+
return <Link {...props} />;
|
|
106
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Types
|
|
2
|
+
export type {
|
|
3
|
+
PlatformAdapter,
|
|
4
|
+
PlatformLinkProps,
|
|
5
|
+
PlatformForm,
|
|
6
|
+
PlatformHeadProps,
|
|
7
|
+
NavigateOptions,
|
|
8
|
+
FormSubmitOptions,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
// Provider + hooks + PlatformLink component
|
|
12
|
+
export {
|
|
13
|
+
PlatformProvider,
|
|
14
|
+
PlatformLink,
|
|
15
|
+
usePlatform,
|
|
16
|
+
usePlatformLink,
|
|
17
|
+
usePlatformNavigate,
|
|
18
|
+
usePlatformUrl,
|
|
19
|
+
usePlatformPageProps,
|
|
20
|
+
usePlatformForm,
|
|
21
|
+
usePlatformHead,
|
|
22
|
+
} from './context';
|
|
23
|
+
|
|
24
|
+
// Adapters — each app picks the one matching its framework
|
|
25
|
+
export { defaultAdapter } from './adapters/default';
|
|
26
|
+
export { createInertiaAdapter } from './adapters/inertia';
|
|
27
|
+
export { createNextjsAdapter } from './adapters/nextjs';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
// ─── Link ────────────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
export interface PlatformLinkProps {
|
|
6
|
+
href: string;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
onClick?: (e?: React.MouseEvent) => void;
|
|
10
|
+
target?: string;
|
|
11
|
+
rel?: string;
|
|
12
|
+
/** Preserve scroll position after navigation (Inertia option, ignored elsewhere) */
|
|
13
|
+
preserveScroll?: boolean;
|
|
14
|
+
/** Replace history entry instead of pushing (SPA routers) */
|
|
15
|
+
replace?: boolean;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ─── Navigate ────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
export interface NavigateOptions {
|
|
22
|
+
replace?: boolean;
|
|
23
|
+
preserveScroll?: boolean;
|
|
24
|
+
preserveState?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ─── useForm ─────────────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
export interface FormSubmitOptions<T = Record<string, unknown>> {
|
|
30
|
+
preserveScroll?: boolean;
|
|
31
|
+
preserveState?: boolean;
|
|
32
|
+
onSuccess?: (data?: unknown) => void;
|
|
33
|
+
onError?: (errors: Partial<Record<keyof T, string>>) => void;
|
|
34
|
+
onFinish?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PlatformForm<T extends Record<string, unknown>> {
|
|
38
|
+
data: T;
|
|
39
|
+
setData: {
|
|
40
|
+
(field: keyof T, value: unknown): void;
|
|
41
|
+
(values: Partial<T>): void;
|
|
42
|
+
};
|
|
43
|
+
errors: Partial<Record<keyof T, string>>;
|
|
44
|
+
processing: boolean;
|
|
45
|
+
wasSuccessful: boolean;
|
|
46
|
+
recentlySuccessful: boolean;
|
|
47
|
+
isDirty: boolean;
|
|
48
|
+
post: (url: string, options?: FormSubmitOptions<T>) => void;
|
|
49
|
+
put: (url: string, options?: FormSubmitOptions<T>) => void;
|
|
50
|
+
patch: (url: string, options?: FormSubmitOptions<T>) => void;
|
|
51
|
+
delete: (url: string, options?: FormSubmitOptions<T>) => void;
|
|
52
|
+
reset: (...fields: (keyof T)[]) => void;
|
|
53
|
+
clearErrors: (...fields: (keyof T)[]) => void;
|
|
54
|
+
setError: (field: keyof T, message: string) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ─── Head ────────────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
export interface PlatformHeadProps {
|
|
60
|
+
title?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─── Adapter ─────────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
export interface PlatformAdapter {
|
|
67
|
+
/**
|
|
68
|
+
* SPA-aware link component. Falls back to <a> in environments
|
|
69
|
+
* where no router is available (Storybook, static sites).
|
|
70
|
+
*/
|
|
71
|
+
Link: ComponentType<PlatformLinkProps>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Programmatic navigation. Uses the platform's router if available,
|
|
75
|
+
* otherwise falls back to window.location.
|
|
76
|
+
*/
|
|
77
|
+
navigate: (href: string, options?: NavigateOptions) => void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns the current URL/pathname. Reactive in SPA routers.
|
|
81
|
+
*/
|
|
82
|
+
useCurrentUrl: () => string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns shared page props injected by the server or a parent provider.
|
|
86
|
+
* In Inertia: usePage<T>().props
|
|
87
|
+
* In Next.js: data from PlatformPagePropsProvider
|
|
88
|
+
* Default: empty object
|
|
89
|
+
*/
|
|
90
|
+
usePageProps: <T extends Record<string, unknown>>() => T;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Inertia-compatible form hook. In Inertia this is the real useForm.
|
|
94
|
+
* In all other environments it is a fetch-based implementation that
|
|
95
|
+
* exposes the same interface.
|
|
96
|
+
*/
|
|
97
|
+
useForm: <T extends Record<string, unknown>>(initialData: T) => PlatformForm<T>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Document head management. In Inertia this is <Head>. In Next.js
|
|
101
|
+
* metadata is managed via the `metadata` export so this is null.
|
|
102
|
+
* Components should render nothing when Head is null.
|
|
103
|
+
*/
|
|
104
|
+
Head: ComponentType<PlatformHeadProps> | null;
|
|
105
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SidebarFixedLayout (Metronic demo1) — structural CSS.
|
|
3
|
+
*
|
|
4
|
+
* Applied via body class ".sidebar-fixed-layout" set by the layout component
|
|
5
|
+
* on mount and removed on unmount.
|
|
6
|
+
*
|
|
7
|
+
* Variables:
|
|
8
|
+
* --sidebar-width current sidebar width (collapses to --sidebar-width-collapse)
|
|
9
|
+
* --sidebar-width-collapse icon-only width when sidebar is collapsed
|
|
10
|
+
* --sidebar-default-width full expanded width (used on hover to re-expand)
|
|
11
|
+
* --header-height height of the fixed header
|
|
12
|
+
* --sidebar-transition-* animation timing
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
@layer components {
|
|
16
|
+
.sidebar-fixed-layout {
|
|
17
|
+
--sidebar-transition-duration: 0.3s;
|
|
18
|
+
--sidebar-transition-timing: ease;
|
|
19
|
+
--sidebar-width: 280px;
|
|
20
|
+
--sidebar-width-collapse: 80px;
|
|
21
|
+
--sidebar-default-width: 280px;
|
|
22
|
+
--header-height: 70px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@media (max-width: theme(--breakpoint-lg)) {
|
|
26
|
+
.sidebar-fixed-layout {
|
|
27
|
+
--sidebar-width: 280px;
|
|
28
|
+
--header-height: 60px;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Base chrome */
|
|
33
|
+
.sidebar-fixed-layout .layout-header {
|
|
34
|
+
height: var(--header-height);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sidebar-fixed-layout .layout-sidebar {
|
|
38
|
+
width: var(--sidebar-width);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Fixed header pushes wrapper down */
|
|
42
|
+
.sidebar-fixed-layout.header-fixed .layout-wrapper {
|
|
43
|
+
padding-top: var(--header-height);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Desktop: fixed sidebar offsets the wrapper */
|
|
47
|
+
@media (min-width: theme(--breakpoint-lg)) {
|
|
48
|
+
.sidebar-fixed-layout .layout-sidebar {
|
|
49
|
+
width: var(--sidebar-width);
|
|
50
|
+
transition: width var(--sidebar-transition-duration)
|
|
51
|
+
var(--sidebar-transition-timing);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.sidebar-fixed-layout .layout-sidebar .sidebar-header {
|
|
55
|
+
height: var(--header-height);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sidebar-fixed-layout .layout-sidebar .sidebar-wrapper {
|
|
59
|
+
width: var(--sidebar-default-width);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sidebar-fixed-layout .layout-sidebar .sidebar-logo {
|
|
63
|
+
width: var(--sidebar-default-width);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sidebar-fixed-layout .layout-sidebar .small-logo {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.sidebar-fixed-layout .layout-wrapper {
|
|
71
|
+
padding-inline-start: var(--sidebar-width);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sidebar-fixed-layout.header-fixed .layout-header {
|
|
75
|
+
inset-inline-start: var(--sidebar-width);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.sidebar-fixed-layout.header-fixed .layout-wrapper {
|
|
79
|
+
padding-top: var(--header-height);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Collapsed state */
|
|
83
|
+
.sidebar-fixed-layout.sidebar-collapse {
|
|
84
|
+
--sidebar-width: var(--sidebar-width-collapse);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.sidebar-fixed-layout.sidebar-collapse .layout-sidebar {
|
|
88
|
+
transition: width var(--sidebar-transition-duration)
|
|
89
|
+
var(--sidebar-transition-timing);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.sidebar-fixed-layout.sidebar-collapse .layout-sidebar:hover {
|
|
93
|
+
width: var(--sidebar-default-width);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.sidebar-fixed-layout.sidebar-collapse .layout-sidebar:not(:hover) .default-logo {
|
|
97
|
+
display: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.sidebar-fixed-layout.sidebar-collapse .layout-sidebar:not(:hover) .small-logo {
|
|
101
|
+
display: flex;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Hide accordion labels/badges when collapsed and not hovered */
|
|
105
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
106
|
+
.layout-sidebar:not(:hover)
|
|
107
|
+
[data-slot='accordion-menu-title'],
|
|
108
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
109
|
+
.layout-sidebar:not(:hover)
|
|
110
|
+
[data-slot='badge'],
|
|
111
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
112
|
+
.layout-sidebar:not(:hover)
|
|
113
|
+
[data-slot='accordion-menu-sub-indicator'] {
|
|
114
|
+
display: none !important;
|
|
115
|
+
transition: none !important;
|
|
116
|
+
animation: none !important;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
120
|
+
.layout-sidebar:not(:hover)
|
|
121
|
+
[data-slot='accordion-menu-sub-content'] {
|
|
122
|
+
visibility: hidden;
|
|
123
|
+
position: absolute;
|
|
124
|
+
height: 0;
|
|
125
|
+
width: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
129
|
+
.layout-sidebar:not(:hover)
|
|
130
|
+
[data-slot='accordion-menu-label'] {
|
|
131
|
+
visibility: hidden;
|
|
132
|
+
position: relative;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sidebar-fixed-layout.sidebar-collapse
|
|
136
|
+
.layout-sidebar:not(:hover)
|
|
137
|
+
[data-slot='accordion-menu-label']::before {
|
|
138
|
+
content: '...';
|
|
139
|
+
color: currentColor;
|
|
140
|
+
font-size: inherit;
|
|
141
|
+
position: absolute;
|
|
142
|
+
visibility: visible;
|
|
143
|
+
display: inline-block;
|
|
144
|
+
inset-inline-start: 0;
|
|
145
|
+
top: 0.25rem;
|
|
146
|
+
margin-inline-start: -0.15rem;
|
|
147
|
+
transform: translateX(100%);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Smooth transitions after layout initialises (avoids flash on mount) */
|
|
152
|
+
.sidebar-fixed-layout.layout-initialized .layout-wrapper {
|
|
153
|
+
transition: padding-inline-start var(--sidebar-transition-duration)
|
|
154
|
+
var(--sidebar-transition-timing);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.sidebar-fixed-layout.layout-initialized .layout-header {
|
|
158
|
+
transition: inset-inline-start var(--sidebar-transition-duration)
|
|
159
|
+
var(--sidebar-transition-timing);
|
|
160
|
+
}
|
|
161
|
+
}
|