@svadmin/lite 0.16.11 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -2
- package/dist/components/LiteActivityFeed.svelte +31 -9
- package/dist/components/LiteActivityFeed.svelte.d.ts +6 -0
- package/dist/components/LiteAffix.svelte +29 -0
- package/dist/components/LiteAffix.svelte.d.ts +13 -0
- package/dist/components/LiteAnchor.svelte +38 -0
- package/dist/components/LiteAnchor.svelte.d.ts +14 -0
- package/dist/components/LiteApprovalActionCard.svelte +8 -5
- package/dist/components/LiteApprovalActionCard.svelte.d.ts +2 -0
- package/dist/components/LiteAuditLog.svelte +9 -9
- package/dist/components/LiteAutoComplete.svelte +41 -0
- package/dist/components/LiteAutoComplete.svelte.d.ts +13 -0
- package/dist/components/LiteBackTop.svelte +16 -0
- package/dist/components/LiteBackTop.svelte.d.ts +8 -0
- package/dist/components/LiteBreadcrumbs.svelte +4 -1
- package/dist/components/LiteBreadcrumbs.svelte.d.ts +2 -0
- package/dist/components/LiteCalendar.svelte +124 -0
- package/dist/components/LiteCalendar.svelte.d.ts +20 -0
- package/dist/components/LiteCanvasAnnotation.svelte +13 -13
- package/dist/components/LiteCarousel.svelte +72 -0
- package/dist/components/LiteCarousel.svelte.d.ts +14 -0
- package/dist/components/LiteChatDialog.svelte +8 -8
- package/dist/components/LiteCollapse.svelte +49 -0
- package/dist/components/LiteCollapse.svelte.d.ts +15 -0
- package/dist/components/LiteColumnHeaderFilter.svelte +4 -1
- package/dist/components/LiteColumnHeaderFilter.svelte.d.ts +2 -0
- package/dist/components/LiteColumnSettings.svelte +7 -4
- package/dist/components/LiteColumnSettings.svelte.d.ts +2 -0
- package/dist/components/LiteCommentThread.svelte +113 -0
- package/dist/components/LiteCommentThread.svelte.d.ts +26 -0
- package/dist/components/LiteConfirmDialog.svelte +2 -2
- package/dist/components/LiteCountdown.svelte +49 -0
- package/dist/components/LiteCountdown.svelte.d.ts +10 -0
- package/dist/components/LiteDecisionTable.svelte +14 -14
- package/dist/components/LiteDetailDrawer.svelte +45 -0
- package/dist/components/LiteDetailDrawer.svelte.d.ts +14 -0
- package/dist/components/LiteDraggableRowTable.svelte +5 -2
- package/dist/components/LiteDraggableRowTable.svelte.d.ts +2 -0
- package/dist/components/LiteDrawerForm.svelte +11 -8
- package/dist/components/LiteDrawerForm.svelte.d.ts +2 -0
- package/dist/components/LiteDynamicFormList.svelte +5 -5
- package/dist/components/LiteEditableTable.svelte +5 -2
- package/dist/components/LiteEditableTable.svelte.d.ts +2 -0
- package/dist/components/LiteEmptyState.svelte +11 -4
- package/dist/components/LiteEmptyState.svelte.d.ts +3 -0
- package/dist/components/LiteFilterBuilder.svelte +8 -5
- package/dist/components/LiteFilterBuilder.svelte.d.ts +2 -0
- package/dist/components/LiteFloatButton.svelte +54 -0
- package/dist/components/LiteFloatButton.svelte.d.ts +15 -0
- package/dist/components/LiteGanttChart.svelte +20 -20
- package/dist/components/LiteGrid.svelte +34 -0
- package/dist/components/LiteGrid.svelte.d.ts +11 -0
- package/dist/components/LiteImage.svelte +54 -0
- package/dist/components/LiteImage.svelte.d.ts +14 -0
- package/dist/components/LiteImageCropper.svelte +7 -4
- package/dist/components/LiteImageCropper.svelte.d.ts +2 -0
- package/dist/components/LiteImagePreview.svelte +36 -0
- package/dist/components/LiteImagePreview.svelte.d.ts +13 -0
- package/dist/components/LiteImportWizard.svelte +7 -7
- package/dist/components/LiteItemList.svelte +50 -0
- package/dist/components/LiteItemList.svelte.d.ts +15 -0
- package/dist/components/LiteJsonSchemaForm.svelte +10 -7
- package/dist/components/LiteJsonSchemaForm.svelte.d.ts +2 -0
- package/dist/components/LiteKanbanBoard.svelte +19 -19
- package/dist/components/LiteLayout.svelte +18 -6
- package/dist/components/LiteLayout.svelte.d.ts +8 -0
- package/dist/components/LiteLink.svelte +32 -0
- package/dist/components/LiteLink.svelte.d.ts +11 -0
- package/dist/components/LiteLogin.svelte +9 -2
- package/dist/components/LiteLogin.svelte.d.ts +2 -0
- package/dist/components/LiteMasterDetailView.svelte +13 -10
- package/dist/components/LiteMasterDetailView.svelte.d.ts +2 -0
- package/dist/components/LiteMediaLibraryModal.svelte +8 -5
- package/dist/components/LiteMediaLibraryModal.svelte.d.ts +2 -0
- package/dist/components/LiteMediaThumbnail.svelte +3 -3
- package/dist/components/LiteMentionsInput.svelte +9 -9
- package/dist/components/LiteMenu.svelte +22 -0
- package/dist/components/LiteMenu.svelte.d.ts +12 -0
- package/dist/components/LiteMenuList.svelte +55 -0
- package/dist/components/LiteMenuList.svelte.d.ts +17 -0
- package/dist/components/LiteModalForm.svelte +9 -6
- package/dist/components/LiteModalForm.svelte.d.ts +2 -0
- package/dist/components/LiteMultiTabKeepAlive.svelte +6 -6
- package/dist/components/LiteNotificationCenter.svelte +85 -0
- package/dist/components/LiteNotificationCenter.svelte.d.ts +22 -0
- package/dist/components/LiteOfflineSyncBanner.svelte +6 -6
- package/dist/components/LiteOtpInput.svelte +50 -0
- package/dist/components/LiteOtpInput.svelte.d.ts +15 -0
- package/dist/components/LitePageHeader.svelte +34 -0
- package/dist/components/LitePageHeader.svelte.d.ts +13 -0
- package/dist/components/LitePagination.svelte +10 -2
- package/dist/components/LitePagination.svelte.d.ts +2 -0
- package/dist/components/LitePdfDocumentViewer.svelte +14 -14
- package/dist/components/LitePermissionMatrix.svelte +8 -8
- package/dist/components/LitePivotTable.svelte +11 -11
- package/dist/components/LitePopconfirm.svelte +49 -0
- package/dist/components/LitePopconfirm.svelte.d.ts +14 -0
- package/dist/components/LitePresenceAvatarGroup.svelte +8 -5
- package/dist/components/LitePresenceAvatarGroup.svelte.d.ts +2 -0
- package/dist/components/LitePrintableBill.svelte +12 -9
- package/dist/components/LitePrintableBill.svelte.d.ts +2 -0
- package/dist/components/LiteProgress.svelte +46 -0
- package/dist/components/LiteProgress.svelte.d.ts +12 -0
- package/dist/components/LiteQRCode.svelte +62 -0
- package/dist/components/LiteQRCode.svelte.d.ts +14 -0
- package/dist/components/LiteResizeBox.svelte +34 -0
- package/dist/components/LiteResizeBox.svelte.d.ts +12 -0
- package/dist/components/LiteResult.svelte +52 -0
- package/dist/components/LiteResult.svelte.d.ts +14 -0
- package/dist/components/LiteRowActions.svelte +36 -0
- package/dist/components/LiteRowActions.svelte.d.ts +17 -0
- package/dist/components/LiteSensitiveDataMask.svelte +4 -1
- package/dist/components/LiteSensitiveDataMask.svelte.d.ts +2 -0
- package/dist/components/LiteShow.svelte +1 -1
- package/dist/components/LiteShowField.svelte +2 -2
- package/dist/components/LiteSignaturePad.svelte +9 -9
- package/dist/components/LiteSkeleton.svelte +100 -0
- package/dist/components/LiteSkeleton.svelte.d.ts +19 -0
- package/dist/components/LiteSpace.svelte +31 -0
- package/dist/components/LiteSpace.svelte.d.ts +12 -0
- package/dist/components/LiteSpin.svelte +27 -0
- package/dist/components/LiteSpin.svelte.d.ts +10 -0
- package/dist/components/LiteSplitPaneLayout.svelte +18 -6
- package/dist/components/LiteSplitPaneLayout.svelte.d.ts +8 -0
- package/dist/components/LiteSpreadsheetView.svelte +8 -8
- package/dist/components/LiteStatistic.svelte +63 -0
- package/dist/components/LiteStatistic.svelte.d.ts +15 -0
- package/dist/components/LiteStatsCard.svelte +5 -2
- package/dist/components/LiteStatsCard.svelte.d.ts +2 -0
- package/dist/components/LiteStatusBadge.svelte +33 -0
- package/dist/components/LiteStatusBadge.svelte.d.ts +12 -0
- package/dist/components/LiteStatusTabs.svelte +35 -0
- package/dist/components/LiteStatusTabs.svelte.d.ts +14 -0
- package/dist/components/LiteStepForm.svelte +14 -11
- package/dist/components/LiteStepForm.svelte.d.ts +2 -0
- package/dist/components/LiteSteps.svelte +64 -0
- package/dist/components/LiteSteps.svelte.d.ts +18 -0
- package/dist/components/LiteTable.svelte +5 -2
- package/dist/components/LiteTable.svelte.d.ts +2 -0
- package/dist/components/LiteTableSummary.svelte +8 -5
- package/dist/components/LiteTableSummary.svelte.d.ts +2 -0
- package/dist/components/LiteTabs.svelte +30 -20
- package/dist/components/LiteTabs.svelte.d.ts +11 -2
- package/dist/components/LiteTag.svelte +31 -0
- package/dist/components/LiteTag.svelte.d.ts +13 -0
- package/dist/components/LiteTimeline.svelte +48 -0
- package/dist/components/LiteTimeline.svelte.d.ts +17 -0
- package/dist/components/LiteTour.svelte +54 -0
- package/dist/components/LiteTour.svelte.d.ts +15 -0
- package/dist/components/LiteTransfer.svelte +9 -6
- package/dist/components/LiteTransfer.svelte.d.ts +2 -0
- package/dist/components/LiteTree.svelte +48 -0
- package/dist/components/LiteTree.svelte.d.ts +17 -0
- package/dist/components/LiteTreeTable.svelte +1 -1
- package/dist/components/LiteTwoFactorStepper.svelte +53 -0
- package/dist/components/LiteTwoFactorStepper.svelte.d.ts +16 -0
- package/dist/components/LiteVersionDiffViewer.svelte +16 -13
- package/dist/components/LiteVersionDiffViewer.svelte.d.ts +2 -0
- package/dist/components/LiteVideoPlayer.svelte +67 -0
- package/dist/components/LiteVideoPlayer.svelte.d.ts +22 -0
- package/dist/components/LiteVirtualTable.svelte +1 -1
- package/dist/components/advanced/LiteAutoSaveIndicator.svelte +42 -13
- package/dist/components/advanced/LiteAutoSaveIndicator.svelte.d.ts +10 -4
- package/dist/components/advanced/LiteDraggableHeader.svelte +2 -2
- package/dist/components/advanced/LiteDrawerForm.svelte +4 -1
- package/dist/components/advanced/LiteDrawerForm.svelte.d.ts +2 -0
- package/dist/components/advanced/LiteInlineEdit.svelte +1 -1
- package/dist/components/advanced/LiteModalForm.svelte +4 -1
- package/dist/components/advanced/LiteModalForm.svelte.d.ts +2 -0
- package/dist/components/advanced/LiteToast.svelte +3 -3
- package/dist/components/advanced/LiteUndoableNotification.svelte +1 -1
- package/dist/components/compatibility/LiteRealtimeStatus.svelte +41 -2
- package/dist/components/compatibility/LiteRealtimeStatus.svelte.d.ts +15 -0
- package/dist/components/fields/LiteBooleanField.svelte +4 -2
- package/dist/components/fields/LiteBooleanField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteCascader.svelte +5 -2
- package/dist/components/fields/LiteCascader.svelte.d.ts +2 -0
- package/dist/components/fields/LiteDateField.svelte +39 -9
- package/dist/components/fields/LiteDateField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteDateRangeField.svelte +1 -1
- package/dist/components/fields/LiteImageField.svelte +6 -2
- package/dist/components/fields/LiteImageField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteJsonField.svelte +1 -1
- package/dist/components/fields/LiteMarkdownField.svelte +49 -3
- package/dist/components/fields/LiteMarkdownField.svelte.d.ts +5 -0
- package/dist/components/fields/LiteNumberField.svelte +5 -3
- package/dist/components/fields/LiteNumberField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteRichTextField.svelte +49 -12
- package/dist/components/fields/LiteRichTextField.svelte.d.ts +3 -0
- package/dist/components/fields/LiteSelectField.svelte +5 -3
- package/dist/components/fields/LiteSelectField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteTagField.svelte +38 -15
- package/dist/components/fields/LiteTagField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteTextField.svelte +26 -5
- package/dist/components/fields/LiteTextField.svelte.d.ts +2 -0
- package/dist/components/fields/LiteTreeSelect.svelte +5 -2
- package/dist/components/fields/LiteTreeSelect.svelte.d.ts +2 -0
- package/dist/components/fields/LiteUrlField.svelte +5 -3
- package/dist/components/fields/LiteUrlField.svelte.d.ts +2 -0
- package/dist/components/layout/LiteAuthenticated.svelte +2 -2
- package/dist/components/layout/LiteCanAccess.svelte +1 -1
- package/dist/components/layout/LiteErrorComponent.svelte +4 -4
- package/dist/components/layout/LiteHeader.svelte +2 -2
- package/dist/components/layout/LiteSidebar.svelte +6 -3
- package/dist/components/layout/LiteSidebar.svelte.d.ts +2 -0
- package/dist/components/pages/LiteCreatePage.svelte +4 -1
- package/dist/components/pages/LiteCreatePage.svelte.d.ts +2 -0
- package/dist/components/pages/LiteEditPage.svelte +4 -1
- package/dist/components/pages/LiteEditPage.svelte.d.ts +2 -0
- package/dist/components/pages/LiteForgotPasswordPage.svelte +7 -7
- package/dist/components/pages/LiteListPage.svelte +6 -3
- package/dist/components/pages/LiteListPage.svelte.d.ts +2 -0
- package/dist/components/pages/LiteProfilePage.svelte +2 -2
- package/dist/components/pages/LiteRegisterPage.svelte +6 -6
- package/dist/components/pages/LiteShowPage.svelte +6 -3
- package/dist/components/pages/LiteShowPage.svelte.d.ts +2 -0
- package/dist/components/pages/LiteUpdatePasswordPage.svelte +4 -4
- package/dist/components/widgets/LiteAnomalyBadge.svelte +6 -3
- package/dist/components/widgets/LiteAnomalyBadge.svelte.d.ts +2 -0
- package/dist/components/widgets/LiteAreaChart.svelte +20 -0
- package/dist/components/widgets/LiteAreaChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteBarChart.svelte +6 -6
- package/dist/components/widgets/LiteChartSvg.svelte +102 -0
- package/dist/components/widgets/LiteChartSvg.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteChartTable.svelte +44 -0
- package/dist/components/widgets/LiteChartTable.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteDonutChart.svelte +20 -0
- package/dist/components/widgets/LiteDonutChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteFunnelChart.svelte +20 -0
- package/dist/components/widgets/LiteFunnelChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteGaugeChart.svelte +20 -0
- package/dist/components/widgets/LiteGaugeChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteHeatmapChart.svelte +20 -0
- package/dist/components/widgets/LiteHeatmapChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteInsightCard.svelte +35 -13
- package/dist/components/widgets/LiteInsightCard.svelte.d.ts +7 -4
- package/dist/components/widgets/LiteLineChart.svelte +13 -10
- package/dist/components/widgets/LiteLineChart.svelte.d.ts +0 -5
- package/dist/components/widgets/LitePieChart.svelte +11 -9
- package/dist/components/widgets/LitePieChart.svelte.d.ts +0 -5
- package/dist/components/widgets/LiteRadarChart.svelte +20 -0
- package/dist/components/widgets/LiteRadarChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteRoseChart.svelte +20 -0
- package/dist/components/widgets/LiteRoseChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteScatterChart.svelte +20 -0
- package/dist/components/widgets/LiteScatterChart.svelte.d.ts +10 -0
- package/dist/components/widgets/LiteWaterfallChart.svelte +20 -0
- package/dist/components/widgets/LiteWaterfallChart.svelte.d.ts +10 -0
- package/dist/components/widgets/chart-geometry.d.ts +65 -0
- package/dist/components/widgets/chart-geometry.js +229 -0
- package/dist/components/widgets/index.d.ts +10 -0
- package/dist/components/widgets/index.js +10 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +47 -0
- package/dist/lite-code-theme.css +139 -0
- package/dist/lite.css +234 -127
- package/dist/rich-content.d.ts +47 -0
- package/dist/rich-content.js +498 -0
- package/dist/schema-generator.js +3 -1
- package/dist/server-adapter.js +6 -11
- package/dist/value-normalization.d.ts +4 -0
- package/dist/value-normalization.js +13 -0
- package/package.json +18 -4
package/README.md
CHANGED
|
@@ -253,13 +253,31 @@ IE11 before the decision is made.
|
|
|
253
253
|
|
|
254
254
|
## Components & Parity (100% Coverage)
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
`LiteQRCode` is an opt-in subpath export because it statically imports the
|
|
257
|
+
optional `qrcode` peer. The root entry `@svadmin/lite` stays importable without
|
|
258
|
+
it, so the rest of Lite has no extra runtime dependency. Install the peer with
|
|
259
|
+
`bun add qrcode` and import the component directly only when you render QR codes:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import LiteQRCode from '@svadmin/lite/components/LiteQRCode.svelte';
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`@svadmin/lite` provides **100% component parity** (179/179 components) corresponding to `@svadmin/ui`. See [PARITY.md](./PARITY.md) for the generated complete matrix and status details.
|
|
257
266
|
|
|
258
267
|
### Core Pages & Layout
|
|
259
268
|
|
|
260
269
|
| Component | Description |
|
|
261
270
|
|-----------|-------------|
|
|
262
271
|
| `LiteLayout` | Responsive sidebar + header + main shell (supports nested `menu` links) |
|
|
272
|
+
| `LitePageHeader` / `LiteStatusTabs` / `LiteStatusBadge` | Page heading, status filters and semantic status pills |
|
|
273
|
+
| `LiteMenu` / `LiteAnchor` / `LiteAffix` / `LiteCollapse` / `LiteLink` | Static navigation, in-page anchors and native disclosure |
|
|
274
|
+
| `LiteSpace` / `LiteGrid` / `LiteResizeBox` / `LiteFloatButton` / `LiteBackTop` | Layout and fixed-action primitives |
|
|
275
|
+
| `LiteImage` / `LiteImagePreview` / `LiteVideoPlayer` / `LiteQRCode` | Media rendering with native controls, links and server-rendered QR |
|
|
276
|
+
| `LiteCalendar` / `LiteCarousel` / `LiteTimeline` / `LiteStatistic` / `LiteCountdown` | Read-only dashboards and chronological displays |
|
|
277
|
+
| `LiteCommentThread` / `LiteTour` / `LiteNotificationCenter` / `LiteDetailDrawer` / `LitePopconfirm` | Server-rendered collaboration and disclosure surfaces |
|
|
278
|
+
| `LiteSteps` / `LiteProgress` / `LiteSpin` / `LiteSkeleton` / `LiteResult` | Progress, loading and outcome surfaces |
|
|
279
|
+
| `LiteTree` / `LiteItemList` / `LiteRowActions` / `LiteOtpInput` / `LiteTwoFactorStepper` | Hierarchical data, row actions and verification flows |
|
|
280
|
+
| `LiteAutoComplete` | Native `datalist` suggestions without async client popovers |
|
|
263
281
|
| `LiteSidebar` / `LiteHeader` | Discrete layout primitives |
|
|
264
282
|
| `LiteListPage` | Full-featured list view with search, table, bulk actions, and pagination |
|
|
265
283
|
| `LiteCreatePage` / `LiteEditPage` | Auto-generated CRUD form pages |
|
|
@@ -301,6 +319,8 @@ IE11 before the decision is made.
|
|
|
301
319
|
|-----------|-------------|
|
|
302
320
|
| `LiteStatsCard`, `LiteMetricStrip`, `LiteInsightCard`, `LiteAnomalyBadge`, `LiteBadge` | Metric KPI cards/strips and semantic status badges |
|
|
303
321
|
| `LiteBarChart`, `LiteLineChart`, `LitePieChart` | Server-rendered SVG/HTML charts with fallback data tables |
|
|
322
|
+
| `LiteAreaChart`, `LiteScatterChart`, `LiteRadarChart`, `LiteGaugeChart` | Bounded chart data tables where a client chart engine is unavailable |
|
|
323
|
+
| `LiteFunnelChart`, `LiteHeatmapChart`, `LiteWaterfallChart`, `LiteRoseChart`, `LiteDonutChart` | Bounded chart data tables with the same fallback contract |
|
|
304
324
|
| `LitePresenceAvatarGroup`, `LiteGanttChart`, `LiteOfflineSyncBanner` | Presence, schedule, and offline mutation status rendered without client hydration |
|
|
305
325
|
|
|
306
326
|
### Compatibility & Degradation Primitives
|
|
@@ -335,7 +355,7 @@ To monitor and maintain 100% component parity between `@svadmin/ui` and `@svadmi
|
|
|
335
355
|
- **CLI Dashboard**: Run `bun run check:parity` to inspect the live coverage matrix in terminal.
|
|
336
356
|
- **Parity Matrix Document**: [PARITY.md](./PARITY.md) is auto-generated with exhaustive module-by-module tables.
|
|
337
357
|
- **Machine-Readable JSON**: `packages/lite/parity.json` provides structured data for automation.
|
|
338
|
-
- **Interactive Showroom**: Visit `/lite/parity` in the example app to interactively preview all
|
|
358
|
+
- **Interactive Showroom**: Visit `/lite/parity` in the example app to interactively preview all 179 components and live metrics.
|
|
339
359
|
- **CI Contract Test**: `scripts/parity-contract.test.ts` runs in CI to prevent regression and ensure every new UI component has a documented Lite counterpart.
|
|
340
360
|
|
|
341
361
|
## Server Utilities
|
|
@@ -352,6 +372,43 @@ To monitor and maintain 100% component parity between `@svadmin/ui` and `@svadmi
|
|
|
352
372
|
|
|
353
373
|
Schema generation is TypeBox-only. The former Zod-named exports and parser-compatible methods were removed; use `Check`, `Errors`, and `Decode` on the returned schema.
|
|
354
374
|
|
|
375
|
+
## Styling Hooks
|
|
376
|
+
|
|
377
|
+
Most components accept a single `class` that is **merged** with the built-in class
|
|
378
|
+
list, never replacing it:
|
|
379
|
+
|
|
380
|
+
```svelte
|
|
381
|
+
<LiteStatsCard class="dense" label="Orders" value={42} />
|
|
382
|
+
<!-- renders class="lite-stats-card lite-card dense" -->
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Fields take the hook on both of their render roots, so one prop covers show and
|
|
386
|
+
edit mode (`LiteTextField` → `.lite-field-value` / `.lite-field-edit`,
|
|
387
|
+
`LiteTagField` → tag container / `.lite-tags-input`, …).
|
|
388
|
+
|
|
389
|
+
Structural components take **named** hooks, because the part you usually restyle is
|
|
390
|
+
inside the wrapper:
|
|
391
|
+
|
|
392
|
+
| Component | Hooks | Lands on |
|
|
393
|
+
| --- | --- | --- |
|
|
394
|
+
| `LiteLayout` | `class`, `classSidebar`, `classMobileNav`, `classMain` | wrapper, desktop sidebar, mobile nav, main region |
|
|
395
|
+
| `LiteSidebar` | `class` | the sidebar `nav` |
|
|
396
|
+
| `LiteSplitPaneLayout` | `class`, `classPane1`, `classDivider`, `classPane2` | container, first pane, divider, second pane |
|
|
397
|
+
|
|
398
|
+
Omitting every hook leaves the rendered HTML byte-identical (the class attribute is
|
|
399
|
+
built with a trimmed template, not an empty interpolation). This is covered by
|
|
400
|
+
`packages/lite/src/components/LiteClassHooks.test.svelte.ts`.
|
|
401
|
+
|
|
402
|
+
Styling hook coverage — how many `exact` mappings expose the same `class` entry the
|
|
403
|
+
reference component does — is tracked separately in `CLASS-HOOKS.md` and never
|
|
404
|
+
changes a parity status. `Lite` ships `lite.css`, so a missing hook is styling debt,
|
|
405
|
+
not a capability gap. Regenerate both artifacts with:
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
bun run check:parity # writes PARITY.md, parity.json, CLASS-HOOKS.md, class-hooks.json
|
|
409
|
+
bun run check:parity:verify
|
|
410
|
+
```
|
|
411
|
+
|
|
355
412
|
## CSS
|
|
356
413
|
|
|
357
414
|
Import `@svadmin/lite/lite.css` in your layout. It's fully self-contained:
|
|
@@ -364,6 +421,18 @@ Import `@svadmin/lite/lite.css` in your layout. It's fully self-contained:
|
|
|
364
421
|
- Print-optimized styles
|
|
365
422
|
- ~800 lines, ~19KB unminified
|
|
366
423
|
|
|
424
|
+
Rich content previews (Markdown, insight, comments, notifications, activity) ship
|
|
425
|
+
literal `tok-*` token colours here. Hosts that can rely on CSS custom properties
|
|
426
|
+
may also import the opt-in theme:
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
import '@svadmin/lite/lite-code-theme.css';
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
It exposes `--lite-token-{comment,keyword,string,number,function,type}` with the
|
|
433
|
+
literal palette as fallbacks and a `lite-dark` preset class, so one override
|
|
434
|
+
re-themes every preview surface.
|
|
435
|
+
|
|
367
436
|
This CSS baseline helps older browsers, but the generated Svelte/SvelteKit application and any Tailwind v4 UI used alongside Lite still require the browser targets configured by those tools (Tailwind v4 itself targets modern browsers).
|
|
368
437
|
|
|
369
438
|
## Optional: Progressive Enhancement
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { renderRichContent, type MarkdownRenderOptions } from '../rich-content.js';
|
|
3
|
+
|
|
2
4
|
interface LiteActivityItem {
|
|
3
5
|
id: string;
|
|
4
6
|
user?: { name: string };
|
|
@@ -13,16 +15,28 @@
|
|
|
13
15
|
activities?: LiteActivityItem[];
|
|
14
16
|
action?: string;
|
|
15
17
|
method?: 'get' | 'post' | 'dialog' | 'GET' | 'POST' | 'DIALOG' | null;
|
|
18
|
+
/** Render note bodies as Markdown/allowlisted HTML. Defaults to plain text. */
|
|
19
|
+
richContent?: boolean;
|
|
20
|
+
richContentOptions?: MarkdownRenderOptions;
|
|
21
|
+
/** Caller class merged with the built-in class list. */
|
|
22
|
+
class?: string;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
let {
|
|
19
26
|
activities = [],
|
|
20
27
|
action = '',
|
|
21
28
|
method = 'POST',
|
|
29
|
+
richContent = false,
|
|
30
|
+
richContentOptions,
|
|
31
|
+
class: className = '',
|
|
22
32
|
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
function body(value: string): string {
|
|
35
|
+
return renderRichContent(value, richContentOptions);
|
|
36
|
+
}
|
|
23
37
|
</script>
|
|
24
38
|
|
|
25
|
-
<div class="lite-activity-card">
|
|
39
|
+
<div class="lite-activity-card {className}">
|
|
26
40
|
<div class="lite-activity-header">
|
|
27
41
|
<strong>Activity & Timeline Stream</strong>
|
|
28
42
|
</div>
|
|
@@ -37,7 +51,12 @@
|
|
|
37
51
|
</div>
|
|
38
52
|
{#if act.comment}
|
|
39
53
|
<div class="lite-activity-comment">
|
|
40
|
-
{
|
|
54
|
+
{#if richContent}
|
|
55
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -- 内容由 renderRichContent 转义或白名单过滤,高亮回调仅允许可信服务端实现。 -->
|
|
56
|
+
<div class="lite-activity-rich">{@html body(act.comment)}</div>
|
|
57
|
+
{:else}
|
|
58
|
+
{act.comment}
|
|
59
|
+
{/if}
|
|
41
60
|
</div>
|
|
42
61
|
{/if}
|
|
43
62
|
</li>
|
|
@@ -61,14 +80,14 @@
|
|
|
61
80
|
<style>
|
|
62
81
|
.lite-activity-card {
|
|
63
82
|
background: #ffffff;
|
|
64
|
-
border: 1px solid #
|
|
83
|
+
border: 1px solid #E5E6EB;
|
|
65
84
|
border-radius: 6px;
|
|
66
85
|
padding: 16px;
|
|
67
86
|
margin-bottom: 16px;
|
|
68
87
|
}
|
|
69
88
|
.lite-activity-header {
|
|
70
89
|
padding-bottom: 8px;
|
|
71
|
-
border-bottom: 1px solid #
|
|
90
|
+
border-bottom: 1px solid #E5E6EB;
|
|
72
91
|
margin-bottom: 12px;
|
|
73
92
|
font-size: 13px;
|
|
74
93
|
}
|
|
@@ -79,20 +98,23 @@
|
|
|
79
98
|
}
|
|
80
99
|
.lite-activity-item {
|
|
81
100
|
padding: 8px 0;
|
|
82
|
-
border-bottom: 1px solid #
|
|
101
|
+
border-bottom: 1px solid #F2F3F5;
|
|
83
102
|
font-size: 12px;
|
|
84
103
|
}
|
|
85
104
|
.lite-activity-time {
|
|
86
|
-
color: #
|
|
105
|
+
color: #86909C;
|
|
87
106
|
margin-left: 8px;
|
|
88
107
|
font-size: 11px;
|
|
89
108
|
}
|
|
90
109
|
.lite-activity-comment {
|
|
91
|
-
background: #
|
|
92
|
-
border: 1px solid #
|
|
110
|
+
background: #F7F8FA;
|
|
111
|
+
border: 1px solid #E5E6EB;
|
|
93
112
|
padding: 6px 10px;
|
|
94
113
|
border-radius: 4px;
|
|
95
114
|
margin-top: 4px;
|
|
96
|
-
color: #
|
|
115
|
+
color: #4E5969;
|
|
97
116
|
}
|
|
117
|
+
.lite-activity-rich :global(p) { margin: 0; }
|
|
118
|
+
.lite-activity-rich :global(a) { color: #165DFF; }
|
|
119
|
+
.lite-activity-rich :global(code) { padding: 1px 4px; border-radius: 3px; background: #F2F3F5; font-family: monospace; font-size: 12px; }
|
|
98
120
|
</style>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type MarkdownRenderOptions } from '../rich-content.js';
|
|
1
2
|
interface LiteActivityItem {
|
|
2
3
|
id: string;
|
|
3
4
|
user?: {
|
|
@@ -13,6 +14,11 @@ interface Props {
|
|
|
13
14
|
activities?: LiteActivityItem[];
|
|
14
15
|
action?: string;
|
|
15
16
|
method?: 'get' | 'post' | 'dialog' | 'GET' | 'POST' | 'DIALOG' | null;
|
|
17
|
+
/** Render note bodies as Markdown/allowlisted HTML. Defaults to plain text. */
|
|
18
|
+
richContent?: boolean;
|
|
19
|
+
richContentOptions?: MarkdownRenderOptions;
|
|
20
|
+
/** Caller class merged with the built-in class list. */
|
|
21
|
+
class?: string;
|
|
16
22
|
}
|
|
17
23
|
declare const LiteActivityFeed: import("svelte").Component<Props, {}, "">;
|
|
18
24
|
type LiteActivityFeed = ReturnType<typeof LiteActivityFeed>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
top?: number;
|
|
6
|
+
bottom?: number;
|
|
7
|
+
zIndex?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Caller class merged with the built-in class list. */
|
|
10
|
+
class?: string;
|
|
11
|
+
children: Snippet;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { top = 16, bottom, zIndex = 10, label = 'Affixed content', class: className = '', children }: Props = $props();
|
|
15
|
+
|
|
16
|
+
// The reference applies `top` always and `bottom` when provided; dropping `top`
|
|
17
|
+
// whenever `bottom` was set made the offset silently wrong.
|
|
18
|
+
const style = $derived(
|
|
19
|
+
`top:${top}px;${bottom === undefined ? '' : `bottom:${bottom}px;`}z-index:${zIndex}`,
|
|
20
|
+
);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<div class={`lite-affix ${className}`.trim()} style={style} aria-label={label}>
|
|
24
|
+
{@render children()}
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<style>
|
|
28
|
+
.lite-affix { position: sticky; }
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
top?: number;
|
|
4
|
+
bottom?: number;
|
|
5
|
+
zIndex?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
/** Caller class merged with the built-in class list. */
|
|
8
|
+
class?: string;
|
|
9
|
+
children: Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const LiteAffix: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type LiteAffix = ReturnType<typeof LiteAffix>;
|
|
13
|
+
export default LiteAffix;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface AnchorItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
level?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
items: AnchorItem[];
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Caller class merged with the built-in class list. */
|
|
12
|
+
class?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { items, label = 'On this page', class: className = '' }: Props = $props();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<nav class="lite-anchor {className}" aria-label={label}>
|
|
19
|
+
<p class="lite-anchor__title">{label}</p>
|
|
20
|
+
<ul>
|
|
21
|
+
{#each items as item (item.id)}
|
|
22
|
+
<li style={`padding-left:${Math.max(0, (item.level ?? 1) - 1) * 12}px`}>
|
|
23
|
+
<a href={`#${item.id}`}>{item.label}</a>
|
|
24
|
+
</li>
|
|
25
|
+
{/each}
|
|
26
|
+
</ul>
|
|
27
|
+
</nav>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.lite-anchor { display: block; min-width: 0; }
|
|
31
|
+
.lite-anchor__title { margin: 0; color: #86909C; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
32
|
+
.lite-anchor ul { display: block; margin: 0; padding: 0; list-style: none; }
|
|
33
|
+
.lite-anchor a { display: block; padding: 4px 8px; border-left: 2px solid transparent; color: #4E5969; font-size: 13px; text-decoration: none; }
|
|
34
|
+
.lite-anchor a:hover { border-left-color: #165DFF; background: #F7F8FA; color: #165DFF; }
|
|
35
|
+
|
|
36
|
+
.lite-anchor > * + * { margin-top: 8px; }
|
|
37
|
+
.lite-anchor li + li { margin-top: 4px; }
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface AnchorItem {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
level?: number;
|
|
5
|
+
}
|
|
6
|
+
interface Props {
|
|
7
|
+
items: AnchorItem[];
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Caller class merged with the built-in class list. */
|
|
10
|
+
class?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const LiteAnchor: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type LiteAnchor = ReturnType<typeof LiteAnchor>;
|
|
14
|
+
export default LiteAnchor;
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
status?: 'pending' | 'approved' | 'rejected' | 'recalled';
|
|
7
7
|
action?: string;
|
|
8
8
|
children?: Snippet;
|
|
9
|
+
/** Caller class merged with the built-in class list. */
|
|
10
|
+
class?: string;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
let {
|
|
@@ -13,13 +15,14 @@
|
|
|
13
15
|
status = 'pending',
|
|
14
16
|
action = '',
|
|
15
17
|
children,
|
|
18
|
+
class: className = '',
|
|
16
19
|
}: Props = $props();
|
|
17
20
|
</script>
|
|
18
21
|
|
|
19
|
-
<div class="lite-approval-card lite-form-group">
|
|
22
|
+
<div class="lite-approval-card lite-form-group {className}">
|
|
20
23
|
<div class="lite-approval-header">
|
|
21
24
|
<strong>{title}</strong>
|
|
22
|
-
<span class="lite-badge lite-badge-{status}">{status
|
|
25
|
+
<span class="lite-badge lite-badge-{status}">{status}</span>
|
|
23
26
|
</div>
|
|
24
27
|
|
|
25
28
|
{#if children}
|
|
@@ -49,8 +52,8 @@
|
|
|
49
52
|
<style>
|
|
50
53
|
.lite-approval-card {
|
|
51
54
|
padding: 12px;
|
|
52
|
-
background: #
|
|
53
|
-
border: 1px solid #
|
|
55
|
+
background: #F7F8FA;
|
|
56
|
+
border: 1px solid #E5E6EB;
|
|
54
57
|
border-radius: 6px;
|
|
55
58
|
margin-bottom: 16px;
|
|
56
59
|
}
|
|
@@ -63,7 +66,7 @@
|
|
|
63
66
|
}
|
|
64
67
|
.lite-approval-body {
|
|
65
68
|
font-size: 12px;
|
|
66
|
-
color: #
|
|
69
|
+
color: #4E5969;
|
|
67
70
|
margin-bottom: 12px;
|
|
68
71
|
}
|
|
69
72
|
.lite-approval-field {
|
|
@@ -4,6 +4,8 @@ interface Props {
|
|
|
4
4
|
status?: 'pending' | 'approved' | 'rejected' | 'recalled';
|
|
5
5
|
action?: string;
|
|
6
6
|
children?: Snippet;
|
|
7
|
+
/** Caller class merged with the built-in class list. */
|
|
8
|
+
class?: string;
|
|
7
9
|
}
|
|
8
10
|
declare const LiteApprovalActionCard: import("svelte").Component<Props, {}, "">;
|
|
9
11
|
type LiteApprovalActionCard = ReturnType<typeof LiteApprovalActionCard>;
|
|
@@ -52,15 +52,15 @@
|
|
|
52
52
|
<tbody>
|
|
53
53
|
{#each logs as log, _i (_i)}
|
|
54
54
|
<tr>
|
|
55
|
-
<td style="font-family:monospace;font-size:12px;color:#
|
|
55
|
+
<td style="font-family:monospace;font-size:12px;color:#4E5969;">{formatDate(log.createdAt)}</td>
|
|
56
56
|
<td>{log.userName ?? '—'}</td>
|
|
57
57
|
<td><span class="lite-badge {actionClass(log.action)}">{log.action}</span></td>
|
|
58
|
-
<td style="color:#
|
|
59
|
-
<td style="font-family:monospace;font-size:12px;color:#
|
|
58
|
+
<td style="color:#4E5969;">{log.resource ?? '—'}</td>
|
|
59
|
+
<td style="font-family:monospace;font-size:12px;color:#4E5969;">{log.ipAddress ?? '—'}</td>
|
|
60
60
|
</tr>
|
|
61
61
|
{:else}
|
|
62
62
|
<tr>
|
|
63
|
-
<td colspan="5" style="text-align:center;padding:24px;color:#
|
|
63
|
+
<td colspan="5" style="text-align:center;padding:24px;color:#86909C;">No audit logs found.</td>
|
|
64
64
|
</tr>
|
|
65
65
|
{/each}
|
|
66
66
|
</tbody>
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
{#if page > 1}
|
|
73
73
|
<a href={`${basePath}page={page - 1}`} class="lite-btn lite-btn-sm">« Prev</a>
|
|
74
74
|
{/if}
|
|
75
|
-
<span style="padding:0 12px;font-size:14px;color:#
|
|
75
|
+
<span style="padding:0 12px;font-size:14px;color:#4E5969;">Page {page} / {totalPages} ({total} total)</span>
|
|
76
76
|
{#if page < totalPages}
|
|
77
77
|
<a href={`${basePath}page={page + 1}`} class="lite-btn lite-btn-sm">Next »</a>
|
|
78
78
|
{/if}
|
|
@@ -88,8 +88,8 @@
|
|
|
88
88
|
font-size: 12px;
|
|
89
89
|
font-weight: 600;
|
|
90
90
|
}
|
|
91
|
-
.lite-badge-danger { background: #
|
|
92
|
-
.lite-badge-success { background: #f0fdf4; color: #
|
|
93
|
-
.lite-badge-warning { background: #
|
|
94
|
-
.lite-badge-default { background: #
|
|
91
|
+
.lite-badge-danger { background: #FFECE8; color: #dc2626; border: 1px solid #FDCDC5; }
|
|
92
|
+
.lite-badge-success { background: #f0fdf4; color: #009A29; border: 1px solid #bbf7d0; }
|
|
93
|
+
.lite-badge-warning { background: #FFF7E8; color: #D25F00; border: 1px solid #FFE4BA; }
|
|
94
|
+
.lite-badge-default { background: #F2F3F5; color: #4E5969; border: 1px solid #E5E6EB; }
|
|
95
95
|
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
name: string;
|
|
4
|
+
options: string[];
|
|
5
|
+
value?: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
listId?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
name,
|
|
15
|
+
options,
|
|
16
|
+
value = '',
|
|
17
|
+
label,
|
|
18
|
+
placeholder = 'Type or choose a suggestion',
|
|
19
|
+
required = false,
|
|
20
|
+
disabled = false,
|
|
21
|
+
listId = `${name}-options`,
|
|
22
|
+
}: Props = $props();
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<label class="lite-form-group">
|
|
26
|
+
{#if label}<span>{label}</span>{/if}
|
|
27
|
+
<input
|
|
28
|
+
class="lite-input"
|
|
29
|
+
type="text"
|
|
30
|
+
{name}
|
|
31
|
+
{value}
|
|
32
|
+
{placeholder}
|
|
33
|
+
{required}
|
|
34
|
+
{disabled}
|
|
35
|
+
list={listId}
|
|
36
|
+
autocomplete="off"
|
|
37
|
+
/>
|
|
38
|
+
<datalist id={listId}>
|
|
39
|
+
{#each options as option (option)}<option value={option}></option>{/each}
|
|
40
|
+
</datalist>
|
|
41
|
+
</label>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
name: string;
|
|
3
|
+
options: string[];
|
|
4
|
+
value?: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
listId?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const LiteAutoComplete: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type LiteAutoComplete = ReturnType<typeof LiteAutoComplete>;
|
|
13
|
+
export default LiteAutoComplete;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
href?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
thresholdText?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { href = '#top', label = 'Back to top', thresholdText = '↑ Top' }: Props = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<a class="lite-back-top" {href} aria-label={label}>{thresholdText}</a>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.lite-back-top { position: fixed; right: 24px; bottom: 80px; display: inline-grid; place-items: center; min-width: 40px; height: 40px; padding: 0 12px; border: 1px solid #E5E6EB; border-radius: 999px; background: #fff; color: #1D2129; box-shadow: 0 6px 20px rgba(29, 33, 41, 0.16); font-size: 12px; text-decoration: none; }
|
|
15
|
+
.lite-back-top:hover { color: #165DFF; text-decoration: none; }
|
|
16
|
+
</style>
|
|
@@ -13,15 +13,18 @@
|
|
|
13
13
|
items: BreadcrumbItem[];
|
|
14
14
|
/** Separator character between items */
|
|
15
15
|
separator?: string;
|
|
16
|
+
/** Caller class merged with the built-in class list. */
|
|
17
|
+
class?: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
let {
|
|
19
21
|
items,
|
|
20
22
|
separator = '/',
|
|
23
|
+
class: className = '',
|
|
21
24
|
}: Props = $props();
|
|
22
25
|
</script>
|
|
23
26
|
|
|
24
|
-
<nav class="lite-breadcrumbs" aria-label="Breadcrumb">
|
|
27
|
+
<nav class="lite-breadcrumbs {className}" aria-label="Breadcrumb">
|
|
25
28
|
<ol>
|
|
26
29
|
{#each items as item, i (i)}
|
|
27
30
|
<li>
|
|
@@ -10,6 +10,8 @@ interface Props {
|
|
|
10
10
|
items: BreadcrumbItem[];
|
|
11
11
|
/** Separator character between items */
|
|
12
12
|
separator?: string;
|
|
13
|
+
/** Caller class merged with the built-in class list. */
|
|
14
|
+
class?: string;
|
|
13
15
|
}
|
|
14
16
|
declare const LiteBreadcrumbs: import("svelte").Component<Props, {}, "">;
|
|
15
17
|
type LiteBreadcrumbs = ReturnType<typeof LiteBreadcrumbs>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface CalendarEvent {
|
|
3
|
+
id: string;
|
|
4
|
+
date: string;
|
|
5
|
+
label: string;
|
|
6
|
+
href?: string;
|
|
7
|
+
tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
value?: string;
|
|
12
|
+
events?: CalendarEvent[];
|
|
13
|
+
locale?: string;
|
|
14
|
+
weekStartsOn?: 0 | 1;
|
|
15
|
+
min?: string;
|
|
16
|
+
max?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
hrefFor?: (iso: string) => string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
value = '',
|
|
23
|
+
events = [],
|
|
24
|
+
locale,
|
|
25
|
+
weekStartsOn = 0,
|
|
26
|
+
min,
|
|
27
|
+
max,
|
|
28
|
+
title,
|
|
29
|
+
hrefFor,
|
|
30
|
+
}: Props = $props();
|
|
31
|
+
|
|
32
|
+
const initial = $derived(value ? new Date(`${value}T12:00:00`) : new Date());
|
|
33
|
+
const year = $derived(initial.getFullYear());
|
|
34
|
+
const month = $derived(initial.getMonth());
|
|
35
|
+
const heading = $derived(title ?? new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' }).format(new Date(year, month, 1)));
|
|
36
|
+
const weekdays = $derived.by(() => {
|
|
37
|
+
const format = new Intl.DateTimeFormat(locale, { weekday: 'short' });
|
|
38
|
+
return Array.from({ length: 7 }, (_, index) => format.format(new Date(2024, 0, 7 + ((index + weekStartsOn) % 7))));
|
|
39
|
+
});
|
|
40
|
+
const days = $derived.by(() => {
|
|
41
|
+
const first = new Date(year, month, 1);
|
|
42
|
+
const offset = (first.getDay() - weekStartsOn + 7) % 7;
|
|
43
|
+
return Array.from({ length: 42 }, (_, index) => {
|
|
44
|
+
const date = new Date(year, month, 1 - offset + index);
|
|
45
|
+
const iso = toIso(date);
|
|
46
|
+
return {
|
|
47
|
+
iso,
|
|
48
|
+
day: date.getDate(),
|
|
49
|
+
outside: date.getMonth() !== month,
|
|
50
|
+
selected: iso === value,
|
|
51
|
+
events: events.filter((event) => event.date === iso),
|
|
52
|
+
disabled: Boolean(min && iso < min) || Boolean(max && iso > max),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
const upcoming = $derived(events.filter((event) => !value || event.date >= value).slice(0, 8));
|
|
57
|
+
|
|
58
|
+
function toIso(date: Date): string {
|
|
59
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<section class="lite-calendar lite-card" aria-label={heading}>
|
|
64
|
+
<header>
|
|
65
|
+
<h2>{heading}</h2>
|
|
66
|
+
{#if value}<span>{value}</span>{/if}
|
|
67
|
+
</header>
|
|
68
|
+
<table>
|
|
69
|
+
<thead>
|
|
70
|
+
<tr>{#each weekdays as weekday (weekday)}<th scope="col">{weekday}</th>{/each}</tr>
|
|
71
|
+
</thead>
|
|
72
|
+
<tbody>
|
|
73
|
+
{#each Array.from({ length: 6 }, (_, week) => week) as week (week)}
|
|
74
|
+
<tr>
|
|
75
|
+
{#each days.slice(week * 7, week * 7 + 7) as day (day.iso)}
|
|
76
|
+
<td data-outside={day.outside || undefined} data-selected={day.selected || undefined} data-disabled={day.disabled || undefined}>
|
|
77
|
+
{#if day.disabled}
|
|
78
|
+
<span>{day.day}</span>
|
|
79
|
+
{:else if hrefFor}
|
|
80
|
+
<a href={hrefFor(day.iso)} aria-current={day.selected ? 'date' : undefined}>{day.day}</a>
|
|
81
|
+
{:else}
|
|
82
|
+
<span aria-current={day.selected ? 'date' : undefined}>{day.day}</span>
|
|
83
|
+
{/if}
|
|
84
|
+
{#if day.events.length > 0}<span class="lite-calendar__dot" title={`${day.events.length} event(s)`}></span>{/if}
|
|
85
|
+
</td>
|
|
86
|
+
{/each}
|
|
87
|
+
</tr>
|
|
88
|
+
{/each}
|
|
89
|
+
</tbody>
|
|
90
|
+
</table>
|
|
91
|
+
{#if upcoming.length > 0}
|
|
92
|
+
<ul class="lite-calendar__events">
|
|
93
|
+
{#each upcoming as event (event.id)}
|
|
94
|
+
<li data-tone={event.tone ?? 'neutral'}>
|
|
95
|
+
<time>{event.date}</time>
|
|
96
|
+
{#if event.href}<a href={event.href}>{event.label}</a>{:else}<span>{event.label}</span>{/if}
|
|
97
|
+
</li>
|
|
98
|
+
{/each}
|
|
99
|
+
</ul>
|
|
100
|
+
{/if}
|
|
101
|
+
</section>
|
|
102
|
+
|
|
103
|
+
<style>
|
|
104
|
+
.lite-calendar { padding: 0; overflow: hidden; }
|
|
105
|
+
.lite-calendar header { display: flex; align-items: baseline; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid #E5E6EB; }
|
|
106
|
+
.lite-calendar h2 { margin: 0; color: #1D2129; font-size: 14px; }
|
|
107
|
+
.lite-calendar header span { color: #86909C; font-size: 12px; }
|
|
108
|
+
.lite-calendar table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
|
109
|
+
.lite-calendar th { padding: 8px 4px; color: #86909C; font-size: 11px; font-weight: 600; text-align: center; }
|
|
110
|
+
.lite-calendar td { position: relative; height: 40px; padding: 4px; border: 1px solid #F2F3F5; color: #1D2129; font-size: 12px; text-align: center; }
|
|
111
|
+
.lite-calendar td a, .lite-calendar td > span:first-child { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 999px; color: inherit; text-decoration: none; }
|
|
112
|
+
.lite-calendar td a:hover { background: #F7F8FA; color: #165DFF; }
|
|
113
|
+
.lite-calendar td[data-selected] a, .lite-calendar td[data-selected] > span:first-child { background: #165DFF; color: #fff; }
|
|
114
|
+
.lite-calendar td[data-outside] { color: #C9CDD4; }
|
|
115
|
+
.lite-calendar td[data-disabled] { color: #E5E6EB; }
|
|
116
|
+
.lite-calendar__dot { position: absolute; right: 50%; bottom: 3px; width: 4px; height: 4px; margin-right: -2px; border-radius: 999px; background: #165DFF; }
|
|
117
|
+
.lite-calendar__events { margin: 0; padding: 8px 16px 12px; border-top: 1px solid #E5E6EB; list-style: none; }
|
|
118
|
+
.lite-calendar__events li { display: flex; padding: 4px 0; color: #4E5969; font-size: 12px; }
|
|
119
|
+
.lite-calendar__events time { color: #86909C; font-variant-numeric: tabular-nums; }
|
|
120
|
+
.lite-calendar__events a { color: #165DFF; }
|
|
121
|
+
|
|
122
|
+
.lite-calendar header > * + * { margin-left: 12px; }
|
|
123
|
+
.lite-calendar__events li > * + * { margin-left: 8px; }
|
|
124
|
+
</style>
|