@rsc-kit/press 0.0.0-stage → 0.30.42
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/README.md +117 -2
- package/dist/admin/actions.d.ts +30 -0
- package/dist/admin/actions.js +171 -0
- package/dist/admin/actions.js.map +1 -0
- package/dist/admin/index.d.ts +5 -0
- package/dist/admin/index.js +2 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/panel.d.ts +96 -0
- package/dist/admin/panel.js +354 -0
- package/dist/admin/panel.js.map +1 -0
- package/dist/admin/registry.d.ts +58 -0
- package/dist/admin/registry.js +90 -0
- package/dist/admin/registry.js.map +1 -0
- package/dist/admin/theme.d.ts +251 -0
- package/dist/admin/theme.js +2 -0
- package/dist/admin/theme.js.map +1 -0
- package/dist/admin/url.d.ts +24 -0
- package/dist/admin/url.js +45 -0
- package/dist/admin/url.js.map +1 -0
- package/dist/blocks.d.ts +46 -0
- package/dist/blocks.js +33 -0
- package/dist/blocks.js.map +1 -0
- package/dist/forms/actions.d.ts +7 -0
- package/dist/forms/actions.js +26 -0
- package/dist/forms/actions.js.map +1 -0
- package/dist/forms/form.d.ts +42 -0
- package/dist/forms/form.js +44 -0
- package/dist/forms/form.js.map +1 -0
- package/dist/forms/honeypot.d.ts +2 -0
- package/dist/forms/honeypot.js +3 -0
- package/dist/forms/honeypot.js.map +1 -0
- package/dist/forms/index.d.ts +3 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/registry.d.ts +10 -0
- package/dist/forms/registry.js +17 -0
- package/dist/forms/registry.js.map +1 -0
- package/dist/forms/theme.d.ts +29 -0
- package/dist/forms/theme.js +2 -0
- package/dist/forms/theme.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/installable.d.ts +173 -0
- package/dist/installable.js +490 -0
- package/dist/installable.js.map +1 -0
- package/dist/memory.d.ts +7 -0
- package/dist/memory.js +50 -0
- package/dist/memory.js.map +1 -0
- package/dist/pages/index.d.ts +2 -0
- package/dist/pages/index.js +2 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/pages.d.ts +78 -0
- package/dist/pages/pages.js +183 -0
- package/dist/pages/pages.js.map +1 -0
- package/dist/plugin.d.ts +51 -0
- package/dist/plugin.js +20 -0
- package/dist/plugin.js.map +1 -0
- package/dist/resource.d.ts +320 -0
- package/dist/resource.js +415 -0
- package/dist/resource.js.map +1 -0
- package/dist/shadcn/breadcrumbs.d.ts +6 -0
- package/dist/shadcn/breadcrumbs.js +21 -0
- package/dist/shadcn/breadcrumbs.js.map +1 -0
- package/dist/shadcn/components/ui/alert-dialog.d.ts +18 -0
- package/dist/shadcn/components/ui/alert-dialog.js +44 -0
- package/dist/shadcn/components/ui/alert-dialog.js.map +1 -0
- package/dist/shadcn/components/ui/avatar.d.ts +11 -0
- package/dist/shadcn/components/ui/avatar.js +25 -0
- package/dist/shadcn/components/ui/avatar.js.map +1 -0
- package/dist/shadcn/components/ui/badge.d.ts +7 -0
- package/dist/shadcn/components/ui/badge.js +34 -0
- package/dist/shadcn/components/ui/badge.js.map +1 -0
- package/dist/shadcn/components/ui/breadcrumb.d.ts +10 -0
- package/dist/shadcn/components/ui/breadcrumb.js +38 -0
- package/dist/shadcn/components/ui/breadcrumb.js.map +1 -0
- package/dist/shadcn/components/ui/button.d.ts +8 -0
- package/dist/shadcn/components/ui/button.js +35 -0
- package/dist/shadcn/components/ui/button.js.map +1 -0
- package/dist/shadcn/components/ui/card.d.ts +11 -0
- package/dist/shadcn/components/ui/card.js +26 -0
- package/dist/shadcn/components/ui/card.js.map +1 -0
- package/dist/shadcn/components/ui/checkbox.d.ts +3 -0
- package/dist/shadcn/components/ui/checkbox.js +10 -0
- package/dist/shadcn/components/ui/checkbox.js.map +1 -0
- package/dist/shadcn/components/ui/dropdown-menu.d.ts +29 -0
- package/dist/shadcn/components/ui/dropdown-menu.js +53 -0
- package/dist/shadcn/components/ui/dropdown-menu.js.map +1 -0
- package/dist/shadcn/components/ui/field.d.ts +24 -0
- package/dist/shadcn/components/ui/field.js +69 -0
- package/dist/shadcn/components/ui/field.js.map +1 -0
- package/dist/shadcn/components/ui/input.d.ts +3 -0
- package/dist/shadcn/components/ui/input.js +9 -0
- package/dist/shadcn/components/ui/input.js.map +1 -0
- package/dist/shadcn/components/ui/label.d.ts +3 -0
- package/dist/shadcn/components/ui/label.js +9 -0
- package/dist/shadcn/components/ui/label.js.map +1 -0
- package/dist/shadcn/components/ui/select.d.ts +15 -0
- package/dist/shadcn/components/ui/select.js +36 -0
- package/dist/shadcn/components/ui/select.js.map +1 -0
- package/dist/shadcn/components/ui/separator.d.ts +3 -0
- package/dist/shadcn/components/ui/separator.js +9 -0
- package/dist/shadcn/components/ui/separator.js.map +1 -0
- package/dist/shadcn/components/ui/sheet.d.ts +14 -0
- package/dist/shadcn/components/ui/sheet.js +39 -0
- package/dist/shadcn/components/ui/sheet.js.map +1 -0
- package/dist/shadcn/components/ui/sidebar.d.ts +63 -0
- package/dist/shadcn/components/ui/sidebar.js +257 -0
- package/dist/shadcn/components/ui/sidebar.js.map +1 -0
- package/dist/shadcn/components/ui/skeleton.d.ts +2 -0
- package/dist/shadcn/components/ui/skeleton.js +7 -0
- package/dist/shadcn/components/ui/skeleton.js.map +1 -0
- package/dist/shadcn/components/ui/sonner.d.ts +3 -0
- package/dist/shadcn/components/ui/sonner.js +38 -0
- package/dist/shadcn/components/ui/sonner.js.map +1 -0
- package/dist/shadcn/components/ui/switch.d.ts +5 -0
- package/dist/shadcn/components/ui/switch.js +9 -0
- package/dist/shadcn/components/ui/switch.js.map +1 -0
- package/dist/shadcn/components/ui/table.d.ts +10 -0
- package/dist/shadcn/components/ui/table.js +30 -0
- package/dist/shadcn/components/ui/table.js.map +1 -0
- package/dist/shadcn/components/ui/textarea.d.ts +3 -0
- package/dist/shadcn/components/ui/textarea.js +8 -0
- package/dist/shadcn/components/ui/textarea.js.map +1 -0
- package/dist/shadcn/components/ui/tooltip.d.ts +6 -0
- package/dist/shadcn/components/ui/tooltip.js +18 -0
- package/dist/shadcn/components/ui/tooltip.js.map +1 -0
- package/dist/shadcn/data-table.d.ts +12 -0
- package/dist/shadcn/data-table.js +195 -0
- package/dist/shadcn/data-table.js.map +1 -0
- package/dist/shadcn/fields.d.ts +20 -0
- package/dist/shadcn/fields.js +179 -0
- package/dist/shadcn/fields.js.map +1 -0
- package/dist/shadcn/flash-toasts.d.ts +2 -0
- package/dist/shadcn/flash-toasts.js +11 -0
- package/dist/shadcn/flash-toasts.js.map +1 -0
- package/dist/shadcn/hooks/use-mobile.d.ts +1 -0
- package/dist/shadcn/hooks/use-mobile.js +16 -0
- package/dist/shadcn/hooks/use-mobile.js.map +1 -0
- package/dist/shadcn/index.d.ts +10 -0
- package/dist/shadcn/index.js +31 -0
- package/dist/shadcn/index.js.map +1 -0
- package/dist/shadcn/mode-toggle.d.ts +7 -0
- package/dist/shadcn/mode-toggle.js +52 -0
- package/dist/shadcn/mode-toggle.js.map +1 -0
- package/dist/shadcn/nav.d.ts +5 -0
- package/dist/shadcn/nav.js +19 -0
- package/dist/shadcn/nav.js.map +1 -0
- package/dist/shadcn/pages.d.ts +15 -0
- package/dist/shadcn/pages.js +59 -0
- package/dist/shadcn/pages.js.map +1 -0
- package/dist/shadcn/plugin-forms.d.ts +16 -0
- package/dist/shadcn/plugin-forms.js +25 -0
- package/dist/shadcn/plugin-forms.js.map +1 -0
- package/dist/shadcn/public-form.d.ts +8 -0
- package/dist/shadcn/public-form.js +26 -0
- package/dist/shadcn/public-form.js.map +1 -0
- package/dist/shadcn/resource-form.d.ts +19 -0
- package/dist/shadcn/resource-form.js +30 -0
- package/dist/shadcn/resource-form.js.map +1 -0
- package/dist/shadcn/styles.css +12 -0
- package/dist/shadcn/tenant-switcher.d.ts +3 -0
- package/dist/shadcn/tenant-switcher.js +17 -0
- package/dist/shadcn/tenant-switcher.js.map +1 -0
- package/dist/shadcn/theme-script.d.ts +7 -0
- package/dist/shadcn/theme-script.js +10 -0
- package/dist/shadcn/theme-script.js.map +1 -0
- package/dist/shadcn/user-menu.d.ts +3 -0
- package/dist/shadcn/user-menu.js +23 -0
- package/dist/shadcn/user-menu.js.map +1 -0
- package/dist/signing.d.ts +43 -0
- package/dist/signing.js +82 -0
- package/dist/signing.js.map +1 -0
- package/dist/tenant.d.ts +12 -0
- package/dist/tenant.js +29 -0
- package/dist/tenant.js.map +1 -0
- package/dist/uploads.d.ts +32 -0
- package/dist/uploads.js +28 -0
- package/dist/uploads.js.map +1 -0
- package/package.json +74 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table.js","sourceRoot":"","sources":["../../src/shadcn/data-table.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport { useEffect, useMemo, useRef, useState, useTransition } from 'react'\nimport type { ReactNode } from 'react'\nimport {\n type ColumnDef,\n type ColumnVisibilityState,\n type PaginationState,\n type SortingState,\n columnVisibilityFeature,\n createPaginatedRowModel,\n createSortedRowModel,\n rowPaginationFeature,\n rowSortingFeature,\n tableFeatures,\n useTable,\n} from '@tanstack/react-table'\nimport Link from '@rsc-kit/core/Link'\nimport { visit } from '@rsc-kit/core/router'\nimport { ArrowDown, ArrowUp, ArrowUpDown, ChevronLeft, ChevronRight, Columns3, MoreHorizontal, Pencil, Search, Trash2, X } from 'lucide-react'\nimport type { TableBulkAction, TableProps, TableQuery, TableRowData } from '../admin/theme.js'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from './components/ui/alert-dialog.js'\nimport { Button } from './components/ui/button.js'\nimport { Checkbox } from './components/ui/checkbox.js'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './components/ui/dropdown-menu.js'\nimport { Input } from './components/ui/input.js'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './components/ui/select.js'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './components/ui/table.js'\n\n/** What is asked before it happens: one row's delete, or an action over the ticked rows. */\ntype Confirming = { row: TableRowData } | { action: TableBulkAction; ids: string[] }\n\nconst features = tableFeatures({\n rowSortingFeature,\n rowPaginationFeature,\n columnVisibilityFeature,\n sortedRowModel: createSortedRowModel(),\n paginatedRowModel: createPaginatedRowModel(),\n})\n\ntype Features = typeof features\n\nconst ALL = '__all__'\n\n/**\n * Every resource's table. One component for both modes, so a table looks and\n * behaves the same wherever its rows are searched:\n *\n * server the url is the state. Typing, a filter, a header and the pager\n * each visit a url, the page asks the source for one page, and a\n * link works with no javascript and can be shared.\n * client every row arrived at once; search, filters, sort and the pager\n * happen here, with no request.\n */\nexport function DataTable({\n mode,\n href,\n columns,\n rows,\n total,\n perPage,\n query,\n filters,\n noun,\n bulk,\n}: TableProps) {\n const server = mode === 'server'\n const [q, setQ] = useState(query.q)\n const [chosen, setChosen] = useState<Record<string, string>>(query.filters)\n const [sorting, setSorting] = useState<SortingState>(query.sort ? [{ id: query.sort, desc: query.dir === 'desc' }] : [])\n const [columnVisibility, setColumnVisibility] = useState<ColumnVisibilityState>(() =>\n Object.fromEntries(columns.filter((column) => !column.visible).map((column) => [column.key, false])),\n )\n const [pagination, setPagination] = useState<PaginationState>({ pageIndex: server ? query.page - 1 : 0, pageSize: perPage })\n const [confirming, setConfirming] = useState<Confirming | null>(null)\n const [deleting, startDelete] = useTransition()\n const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set())\n const [running, startRun] = useTransition()\n\n // New rows - another page, a search, the table after an action - start\n // with nothing ticked: a selection is of rows the visitor can see.\n useEffect(() => setSelected(new Set()), [rows])\n const [, startVisit] = useTransition()\n\n // Server mode: the url this state names. Empty values are left out, so a\n // cleared search is the plain list url and not ?q=.\n const urlFor = (changes: Partial<Omit<TableQuery, 'filters'>> & { filters?: Record<string, string> }) => {\n const next = { ...query, q, filters: chosen, ...changes }\n const search = new URLSearchParams()\n\n if (next.q) search.set('q', next.q)\n if (next.sort) search.set('sort', next.sort)\n if (next.sort && next.dir === 'desc') search.set('dir', 'desc')\n if (next.page > 1) search.set('page', String(next.page))\n for (const [key, value] of Object.entries(next.filters)) if (value) search.set(key, value)\n\n const qs = search.toString()\n\n return qs ? `${href}?${qs}` : href\n }\n\n const go = (url: string) => startVisit(() => void visit(url as never, { replace: true }))\n\n // Typing searches after a pause, not per keystroke; the page resets to the first.\n const typed = useRef(false)\n\n useEffect(() => {\n if (!server || !typed.current) return\n\n const timer = setTimeout(() => go(urlFor({ q, page: 1 })), 300)\n\n return () => clearTimeout(timer)\n }, [q])\n\n // Client mode: search and filters here, before the table sorts and pages.\n const visible = useMemo(() => {\n if (server) return rows\n\n const needle = q.trim().toLowerCase()\n const searchable = columns.filter((column) => column.searchable).map((column) => column.key)\n\n return rows.filter(\n (row) =>\n Object.entries(chosen).every(([key, value]) => !value || String(row.values[key]) === value) &&\n (!needle || searchable.some((key) => String(row.values[key] ?? '').toLowerCase().includes(needle))),\n )\n }, [server, rows, q, chosen, columns])\n\n const columnDefs = useMemo<ColumnDef<Features, TableRowData>[]>(\n () =>\n columns.map((column) => ({\n id: column.key,\n accessorFn: (row: TableRowData) => row.values[column.key],\n header: column.label,\n cell: ({ row }: { row: { original: TableRowData } }) => row.original.cells[column.key],\n enableSorting: column.sortable,\n enableHiding: true,\n sortFn: (a, b, id) => compare(a.getValue(id), b.getValue(id)),\n })) as ColumnDef<Features, TableRowData>[],\n [columns],\n )\n\n const table = useTable({\n features,\n data: visible,\n columns: columnDefs,\n getRowId: (row: TableRowData) => row.id,\n manualSorting: server,\n manualPagination: server,\n ...(server ? { pageCount: Math.max(1, Math.ceil(total / perPage)) } : {}),\n onSortingChange: setSorting,\n onPaginationChange: setPagination,\n onColumnVisibilityChange: setColumnVisibility,\n state: { sorting, pagination, columnVisibility },\n })\n\n const onPage = table.getRowModel().rows.map((row) => row.id)\n const ticked = onPage.filter((id) => selected.has(id))\n const allTicked = onPage.length > 0 && ticked.length === onPage.length\n\n const tick = (ids: string[], on: boolean) =>\n setSelected((current) => {\n const next = new Set(current)\n\n for (const id of ids) on ? next.add(id) : next.delete(id)\n\n return next\n })\n\n const runBulk = (action: TableBulkAction, ids: string[]) =>\n startRun(async () => {\n await bulk?.run(action.name, ids)\n setSelected(new Set())\n setConfirming(null)\n })\n\n const searchable = columns.some((column) => column.searchable)\n const hasActions = rows.some((row) => row.edit || row.remove)\n const pageCount = server ? Math.max(1, Math.ceil(total / perPage)) : Math.max(1, table.getPageCount())\n const page = server ? query.page : pagination.pageIndex + 1\n const count = server ? total : visible.length\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {searchable && (\n // A form, so Enter searches and a server-mode search works before\n // the page has javascript: it is a GET of the list url.\n <form\n action={href}\n method=\"get\"\n className=\"relative w-full sm:max-w-xs\"\n onSubmit={(event) => {\n event.preventDefault()\n if (server) go(urlFor({ q, page: 1 }))\n }}\n >\n <Search className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n name=\"q\"\n type=\"search\"\n placeholder={`Search ${noun.many.toLowerCase()}…`}\n aria-label={`Search ${noun.many.toLowerCase()}`}\n className=\"pl-8\"\n value={q}\n onChange={(event) => {\n typed.current = true\n setQ(event.target.value)\n if (!server) table.setPageIndex(0)\n }}\n />\n </form>\n )}\n {filters.map((filter) => (\n <Select\n key={filter.key}\n items={[{ value: ALL, label: `All ${filter.label.toLowerCase()}` }, ...filter.options]}\n value={chosen[filter.key] || ALL}\n onValueChange={(value) => {\n const next = { ...chosen, [filter.key]: value === ALL || value === null ? '' : String(value) }\n\n setChosen(next)\n if (server) go(urlFor({ filters: next, page: 1 }))\n else table.setPageIndex(0)\n }}\n >\n <SelectTrigger aria-label={filter.label} className=\"w-full sm:w-44\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All {filter.label.toLowerCase()}</SelectItem>\n {filter.options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ))}\n <DropdownMenu>\n <DropdownMenuTrigger render={<Button variant=\"outline\" className=\"ml-auto\" />}>\n <Columns3 />\n <span className=\"hidden sm:inline\">Columns</span>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-44\">\n <DropdownMenuGroup>\n <DropdownMenuLabel>Show columns</DropdownMenuLabel>\n {table\n .getAllColumns()\n .filter((column) => column.getCanHide())\n .map((column) => (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) => column.toggleVisibility(!!value)}\n >\n {columns.find((candidate) => candidate.key === column.id)?.label}\n </DropdownMenuCheckboxItem>\n ))}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n <div className=\"overflow-hidden rounded-lg border\">\n <Table>\n <TableHeader className=\"bg-muted/50\">\n {table.getHeaderGroups().map((group) => (\n <TableRow key={group.id}>\n {bulk && (\n <TableHead className=\"w-10\">\n <Checkbox\n aria-label={`Select every ${noun.one.toLowerCase()} on this page`}\n checked={allTicked}\n indeterminate={ticked.length > 0 && !allTicked}\n disabled={onPage.length === 0}\n onCheckedChange={() => tick(onPage, !allTicked)}\n />\n </TableHead>\n )}\n {group.headers.map((header) => {\n const column = header.column\n const label = columns.find((candidate) => candidate.key === column.id)?.label\n const sorted = server ? (query.sort === column.id ? query.dir : false) : column.getIsSorted()\n const Arrow = sorted === 'asc' ? ArrowUp : sorted === 'desc' ? ArrowDown : ArrowUpDown\n\n return (\n <TableHead key={header.id} aria-sort={sorted === 'asc' ? 'ascending' : sorted === 'desc' ? 'descending' : undefined}>\n {!column.getCanSort() ? (\n label\n ) : server ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"-ml-2.5 h-8\"\n nativeButton={false}\n render={<Link href={urlFor({ sort: column.id, dir: sorted === 'asc' ? 'desc' : 'asc', page: 1 }) as never} replace />}\n >\n {label}\n <Arrow className={sorted ? undefined : 'text-muted-foreground/60'} />\n </Button>\n ) : (\n <Button variant=\"ghost\" size=\"sm\" className=\"-ml-2.5 h-8\" onClick={() => column.toggleSorting(sorted === 'asc')}>\n {label}\n <Arrow className={sorted ? undefined : 'text-muted-foreground/60'} />\n </Button>\n )}\n </TableHead>\n )\n })}\n {hasActions && (\n <TableHead className=\"w-12\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n )}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {table.getRowModel().rows.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={selected.has(row.id) ? 'selected' : undefined}>\n {bulk && (\n <TableCell>\n <Checkbox aria-label=\"Select row\" checked={selected.has(row.id)} onCheckedChange={(on) => tick([row.id], on)} />\n </TableCell>\n )}\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n <table.FlexRender cell={cell} />\n </TableCell>\n ))}\n {hasActions && (\n <TableCell className=\"text-right\">\n <RowActions row={row.original} onDelete={() => setConfirming({ row: row.original })} />\n </TableCell>\n )}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length + (hasActions ? 1 : 0) + (bulk ? 1 : 0)} className=\"h-24 text-center text-muted-foreground\">\n No {noun.many.toLowerCase()} found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex items-center justify-between gap-2\">\n {/* The ticked rows' actions take the count's place, below the table:\n above it they would push the rows down under the next click. */}\n {bulk && ticked.length > 0 ? (\n <div role=\"toolbar\" aria-label=\"Selected rows\" className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium\">{ticked.length} selected</span>\n {bulk.actions.map((action) => (\n <Button\n key={action.name}\n size=\"sm\"\n variant={action.destructive ? 'destructive' : 'outline'}\n disabled={running}\n onClick={() => (action.destructive ? setConfirming({ action, ids: ticked }) : runBulk(action, ticked))}\n >\n {action.name === 'delete' && <Trash2 />}\n {action.label}\n </Button>\n ))}\n <Button size=\"icon-sm\" variant=\"ghost\" aria-label=\"Clear selection\" disabled={running} onClick={() => setSelected(new Set())}>\n <X />\n </Button>\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {count} {count === 1 ? noun.one.toLowerCase() : noun.many.toLowerCase()}\n </p>\n )}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n Page {page} of {pageCount}\n </span>\n {server ? (\n <>\n <Pager to={page > 1 ? urlFor({ page: page - 1 }) : null} label=\"Previous page\">\n <ChevronLeft />\n </Pager>\n <Pager to={page < pageCount ? urlFor({ page: page + 1 }) : null} label=\"Next page\">\n <ChevronRight />\n </Pager>\n </>\n ) : (\n <>\n <Button variant=\"outline\" size=\"icon-sm\" aria-label=\"Previous page\" disabled={!table.getCanPreviousPage()} onClick={() => table.previousPage()}>\n <ChevronLeft />\n </Button>\n <Button variant=\"outline\" size=\"icon-sm\" aria-label=\"Next page\" disabled={!table.getCanNextPage()} onClick={() => table.nextPage()}>\n <ChevronRight />\n </Button>\n </>\n )}\n </div>\n </div>\n\n <AlertDialog open={confirming !== null} onOpenChange={(open) => !open && !deleting && !running && setConfirming(null)}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{confirmTitle(confirming, noun)}</AlertDialogTitle>\n <AlertDialogDescription>\n {confirmDescription(confirming)}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deleting || running}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n disabled={deleting || running}\n onClick={() => {\n if (confirming && 'ids' in confirming) return runBulk(confirming.action, confirming.ids)\n\n startDelete(async () => {\n await confirming?.row.remove?.()\n setConfirming(null)\n })\n }}\n >\n {confirming && 'ids' in confirming ? (running ? 'Working…' : confirming.action.label) : deleting ? 'Deleting…' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n )\n}\n\nfunction confirmTitle(confirming: Confirming | null, noun: { one: string; many: string }): string {\n if (!confirming || 'row' in confirming) return `Delete this ${noun.one.toLowerCase()}?`\n\n const { action, ids } = confirming\n const counted = `${ids.length} ${(ids.length === 1 ? noun.one : noun.many).toLowerCase()}`\n\n return action.name === 'delete' ? `Delete ${counted}?` : `${action.label}: ${counted}?`\n}\n\nfunction confirmDescription(confirming: Confirming | null): string {\n if (confirming && 'ids' in confirming && confirming.action.name !== 'delete') return 'This cannot be undone.'\n\n const many = confirming !== null && 'ids' in confirming && confirming.ids.length > 1\n\n return `${many ? 'They are' : 'It is'} removed for good. This cannot be undone.`\n}\n\nfunction Pager({ to, label, children }: { to: string | null; label: string; children: ReactNode }) {\n if (!to) {\n return (\n <Button variant=\"outline\" size=\"icon-sm\" aria-label={label} disabled>\n {children}\n </Button>\n )\n }\n\n return <Button variant=\"outline\" size=\"icon-sm\" aria-label={label} nativeButton={false} render={<Link href={to as never} replace />}>{children}</Button>\n}\n\nfunction RowActions({ row, onDelete }: { row: TableRowData; onDelete: () => void }) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger render={<Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Actions\" />}>\n <MoreHorizontal />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-36\">\n {row.edit && (\n <DropdownMenuItem render={<Link href={row.edit as never} />}>\n <Pencil />\n Edit\n </DropdownMenuItem>\n )}\n {row.edit && row.remove && <DropdownMenuSeparator />}\n {row.remove && (\n <DropdownMenuItem variant=\"destructive\" onClick={onDelete}>\n <Trash2 />\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction compare(a: unknown, b: unknown): number {\n if (a === b) return 0\n if (a === null || a === undefined) return 1\n if (b === null || b === undefined) return -1\n if (typeof a === 'number' && typeof b === 'number') return a - b\n if (typeof a === 'boolean' && typeof b === 'boolean') return Number(a) - Number(b)\n\n return String(a).localeCompare(String(b), undefined, { numeric: true })\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Field as FieldSpec } from '../resource.js';
|
|
2
|
+
/**
|
|
3
|
+
* Each field as its shadcn control, labelled, with its message under it: the
|
|
4
|
+
* browser's while the value is still wrong, else the server's. Shared by the
|
|
5
|
+
* panel's forms and the public ones, so a field looks and checks the same in
|
|
6
|
+
* both.
|
|
7
|
+
*/
|
|
8
|
+
export declare function FieldList({ fields, values, error }: {
|
|
9
|
+
fields: FieldSpec[];
|
|
10
|
+
values: Record<string, unknown>;
|
|
11
|
+
error: (name: string) => string | undefined;
|
|
12
|
+
}): import("react").JSX.Element[];
|
|
13
|
+
/**
|
|
14
|
+
* The browser's own validation, shown the shadcn way. A submit fires
|
|
15
|
+
* 'invalid' at each control that fails its constraints; that is cancelled -
|
|
16
|
+
* no bubble - and its validationMessage, in the visitor's language, is kept
|
|
17
|
+
* under its name. Fixing the value clears it. 'invalid' does not bubble, so
|
|
18
|
+
* the form listens in the capture phase.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useBrowserErrors(form: React.RefObject<HTMLFormElement | null>): Record<string, string>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useState } from 'react';
|
|
4
|
+
import { ArrowDown, ArrowUp, FileIcon, Plus, Trash2 } from 'lucide-react';
|
|
5
|
+
import { sizeOf } from '../uploads.js';
|
|
6
|
+
import { Button } from './components/ui/button.js';
|
|
7
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from './components/ui/dropdown-menu.js';
|
|
8
|
+
import { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet } from './components/ui/field.js';
|
|
9
|
+
import { Input } from './components/ui/input.js';
|
|
10
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './components/ui/select.js';
|
|
11
|
+
import { Switch } from './components/ui/switch.js';
|
|
12
|
+
import { Textarea } from './components/ui/textarea.js';
|
|
13
|
+
/**
|
|
14
|
+
* Each field as its shadcn control, labelled, with its message under it: the
|
|
15
|
+
* browser's while the value is still wrong, else the server's. Shared by the
|
|
16
|
+
* panel's forms and the public ones, so a field looks and checks the same in
|
|
17
|
+
* both.
|
|
18
|
+
*/
|
|
19
|
+
export function FieldList({ fields, values, error }) {
|
|
20
|
+
return fields.map((field) => {
|
|
21
|
+
const id = `field-${field.name}`;
|
|
22
|
+
const invalid = !!error(field.name);
|
|
23
|
+
if (field.type === 'blocks') {
|
|
24
|
+
return _jsx(BlocksField, { field: field, value: values[field.name], error: error }, field.name);
|
|
25
|
+
}
|
|
26
|
+
if (field.type === 'toggle') {
|
|
27
|
+
return (_jsxs(Field, { orientation: "horizontal", "data-invalid": invalid || undefined, children: [_jsxs(FieldContent, { children: [_jsx(FieldLabel, { htmlFor: id, children: field.label }), field.description && _jsx(FieldDescription, { children: field.description }), invalid && _jsx(FieldError, { children: error(field.name) })] }), _jsx(Switch, { id: id, name: field.name, defaultChecked: Boolean(values[field.name]), "aria-invalid": invalid || undefined })] }, field.name));
|
|
28
|
+
}
|
|
29
|
+
return (_jsxs(Field, { "data-invalid": invalid || undefined, children: [_jsxs(FieldLabel, { htmlFor: id, children: [field.label, field.required && _jsx("span", { className: "text-destructive", children: "*" })] }), field.type === 'file' || field.type === 'image' ? (_jsx(FileControl, { id: id, field: field, value: values[field.name], invalid: invalid }, String(values[field.name] ?? ''))) : (_jsx(Control, { id: id, field: field, value: values[field.name], invalid: invalid })), (field.description ?? limitOf(field)) && _jsx(FieldDescription, { children: field.description ?? limitOf(field) }), invalid && _jsx(FieldError, { children: error(field.name) })] }, field.name));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A list of blocks an editor adds, orders and removes, each with its own
|
|
34
|
+
* fields. Every control stays an ordinary named input - block i's heading is
|
|
35
|
+
* `content.i.heading` - so it submits with the form, is checked by the
|
|
36
|
+
* browser like any other, and shows the server's refusal under itself. Each
|
|
37
|
+
* block keeps a key of its own, so moving one moves what was typed into it.
|
|
38
|
+
*/
|
|
39
|
+
function BlocksField({ field, value, error }) {
|
|
40
|
+
const kinds = field.blocks ?? [];
|
|
41
|
+
const prefix = useId();
|
|
42
|
+
const saved = Array.isArray(value) ? value : [];
|
|
43
|
+
// A kind the app no longer offers has no fields to draw; it is left out,
|
|
44
|
+
// and saving drops it.
|
|
45
|
+
const retired = saved.filter((item) => !kinds.some((kind) => kind.name === item.type)).length;
|
|
46
|
+
const [items, setItems] = useState(() => saved
|
|
47
|
+
.filter((item) => kinds.some((kind) => kind.name === item.type))
|
|
48
|
+
.map((item, index) => ({ key: `${prefix}-${index}`, type: item.type, data: item.data ?? {} })));
|
|
49
|
+
const [made, setMade] = useState(0);
|
|
50
|
+
const add = (kind) => {
|
|
51
|
+
setItems((current) => [...current, { key: `${prefix}-new-${made}`, type: kind.name, data: {} }]);
|
|
52
|
+
setMade((count) => count + 1);
|
|
53
|
+
};
|
|
54
|
+
const move = (from, to) => setItems((current) => {
|
|
55
|
+
const next = [...current];
|
|
56
|
+
const [item] = next.splice(from, 1);
|
|
57
|
+
next.splice(to, 0, item);
|
|
58
|
+
return next;
|
|
59
|
+
});
|
|
60
|
+
const remove = (at) => setItems((current) => current.filter((_, index) => index !== at));
|
|
61
|
+
return (_jsxs(FieldSet, { children: [_jsx(FieldLegend, { variant: "label", children: field.label }), field.description && _jsx(FieldDescription, { children: field.description }), items.length === 0 && _jsx("p", { className: "text-sm text-muted-foreground", children: "No blocks yet." }), retired > 0 && (_jsxs("p", { className: "text-sm text-muted-foreground", children: [retired === 1 ? 'One block is' : `${retired} blocks are`, " of a kind no longer offered, and saving removes ", retired === 1 ? 'it' : 'them', "."] })), items.map((item, index) => {
|
|
62
|
+
const kind = kinds.find((candidate) => candidate.name === item.type);
|
|
63
|
+
const base = `${field.name}.${index}.`;
|
|
64
|
+
return (_jsxs("div", { className: "rounded-lg border", children: [_jsxs("div", { className: "flex items-center gap-1 border-b px-3 py-2", children: [_jsx("span", { className: "text-sm font-medium", children: kind.label }), _jsx("input", { type: "hidden", name: `${base}type`, value: item.type }), _jsxs("div", { className: "ml-auto flex gap-1", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Move up", disabled: index === 0, onClick: () => move(index, index - 1), children: _jsx(ArrowUp, {}) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Move down", disabled: index === items.length - 1, onClick: () => move(index, index + 1), children: _jsx(ArrowDown, {}) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Remove", onClick: () => remove(index), children: _jsx(Trash2, {}) })] })] }), _jsx("div", { className: "p-3", children: _jsx(FieldGroup, { children: _jsx(FieldList, { fields: kind.fields.map((inner) => ({ ...inner, name: base + inner.name })), values: Object.fromEntries(Object.entries(item.data).map(([name, data]) => [base + name, data])), error: error }) }) }), error(`${field.name}.${index}`) && _jsx(FieldError, { className: "px-3 pb-3", children: error(`${field.name}.${index}`) })] }, item.key));
|
|
65
|
+
}), _jsx("div", { children: _jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { render: _jsx(Button, { type: "button", variant: "outline" }), children: [_jsx(Plus, {}), "Add block"] }), _jsx(DropdownMenuContent, { align: "start", children: kinds.map((kind) => (_jsx(DropdownMenuItem, { onClick: () => add(kind), children: kind.label }, kind.name))) })] }) })] }));
|
|
66
|
+
}
|
|
67
|
+
const isControl = (target) => target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement;
|
|
68
|
+
/**
|
|
69
|
+
* The browser's own validation, shown the shadcn way. A submit fires
|
|
70
|
+
* 'invalid' at each control that fails its constraints; that is cancelled -
|
|
71
|
+
* no bubble - and its validationMessage, in the visitor's language, is kept
|
|
72
|
+
* under its name. Fixing the value clears it. 'invalid' does not bubble, so
|
|
73
|
+
* the form listens in the capture phase.
|
|
74
|
+
*/
|
|
75
|
+
export function useBrowserErrors(form) {
|
|
76
|
+
const [errors, setErrors] = useState({});
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const element = form.current;
|
|
79
|
+
if (!element)
|
|
80
|
+
return;
|
|
81
|
+
let focusing = false;
|
|
82
|
+
const onInvalid = (event) => {
|
|
83
|
+
if (!isControl(event.target) || !event.target.name)
|
|
84
|
+
return;
|
|
85
|
+
const { name, validationMessage } = event.target;
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
setErrors((current) => (current[name] === validationMessage ? current : { ...current, [name]: validationMessage }));
|
|
88
|
+
// Cancelling the bubble also cancels the browser's focus on the first
|
|
89
|
+
// wrong field. Every control's 'invalid' fires before the next task, so
|
|
90
|
+
// give focus back once, to the first one, after they all have.
|
|
91
|
+
if (!focusing) {
|
|
92
|
+
focusing = true;
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
focusing = false;
|
|
95
|
+
element.querySelector(':invalid')?.focus();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const onEdit = (event) => {
|
|
100
|
+
if (!isControl(event.target) || !event.target.name)
|
|
101
|
+
return;
|
|
102
|
+
const { name, validity, validationMessage } = event.target;
|
|
103
|
+
setErrors((current) => {
|
|
104
|
+
if (!(name in current))
|
|
105
|
+
return current;
|
|
106
|
+
if (!validity.valid)
|
|
107
|
+
return { ...current, [name]: validationMessage };
|
|
108
|
+
const { [name]: _, ...rest } = current;
|
|
109
|
+
return rest;
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
element.addEventListener('invalid', onInvalid, true);
|
|
113
|
+
element.addEventListener('input', onEdit);
|
|
114
|
+
element.addEventListener('change', onEdit);
|
|
115
|
+
return () => {
|
|
116
|
+
element.removeEventListener('invalid', onInvalid, true);
|
|
117
|
+
element.removeEventListener('input', onEdit);
|
|
118
|
+
element.removeEventListener('change', onEdit);
|
|
119
|
+
};
|
|
120
|
+
}, [form]);
|
|
121
|
+
return errors;
|
|
122
|
+
}
|
|
123
|
+
function Control({ id, field, value, invalid }) {
|
|
124
|
+
const shared = {
|
|
125
|
+
id,
|
|
126
|
+
name: field.name,
|
|
127
|
+
required: field.required,
|
|
128
|
+
'aria-invalid': invalid || undefined,
|
|
129
|
+
};
|
|
130
|
+
const lengths = { minLength: field.minLength, maxLength: field.maxLength };
|
|
131
|
+
switch (field.type) {
|
|
132
|
+
case 'textarea':
|
|
133
|
+
return _jsx(Textarea, { ...shared, ...lengths, rows: 4, defaultValue: String(value ?? '') });
|
|
134
|
+
case 'select': {
|
|
135
|
+
// An optional select can be left empty: its first choice is "None",
|
|
136
|
+
// which arrives as "" and is left out of the values, as any empty
|
|
137
|
+
// optional field is. A required one starts on its first real choice.
|
|
138
|
+
const options = field.required ? (field.options ?? []) : [{ value: '', label: 'None' }, ...(field.options ?? [])];
|
|
139
|
+
return (_jsxs(Select, { name: field.name, items: options, defaultValue: value === null || value === undefined ? (options[0]?.value ?? '') : String(value), children: [_jsx(SelectTrigger, { id: id, "aria-invalid": invalid || undefined, className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: options.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }));
|
|
140
|
+
}
|
|
141
|
+
case 'number':
|
|
142
|
+
return (_jsx(Input, { ...shared, type: "number", min: field.min, max: field.max, step: field.step ?? 'any', defaultValue: value === undefined || value === null ? '' : String(value) }));
|
|
143
|
+
case 'email':
|
|
144
|
+
return _jsx(Input, { ...shared, ...lengths, type: "email", defaultValue: String(value ?? '') });
|
|
145
|
+
case 'date':
|
|
146
|
+
return _jsx(Input, { ...shared, type: "date", defaultValue: String(value ?? '').slice(0, 10) });
|
|
147
|
+
default:
|
|
148
|
+
return _jsx(Input, { ...shared, ...lengths, pattern: field.pattern, defaultValue: String(value ?? '') });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** A file field's size limit, said under it when the app said nothing else. */
|
|
152
|
+
function limitOf(field) {
|
|
153
|
+
return (field.type === 'file' || field.type === 'image') && field.maxSize !== undefined ? `Up to ${sizeOf(field.maxSize)}.` : undefined;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A file or image field: what it holds now, and a file input to replace it.
|
|
157
|
+
* The value it holds goes back with the form in a hidden input under the
|
|
158
|
+
* same name, so a save that chooses nothing keeps it; the server keeps it
|
|
159
|
+
* only if the record already had it. A file over the size limit is refused
|
|
160
|
+
* as it is chosen, through the input's own validity, so it shows as any
|
|
161
|
+
* other field's message and never makes the trip.
|
|
162
|
+
*/
|
|
163
|
+
function FileControl({ id, field, value, invalid }) {
|
|
164
|
+
const [kept, setKept] = useState(typeof value === 'string' ? value : '');
|
|
165
|
+
const [preview, setPreview] = useState(null);
|
|
166
|
+
useEffect(() => () => {
|
|
167
|
+
if (preview)
|
|
168
|
+
URL.revokeObjectURL(preview);
|
|
169
|
+
}, [preview]);
|
|
170
|
+
const choose = (event) => {
|
|
171
|
+
const input = event.currentTarget;
|
|
172
|
+
const file = input.files?.[0];
|
|
173
|
+
input.setCustomValidity(file && field.maxSize !== undefined && file.size > field.maxSize ? `Choose a file of ${sizeOf(field.maxSize)} or less.` : '');
|
|
174
|
+
setPreview(file && field.type === 'image' && input.validity.valid ? URL.createObjectURL(file) : null);
|
|
175
|
+
};
|
|
176
|
+
const shown = preview ?? (kept || null);
|
|
177
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [shown && field.type === 'image' && _jsx("img", { src: shown, alt: "", className: "h-32 w-fit max-w-full rounded-md border object-cover" }), kept && !preview && field.type === 'file' && (_jsxs("a", { href: kept, target: "_blank", rel: "noreferrer", className: "flex w-fit items-center gap-2 text-sm underline-offset-4 hover:underline", children: [_jsx(FileIcon, { className: "size-4" }), decodeURIComponent(kept.split(/[/?#]/).filter(Boolean).pop() ?? kept)] })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { id: id, name: field.name, type: "file", accept: field.accept, required: field.required && !kept, "aria-invalid": invalid || undefined, onChange: choose }), kept && field.nullable && (_jsx(Button, { type: "button", variant: "outline", onClick: () => setKept(''), children: "Remove" }))] }), _jsx("input", { type: "hidden", name: field.name, value: kept })] }));
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/shadcn/fields.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport { useEffect, useId, useState } from 'react'\nimport { ArrowDown, ArrowUp, FileIcon, Plus, Trash2 } from 'lucide-react'\nimport type { BlockSpec, Field as FieldSpec } from '../resource.js'\nimport { sizeOf } from '../uploads.js'\nimport { Button } from './components/ui/button.js'\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from './components/ui/dropdown-menu.js'\nimport { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet } from './components/ui/field.js'\nimport { Input } from './components/ui/input.js'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './components/ui/select.js'\nimport { Switch } from './components/ui/switch.js'\nimport { Textarea } from './components/ui/textarea.js'\n\n/**\n * Each field as its shadcn control, labelled, with its message under it: the\n * browser's while the value is still wrong, else the server's. Shared by the\n * panel's forms and the public ones, so a field looks and checks the same in\n * both.\n */\nexport function FieldList({ fields, values, error }: { fields: FieldSpec[]; values: Record<string, unknown>; error: (name: string) => string | undefined }) {\n return fields.map((field) => {\n const id = `field-${field.name}`\n const invalid = !!error(field.name)\n\n if (field.type === 'blocks') {\n return <BlocksField key={field.name} field={field} value={values[field.name]} error={error} />\n }\n\n if (field.type === 'toggle') {\n return (\n <Field key={field.name} orientation=\"horizontal\" data-invalid={invalid || undefined}>\n <FieldContent>\n <FieldLabel htmlFor={id}>{field.label}</FieldLabel>\n {field.description && <FieldDescription>{field.description}</FieldDescription>}\n {invalid && <FieldError>{error(field.name)}</FieldError>}\n </FieldContent>\n <Switch id={id} name={field.name} defaultChecked={Boolean(values[field.name])} aria-invalid={invalid || undefined} />\n </Field>\n )\n }\n\n return (\n <Field key={field.name} data-invalid={invalid || undefined}>\n <FieldLabel htmlFor={id}>\n {field.label}\n {field.required && <span className=\"text-destructive\">*</span>}\n </FieldLabel>\n {field.type === 'file' || field.type === 'image' ? (\n <FileControl key={String(values[field.name] ?? '')} id={id} field={field} value={values[field.name]} invalid={invalid} />\n ) : (\n <Control id={id} field={field} value={values[field.name]} invalid={invalid} />\n )}\n {(field.description ?? limitOf(field)) && <FieldDescription>{field.description ?? limitOf(field)}</FieldDescription>}\n {invalid && <FieldError>{error(field.name)}</FieldError>}\n </Field>\n )\n })\n}\n\ninterface Item {\n key: string\n type: string\n data: Record<string, unknown>\n}\n\n/**\n * A list of blocks an editor adds, orders and removes, each with its own\n * fields. Every control stays an ordinary named input - block i's heading is\n * `content.i.heading` - so it submits with the form, is checked by the\n * browser like any other, and shows the server's refusal under itself. Each\n * block keeps a key of its own, so moving one moves what was typed into it.\n */\nfunction BlocksField({ field, value, error }: { field: FieldSpec; value: unknown; error: (name: string) => string | undefined }) {\n const kinds = field.blocks ?? []\n const prefix = useId()\n const saved = Array.isArray(value) ? (value as { type: string; data?: Record<string, unknown> }[]) : []\n // A kind the app no longer offers has no fields to draw; it is left out,\n // and saving drops it.\n const retired = saved.filter((item) => !kinds.some((kind) => kind.name === item.type)).length\n const [items, setItems] = useState<Item[]>(() =>\n saved\n .filter((item) => kinds.some((kind) => kind.name === item.type))\n .map((item, index) => ({ key: `${prefix}-${index}`, type: item.type, data: item.data ?? {} })),\n )\n const [made, setMade] = useState(0)\n\n const add = (kind: BlockSpec) => {\n setItems((current) => [...current, { key: `${prefix}-new-${made}`, type: kind.name, data: {} }])\n setMade((count) => count + 1)\n }\n\n const move = (from: number, to: number) =>\n setItems((current) => {\n const next = [...current]\n const [item] = next.splice(from, 1)\n\n next.splice(to, 0, item!)\n\n return next\n })\n\n const remove = (at: number) => setItems((current) => current.filter((_, index) => index !== at))\n\n return (\n <FieldSet>\n <FieldLegend variant=\"label\">{field.label}</FieldLegend>\n {field.description && <FieldDescription>{field.description}</FieldDescription>}\n {items.length === 0 && <p className=\"text-sm text-muted-foreground\">No blocks yet.</p>}\n {retired > 0 && (\n <p className=\"text-sm text-muted-foreground\">\n {retired === 1 ? 'One block is' : `${retired} blocks are`} of a kind no longer offered, and saving removes {retired === 1 ? 'it' : 'them'}.\n </p>\n )}\n {items.map((item, index) => {\n const kind = kinds.find((candidate) => candidate.name === item.type)!\n const base = `${field.name}.${index}.`\n\n return (\n <div key={item.key} className=\"rounded-lg border\">\n <div className=\"flex items-center gap-1 border-b px-3 py-2\">\n <span className=\"text-sm font-medium\">{kind.label}</span>\n <input type=\"hidden\" name={`${base}type`} value={item.type} />\n <div className=\"ml-auto flex gap-1\">\n <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label=\"Move up\" disabled={index === 0} onClick={() => move(index, index - 1)}>\n <ArrowUp />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Move down\"\n disabled={index === items.length - 1}\n onClick={() => move(index, index + 1)}\n >\n <ArrowDown />\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label=\"Remove\" onClick={() => remove(index)}>\n <Trash2 />\n </Button>\n </div>\n </div>\n <div className=\"p-3\">\n <FieldGroup>\n <FieldList\n fields={kind.fields.map((inner) => ({ ...inner, name: base + inner.name }))}\n values={Object.fromEntries(Object.entries(item.data).map(([name, data]) => [base + name, data]))}\n error={error}\n />\n </FieldGroup>\n </div>\n {error(`${field.name}.${index}`) && <FieldError className=\"px-3 pb-3\">{error(`${field.name}.${index}`)}</FieldError>}\n </div>\n )\n })}\n <div>\n <DropdownMenu>\n <DropdownMenuTrigger render={<Button type=\"button\" variant=\"outline\" />}>\n <Plus />\n Add block\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {kinds.map((kind) => (\n <DropdownMenuItem key={kind.name} onClick={() => add(kind)}>\n {kind.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </FieldSet>\n )\n}\n\ntype Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement\n\nconst isControl = (target: EventTarget | null): target is Control =>\n target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement\n\n/**\n * The browser's own validation, shown the shadcn way. A submit fires\n * 'invalid' at each control that fails its constraints; that is cancelled -\n * no bubble - and its validationMessage, in the visitor's language, is kept\n * under its name. Fixing the value clears it. 'invalid' does not bubble, so\n * the form listens in the capture phase.\n */\nexport function useBrowserErrors(form: React.RefObject<HTMLFormElement | null>): Record<string, string> {\n const [errors, setErrors] = useState<Record<string, string>>({})\n\n useEffect(() => {\n const element = form.current\n\n if (!element) return\n\n let focusing = false\n\n const onInvalid = (event: Event) => {\n if (!isControl(event.target) || !event.target.name) return\n\n const { name, validationMessage } = event.target\n\n event.preventDefault()\n setErrors((current) => (current[name] === validationMessage ? current : { ...current, [name]: validationMessage }))\n\n // Cancelling the bubble also cancels the browser's focus on the first\n // wrong field. Every control's 'invalid' fires before the next task, so\n // give focus back once, to the first one, after they all have.\n if (!focusing) {\n focusing = true\n setTimeout(() => {\n focusing = false\n element.querySelector<Control>(':invalid')?.focus()\n })\n }\n }\n\n const onEdit = (event: Event) => {\n if (!isControl(event.target) || !event.target.name) return\n\n const { name, validity, validationMessage } = event.target\n\n setErrors((current) => {\n if (!(name in current)) return current\n if (!validity.valid) return { ...current, [name]: validationMessage }\n\n const { [name]: _, ...rest } = current\n\n return rest\n })\n }\n\n element.addEventListener('invalid', onInvalid, true)\n element.addEventListener('input', onEdit)\n element.addEventListener('change', onEdit)\n\n return () => {\n element.removeEventListener('invalid', onInvalid, true)\n element.removeEventListener('input', onEdit)\n element.removeEventListener('change', onEdit)\n }\n }, [form])\n\n return errors\n}\n\nfunction Control({ id, field, value, invalid }: { id: string; field: FieldSpec; value: unknown; invalid: boolean }) {\n const shared = {\n id,\n name: field.name,\n required: field.required,\n 'aria-invalid': invalid || undefined,\n }\n const lengths = { minLength: field.minLength, maxLength: field.maxLength }\n\n switch (field.type) {\n case 'textarea':\n return <Textarea {...shared} {...lengths} rows={4} defaultValue={String(value ?? '')} />\n case 'select': {\n // An optional select can be left empty: its first choice is \"None\",\n // which arrives as \"\" and is left out of the values, as any empty\n // optional field is. A required one starts on its first real choice.\n const options = field.required ? (field.options ?? []) : [{ value: '', label: 'None' }, ...(field.options ?? [])]\n\n return (\n <Select name={field.name} items={options} defaultValue={value === null || value === undefined ? (options[0]?.value ?? '') : String(value)}>\n <SelectTrigger id={id} aria-invalid={invalid || undefined} className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n }\n case 'number':\n return (\n <Input\n {...shared}\n type=\"number\"\n min={field.min}\n max={field.max}\n step={field.step ?? 'any'}\n defaultValue={value === undefined || value === null ? '' : String(value)}\n />\n )\n case 'email':\n return <Input {...shared} {...lengths} type=\"email\" defaultValue={String(value ?? '')} />\n case 'date':\n return <Input {...shared} type=\"date\" defaultValue={String(value ?? '').slice(0, 10)} />\n default:\n return <Input {...shared} {...lengths} pattern={field.pattern} defaultValue={String(value ?? '')} />\n }\n}\n\n/** A file field's size limit, said under it when the app said nothing else. */\nfunction limitOf(field: FieldSpec): string | undefined {\n return (field.type === 'file' || field.type === 'image') && field.maxSize !== undefined ? `Up to ${sizeOf(field.maxSize)}.` : undefined\n}\n\n/**\n * A file or image field: what it holds now, and a file input to replace it.\n * The value it holds goes back with the form in a hidden input under the\n * same name, so a save that chooses nothing keeps it; the server keeps it\n * only if the record already had it. A file over the size limit is refused\n * as it is chosen, through the input's own validity, so it shows as any\n * other field's message and never makes the trip.\n */\nfunction FileControl({ id, field, value, invalid }: { id: string; field: FieldSpec; value: unknown; invalid: boolean }) {\n const [kept, setKept] = useState(typeof value === 'string' ? value : '')\n const [preview, setPreview] = useState<string | null>(null)\n\n useEffect(() => () => {\n if (preview) URL.revokeObjectURL(preview)\n }, [preview])\n\n const choose = (event: React.ChangeEvent<HTMLInputElement>) => {\n const input = event.currentTarget\n const file = input.files?.[0]\n\n input.setCustomValidity(file && field.maxSize !== undefined && file.size > field.maxSize ? `Choose a file of ${sizeOf(field.maxSize)} or less.` : '')\n setPreview(file && field.type === 'image' && input.validity.valid ? URL.createObjectURL(file) : null)\n }\n\n const shown = preview ?? (kept || null)\n\n return (\n <div className=\"flex flex-col gap-3\">\n {shown && field.type === 'image' && <img src={shown} alt=\"\" className=\"h-32 w-fit max-w-full rounded-md border object-cover\" />}\n {kept && !preview && field.type === 'file' && (\n <a href={kept} target=\"_blank\" rel=\"noreferrer\" className=\"flex w-fit items-center gap-2 text-sm underline-offset-4 hover:underline\">\n <FileIcon className=\"size-4\" />\n {decodeURIComponent(kept.split(/[/?#]/).filter(Boolean).pop() ?? kept)}\n </a>\n )}\n <div className=\"flex items-center gap-2\">\n <Input\n id={id}\n name={field.name}\n type=\"file\"\n accept={field.accept}\n required={field.required && !kept}\n aria-invalid={invalid || undefined}\n onChange={choose}\n />\n {kept && field.nullable && (\n <Button type=\"button\" variant=\"outline\" onClick={() => setKept('')}>\n Remove\n </Button>\n )}\n </div>\n <input type=\"hidden\" name={field.name} value={kept} />\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useFlash } from '@rsc-kit/core/useFlash';
|
|
4
|
+
import { toast } from 'sonner';
|
|
5
|
+
import { Toaster } from './components/ui/sonner.js';
|
|
6
|
+
/** Each message a save or delete flashed, as a toast: "Product saved." on the list the save lands on. */
|
|
7
|
+
export function FlashToasts() {
|
|
8
|
+
useFlash(({ message, kind }) => toast[kind](message));
|
|
9
|
+
return _jsx(Toaster, { position: "bottom-right" });
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=flash-toasts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flash-toasts.js","sourceRoot":"","sources":["../../src/shadcn/flash-toasts.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAEnD,yGAAyG;AACzG,MAAM,UAAU,WAAW;IACzB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;IAErD,OAAO,KAAC,OAAO,IAAC,QAAQ,EAAC,cAAc,GAAG,CAAA;AAC5C,CAAC","sourcesContent":["'use client'\n\nimport { useFlash } from '@rsc-kit/core/useFlash'\nimport { toast } from 'sonner'\nimport { Toaster } from './components/ui/sonner.js'\n\n/** Each message a save or delete flashed, as a toast: \"Product saved.\" on the list the save lands on. */\nexport function FlashToasts() {\n useFlash(({ message, kind }) => toast[kind](message))\n\n return <Toaster position=\"bottom-right\" />\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useIsMobile(): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
const MOBILE_BREAKPOINT = 768;
|
|
3
|
+
export function useIsMobile() {
|
|
4
|
+
const [isMobile, setIsMobile] = React.useState(undefined);
|
|
5
|
+
React.useEffect(() => {
|
|
6
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
7
|
+
const onChange = () => {
|
|
8
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
9
|
+
};
|
|
10
|
+
mql.addEventListener("change", onChange);
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
12
|
+
return () => mql.removeEventListener("change", onChange);
|
|
13
|
+
}, []);
|
|
14
|
+
return !!isMobile;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=use-mobile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mobile.js","sourceRoot":"","sources":["../../../src/shadcn/hooks/use-mobile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,MAAM,iBAAiB,GAAG,GAAG,CAAA;AAE7B,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAsB,SAAS,CAAC,CAAA;IAE9E,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,eAAe,iBAAiB,GAAG,CAAC,KAAK,CAAC,CAAA;QACxE,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,WAAW,CAAC,MAAM,CAAC,UAAU,GAAG,iBAAiB,CAAC,CAAA;QACpD,CAAC,CAAA;QACD,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QACxC,WAAW,CAAC,MAAM,CAAC,UAAU,GAAG,iBAAiB,CAAC,CAAA;QAClD,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CAAC,CAAC,QAAQ,CAAA;AACnB,CAAC","sourcesContent":["import * as React from \"react\"\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener(\"change\", onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener(\"change\", onChange)\n }, [])\n\n return !!isMobile\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AdminTheme } from '../admin/theme.js';
|
|
2
|
+
import type { FormsTheme } from '../forms/theme.js';
|
|
3
|
+
/**
|
|
4
|
+
* Panels and public forms drawn with shadcn/ui: its sidebar layout, data table, fields and
|
|
5
|
+
* cards, in the app's own theme variables, so it follows the app's colours,
|
|
6
|
+
* radius, fonts and dark mode. Its classes reach the app's stylesheet through
|
|
7
|
+
*
|
|
8
|
+
* @import "@rsc-kit/press/shadcn.css";
|
|
9
|
+
*/
|
|
10
|
+
export declare const shadcn: AdminTheme & FormsTheme;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PanelBreadcrumbs } from './breadcrumbs.js';
|
|
2
|
+
import { DataTable } from './data-table.js';
|
|
3
|
+
import { PanelNav } from './nav.js';
|
|
4
|
+
import { PublicForm } from './public-form.js';
|
|
5
|
+
import { Brand, Cell, Dashboard, Form, Index, Loading, Plugins, Shell } from './pages.js';
|
|
6
|
+
import { TenantSwitcher } from './tenant-switcher.js';
|
|
7
|
+
import { UserMenu } from './user-menu.js';
|
|
8
|
+
/**
|
|
9
|
+
* Panels and public forms drawn with shadcn/ui: its sidebar layout, data table, fields and
|
|
10
|
+
* cards, in the app's own theme variables, so it follows the app's colours,
|
|
11
|
+
* radius, fonts and dark mode. Its classes reach the app's stylesheet through
|
|
12
|
+
*
|
|
13
|
+
* @import "@rsc-kit/press/shadcn.css";
|
|
14
|
+
*/
|
|
15
|
+
export const shadcn = {
|
|
16
|
+
Shell,
|
|
17
|
+
Brand,
|
|
18
|
+
TenantSwitcher,
|
|
19
|
+
Nav: PanelNav,
|
|
20
|
+
Breadcrumbs: PanelBreadcrumbs,
|
|
21
|
+
UserMenu,
|
|
22
|
+
Dashboard,
|
|
23
|
+
Index,
|
|
24
|
+
Table: DataTable,
|
|
25
|
+
Form,
|
|
26
|
+
Plugins,
|
|
27
|
+
Cell,
|
|
28
|
+
Loading,
|
|
29
|
+
PublicForm,
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shadcn/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAA4B;IAC7C,KAAK;IACL,KAAK;IACL,cAAc;IACd,GAAG,EAAE,QAAQ;IACb,WAAW,EAAE,gBAAgB;IAC7B,QAAQ;IACR,SAAS;IACT,KAAK;IACL,KAAK,EAAE,SAAS;IAChB,IAAI;IACJ,OAAO;IACP,IAAI;IACJ,OAAO;IACP,UAAU;CACX,CAAA","sourcesContent":["import type { AdminTheme } from '../admin/theme.js'\nimport type { FormsTheme } from '../forms/theme.js'\nimport { PanelBreadcrumbs } from './breadcrumbs.js'\nimport { DataTable } from './data-table.js'\nimport { PanelNav } from './nav.js'\nimport { PublicForm } from './public-form.js'\nimport { Brand, Cell, Dashboard, Form, Index, Loading, Plugins, Shell } from './pages.js'\nimport { TenantSwitcher } from './tenant-switcher.js'\nimport { UserMenu } from './user-menu.js'\n\n/**\n * Panels and public forms drawn with shadcn/ui: its sidebar layout, data table, fields and\n * cards, in the app's own theme variables, so it follows the app's colours,\n * radius, fonts and dark mode. Its classes reach the app's stylesheet through\n *\n * @import \"@rsc-kit/press/shadcn.css\";\n */\nexport const shadcn: AdminTheme & FormsTheme = {\n Shell,\n Brand,\n TenantSwitcher,\n Nav: PanelNav,\n Breadcrumbs: PanelBreadcrumbs,\n UserMenu,\n Dashboard,\n Index,\n Table: DataTable,\n Form,\n Plugins,\n Cell,\n Loading,\n PublicForm,\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Light, dark or the system's, by the `dark` class on <html> that shadcn's
|
|
3
|
+
* theme keys on - shadcn's own mode toggle. System is the default and follows
|
|
4
|
+
* the OS as it changes. Remembered in this browser only. An app with its own
|
|
5
|
+
* theme switch hides this: definePanel({ modeToggle: false }).
|
|
6
|
+
*/
|
|
7
|
+
export declare function ModeToggle(): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Monitor, Moon, Sun } from 'lucide-react';
|
|
5
|
+
import { Button } from './components/ui/button.js';
|
|
6
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from './components/ui/dropdown-menu.js';
|
|
7
|
+
import { THEME_KEY as KEY } from './theme-script.js';
|
|
8
|
+
function apply(theme) {
|
|
9
|
+
const dark = theme === 'dark' || (theme === 'system' && matchMedia('(prefers-color-scheme: dark)').matches);
|
|
10
|
+
document.documentElement.classList.toggle('dark', dark);
|
|
11
|
+
document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Light, dark or the system's, by the `dark` class on <html> that shadcn's
|
|
15
|
+
* theme keys on - shadcn's own mode toggle. System is the default and follows
|
|
16
|
+
* the OS as it changes. Remembered in this browser only. An app with its own
|
|
17
|
+
* theme switch hides this: definePanel({ modeToggle: false }).
|
|
18
|
+
*/
|
|
19
|
+
export function ModeToggle() {
|
|
20
|
+
const [theme, setTheme] = useState('system');
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let stored = null;
|
|
23
|
+
try {
|
|
24
|
+
stored = localStorage.getItem(KEY);
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
if (stored === 'light' || stored === 'dark')
|
|
28
|
+
setTheme(stored);
|
|
29
|
+
}, []);
|
|
30
|
+
// Following the system: a change in the OS changes the page.
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (theme !== 'system')
|
|
33
|
+
return;
|
|
34
|
+
const media = matchMedia('(prefers-color-scheme: dark)');
|
|
35
|
+
const follow = () => apply('system');
|
|
36
|
+
media.addEventListener('change', follow);
|
|
37
|
+
return () => media.removeEventListener('change', follow);
|
|
38
|
+
}, [theme]);
|
|
39
|
+
const choose = (next) => {
|
|
40
|
+
setTheme(next);
|
|
41
|
+
apply(next);
|
|
42
|
+
try {
|
|
43
|
+
if (next === 'system')
|
|
44
|
+
localStorage.removeItem(KEY);
|
|
45
|
+
else
|
|
46
|
+
localStorage.setItem(KEY, next);
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
};
|
|
50
|
+
return (_jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { render: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Theme" }), children: [_jsx(Sun, { className: "scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }), _jsx(Moon, { className: "absolute scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" })] }), _jsx(DropdownMenuContent, { align: "end", children: _jsxs(DropdownMenuRadioGroup, { value: theme, onValueChange: (value) => choose(value), children: [_jsxs(DropdownMenuRadioItem, { value: "light", children: [_jsx(Sun, {}), " Light"] }), _jsxs(DropdownMenuRadioItem, { value: "dark", children: [_jsx(Moon, {}), " Dark"] }), _jsxs(DropdownMenuRadioItem, { value: "system", children: [_jsx(Monitor, {}), " System"] })] }) })] }));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=mode-toggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode-toggle.js","sourceRoot":"","sources":["../../src/shadcn/mode-toggle.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { Monitor, Moon, Sun } from 'lucide-react'\nimport { Button } from './components/ui/button.js'\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from './components/ui/dropdown-menu.js'\n\nimport { THEME_KEY as KEY } from './theme-script.js'\n\ntype Theme = 'light' | 'dark' | 'system'\n\nfunction apply(theme: Theme) {\n const dark = theme === 'dark' || (theme === 'system' && matchMedia('(prefers-color-scheme: dark)').matches)\n\n document.documentElement.classList.toggle('dark', dark)\n document.documentElement.style.colorScheme = dark ? 'dark' : 'light'\n}\n\n/**\n * Light, dark or the system's, by the `dark` class on <html> that shadcn's\n * theme keys on - shadcn's own mode toggle. System is the default and follows\n * the OS as it changes. Remembered in this browser only. An app with its own\n * theme switch hides this: definePanel({ modeToggle: false }).\n */\nexport function ModeToggle() {\n const [theme, setTheme] = useState<Theme>('system')\n\n useEffect(() => {\n let stored: string | null = null\n\n try {\n stored = localStorage.getItem(KEY)\n } catch {}\n\n if (stored === 'light' || stored === 'dark') setTheme(stored)\n }, [])\n\n // Following the system: a change in the OS changes the page.\n useEffect(() => {\n if (theme !== 'system') return\n\n const media = matchMedia('(prefers-color-scheme: dark)')\n const follow = () => apply('system')\n\n media.addEventListener('change', follow)\n\n return () => media.removeEventListener('change', follow)\n }, [theme])\n\n const choose = (next: Theme) => {\n setTheme(next)\n apply(next)\n\n try {\n if (next === 'system') localStorage.removeItem(KEY)\n else localStorage.setItem(KEY, next)\n } catch {}\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger render={<Button variant=\"ghost\" size=\"icon\" aria-label=\"Theme\" />}>\n <Sun className=\"scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90\" />\n <Moon className=\"absolute scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuRadioGroup value={theme} onValueChange={(value) => choose(value as Theme)}>\n <DropdownMenuRadioItem value=\"light\">\n <Sun /> Light\n </DropdownMenuRadioItem>\n <DropdownMenuRadioItem value=\"dark\">\n <Moon /> Dark\n </DropdownMenuRadioItem>\n <DropdownMenuRadioItem value=\"system\">\n <Monitor /> System\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from '@rsc-kit/core/Link';
|
|
4
|
+
import { usePathname } from '@rsc-kit/core/usePathname';
|
|
5
|
+
import { LayoutDashboard, Puzzle, Table2 } from 'lucide-react';
|
|
6
|
+
import { SidebarMenuButton, SidebarMenuItem, useSidebar } from './components/ui/sidebar.js';
|
|
7
|
+
/** The icon a link has when its resource brought none. */
|
|
8
|
+
const icons = { dashboard: LayoutDashboard, resource: Table2, installed: Puzzle, plugins: Puzzle };
|
|
9
|
+
/** The sidebar's links, lit up for the page you are on. Closes the sheet on a phone. */
|
|
10
|
+
export function PanelNav({ items }) {
|
|
11
|
+
const pathname = usePathname();
|
|
12
|
+
const { isMobile, setOpenMobile } = useSidebar();
|
|
13
|
+
return items.map((item) => {
|
|
14
|
+
const Icon = icons[item.kind];
|
|
15
|
+
const active = item.exact ? pathname === item.href : pathname === item.href || pathname.startsWith(item.href + '/');
|
|
16
|
+
return (_jsx(SidebarMenuItem, { children: _jsxs(SidebarMenuButton, { isActive: active, tooltip: item.label, render: _jsx(Link, { href: item.href, onClick: () => isMobile && setOpenMobile(false) }), children: [item.icon ?? _jsx(Icon, {}), _jsx("span", { children: item.label })] }) }, item.href));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.js","sourceRoot":"","sources":["../../src/shadcn/nav.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,oBAAoB,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE9D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAE3F,0DAA0D;AAC1D,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AAElG,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,EAAE,KAAK,EAAwB;IACtD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,UAAU,EAAE,CAAA;IAEhD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,CAAA;QAEnH,OAAO,CACL,KAAC,eAAe,cACd,MAAC,iBAAiB,IAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,IAAI,CAAC,KAAK,EACnB,MAAM,EAAE,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,CAAC,IAAa,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,aAAa,CAAC,KAAK,CAAC,GAAI,aAE1F,IAAI,CAAC,IAAI,IAAI,KAAC,IAAI,KAAG,EACtB,yBAAO,IAAI,CAAC,KAAK,GAAQ,IACP,IARA,IAAI,CAAC,IAAI,CASb,CACnB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["'use client'\n\nimport Link from '@rsc-kit/core/Link'\nimport { usePathname } from '@rsc-kit/core/usePathname'\nimport { LayoutDashboard, Puzzle, Table2 } from 'lucide-react'\nimport type { NavItem } from '../admin/theme.js'\nimport { SidebarMenuButton, SidebarMenuItem, useSidebar } from './components/ui/sidebar.js'\n\n/** The icon a link has when its resource brought none. */\nconst icons = { dashboard: LayoutDashboard, resource: Table2, installed: Puzzle, plugins: Puzzle }\n\n/** The sidebar's links, lit up for the page you are on. Closes the sheet on a phone. */\nexport function PanelNav({ items }: { items: NavItem[] }) {\n const pathname = usePathname()\n const { isMobile, setOpenMobile } = useSidebar()\n\n return items.map((item) => {\n const Icon = icons[item.kind]\n const active = item.exact ? pathname === item.href : pathname === item.href || pathname.startsWith(item.href + '/')\n\n return (\n <SidebarMenuItem key={item.href}>\n <SidebarMenuButton\n isActive={active}\n tooltip={item.label}\n render={<Link href={item.href as never} onClick={() => isMobile && setOpenMobile(false)} />}\n >\n {item.icon ?? <Icon />}\n <span>{item.label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\n })\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BrandProps, DashboardProps, FormProps, IndexProps, PluginsProps, ShellProps } from '../admin/theme.js';
|
|
2
|
+
/** shadcn's sidebar layout: the sidebar, a header with the trigger and breadcrumbs, the page. */
|
|
3
|
+
export declare function Shell({ title, brand, nav, user, crumbs, modeToggle, children }: ShellProps): import("react").JSX.Element;
|
|
4
|
+
export declare function Brand({ href, title, logo }: BrandProps): import("react").JSX.Element;
|
|
5
|
+
export declare function Dashboard({ description, counts, widgets }: DashboardProps): import("react").JSX.Element;
|
|
6
|
+
export declare function Index({ title, description, create, table }: IndexProps): import("react").JSX.Element;
|
|
7
|
+
export declare function Form({ title, description, ...form }: FormProps): import("react").JSX.Element;
|
|
8
|
+
export declare function Plugins({ description, allowed, review, reviewing, installed }: PluginsProps): import("react").JSX.Element;
|
|
9
|
+
export declare function Cell({ format, value }: {
|
|
10
|
+
format: 'money' | 'badge' | 'boolean' | 'date';
|
|
11
|
+
value: unknown;
|
|
12
|
+
}): string | import("react").JSX.Element | null;
|
|
13
|
+
export declare function Loading({ kind }: {
|
|
14
|
+
kind: 'dashboard' | 'table' | 'form' | 'menu';
|
|
15
|
+
}): import("react").JSX.Element;
|