@pilotiq/pilotiq 0.24.1 → 0.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,579 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useCallback, useEffect, useMemo, useRef, type ReactNode } from 'react'
|
|
4
|
-
import { Sparkles, Rows2, Rows3, Rows4 } from 'lucide-react'
|
|
5
|
-
import { radiusMap } from '../theme/radius.js'
|
|
6
|
-
|
|
7
|
-
import type { ThemeConfig, BaseColor } from '../theme/types.js'
|
|
8
|
-
import { useTheme } from './ThemeProvider.js'
|
|
9
|
-
import {
|
|
10
|
-
Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger,
|
|
11
|
-
} from './ui/select.js'
|
|
12
|
-
import { applyToParent, applyConfigToDoc } from './theme-preview/apply.js'
|
|
13
|
-
import { buildStaticPreviewHTML } from './theme-preview/build-html.js'
|
|
14
|
-
|
|
15
|
-
// ─── Constants ──────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
import { colors, BASE_COLOR_NAMES, HUE_NAMES } from '../theme/colors.js'
|
|
18
|
-
import { PRESET_FONTS, PRESET_RADIUS, PRESET_SPACING } from '../theme/presets.js'
|
|
19
|
-
import { spacingMap } from '../theme/spacing.js'
|
|
20
|
-
import type { StylePreset } from '../theme/types.js'
|
|
21
|
-
|
|
22
|
-
const PRESETS = ['vega', 'nova', 'maia', 'lyra', 'mira', 'luma', 'sera'] as const
|
|
23
|
-
const BASE_COLORS = BASE_COLOR_NAMES
|
|
24
|
-
const THEME_COLORS = ['base', ...HUE_NAMES] as const
|
|
25
|
-
const CHART_COLORS = ['base', ...HUE_NAMES] as const
|
|
26
|
-
// Order: 'default' first (= medium semantically) so it's the leading option.
|
|
27
|
-
const RADII = ['default', 'none', 'small', 'medium', 'large', 'xlarge'] as const
|
|
28
|
-
// Spacing density — `'default'` is a sentinel that resolves through
|
|
29
|
-
// PRESET_SPACING; the explicit values drive Tailwind's `--spacing` directly.
|
|
30
|
-
const SPACINGS = ['default', 'compact', 'comfortable'] as const
|
|
31
|
-
const ICON_LIBRARIES = ['lucide', 'tabler', 'phosphor', 'remix'] as const
|
|
32
|
-
|
|
33
|
-
// Fonts grouped by type. Renders inside the Heading/Font picker dropdown
|
|
34
|
-
// with each group's name as a non-selectable label, mirroring shadcn/ui/create.
|
|
35
|
-
const FONT_GROUPS: Record<string, string[]> = {
|
|
36
|
-
Sans: [
|
|
37
|
-
'Satoshi', 'Inter', 'Geist', 'Space Grotesk', 'Plus Jakarta Sans', 'DM Sans',
|
|
38
|
-
'Manrope', 'Outfit', 'Sora', 'Figtree', 'Poppins',
|
|
39
|
-
'Nunito', 'Raleway', 'Open Sans', 'Lato', 'Roboto', 'Noto Sans',
|
|
40
|
-
],
|
|
41
|
-
Serif: ['Playfair Display'],
|
|
42
|
-
Mono: ['JetBrains Mono', 'Geist Mono'],
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Swatch preview color for each picker option — pulls from the canonical
|
|
46
|
-
// scale at step 600 so swatches stay in sync if a hue is retuned in colors.ts.
|
|
47
|
-
const HUE_SWATCHES: Record<string, string> = Object.fromEntries(
|
|
48
|
-
HUE_NAMES.map(name => [name, colors[name][600]]),
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
// ─── Helpers ────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
function randomPick<T>(arr: readonly T[]): T {
|
|
54
|
-
return arr[Math.floor(Math.random() * arr.length)]!
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ─── Preview Iframe ─────────────────────────────────────────
|
|
58
|
-
|
|
59
|
-
function PreviewIframe({ config, mode }: { config: Partial<ThemeConfig>; mode: 'light' | 'dark' }) {
|
|
60
|
-
const [mounted, setMounted] = useState(false)
|
|
61
|
-
const [loaded, setLoaded] = useState(false)
|
|
62
|
-
const iframeRef = useRef<HTMLIFrameElement>(null)
|
|
63
|
-
// Refs so the onLoad handler always patches with the freshest values
|
|
64
|
-
// (handler is bound once, but config/mode change between mount and load).
|
|
65
|
-
const configRef = useRef(config)
|
|
66
|
-
const modeRef = useRef(mode)
|
|
67
|
-
configRef.current = config
|
|
68
|
-
modeRef.current = mode
|
|
69
|
-
|
|
70
|
-
useEffect(() => setMounted(true), [])
|
|
71
|
-
|
|
72
|
-
// Static skeleton — config-independent so srcDoc never changes.
|
|
73
|
-
// Memoized so the iframe doesn't reload (which would lose scroll position).
|
|
74
|
-
const staticHTML = useMemo(() => buildStaticPreviewHTML(), [])
|
|
75
|
-
|
|
76
|
-
// Patch the live document on every config / mode change. No reload, no
|
|
77
|
-
// flicker, no scroll loss — only CSS vars + font links + class change.
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
if (!loaded) return
|
|
80
|
-
const doc = iframeRef.current?.contentDocument
|
|
81
|
-
if (doc) applyConfigToDoc(doc, config, mode)
|
|
82
|
-
}, [config, mode, loaded])
|
|
83
|
-
|
|
84
|
-
const handleLoad = () => {
|
|
85
|
-
const doc = iframeRef.current?.contentDocument
|
|
86
|
-
if (doc) applyConfigToDoc(doc, configRef.current, modeRef.current)
|
|
87
|
-
if (!loaded) setLoaded(true)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<div className="relative w-full h-full">
|
|
92
|
-
{(!mounted || !loaded) && (
|
|
93
|
-
<div className="absolute inset-0 flex items-center justify-center z-10">
|
|
94
|
-
<div className="h-5 w-5 animate-spin rounded-full border-2 border-muted-foreground border-t-transparent" />
|
|
95
|
-
</div>
|
|
96
|
-
)}
|
|
97
|
-
{mounted && (
|
|
98
|
-
<iframe
|
|
99
|
-
ref={iframeRef}
|
|
100
|
-
srcDoc={staticHTML}
|
|
101
|
-
onLoad={handleLoad}
|
|
102
|
-
className={`w-full h-full transition-opacity duration-150 ${loaded ? 'opacity-100' : 'opacity-0'}`}
|
|
103
|
-
title="Theme Preview"
|
|
104
|
-
/>
|
|
105
|
-
)}
|
|
106
|
-
</div>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ─── Component ─────────────────────────────────��────────────
|
|
111
|
-
|
|
112
|
-
interface ThemeSettingsPageProps {
|
|
113
|
-
panelPath: string
|
|
114
|
-
initialConfig?: Partial<ThemeConfig>
|
|
115
|
-
/** Called after save/reset to force Vike to re-fetch server data. Provided by generated page. */
|
|
116
|
-
onNavigate?: (url: string) => Promise<void>
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function ThemeSettingsPage({ panelPath, initialConfig, onNavigate }: ThemeSettingsPageProps) {
|
|
120
|
-
const codeDefaults = initialConfig ?? {}
|
|
121
|
-
const [config, setConfig] = useState<Partial<ThemeConfig>>({ ...codeDefaults })
|
|
122
|
-
const [saving, setSaving] = useState(false)
|
|
123
|
-
const [saved, setSaved] = useState(false)
|
|
124
|
-
const { resolved: contextMode } = useTheme()
|
|
125
|
-
const [hydrated, setHydrated] = useState(false)
|
|
126
|
-
useEffect(() => setHydrated(true), [])
|
|
127
|
-
// Before hydration, useTheme defaults to 'light' — read DOM class instead (FOUC script sets it).
|
|
128
|
-
// After hydration, useTheme is reactive and tracks toggle changes.
|
|
129
|
-
const previewMode: 'light' | 'dark' = hydrated
|
|
130
|
-
? contextMode
|
|
131
|
-
: (typeof document !== 'undefined' && document.documentElement.classList.contains('dark') ? 'dark' : 'light')
|
|
132
|
-
|
|
133
|
-
const update = useCallback((key: string, value: unknown) => {
|
|
134
|
-
setConfig(prev => ({ ...prev, [key]: value }))
|
|
135
|
-
setSaved(false)
|
|
136
|
-
}, [])
|
|
137
|
-
|
|
138
|
-
const updateFont = useCallback((key: 'heading' | 'body', value: string) => {
|
|
139
|
-
setConfig(prev => ({
|
|
140
|
-
...prev,
|
|
141
|
-
fonts: { ...prev.fonts, [key]: value || undefined },
|
|
142
|
-
}))
|
|
143
|
-
setSaved(false)
|
|
144
|
-
}, [])
|
|
145
|
-
|
|
146
|
-
const reNavigate = async () => {
|
|
147
|
-
if (!onNavigate) return
|
|
148
|
-
const scrollY = window.scrollY
|
|
149
|
-
await onNavigate(`${panelPath}/theme`)
|
|
150
|
-
requestAnimationFrame(() => window.scrollTo(0, scrollY))
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const handleSave = async () => {
|
|
154
|
-
setSaving(true)
|
|
155
|
-
applyToParent(config)
|
|
156
|
-
try {
|
|
157
|
-
await fetch(`${panelPath}/api/_theme`, {
|
|
158
|
-
method: 'PUT',
|
|
159
|
-
headers: { 'Content-Type': 'application/json' },
|
|
160
|
-
body: JSON.stringify(config),
|
|
161
|
-
})
|
|
162
|
-
await reNavigate()
|
|
163
|
-
} catch { /* visual update already applied */ }
|
|
164
|
-
setSaved(true)
|
|
165
|
-
setSaving(false)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const handleReset = async () => {
|
|
169
|
-
// Snap state to truly empty (NOT `codeDefaults`, which is `initialConfig`
|
|
170
|
-
// = code .theme() defaults merged with whatever DB overrides existed at
|
|
171
|
-
// page-load time). With config = {}, the preview resolves the bare
|
|
172
|
-
// `vega` preset — i.e. the package's factory default.
|
|
173
|
-
setConfig({})
|
|
174
|
-
applyToParent({})
|
|
175
|
-
try {
|
|
176
|
-
await fetch(`${panelPath}/api/_theme`, { method: 'DELETE' })
|
|
177
|
-
await reNavigate()
|
|
178
|
-
} catch { /* visual update already applied */ }
|
|
179
|
-
setSaved(false)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const handleShuffle = () => {
|
|
183
|
-
const next: Partial<ThemeConfig> = {
|
|
184
|
-
preset: randomPick(PRESETS),
|
|
185
|
-
baseColor: randomPick(BASE_COLORS),
|
|
186
|
-
themeColor: randomPick(THEME_COLORS),
|
|
187
|
-
chartColor: randomPick(CHART_COLORS),
|
|
188
|
-
radius: randomPick(RADII),
|
|
189
|
-
spacing: randomPick(SPACINGS),
|
|
190
|
-
}
|
|
191
|
-
if (config.fonts) next.fonts = config.fonts
|
|
192
|
-
if (config.iconLibrary) next.iconLibrary = config.iconLibrary
|
|
193
|
-
setConfig(next)
|
|
194
|
-
setSaved(false)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// ── Indicator helpers ──────────────────────────────────
|
|
198
|
-
// Each control's trigger and items show a leading visual cue. Defined here
|
|
199
|
-
// so the picker components below can stay declarative.
|
|
200
|
-
|
|
201
|
-
// Resolved active style + its preset font pair. Pulled up here so the
|
|
202
|
-
// RadiusGlyph and font pickers below can both reference them.
|
|
203
|
-
const presetName = (config.preset ?? 'vega') as StylePreset
|
|
204
|
-
const presetFonts = PRESET_FONTS[presetName]
|
|
205
|
-
|
|
206
|
-
const baseName: BaseColor = config.baseColor ?? 'neutral'
|
|
207
|
-
const baseSwatch = colors[baseName][600]
|
|
208
|
-
const themeSwatch = config.themeColor && config.themeColor !== 'base' && config.themeColor in HUE_SWATCHES
|
|
209
|
-
? HUE_SWATCHES[config.themeColor]
|
|
210
|
-
: baseSwatch
|
|
211
|
-
const chartSwatch = config.chartColor && config.chartColor !== 'base' && config.chartColor in HUE_SWATCHES
|
|
212
|
-
? HUE_SWATCHES[config.chartColor]
|
|
213
|
-
: baseSwatch
|
|
214
|
-
|
|
215
|
-
// Dot renders inside the dark sidebar — use a translucent white border for
|
|
216
|
-
// contrast against both light dots (e.g. cream) and dark dots (e.g. neutral 600).
|
|
217
|
-
// `block` is required so `size-3` (width/height) actually applies — inline
|
|
218
|
-
// <span> ignores width/height by default.
|
|
219
|
-
const Dot = ({ color }: { color: string | undefined }) => (
|
|
220
|
-
<span className="block size-3 rounded-full border border-white/30 ring-1 ring-black/20" style={{ backgroundColor: color }} />
|
|
221
|
-
)
|
|
222
|
-
const AaGlyph = () => <span className="text-[12px] font-semibold tracking-tight">Aa</span>
|
|
223
|
-
// `block` so `size-3` actually applies — inline <span> ignores width/height.
|
|
224
|
-
// Resolve through PRESET_RADIUS so the preview corner matches what
|
|
225
|
-
// resolve.ts will actually render (e.g. Maia + Default → large).
|
|
226
|
-
// Only top + end borders are drawn so the rendered corner reads as a single
|
|
227
|
-
// rounded quadrant (matches shadcn/ui/create's radius indicator). The radius
|
|
228
|
-
// is resolved through PRESET_RADIUS so the glyph reflects what resolve.ts
|
|
229
|
-
// will actually emit (e.g. Maia + Default → large).
|
|
230
|
-
const RadiusGlyph = () => {
|
|
231
|
-
const key = config.radius && config.radius !== 'default' ? config.radius : PRESET_RADIUS[presetName]
|
|
232
|
-
return (
|
|
233
|
-
<span
|
|
234
|
-
className="block size-3 border-t border-e border-current"
|
|
235
|
-
style={{ borderTopRightRadius: radiusMap[key] }}
|
|
236
|
-
/>
|
|
237
|
-
)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Density indicator — fewer rows = roomier, more rows = tighter.
|
|
241
|
-
// Mirrors the resolved spacing value (compact / default / comfortable).
|
|
242
|
-
// `strokeWidth` is passed as a prop (not via className) because Lucide
|
|
243
|
-
// writes it as an SVG presentation attribute that wins over inherited CSS,
|
|
244
|
-
// so `stroke-[1.5]` alone would be a no-op against the default `2`.
|
|
245
|
-
const SpacingGlyph = ({ value, className = 'size-3.5 text-white' }: { value: string | undefined; className?: string }) => {
|
|
246
|
-
const key = value && value !== 'default' ? value : PRESET_SPACING[presetName]
|
|
247
|
-
const props = { className, strokeWidth: 1.5 }
|
|
248
|
-
if (key === 'compact') return <Rows4 {...props} />
|
|
249
|
-
if (key === 'comfortable') return <Rows2 {...props} />
|
|
250
|
-
return <Rows3 {...props} />
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Each Style gets its own geometric glyph so the preset has a distinct
|
|
254
|
-
// visual identity — the shape hints at the preset's personality
|
|
255
|
-
// (Maia → circle, Lyra → hexagon, Sera → sharp square, Luma → horizontal
|
|
256
|
-
// pill, Mira → rotated rounded square, etc.).
|
|
257
|
-
//
|
|
258
|
-
// Inner shapes deliberately omit a `stroke-width` attribute so they inherit
|
|
259
|
-
// the SVG's CSS `stroke-width` (set via Tailwind `stroke-[1.5]` at the call
|
|
260
|
-
// site). A presentation attribute would override the inherited value and
|
|
261
|
-
// make the className tweak a no-op.
|
|
262
|
-
const StyleGlyph = ({ preset, className = 'size-3' }: { preset: StylePreset; className?: string }) => {
|
|
263
|
-
const common = { fill: 'none', stroke: 'currentColor', strokeLinejoin: 'round' as const }
|
|
264
|
-
return (
|
|
265
|
-
<svg viewBox="0 0 16 16" className={className} aria-hidden="true">
|
|
266
|
-
{preset === 'vega' && <rect x="2.5" y="2.5" width="11" height="11" rx="3.5" {...common} />}
|
|
267
|
-
{preset === 'nova' && <rect x="2" y="3.5" width="12" height="9" rx="3" {...common} />}
|
|
268
|
-
{preset === 'maia' && <circle cx="8" cy="8" r="5.5" {...common} />}
|
|
269
|
-
{preset === 'lyra' && <polygon points="8,2 13.2,5 13.2,11 8,14 2.8,11 2.8,5" {...common} />}
|
|
270
|
-
{preset === 'mira' && <rect x="2.5" y="2.5" width="11" height="11" rx="3.5" transform="rotate(45 8 8)" {...common} />}
|
|
271
|
-
{preset === 'luma' && <rect x="1.5" y="4.5" width="13" height="7" rx="3.5" {...common} />}
|
|
272
|
-
{preset === 'sera' && <rect x="2.5" y="2.5" width="11" height="11" rx="0" {...common} />}
|
|
273
|
-
</svg>
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Build option lists. Theme + Chart pin the `'base'` sentinel at the top
|
|
278
|
-
// (separator below), labeled with the current base color name.
|
|
279
|
-
const styleOptions = PRESETS.map(p => ({ value: p, label: cap(p), indicator: <StyleGlyph preset={p} className="size-3.5" /> }))
|
|
280
|
-
const baseOptions = BASE_COLORS.map(c => ({ value: c, label: cap(c), indicator: <Dot color={colors[c][600]} /> }))
|
|
281
|
-
const themeOptions = [
|
|
282
|
-
{ value: 'base', label: cap(baseName), indicator: <Dot color={baseSwatch} /> },
|
|
283
|
-
...HUE_NAMES.map(c => ({ value: c, label: cap(c), indicator: <Dot color={HUE_SWATCHES[c]} /> })),
|
|
284
|
-
]
|
|
285
|
-
const chartOptions = [
|
|
286
|
-
{ value: 'base', label: cap(baseName), indicator: <Dot color={baseSwatch} /> },
|
|
287
|
-
...HUE_NAMES.map(c => ({ value: c, label: cap(c), indicator: <Dot color={HUE_SWATCHES[c]} /> })),
|
|
288
|
-
]
|
|
289
|
-
// Pin each picker's preset default at the top with a separator below, then
|
|
290
|
-
// list the rest of the fonts grouped by type (Sans / Serif / Mono) with
|
|
291
|
-
// a non-selectable header per group. Mirrors shadcn/ui/create's font menu.
|
|
292
|
-
// Heading and body get separate lists so each can pin its own preset font
|
|
293
|
-
// (which may differ — e.g. Sera = Playfair Display + Noto Sans).
|
|
294
|
-
const headingFontOptions = buildFontOptions(presetFonts.heading)
|
|
295
|
-
const bodyFontOptions = buildFontOptions(presetFonts.body)
|
|
296
|
-
const iconOptions = ICON_LIBRARIES.map(l => ({ value: l, label: cap(l), indicator: <Sparkles className="size-3" /> }))
|
|
297
|
-
const radiusOptions = RADII.map(r => ({
|
|
298
|
-
value: r,
|
|
299
|
-
label: cap(r),
|
|
300
|
-
indicator: (
|
|
301
|
-
<span
|
|
302
|
-
className="block size-3 border-t border-e border-current"
|
|
303
|
-
style={{ borderTopRightRadius: radiusMap[r] }}
|
|
304
|
-
/>
|
|
305
|
-
),
|
|
306
|
-
}))
|
|
307
|
-
const spacingOptions = SPACINGS.map(s => ({
|
|
308
|
-
value: s,
|
|
309
|
-
label: cap(s),
|
|
310
|
-
indicator: <SpacingGlyph value={s} />,
|
|
311
|
-
}))
|
|
312
|
-
|
|
313
|
-
return (
|
|
314
|
-
<div className="flex items-start h-full gap-6">
|
|
315
|
-
{/* Controls Sidebar — frosted-glass card on top of the page surface,
|
|
316
|
-
matching shadcn's customizer panel. `dark` scopes the inner
|
|
317
|
-
`bg-card/90`, `text-card-foreground`, etc. to the dark variants. */}
|
|
318
|
-
<div
|
|
319
|
-
className="dark isolate z-10 overflow-hidden flex flex-col gap-2 shrink-0 self-start min-h-0 rounded-lg bg-card/90 text-sm text-card-foreground ring-1 ring-foreground/10 shadow-xl backdrop-blur-xl"
|
|
320
|
-
style={{ maxHeight: 'calc(100vh - 106px)', width: '14rem' }}
|
|
321
|
-
>
|
|
322
|
-
<div className='h-full overflow-y-auto flex flex-col gap-3 p-3'>
|
|
323
|
-
<PickerCard
|
|
324
|
-
label="Style"
|
|
325
|
-
value={config.preset ?? 'vega'}
|
|
326
|
-
options={styleOptions}
|
|
327
|
-
onValueChange={v => update('preset', v)}
|
|
328
|
-
triggerIcon={<StyleGlyph preset={presetName} className="size-3.5 text-white" />}
|
|
329
|
-
keepOpenOnSelect
|
|
330
|
-
/>
|
|
331
|
-
|
|
332
|
-
<PickerCard
|
|
333
|
-
label="Base Color"
|
|
334
|
-
value={config.baseColor ?? 'neutral'}
|
|
335
|
-
options={baseOptions}
|
|
336
|
-
onValueChange={v => update('baseColor', v)}
|
|
337
|
-
triggerIcon={<Dot color={baseSwatch} />}
|
|
338
|
-
keepOpenOnSelect
|
|
339
|
-
/>
|
|
340
|
-
|
|
341
|
-
<PickerCard
|
|
342
|
-
label="Theme"
|
|
343
|
-
value={config.themeColor ?? 'base'}
|
|
344
|
-
options={themeOptions}
|
|
345
|
-
separatorAfter="base"
|
|
346
|
-
onValueChange={v => update('themeColor', v)}
|
|
347
|
-
triggerIcon={<Dot color={themeSwatch} />}
|
|
348
|
-
formatTriggerValue={v => v === 'base' ? cap(baseName) : cap(v)}
|
|
349
|
-
keepOpenOnSelect
|
|
350
|
-
/>
|
|
351
|
-
|
|
352
|
-
<PickerCard
|
|
353
|
-
label="Chart Color"
|
|
354
|
-
value={config.chartColor ?? 'base'}
|
|
355
|
-
options={chartOptions}
|
|
356
|
-
separatorAfter="base"
|
|
357
|
-
onValueChange={v => update('chartColor', v)}
|
|
358
|
-
triggerIcon={<Dot color={chartSwatch} />}
|
|
359
|
-
formatTriggerValue={v => v === 'base' ? cap(baseName) : cap(v)}
|
|
360
|
-
keepOpenOnSelect
|
|
361
|
-
/>
|
|
362
|
-
|
|
363
|
-
<PickerCard
|
|
364
|
-
label="Heading"
|
|
365
|
-
value={config.fonts?.heading ?? presetFonts.heading}
|
|
366
|
-
options={headingFontOptions}
|
|
367
|
-
separatorAfter={presetFonts.heading}
|
|
368
|
-
onValueChange={v => updateFont('heading', v)}
|
|
369
|
-
triggerIcon={<AaGlyph />}
|
|
370
|
-
keepOpenOnSelect
|
|
371
|
-
/>
|
|
372
|
-
|
|
373
|
-
<PickerCard
|
|
374
|
-
label="Font"
|
|
375
|
-
value={config.fonts?.body ?? presetFonts.body}
|
|
376
|
-
options={bodyFontOptions}
|
|
377
|
-
separatorAfter={presetFonts.body}
|
|
378
|
-
onValueChange={v => updateFont('body', v)}
|
|
379
|
-
triggerIcon={<AaGlyph />}
|
|
380
|
-
keepOpenOnSelect
|
|
381
|
-
/>
|
|
382
|
-
|
|
383
|
-
<PickerCard
|
|
384
|
-
label="Icon Library"
|
|
385
|
-
value={config.iconLibrary ?? 'lucide'}
|
|
386
|
-
options={iconOptions}
|
|
387
|
-
onValueChange={v => update('iconLibrary', v)}
|
|
388
|
-
triggerIcon={<Sparkles className="stroke-[1.5] text-white" />}
|
|
389
|
-
/>
|
|
390
|
-
|
|
391
|
-
<PickerCard
|
|
392
|
-
label="Radius"
|
|
393
|
-
value={config.radius ?? 'default'}
|
|
394
|
-
options={radiusOptions}
|
|
395
|
-
separatorAfter="default"
|
|
396
|
-
onValueChange={v => update('radius', v)}
|
|
397
|
-
triggerIcon={<RadiusGlyph />}
|
|
398
|
-
keepOpenOnSelect
|
|
399
|
-
/>
|
|
400
|
-
|
|
401
|
-
<PickerCard
|
|
402
|
-
label="Spacing"
|
|
403
|
-
value={config.spacing ?? 'default'}
|
|
404
|
-
options={spacingOptions}
|
|
405
|
-
separatorAfter="default"
|
|
406
|
-
onValueChange={v => update('spacing', v)}
|
|
407
|
-
triggerIcon={<SpacingGlyph value={config.spacing} />}
|
|
408
|
-
keepOpenOnSelect
|
|
409
|
-
/>
|
|
410
|
-
</div>
|
|
411
|
-
{/* Actions */}
|
|
412
|
-
<div className="p-3 space-y-2 bg-muted/50 border-t">
|
|
413
|
-
<button
|
|
414
|
-
onClick={handleShuffle}
|
|
415
|
-
className="w-full px-3 py-1.5 text-xs rounded-md border border-white/10 bg-white/5 hover:bg-white/10 transition-colors"
|
|
416
|
-
>
|
|
417
|
-
Shuffle
|
|
418
|
-
</button>
|
|
419
|
-
<button
|
|
420
|
-
onClick={handleReset}
|
|
421
|
-
className="w-full px-3 py-1.5 text-xs rounded-md border border-white/10 bg-white/5 hover:bg-white/10 transition-colors opacity-70"
|
|
422
|
-
>
|
|
423
|
-
Reset to Defaults
|
|
424
|
-
</button>
|
|
425
|
-
<button
|
|
426
|
-
onClick={handleSave}
|
|
427
|
-
disabled={saving}
|
|
428
|
-
className="w-full px-3 py-1.5 text-xs rounded-md bg-zinc-100 text-zinc-900 hover:bg-white transition-colors disabled:opacity-50"
|
|
429
|
-
>
|
|
430
|
-
{saving ? 'Saving...' : saved ? 'Saved!' : 'Save Theme'}
|
|
431
|
-
</button>
|
|
432
|
-
</div>
|
|
433
|
-
</div>
|
|
434
|
-
|
|
435
|
-
{/* Preview Area — isolated iframe, syncs with panel dark/light toggle */}
|
|
436
|
-
<div className="flex-1 overflow-hidden h-full ring ring-foreground/10 md:ring-muted bg-muted dark:bg-background rounded-xl">
|
|
437
|
-
<PreviewIframe config={config} mode={previewMode} />
|
|
438
|
-
</div>
|
|
439
|
-
</div>
|
|
440
|
-
)
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// ─── Sub-components ─────────────────────────────────────────
|
|
444
|
-
|
|
445
|
-
const cap = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
|
|
446
|
-
|
|
447
|
-
interface PickerOption {
|
|
448
|
-
value: string
|
|
449
|
-
label: string
|
|
450
|
-
indicator?: ReactNode
|
|
451
|
-
/** Render this row as a non-selectable group header (no value, no check). */
|
|
452
|
-
header?: boolean
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Build a flat option list from `FONT_GROUPS`, with the pinned font at top
|
|
457
|
-
* and a separator after, then each group introduced by a header row. The
|
|
458
|
-
* pinned font is filtered out of its own group so it doesn't appear twice.
|
|
459
|
-
*/
|
|
460
|
-
function buildFontOptions(pinnedFont: string): PickerOption[] {
|
|
461
|
-
const items: PickerOption[] = [
|
|
462
|
-
{ value: pinnedFont, label: pinnedFont, indicator: <AaGlyphStatic /> },
|
|
463
|
-
]
|
|
464
|
-
for (const [groupName, fonts] of Object.entries(FONT_GROUPS)) {
|
|
465
|
-
const filtered = fonts.filter(f => f !== pinnedFont)
|
|
466
|
-
if (filtered.length === 0) continue
|
|
467
|
-
items.push({ value: `__header_${groupName}`, label: groupName, header: true })
|
|
468
|
-
for (const f of filtered) {
|
|
469
|
-
items.push({ value: f, label: f, indicator: <AaGlyphStatic /> })
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return items
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Standalone glyph (no closure over component state) so `buildFontOptions`
|
|
476
|
-
// can run outside the component scope.
|
|
477
|
-
function AaGlyphStatic() {
|
|
478
|
-
return <span className="text-[11px] font-semibold tracking-tight">Aa</span>
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
interface PickerCardProps {
|
|
482
|
-
label: string
|
|
483
|
-
value: string
|
|
484
|
-
options: PickerOption[]
|
|
485
|
-
onValueChange: (value: string) => void
|
|
486
|
-
triggerIcon?: ReactNode
|
|
487
|
-
/** Insert a `<SelectSeparator />` after the option whose `value` matches this. */
|
|
488
|
-
separatorAfter?: string
|
|
489
|
-
/** Custom formatter for the value displayed in the trigger (e.g. `'base'` → current base name). */
|
|
490
|
-
formatTriggerValue?: (value: string) => string
|
|
491
|
-
/**
|
|
492
|
-
* Keep the popup open after selecting an item — lets the user click through
|
|
493
|
-
* options and watch the live preview update without re-opening each time.
|
|
494
|
-
* Outside-press, Escape, and trigger-press still close normally.
|
|
495
|
-
*/
|
|
496
|
-
keepOpenOnSelect?: boolean
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
function PickerCard({
|
|
500
|
-
label, value, options, onValueChange, triggerIcon, separatorAfter, formatTriggerValue, keepOpenOnSelect,
|
|
501
|
-
}: PickerCardProps) {
|
|
502
|
-
const current = options.find(o => o.value === value)
|
|
503
|
-
const triggerLabel = formatTriggerValue ? formatTriggerValue(value) : (current?.label ?? value)
|
|
504
|
-
const [open, setOpen] = useState(false)
|
|
505
|
-
|
|
506
|
-
return (
|
|
507
|
-
<Select
|
|
508
|
-
value={value}
|
|
509
|
-
onValueChange={(v) => onValueChange(v as string)}
|
|
510
|
-
open={open}
|
|
511
|
-
onOpenChange={(nextOpen, details) => {
|
|
512
|
-
// Suppress the auto-close that follows an item press for browseable
|
|
513
|
-
// pickers (Style / Base / Theme / Chart). The popup stays mounted;
|
|
514
|
-
// we render the checkmark ourselves below from `opt.value === value`
|
|
515
|
-
// so we don't depend on Base UI's `selectedIndex`, which only re-syncs
|
|
516
|
-
// when the popup closes.
|
|
517
|
-
if (keepOpenOnSelect && !nextOpen && details?.reason === 'item-press') return
|
|
518
|
-
setOpen(nextOpen)
|
|
519
|
-
}}
|
|
520
|
-
>
|
|
521
|
-
<SelectTrigger
|
|
522
|
-
hideIcon
|
|
523
|
-
className="w-full h-auto! items-start py-2 px-3 rounded-md border-white/10 --bg-white/5 hover:bg-white/10 text-left shadow-none transition-colors"
|
|
524
|
-
>
|
|
525
|
-
<div className="flex items-center justify-between gap-2 w-full">
|
|
526
|
-
<div className="flex flex-col min-w-0">
|
|
527
|
-
<span className="text-[11px] text-white/50">{label}</span>
|
|
528
|
-
<span className="text-sm font-medium truncate">{triggerLabel}</span>
|
|
529
|
-
</div>
|
|
530
|
-
{triggerIcon && <span className="shrink-0 mt-0.5">{triggerIcon}</span>}
|
|
531
|
-
</div>
|
|
532
|
-
</SelectTrigger>
|
|
533
|
-
{/* Open to the right of the trigger so users can click through items
|
|
534
|
-
and watch the preview update beside the dropdown — matches the
|
|
535
|
-
shadcn/ui/create flow. `align: 'none'` disables Base UI's vertical
|
|
536
|
-
shift so the popup's top edge stays anchored to the trigger's top
|
|
537
|
-
edge even when the list overflows. Max-height + overflow live on
|
|
538
|
-
the inner List (in select.tsx), not here, to avoid iOS clipping. */}
|
|
539
|
-
<SelectContent
|
|
540
|
-
side="right"
|
|
541
|
-
align="start"
|
|
542
|
-
sideOffset={24}
|
|
543
|
-
collisionAvoidance={{ side: 'flip', align: 'none' }}
|
|
544
|
-
className="dark min-w-[200px] rounded-lg border-0 bg-card/80 text-sm text-card-foreground ring-1 ring-foreground/10 backdrop-blur-xl shadow-2xl"
|
|
545
|
-
>
|
|
546
|
-
{options.map((opt, i) => (
|
|
547
|
-
<PickerOptionItem
|
|
548
|
-
key={opt.value || `__empty_${i}`}
|
|
549
|
-
opt={opt}
|
|
550
|
-
selected={opt.value === value}
|
|
551
|
-
separator={opt.value === separatorAfter}
|
|
552
|
-
/>
|
|
553
|
-
))}
|
|
554
|
-
</SelectContent>
|
|
555
|
-
</Select>
|
|
556
|
-
)
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// Item rendering: text label + a trailing check rendered manually based on
|
|
560
|
-
// the controlled `selected` flag (NOT Base UI's SelectItemIndicator). This
|
|
561
|
-
// keeps the popup state in lockstep with React state even when we suppress
|
|
562
|
-
// the auto-close on item-press.
|
|
563
|
-
function PickerOptionItem({ opt, selected, separator }: { opt: PickerOption; selected: boolean; separator?: boolean }) {
|
|
564
|
-
if (opt.header) {
|
|
565
|
-
return (
|
|
566
|
-
<div className="px-2 pt-2 pb-1 text-sm text-white/50 select-none">
|
|
567
|
-
{opt.label}
|
|
568
|
-
</div>
|
|
569
|
-
)
|
|
570
|
-
}
|
|
571
|
-
return (
|
|
572
|
-
<>
|
|
573
|
-
<SelectItem className="rounded-md" value={opt.value} hideIndicator selected={selected}>
|
|
574
|
-
<span>{opt.label}</span>
|
|
575
|
-
</SelectItem>
|
|
576
|
-
{separator && <SelectSeparator className='bg-input'/>}
|
|
577
|
-
</>
|
|
578
|
-
)
|
|
579
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useTheme } from './ThemeProvider.js'
|
|
4
|
-
|
|
5
|
-
export function ThemeToggle() {
|
|
6
|
-
const { resolved, setTheme } = useTheme()
|
|
7
|
-
|
|
8
|
-
return (
|
|
9
|
-
<button
|
|
10
|
-
type="button"
|
|
11
|
-
onClick={() => setTheme(resolved === 'dark' ? 'light' : 'dark')}
|
|
12
|
-
className="inline-flex items-center justify-center size-8 rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
13
|
-
>
|
|
14
|
-
{/* Sun — shown in dark mode (click to switch to light) */}
|
|
15
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="hidden dark:block"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
|
|
16
|
-
{/* Moon — shown in light mode (click to switch to dark) */}
|
|
17
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="block dark:hidden"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg>
|
|
18
|
-
</button>
|
|
19
|
-
)
|
|
20
|
-
}
|