@classic-homes/theme-mcp 0.1.15 → 0.1.17
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/dist/cli.js +1036 -378
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1036 -378
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2733,7 +2733,7 @@ var component_catalog_default = {
|
|
|
2733
2733
|
},
|
|
2734
2734
|
{
|
|
2735
2735
|
name: "DataTable",
|
|
2736
|
-
description: "Powerful data table with
|
|
2736
|
+
description: "Powerful data table with native Svelte 5 runes - sorting, filtering, pagination, virtualization, and inline editing",
|
|
2737
2737
|
category: "data",
|
|
2738
2738
|
importPath: "@classic-homes/theme-svelte",
|
|
2739
2739
|
props: [
|
|
@@ -2787,7 +2787,7 @@ var component_catalog_default = {
|
|
|
2787
2787
|
name: "onSort",
|
|
2788
2788
|
type: "(column: string, direction: 'asc' | 'desc') => void",
|
|
2789
2789
|
required: false,
|
|
2790
|
-
description: "Sort callback"
|
|
2790
|
+
description: "Sort callback (enables server-side sorting)"
|
|
2791
2791
|
},
|
|
2792
2792
|
{
|
|
2793
2793
|
name: "onRowClick",
|
|
@@ -2812,6 +2812,26 @@ var component_catalog_default = {
|
|
|
2812
2812
|
type: "string",
|
|
2813
2813
|
required: false,
|
|
2814
2814
|
description: "Additional classes"
|
|
2815
|
+
},
|
|
2816
|
+
{
|
|
2817
|
+
name: "enablePagination",
|
|
2818
|
+
type: "boolean",
|
|
2819
|
+
default: "false",
|
|
2820
|
+
required: false,
|
|
2821
|
+
description: "Enable built-in pagination"
|
|
2822
|
+
},
|
|
2823
|
+
{
|
|
2824
|
+
name: "pageSize",
|
|
2825
|
+
type: "number",
|
|
2826
|
+
default: "10",
|
|
2827
|
+
required: false,
|
|
2828
|
+
description: "Rows per page"
|
|
2829
|
+
},
|
|
2830
|
+
{
|
|
2831
|
+
name: "getRowId",
|
|
2832
|
+
type: "(row: T, index: number) => string",
|
|
2833
|
+
required: false,
|
|
2834
|
+
description: "Function to get unique row ID"
|
|
2815
2835
|
}
|
|
2816
2836
|
],
|
|
2817
2837
|
variants: [
|
|
@@ -2841,92 +2861,104 @@ var component_catalog_default = {
|
|
|
2841
2861
|
events: [],
|
|
2842
2862
|
examples: [
|
|
2843
2863
|
{
|
|
2844
|
-
title: "Creating a
|
|
2864
|
+
title: "Creating a Table Instance",
|
|
2845
2865
|
code: `<script lang="ts">
|
|
2846
2866
|
import {
|
|
2847
2867
|
createDataTable,
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
type
|
|
2868
|
+
DataTableToolbar,
|
|
2869
|
+
DataTablePagination,
|
|
2870
|
+
type DataTableColumn,
|
|
2851
2871
|
} from '@classic-homes/theme-svelte';
|
|
2852
2872
|
|
|
2853
2873
|
interface User {
|
|
2854
2874
|
id: number;
|
|
2855
2875
|
name: string;
|
|
2856
2876
|
email: string;
|
|
2877
|
+
role: string;
|
|
2857
2878
|
}
|
|
2858
2879
|
|
|
2859
|
-
//
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2880
|
+
// Column definitions
|
|
2881
|
+
const columns: DataTableColumn<User>[] = [
|
|
2882
|
+
{ id: 'id', header: 'ID', accessor: 'id', sortable: true },
|
|
2883
|
+
{ id: 'name', header: 'Name', accessor: 'name', sortable: true },
|
|
2884
|
+
{ id: 'email', header: 'Email', accessor: 'email', sortable: true },
|
|
2885
|
+
{
|
|
2886
|
+
id: 'role',
|
|
2887
|
+
header: 'Role',
|
|
2888
|
+
accessor: 'role',
|
|
2889
|
+
filterOptions: [
|
|
2890
|
+
{ value: 'Admin', label: 'Admin' },
|
|
2891
|
+
{ value: 'Editor', label: 'Editor' },
|
|
2892
|
+
{ value: 'Viewer', label: 'Viewer' },
|
|
2893
|
+
],
|
|
2894
|
+
},
|
|
2868
2895
|
];
|
|
2869
2896
|
|
|
2870
2897
|
// Create table instance
|
|
2871
|
-
const
|
|
2898
|
+
const table = createDataTable<User>(() => ({
|
|
2872
2899
|
data: users,
|
|
2873
2900
|
columns,
|
|
2874
|
-
|
|
2875
|
-
onSortingChange: (updater) => {
|
|
2876
|
-
sorting = typeof updater === 'function' ? updater(sorting) : updater;
|
|
2877
|
-
},
|
|
2878
|
-
onRowSelectionChange: (updater) => {
|
|
2879
|
-
rowSelection = typeof updater === 'function' ? updater(rowSelection) : updater;
|
|
2880
|
-
},
|
|
2881
|
-
enableRowSelection: true,
|
|
2882
|
-
enableSorting: true,
|
|
2901
|
+
getRowId: (row) => String(row.id),
|
|
2883
2902
|
}));
|
|
2903
|
+
</script>
|
|
2884
2904
|
|
|
2885
|
-
|
|
2886
|
-
|
|
2905
|
+
<!-- Toolbar with search and filters -->
|
|
2906
|
+
<DataTableToolbar {table} />
|
|
2907
|
+
|
|
2908
|
+
<!-- Table rendering -->
|
|
2909
|
+
<table>
|
|
2910
|
+
<thead>
|
|
2911
|
+
<tr>
|
|
2912
|
+
{#each table.columns as column}
|
|
2913
|
+
<th onclick={() => column.sortable && table.toggleSort(column.id)}>
|
|
2914
|
+
{column.header}
|
|
2915
|
+
</th>
|
|
2916
|
+
{/each}
|
|
2917
|
+
</tr>
|
|
2918
|
+
</thead>
|
|
2919
|
+
<tbody>
|
|
2920
|
+
{#each table.rows as row}
|
|
2921
|
+
<tr>
|
|
2922
|
+
{#each table.columns as column}
|
|
2923
|
+
<td>{table.getFormattedCellValue(row.original, column)}</td>
|
|
2924
|
+
{/each}
|
|
2925
|
+
</tr>
|
|
2926
|
+
{/each}
|
|
2927
|
+
</tbody>
|
|
2928
|
+
</table>
|
|
2929
|
+
|
|
2930
|
+
<!-- Pagination -->
|
|
2931
|
+
<DataTablePagination {table} />`
|
|
2887
2932
|
},
|
|
2888
2933
|
{
|
|
2889
2934
|
title: "Row Selection",
|
|
2890
2935
|
description: "Enable checkbox selection for rows:",
|
|
2891
|
-
code: "<script>\n let rowSelection = $state<
|
|
2936
|
+
code: "<script>\n let rowSelection = $state<Set<string>>(new Set());\n\n const table = createDataTable<User>(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n onRowSelectionChange: (selection) => {\n rowSelection = selection;\n },\n }));\n</script>\n\n<!-- Render checkbox in header -->\n<th>\n <Checkbox\n checked={table.isAllSelected}\n indeterminate={table.isSomeSelected}\n onCheckedChange={() => table.toggleAllRows()}\n />\n</th>\n\n<!-- Render checkbox in each row -->\n{#each table.rows as row}\n <td>\n <Checkbox checked={row.isSelected} onCheckedChange={() => table.toggleRowSelection(row.id)} />\n </td>\n{/each}"
|
|
2892
2937
|
},
|
|
2893
2938
|
{
|
|
2894
2939
|
title: "Column Visibility",
|
|
2895
2940
|
description: "Allow users to toggle column visibility:",
|
|
2896
|
-
code: "<script>\n let columnVisibility = $state<
|
|
2941
|
+
code: "<script>\n let columnVisibility = $state<Set<string>>(new Set());\n\n const table = createDataTable<User>(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n onColumnVisibilityChange: (hidden) => {\n columnVisibility = hidden;\n },\n }));\n</script>\n\n<!-- DataTableToolbar includes column visibility dropdown -->\n<DataTableToolbar {table} />"
|
|
2897
2942
|
},
|
|
2898
2943
|
{
|
|
2899
2944
|
title: "Global Search",
|
|
2900
2945
|
description: "Filter across all columns:",
|
|
2901
|
-
code: "<script>\n let globalFilter = $state('');\n\n const
|
|
2946
|
+
code: "<script>\n let globalFilter = $state('');\n\n const table = createDataTable<User>(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n onGlobalFilterChange: (filter) => {\n globalFilter = filter;\n },\n }));\n</script>\n\n<!-- DataTableToolbar includes a search input -->\n<DataTableToolbar {table} />"
|
|
2902
2947
|
},
|
|
2903
2948
|
{
|
|
2904
2949
|
title: "Column Filters",
|
|
2905
2950
|
description: "Filter individual columns with faceted filtering:",
|
|
2906
|
-
code: "<script>\n
|
|
2907
|
-
},
|
|
2908
|
-
{
|
|
2909
|
-
title: "Pagination",
|
|
2910
|
-
description: "Add pagination controls:",
|
|
2911
|
-
code: "<script>\n const tableApi = createDataTable<User>(() => ({\n data: users,\n columns,\n // Pagination is enabled by default\n }));\n</script>\n\n<!-- Table content -->\n<table>...</table>\n\n<!-- Pagination controls -->\n<DataTablePagination {table} />"
|
|
2951
|
+
code: "<script>\n const columns: DataTableColumn<User>[] = [\n {\n id: 'role',\n header: 'Role',\n accessor: 'role',\n filterOptions: [\n { value: 'Admin', label: 'Admin' },\n { value: 'Editor', label: 'Editor' },\n { value: 'Viewer', label: 'Viewer' },\n ],\n },\n {\n id: 'status',\n header: 'Status',\n accessor: 'status',\n filterOptions: [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n ],\n },\n ];\n\n const table = createDataTable<User>(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n }));\n</script>\n\n<!-- DataTableToolbar renders filter dropdowns for columns with filterOptions -->\n<DataTableToolbar {table} />"
|
|
2912
2952
|
},
|
|
2913
2953
|
{
|
|
2914
2954
|
title: "Virtualization",
|
|
2915
2955
|
description: "Render thousands of rows efficiently:",
|
|
2916
|
-
code: '<script>\n const
|
|
2956
|
+
code: '<script>\n const table = createDataTable<User>(() => ({\n data: largeDataset, // 10,000+ rows\n columns,\n getRowId: (row) => String(row.id),\n manualPagination: true, // Disable pagination for virtualization\n }));\n</script>\n\n<DataTableVirtual\n {table}\n rowHeight={48}\n overscan={10}\n height="500px"\n onRowClick={(row) => console.log(row)}\n/>'
|
|
2917
2957
|
},
|
|
2918
2958
|
{
|
|
2919
2959
|
title: "Inline Editing",
|
|
2920
2960
|
description: "Enable double-click cell editing:",
|
|
2921
|
-
code: "<script>\n function handleCellEdit(rowId: string, columnId: string, value: unknown, row: User) {\n // Update your data source\n const index = users.findIndex((u) => u.id ===
|
|
2922
|
-
},
|
|
2923
|
-
{
|
|
2924
|
-
title: "User Management Table",
|
|
2925
|
-
code: "<script>\n const columns = [\n { id: 'name', header: 'Name', accessor: 'name', sortable: true },\n { id: 'email', header: 'Email', accessor: 'email', sortable: true },\n { id: 'role', header: 'Role', accessor: 'role' },\n {\n id: 'joined',\n header: 'Joined',\n accessor: 'createdAt',\n sortable: true,\n format: (v) => new Date(v).toLocaleDateString(),\n },\n ];\n</script>\n\n<DataTable\n data={users}\n {columns}\n caption=\"User management table\"\n onRowClick={(user) => goto(`/users/${user.id}`)}\n/>"
|
|
2926
|
-
},
|
|
2927
|
-
{
|
|
2928
|
-
title: "Product Inventory",
|
|
2929
|
-
code: "<script>\n const columns = [\n { id: 'sku', header: 'SKU', accessor: 'sku', width: '120px' },\n { id: 'name', header: 'Product', accessor: 'name', sortable: true },\n {\n id: 'stock',\n header: 'Stock',\n accessor: 'quantity',\n align: 'right',\n sortable: true,\n },\n {\n id: 'price',\n header: 'Price',\n accessor: 'price',\n align: 'right',\n format: (v) => `$${v.toFixed(2)}`,\n },\n ];\n</script>\n\n<DataTable data={products} {columns} emptyMessage=\"No products found\" />"
|
|
2961
|
+
code: "<script>\n function handleCellEdit(rowId: string, columnId: string, value: unknown, row: User) {\n // Update your data source\n const index = users.findIndex((u) => String(u.id) === rowId);\n if (index !== -1) {\n users[index] = { ...users[index], [columnId]: value };\n }\n }\n\n const columns: DataTableColumn<User>[] = [\n { id: 'name', header: 'Name', accessor: 'name', enableEditing: true },\n { id: 'email', header: 'Email', accessor: 'email', enableEditing: true },\n ];\n</script>\n\n{#each table.rows as row}\n <tr>\n {#each table.columns as column}\n <td>\n <DataTableEditableCell {row} {column} onSave={handleCellEdit} />\n </td>\n {/each}\n </tr>\n{/each}"
|
|
2930
2962
|
}
|
|
2931
2963
|
],
|
|
2932
2964
|
relatedComponents: [
|
|
@@ -2942,12 +2974,19 @@ var component_catalog_default = {
|
|
|
2942
2974
|
category: "data",
|
|
2943
2975
|
importPath: "@classic-homes/theme-svelte",
|
|
2944
2976
|
props: [
|
|
2977
|
+
{
|
|
2978
|
+
name: "table",
|
|
2979
|
+
type: "DataTableInstance<T>",
|
|
2980
|
+
default: "**required**",
|
|
2981
|
+
required: false,
|
|
2982
|
+
description: "The table instance from createDataTable"
|
|
2983
|
+
},
|
|
2945
2984
|
{
|
|
2946
2985
|
name: "column",
|
|
2947
|
-
type: "
|
|
2986
|
+
type: "DataTableColumn<T>",
|
|
2948
2987
|
default: "**required**",
|
|
2949
2988
|
required: false,
|
|
2950
|
-
description: "The
|
|
2989
|
+
description: "The column to filter"
|
|
2951
2990
|
},
|
|
2952
2991
|
{
|
|
2953
2992
|
name: "placeholder",
|
|
@@ -2982,23 +3021,23 @@ var component_catalog_default = {
|
|
|
2982
3021
|
examples: [
|
|
2983
3022
|
{
|
|
2984
3023
|
title: "Basic Usage",
|
|
2985
|
-
code: "<script>\n import { createDataTable, DataTableColumnFilter } from '@classic-homes/theme-svelte';\n\n
|
|
3024
|
+
code: "<script>\n import { createDataTable, DataTableColumnFilter } from '@classic-homes/theme-svelte';\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n }));\n\n // Get a specific column for filtering\n const nameColumn = $derived(table.columns.find((c) => c.id === 'name'));\n</script>\n\n<!-- Filter for the name column -->\n{#if nameColumn}\n <DataTableColumnFilter {table} column={nameColumn} />\n{/if}"
|
|
2986
3025
|
},
|
|
2987
3026
|
{
|
|
2988
3027
|
title: "Custom Placeholder",
|
|
2989
|
-
code: '<DataTableColumnFilter {column} placeholder="Search names..." />'
|
|
3028
|
+
code: '<DataTableColumnFilter {table} {column} placeholder="Search names..." />'
|
|
2990
3029
|
},
|
|
2991
3030
|
{
|
|
2992
3031
|
title: "Faster Debounce",
|
|
2993
|
-
code: "<DataTableColumnFilter {column} debounceMs={150} />"
|
|
3032
|
+
code: "<DataTableColumnFilter {table} {column} debounceMs={150} />"
|
|
2994
3033
|
},
|
|
2995
3034
|
{
|
|
2996
3035
|
title: "In Table Header",
|
|
2997
|
-
code: '<thead>\n <tr>\n {#each table.
|
|
3036
|
+
code: '<thead>\n <tr>\n {#each table.columns as column}\n <th>\n {column.header}\n <DataTableColumnFilter {table} {column} class="mt-1" />\n </th>\n {/each}\n </tr>\n</thead>'
|
|
2998
3037
|
},
|
|
2999
3038
|
{
|
|
3000
3039
|
title: "Multiple Column Filters",
|
|
3001
|
-
code: '<div class="flex gap-2">\n {#each table.
|
|
3040
|
+
code: '<div class="flex gap-2">\n {#each table.columns as column}\n <DataTableColumnFilter {table} {column} class="w-40" />\n {/each}\n</div>'
|
|
3002
3041
|
}
|
|
3003
3042
|
],
|
|
3004
3043
|
relatedComponents: [
|
|
@@ -3015,16 +3054,10 @@ var component_catalog_default = {
|
|
|
3015
3054
|
props: [
|
|
3016
3055
|
{
|
|
3017
3056
|
name: "table",
|
|
3018
|
-
type: "
|
|
3057
|
+
type: "DataTableInstance<T>",
|
|
3019
3058
|
default: "**required**",
|
|
3020
3059
|
required: false,
|
|
3021
|
-
description: "The
|
|
3022
|
-
},
|
|
3023
|
-
{
|
|
3024
|
-
name: "visibilityState",
|
|
3025
|
-
type: "VisibilityState",
|
|
3026
|
-
required: false,
|
|
3027
|
-
description: "Optional visibility state for reactivity"
|
|
3060
|
+
description: "The table instance from createDataTable"
|
|
3028
3061
|
},
|
|
3029
3062
|
{
|
|
3030
3063
|
name: "class",
|
|
@@ -3045,20 +3078,15 @@ var component_catalog_default = {
|
|
|
3045
3078
|
examples: [
|
|
3046
3079
|
{
|
|
3047
3080
|
title: "Basic Usage",
|
|
3048
|
-
code: "<script>\n import { createDataTable, DataTableColumnVisibility } from '@classic-homes/theme-svelte';\n\n let columnVisibility = $state(
|
|
3081
|
+
code: "<script>\n import { createDataTable, DataTableColumnVisibility } from '@classic-homes/theme-svelte';\n\n let columnVisibility = $state<Set<string>>(new Set());\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n onColumnVisibilityChange: (hidden) => {\n columnVisibility = hidden;\n },\n }));\n</script>\n\n<DataTableColumnVisibility {table} />"
|
|
3049
3082
|
},
|
|
3050
3083
|
{
|
|
3051
|
-
title: "With
|
|
3052
|
-
|
|
3053
|
-
code: "<script>\n let columnVisibility = $state({\n email: false, // Hide email column by default\n phone: false, // Hide phone column by default\n });\n</script>\n\n<DataTableColumnVisibility {table} visibilityState={columnVisibility} />"
|
|
3084
|
+
title: "With Initial Hidden Columns",
|
|
3085
|
+
code: "<script>\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n initialHiddenColumns: ['email', 'phone'], // Hide these by default\n }));\n</script>\n\n<DataTableColumnVisibility {table} />"
|
|
3054
3086
|
},
|
|
3055
3087
|
{
|
|
3056
3088
|
title: "In Toolbar",
|
|
3057
3089
|
code: '<div class="flex items-center gap-2">\n <DataTableSearch {table} />\n <DataTableColumnVisibility {table} />\n</div>'
|
|
3058
|
-
},
|
|
3059
|
-
{
|
|
3060
|
-
title: "Hide Specific Columns Initially",
|
|
3061
|
-
code: "<script>\n // Some columns hidden by default\n let columnVisibility = $state({\n createdAt: false,\n updatedAt: false,\n internalId: false,\n });\n\n const tableApi = createDataTable(() => ({\n data,\n columns,\n state: { columnVisibility },\n onColumnVisibilityChange: (updater) => {\n columnVisibility = typeof updater === 'function' ? updater(columnVisibility) : updater;\n },\n enableHiding: true,\n }));\n</script>\n\n<DataTableColumnVisibility {table} visibilityState={columnVisibility} />"
|
|
3062
3090
|
}
|
|
3063
3091
|
],
|
|
3064
3092
|
relatedComponents: [
|
|
@@ -3074,18 +3102,18 @@ var component_catalog_default = {
|
|
|
3074
3102
|
importPath: "@classic-homes/theme-svelte",
|
|
3075
3103
|
props: [
|
|
3076
3104
|
{
|
|
3077
|
-
name: "
|
|
3078
|
-
type: "
|
|
3105
|
+
name: "row",
|
|
3106
|
+
type: "DataTableRow<T>",
|
|
3079
3107
|
default: "**required**",
|
|
3080
3108
|
required: false,
|
|
3081
|
-
description: "The
|
|
3109
|
+
description: "The row object from table.rows"
|
|
3082
3110
|
},
|
|
3083
3111
|
{
|
|
3084
|
-
name: "
|
|
3085
|
-
type: "T",
|
|
3112
|
+
name: "column",
|
|
3113
|
+
type: "DataTableColumn<T>",
|
|
3086
3114
|
default: "**required**",
|
|
3087
3115
|
required: false,
|
|
3088
|
-
description: "The
|
|
3116
|
+
description: "The column definition"
|
|
3089
3117
|
},
|
|
3090
3118
|
{
|
|
3091
3119
|
name: "onSave",
|
|
@@ -3113,21 +3141,25 @@ var component_catalog_default = {
|
|
|
3113
3141
|
examples: [
|
|
3114
3142
|
{
|
|
3115
3143
|
title: "Basic Usage",
|
|
3116
|
-
code: "<script>\n import { createDataTable, DataTableEditableCell } from '@classic-homes/theme-svelte';\n\n function handleCellEdit(rowId, columnId, value, row) {\n // Update your data source\n const index = users.findIndex((u) => u.id ===
|
|
3144
|
+
code: "<script>\n import { createDataTable, DataTableEditableCell } from '@classic-homes/theme-svelte';\n\n function handleCellEdit(rowId, columnId, value, row) {\n // Update your data source\n const index = users.findIndex((u) => String(u.id) === rowId);\n if (index !== -1) {\n users[index] = { ...users[index], [columnId]: value };\n }\n }\n\n const columns = [\n { id: 'name', header: 'Name', accessor: 'name', enableEditing: true },\n { id: 'email', header: 'Email', accessor: 'email', enableEditing: true },\n { id: 'role', header: 'Role', accessor: 'role' }, // Not editable\n ];\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n }));\n</script>\n\n{#each table.rows as row}\n <tr>\n {#each table.columns as column}\n <td>\n <DataTableEditableCell {row} {column} onSave={handleCellEdit} />\n </td>\n {/each}\n </tr>\n{/each}"
|
|
3117
3145
|
},
|
|
3118
3146
|
{
|
|
3119
3147
|
title: "With Custom Formatting",
|
|
3120
3148
|
description: "Cells can have custom display formatting while editing the raw value:",
|
|
3121
|
-
code: "<script>\n const columns = [\n {\n
|
|
3149
|
+
code: "<script>\n const columns = [\n {\n id: 'price',\n header: 'Price',\n accessor: 'price',\n enableEditing: true,\n format: (value) => `$${Number(value).toFixed(2)}`,\n },\n ];\n</script>"
|
|
3122
3150
|
},
|
|
3123
3151
|
{
|
|
3124
3152
|
title: "Async Save Handler",
|
|
3125
|
-
code: "<script>\n async function handleCellEdit(rowId, columnId, value, row) {\n try {\n await api.updateUser(row.id, { [columnId]: value });\n // Update local state after successful save\n users = users.map((u) => (u.id ===
|
|
3153
|
+
code: "<script>\n async function handleCellEdit(rowId, columnId, value, row) {\n try {\n await api.updateUser(row.id, { [columnId]: value });\n // Update local state after successful save\n users = users.map((u) => (String(u.id) === rowId ? { ...u, [columnId]: value } : u));\n } catch (error) {\n console.error('Failed to save:', error);\n // Optionally show error toast\n }\n }\n</script>"
|
|
3154
|
+
},
|
|
3155
|
+
{
|
|
3156
|
+
title: "With Type Conversion",
|
|
3157
|
+
code: "<script>\n function handleCellEdit(rowId, columnId, value, row) {\n let parsedValue = value;\n\n // Convert to number for numeric columns\n if (columnId === 'salary' || columnId === 'quantity') {\n parsedValue = parseInt(String(value), 10) || 0;\n }\n\n const index = data.findIndex((item) => String(item.id) === rowId);\n if (index !== -1) {\n data[index] = { ...data[index], [columnId]: parsedValue };\n }\n }\n</script>"
|
|
3126
3158
|
}
|
|
3127
3159
|
],
|
|
3128
3160
|
relatedComponents: [
|
|
3129
3161
|
"DataTable",
|
|
3130
|
-
"
|
|
3162
|
+
"DataTableVirtual"
|
|
3131
3163
|
]
|
|
3132
3164
|
},
|
|
3133
3165
|
{
|
|
@@ -3137,11 +3169,18 @@ var component_catalog_default = {
|
|
|
3137
3169
|
importPath: "@classic-homes/theme-svelte",
|
|
3138
3170
|
props: [
|
|
3139
3171
|
{
|
|
3140
|
-
name: "
|
|
3141
|
-
type: "
|
|
3172
|
+
name: "table",
|
|
3173
|
+
type: "DataTableInstance<T>",
|
|
3174
|
+
default: "**required**",
|
|
3175
|
+
required: false,
|
|
3176
|
+
description: "The table instance from createDataTable"
|
|
3177
|
+
},
|
|
3178
|
+
{
|
|
3179
|
+
name: "columnId",
|
|
3180
|
+
type: "string",
|
|
3142
3181
|
default: "**required**",
|
|
3143
3182
|
required: false,
|
|
3144
|
-
description: "The
|
|
3183
|
+
description: "The column ID to filter"
|
|
3145
3184
|
},
|
|
3146
3185
|
{
|
|
3147
3186
|
name: "title",
|
|
@@ -3179,24 +3218,16 @@ var component_catalog_default = {
|
|
|
3179
3218
|
code: `<script>
|
|
3180
3219
|
import { createDataTable, DataTableFacetedFilter } from '@classic-homes/theme-svelte';
|
|
3181
3220
|
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
const tableApi = createDataTable(() => ({
|
|
3221
|
+
const table = createDataTable(() => ({
|
|
3185
3222
|
data: users,
|
|
3186
3223
|
columns,
|
|
3187
|
-
|
|
3188
|
-
onColumnFiltersChange: (updater) => {
|
|
3189
|
-
columnFilters = typeof updater === 'function' ? updater(columnFilters) : updater;
|
|
3190
|
-
},
|
|
3191
|
-
enableColumnFilters: true,
|
|
3224
|
+
getRowId: (row) => String(row.id),
|
|
3192
3225
|
}));
|
|
3193
|
-
|
|
3194
|
-
const table = $derived(tableApi.instance);
|
|
3195
|
-
const statusColumn = $derived(table.getColumn('status'));
|
|
3196
3226
|
</script>
|
|
3197
3227
|
|
|
3198
3228
|
<DataTableFacetedFilter
|
|
3199
|
-
|
|
3229
|
+
{table}
|
|
3230
|
+
columnId="status"
|
|
3200
3231
|
title="Status"
|
|
3201
3232
|
options={[
|
|
3202
3233
|
{ value: 'active', label: 'Active' },
|
|
@@ -3223,59 +3254,19 @@ var component_catalog_default = {
|
|
|
3223
3254
|
]);
|
|
3224
3255
|
</script>
|
|
3225
3256
|
|
|
3226
|
-
<DataTableFacetedFilter
|
|
3257
|
+
<DataTableFacetedFilter {table} columnId="status" title="Status" options={statusOptions} />`
|
|
3227
3258
|
},
|
|
3228
3259
|
{
|
|
3229
3260
|
title: "Multiple Filters",
|
|
3230
|
-
code:
|
|
3231
|
-
<DataTableFacetedFilter
|
|
3232
|
-
column={table.getColumn('status')}
|
|
3233
|
-
title="Status"
|
|
3234
|
-
options={statusOptions}
|
|
3235
|
-
/>
|
|
3236
|
-
<DataTableFacetedFilter column={table.getColumn('role')} title="Role" options={roleOptions} />
|
|
3237
|
-
<DataTableFacetedFilter
|
|
3238
|
-
column={table.getColumn('department')}
|
|
3239
|
-
title="Department"
|
|
3240
|
-
options={departmentOptions}
|
|
3241
|
-
/>
|
|
3242
|
-
</div>`
|
|
3261
|
+
code: '<div class="flex gap-2">\n <DataTableFacetedFilter {table} columnId="status" title="Status" options={statusOptions} />\n <DataTableFacetedFilter {table} columnId="role" title="Role" options={roleOptions} />\n <DataTableFacetedFilter\n {table}\n columnId="department"\n title="Department"\n options={departmentOptions}\n />\n</div>'
|
|
3243
3262
|
},
|
|
3244
3263
|
{
|
|
3245
3264
|
title: "In DataTableToolbar",
|
|
3246
|
-
code:
|
|
3247
|
-
{#snippet filters()}
|
|
3248
|
-
<DataTableFacetedFilter
|
|
3249
|
-
column={table.getColumn('status')}
|
|
3250
|
-
title="Status"
|
|
3251
|
-
options={statusOptions}
|
|
3252
|
-
/>
|
|
3253
|
-
<DataTableFacetedFilter
|
|
3254
|
-
column={table.getColumn('priority')}
|
|
3255
|
-
title="Priority"
|
|
3256
|
-
options={priorityOptions}
|
|
3257
|
-
/>
|
|
3258
|
-
{/snippet}
|
|
3259
|
-
</DataTableToolbar>`
|
|
3265
|
+
code: '<DataTableToolbar {table}>\n {#snippet filters()}\n <DataTableFacetedFilter {table} columnId="status" title="Status" options={statusOptions} />\n <DataTableFacetedFilter\n {table}\n columnId="priority"\n title="Priority"\n options={priorityOptions}\n />\n {/snippet}\n</DataTableToolbar>'
|
|
3260
3266
|
},
|
|
3261
3267
|
{
|
|
3262
3268
|
title: "Dynamic Options from Data",
|
|
3263
|
-
code:
|
|
3264
|
-
// Extract unique values from data
|
|
3265
|
-
const uniqueStatuses = $derived(
|
|
3266
|
-
[...new Set(users.map((u) => u.status))].map((status) => ({
|
|
3267
|
-
value: status,
|
|
3268
|
-
label: status.charAt(0).toUpperCase() + status.slice(1),
|
|
3269
|
-
count: users.filter((u) => u.status === status).length,
|
|
3270
|
-
}))
|
|
3271
|
-
);
|
|
3272
|
-
</script>
|
|
3273
|
-
|
|
3274
|
-
<DataTableFacetedFilter
|
|
3275
|
-
column={table.getColumn('status')}
|
|
3276
|
-
title="Status"
|
|
3277
|
-
options={uniqueStatuses}
|
|
3278
|
-
/>`
|
|
3269
|
+
code: '<script>\n // Extract unique values from data\n const uniqueStatuses = $derived(\n [...new Set(users.map((u) => u.status))].map((status) => ({\n value: status,\n label: status.charAt(0).toUpperCase() + status.slice(1),\n count: users.filter((u) => u.status === status).length,\n }))\n );\n</script>\n\n<DataTableFacetedFilter {table} columnId="status" title="Status" options={uniqueStatuses} />'
|
|
3279
3270
|
}
|
|
3280
3271
|
],
|
|
3281
3272
|
relatedComponents: [
|
|
@@ -3286,16 +3277,16 @@ var component_catalog_default = {
|
|
|
3286
3277
|
},
|
|
3287
3278
|
{
|
|
3288
3279
|
name: "DataTablePagination",
|
|
3289
|
-
description: "Pagination controls for
|
|
3280
|
+
description: "Pagination controls for DataTable with page navigation and rows per page selector",
|
|
3290
3281
|
category: "data",
|
|
3291
3282
|
importPath: "@classic-homes/theme-svelte",
|
|
3292
3283
|
props: [
|
|
3293
3284
|
{
|
|
3294
3285
|
name: "table",
|
|
3295
|
-
type: "
|
|
3286
|
+
type: "DataTableInstance<T>",
|
|
3296
3287
|
default: "**required**",
|
|
3297
3288
|
required: false,
|
|
3298
|
-
description: "The
|
|
3289
|
+
description: "The table instance from createDataTable"
|
|
3299
3290
|
},
|
|
3300
3291
|
{
|
|
3301
3292
|
name: "pageSizeOptions",
|
|
@@ -3330,7 +3321,7 @@ var component_catalog_default = {
|
|
|
3330
3321
|
examples: [
|
|
3331
3322
|
{
|
|
3332
3323
|
title: "Basic Usage",
|
|
3333
|
-
code: "<script>\n import { createDataTable, DataTablePagination } from '@classic-homes/theme-svelte';\n\n const
|
|
3324
|
+
code: "<script>\n import { createDataTable, DataTablePagination } from '@classic-homes/theme-svelte';\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n }));\n</script>\n\n<table>...</table>\n<DataTablePagination {table} />"
|
|
3334
3325
|
},
|
|
3335
3326
|
{
|
|
3336
3327
|
title: "Custom Page Sizes",
|
|
@@ -3358,10 +3349,10 @@ var component_catalog_default = {
|
|
|
3358
3349
|
props: [
|
|
3359
3350
|
{
|
|
3360
3351
|
name: "table",
|
|
3361
|
-
type: "
|
|
3352
|
+
type: "DataTableInstance<T>",
|
|
3362
3353
|
default: "**required**",
|
|
3363
3354
|
required: false,
|
|
3364
|
-
description: "The
|
|
3355
|
+
description: "The table instance from createDataTable"
|
|
3365
3356
|
},
|
|
3366
3357
|
{
|
|
3367
3358
|
name: "placeholder",
|
|
@@ -3396,7 +3387,7 @@ var component_catalog_default = {
|
|
|
3396
3387
|
examples: [
|
|
3397
3388
|
{
|
|
3398
3389
|
title: "Basic Usage",
|
|
3399
|
-
code: "<script>\n import { createDataTable, DataTableSearch } from '@classic-homes/theme-svelte';\n\n let globalFilter = $state('');\n\n const
|
|
3390
|
+
code: "<script>\n import { createDataTable, DataTableSearch } from '@classic-homes/theme-svelte';\n\n let globalFilter = $state('');\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n onGlobalFilterChange: (filter) => {\n globalFilter = filter;\n },\n }));\n</script>\n\n<DataTableSearch {table} /><table>...</table>"
|
|
3400
3391
|
},
|
|
3401
3392
|
{
|
|
3402
3393
|
title: "Custom Placeholder",
|
|
@@ -3435,10 +3426,10 @@ var component_catalog_default = {
|
|
|
3435
3426
|
props: [
|
|
3436
3427
|
{
|
|
3437
3428
|
name: "table",
|
|
3438
|
-
type: "
|
|
3429
|
+
type: "DataTableInstance<T>",
|
|
3439
3430
|
default: "**required**",
|
|
3440
3431
|
required: false,
|
|
3441
|
-
description: "The
|
|
3432
|
+
description: "The table instance from createDataTable"
|
|
3442
3433
|
},
|
|
3443
3434
|
{
|
|
3444
3435
|
name: "showSearch",
|
|
@@ -3461,12 +3452,6 @@ var component_catalog_default = {
|
|
|
3461
3452
|
required: false,
|
|
3462
3453
|
description: "Placeholder text for search input"
|
|
3463
3454
|
},
|
|
3464
|
-
{
|
|
3465
|
-
name: "visibilityState",
|
|
3466
|
-
type: "VisibilityState",
|
|
3467
|
-
required: false,
|
|
3468
|
-
description: "Optional visibility state for reactivity"
|
|
3469
|
-
},
|
|
3470
3455
|
{
|
|
3471
3456
|
name: "filters",
|
|
3472
3457
|
type: "Snippet",
|
|
@@ -3498,7 +3483,7 @@ var component_catalog_default = {
|
|
|
3498
3483
|
examples: [
|
|
3499
3484
|
{
|
|
3500
3485
|
title: "Basic Usage",
|
|
3501
|
-
code: "<script>\n import { createDataTable, DataTableToolbar } from '@classic-homes/theme-svelte';\n\n const
|
|
3486
|
+
code: "<script>\n import { createDataTable, DataTableToolbar } from '@classic-homes/theme-svelte';\n\n const table = createDataTable(() => ({\n data: users,\n columns,\n getRowId: (row) => String(row.id),\n }));\n</script>\n\n<DataTableToolbar {table} /><table>...</table>"
|
|
3502
3487
|
},
|
|
3503
3488
|
{
|
|
3504
3489
|
title: "Search Only",
|
|
@@ -3548,10 +3533,10 @@ var component_catalog_default = {
|
|
|
3548
3533
|
props: [
|
|
3549
3534
|
{
|
|
3550
3535
|
name: "table",
|
|
3551
|
-
type: "
|
|
3536
|
+
type: "DataTableInstance<T>",
|
|
3552
3537
|
default: "**required**",
|
|
3553
3538
|
required: false,
|
|
3554
|
-
description: "The
|
|
3539
|
+
description: "The table instance from createDataTable"
|
|
3555
3540
|
},
|
|
3556
3541
|
{
|
|
3557
3542
|
name: "rowHeight",
|
|
@@ -3563,7 +3548,7 @@ var component_catalog_default = {
|
|
|
3563
3548
|
{
|
|
3564
3549
|
name: "overscan",
|
|
3565
3550
|
type: "number",
|
|
3566
|
-
default: "
|
|
3551
|
+
default: "10",
|
|
3567
3552
|
required: false,
|
|
3568
3553
|
description: "Number of rows to render outside visible area"
|
|
3569
3554
|
},
|
|
@@ -3580,13 +3565,6 @@ var component_catalog_default = {
|
|
|
3580
3565
|
required: false,
|
|
3581
3566
|
description: "Callback when row is clicked"
|
|
3582
3567
|
},
|
|
3583
|
-
{
|
|
3584
|
-
name: "enableRowSelection",
|
|
3585
|
-
type: "boolean",
|
|
3586
|
-
default: "false",
|
|
3587
|
-
required: false,
|
|
3588
|
-
description: "Enable row selection checkboxes"
|
|
3589
|
-
},
|
|
3590
3568
|
{
|
|
3591
3569
|
name: "class",
|
|
3592
3570
|
type: "string",
|
|
@@ -3609,13 +3587,12 @@ var component_catalog_default = {
|
|
|
3609
3587
|
code: `<script>
|
|
3610
3588
|
import { createDataTable, DataTableVirtual } from '@classic-homes/theme-svelte';
|
|
3611
3589
|
|
|
3612
|
-
const
|
|
3590
|
+
const table = createDataTable(() => ({
|
|
3613
3591
|
data: largeDataset, // 10,000+ rows
|
|
3614
3592
|
columns,
|
|
3593
|
+
getRowId: (row) => String(row.id),
|
|
3615
3594
|
manualPagination: true, // Disable pagination for virtualization
|
|
3616
3595
|
}));
|
|
3617
|
-
|
|
3618
|
-
const table = $derived(tableApi.instance);
|
|
3619
3596
|
</script>
|
|
3620
3597
|
|
|
3621
3598
|
<DataTableVirtual {table} height="600px" />`
|
|
@@ -3627,7 +3604,7 @@ var component_catalog_default = {
|
|
|
3627
3604
|
{
|
|
3628
3605
|
title: "With More Overscan",
|
|
3629
3606
|
description: "For smoother scrolling, increase the overscan:",
|
|
3630
|
-
code: '<DataTableVirtual {table} overscan={
|
|
3607
|
+
code: '<DataTableVirtual {table} overscan={15} height="600px" />'
|
|
3631
3608
|
},
|
|
3632
3609
|
{
|
|
3633
3610
|
title: "With Row Click Handler",
|
|
@@ -3635,22 +3612,7 @@ var component_catalog_default = {
|
|
|
3635
3612
|
},
|
|
3636
3613
|
{
|
|
3637
3614
|
title: "With Row Selection",
|
|
3638
|
-
code:
|
|
3639
|
-
let rowSelection = $state({});
|
|
3640
|
-
|
|
3641
|
-
const tableApi = createDataTable(() => ({
|
|
3642
|
-
data: largeDataset,
|
|
3643
|
-
columns,
|
|
3644
|
-
state: { rowSelection },
|
|
3645
|
-
onRowSelectionChange: (updater) => {
|
|
3646
|
-
rowSelection = typeof updater === 'function' ? updater(rowSelection) : updater;
|
|
3647
|
-
},
|
|
3648
|
-
enableRowSelection: true,
|
|
3649
|
-
manualPagination: true,
|
|
3650
|
-
}));
|
|
3651
|
-
</script>
|
|
3652
|
-
|
|
3653
|
-
<DataTableVirtual {table} enableRowSelection height="600px" />`
|
|
3615
|
+
code: '<script>\n let rowSelection = $state<Set<string>>(new Set());\n\n const table = createDataTable(() => ({\n data: largeDataset,\n columns,\n getRowId: (row) => String(row.id),\n manualPagination: true,\n onRowSelectionChange: (selection) => {\n rowSelection = selection;\n },\n }));\n</script>\n\n<DataTableVirtual {table} height="600px" />'
|
|
3654
3616
|
},
|
|
3655
3617
|
{
|
|
3656
3618
|
title: "Full Height Container",
|
|
@@ -4419,69 +4381,6 @@ var component_catalog_default = {
|
|
|
4419
4381
|
"Button"
|
|
4420
4382
|
]
|
|
4421
4383
|
},
|
|
4422
|
-
{
|
|
4423
|
-
name: "FlexRender",
|
|
4424
|
-
description: "Dynamic content renderer for TanStack Table cells and headers",
|
|
4425
|
-
category: "data",
|
|
4426
|
-
importPath: "@classic-homes/theme-svelte",
|
|
4427
|
-
props: [
|
|
4428
|
-
{
|
|
4429
|
-
name: "content",
|
|
4430
|
-
type: "unknown",
|
|
4431
|
-
default: "**required**",
|
|
4432
|
-
required: false,
|
|
4433
|
-
description: "Content to render (string, component, or function)"
|
|
4434
|
-
},
|
|
4435
|
-
{
|
|
4436
|
-
name: "props",
|
|
4437
|
-
type: "TProps",
|
|
4438
|
-
default: "**required**",
|
|
4439
|
-
required: false,
|
|
4440
|
-
description: "Props to pass to component or function"
|
|
4441
|
-
},
|
|
4442
|
-
{
|
|
4443
|
-
name: "asComponent",
|
|
4444
|
-
type: "boolean",
|
|
4445
|
-
default: "false",
|
|
4446
|
-
required: false,
|
|
4447
|
-
description: "Explicitly mark content as a Svelte component"
|
|
4448
|
-
}
|
|
4449
|
-
],
|
|
4450
|
-
variants: [],
|
|
4451
|
-
slots: [
|
|
4452
|
-
{
|
|
4453
|
-
name: "children",
|
|
4454
|
-
description: "Main content",
|
|
4455
|
-
required: false
|
|
4456
|
-
}
|
|
4457
|
-
],
|
|
4458
|
-
events: [],
|
|
4459
|
-
examples: [
|
|
4460
|
-
{
|
|
4461
|
-
title: "Basic Usage",
|
|
4462
|
-
code: "<script>\n import { createDataTable, FlexRender } from '@classic-homes/theme-svelte';\n\n const tableApi = createDataTable(() => ({ data: users, columns }));\n const table = $derived(tableApi.instance);\n</script>\n\n<table>\n <thead>\n {#each table.getHeaderGroups() as headerGroup}\n <tr>\n {#each headerGroup.headers as header}\n <th>\n <FlexRender content={header.column.columnDef.header} props={header.getContext()} />\n </th>\n {/each}\n </tr>\n {/each}\n </thead>\n <tbody>\n {#each table.getRowModel().rows as row}\n <tr>\n {#each row.getVisibleCells() as cell}\n <td>\n <FlexRender content={cell.column.columnDef.cell} props={cell.getContext()} />\n </td>\n {/each}\n </tr>\n {/each}\n </tbody>\n</table>"
|
|
4463
|
-
},
|
|
4464
|
-
{
|
|
4465
|
-
title: "With Custom Cell Component",
|
|
4466
|
-
code: `<!-- StatusBadge.svelte -->
|
|
4467
|
-
<script lang="ts">
|
|
4468
|
-
import type { CellContext } from '@classic-homes/theme-svelte';
|
|
4469
|
-
import Badge from './Badge.svelte';
|
|
4470
|
-
|
|
4471
|
-
let { getValue }: CellContext<User, string> = $props();
|
|
4472
|
-
const status = $derived(getValue());
|
|
4473
|
-
</script>
|
|
4474
|
-
|
|
4475
|
-
<Badge variant={status === 'active' ? 'success' : 'secondary'}>
|
|
4476
|
-
{status}
|
|
4477
|
-
</Badge>`
|
|
4478
|
-
}
|
|
4479
|
-
],
|
|
4480
|
-
relatedComponents: [
|
|
4481
|
-
"DataTable",
|
|
4482
|
-
"DataTableEditableCell"
|
|
4483
|
-
]
|
|
4484
|
-
},
|
|
4485
4384
|
{
|
|
4486
4385
|
name: "Footer",
|
|
4487
4386
|
description: "Site footer with link sections and branding",
|
|
@@ -6699,48 +6598,554 @@ var component_catalog_default = {
|
|
|
6699
6598
|
description: "Label text"
|
|
6700
6599
|
},
|
|
6701
6600
|
{
|
|
6702
|
-
name: "hint",
|
|
6703
|
-
type: "string",
|
|
6704
|
-
required: false,
|
|
6705
|
-
description: "Hint text below the input"
|
|
6601
|
+
name: "hint",
|
|
6602
|
+
type: "string",
|
|
6603
|
+
required: false,
|
|
6604
|
+
description: "Hint text below the input"
|
|
6605
|
+
},
|
|
6606
|
+
{
|
|
6607
|
+
name: "error",
|
|
6608
|
+
type: "string",
|
|
6609
|
+
required: false,
|
|
6610
|
+
description: "Error message"
|
|
6611
|
+
},
|
|
6612
|
+
{
|
|
6613
|
+
name: "max",
|
|
6614
|
+
type: "number",
|
|
6615
|
+
required: false,
|
|
6616
|
+
description: "Maximum selections allowed"
|
|
6617
|
+
},
|
|
6618
|
+
{
|
|
6619
|
+
name: "loading",
|
|
6620
|
+
type: "boolean",
|
|
6621
|
+
default: "false",
|
|
6622
|
+
required: false,
|
|
6623
|
+
description: "Shows loading state"
|
|
6624
|
+
},
|
|
6625
|
+
{
|
|
6626
|
+
name: "debounceMs",
|
|
6627
|
+
type: "number",
|
|
6628
|
+
default: "300",
|
|
6629
|
+
required: false,
|
|
6630
|
+
description: "Debounce time for search"
|
|
6631
|
+
},
|
|
6632
|
+
{
|
|
6633
|
+
name: "onValueChange",
|
|
6634
|
+
type: "(value: string[]) => void",
|
|
6635
|
+
required: false,
|
|
6636
|
+
description: "Callback when value changes"
|
|
6637
|
+
},
|
|
6638
|
+
{
|
|
6639
|
+
name: "onSearch",
|
|
6640
|
+
type: "(query: string) => void",
|
|
6641
|
+
required: false,
|
|
6642
|
+
description: "Callback for search queries"
|
|
6643
|
+
},
|
|
6644
|
+
{
|
|
6645
|
+
name: "class",
|
|
6646
|
+
type: "string",
|
|
6647
|
+
required: false,
|
|
6648
|
+
description: "Additional CSS classes"
|
|
6649
|
+
}
|
|
6650
|
+
],
|
|
6651
|
+
variants: [],
|
|
6652
|
+
slots: [
|
|
6653
|
+
{
|
|
6654
|
+
name: "children",
|
|
6655
|
+
description: "Main content",
|
|
6656
|
+
required: false
|
|
6657
|
+
}
|
|
6658
|
+
],
|
|
6659
|
+
events: [],
|
|
6660
|
+
examples: [
|
|
6661
|
+
{
|
|
6662
|
+
title: "Basic Usage",
|
|
6663
|
+
code: `<script>
|
|
6664
|
+
let selected = $state([]);
|
|
6665
|
+
|
|
6666
|
+
const options = [
|
|
6667
|
+
{ value: 'react', label: 'React' },
|
|
6668
|
+
{ value: 'svelte', label: 'Svelte' },
|
|
6669
|
+
{ value: 'vue', label: 'Vue' },
|
|
6670
|
+
{ value: 'angular', label: 'Angular' },
|
|
6671
|
+
];
|
|
6672
|
+
</script>
|
|
6673
|
+
|
|
6674
|
+
<MultiSelect {options} bind:value={selected} placeholder="Select frameworks..." />`
|
|
6675
|
+
},
|
|
6676
|
+
{
|
|
6677
|
+
title: "Tag Selector",
|
|
6678
|
+
code: `<script>
|
|
6679
|
+
let tags = $state([]);
|
|
6680
|
+
const tagOptions = [
|
|
6681
|
+
{ value: 'urgent', label: 'Urgent' },
|
|
6682
|
+
{ value: 'bug', label: 'Bug' },
|
|
6683
|
+
{ value: 'feature', label: 'Feature' },
|
|
6684
|
+
{ value: 'docs', label: 'Documentation' },
|
|
6685
|
+
];
|
|
6686
|
+
</script>
|
|
6687
|
+
|
|
6688
|
+
<MultiSelect
|
|
6689
|
+
label="Tags"
|
|
6690
|
+
hint="Add relevant tags"
|
|
6691
|
+
options={tagOptions}
|
|
6692
|
+
bind:value={tags}
|
|
6693
|
+
placeholder="Add tags..."
|
|
6694
|
+
/>`
|
|
6695
|
+
},
|
|
6696
|
+
{
|
|
6697
|
+
title: "Team Members",
|
|
6698
|
+
code: '<MultiSelect\n label="Assign to"\n hint="Select team members to assign this task"\n options={teamMembers}\n bind:value={assignees}\n max={5}\n placeholder="Select team members..."\n/>'
|
|
6699
|
+
}
|
|
6700
|
+
],
|
|
6701
|
+
relatedComponents: [
|
|
6702
|
+
"Select",
|
|
6703
|
+
"Combobox",
|
|
6704
|
+
"Checkbox"
|
|
6705
|
+
]
|
|
6706
|
+
},
|
|
6707
|
+
{
|
|
6708
|
+
name: "NoticeBanner",
|
|
6709
|
+
description: "Banner component for displaying scheduled, dismissible announcements",
|
|
6710
|
+
category: "feedback",
|
|
6711
|
+
importPath: "@classic-homes/theme-svelte",
|
|
6712
|
+
props: [
|
|
6713
|
+
{
|
|
6714
|
+
name: "class",
|
|
6715
|
+
type: "string",
|
|
6716
|
+
required: false,
|
|
6717
|
+
description: "Additional CSS classes"
|
|
6718
|
+
}
|
|
6719
|
+
],
|
|
6720
|
+
variants: [],
|
|
6721
|
+
slots: [
|
|
6722
|
+
{
|
|
6723
|
+
name: "children",
|
|
6724
|
+
description: "Main content",
|
|
6725
|
+
required: false
|
|
6726
|
+
}
|
|
6727
|
+
],
|
|
6728
|
+
events: [],
|
|
6729
|
+
examples: [
|
|
6730
|
+
{
|
|
6731
|
+
title: "Maintenance Notice",
|
|
6732
|
+
code: "<script>\n const notices = [\n {\n id: 'maintenance',\n title: 'Scheduled Maintenance',\n message: 'The system will be unavailable on Sunday 2-4 AM EST.',\n variant: 'warning',\n location: 'banner',\n dismissible: true,\n startDate: '2025-01-15',\n endDate: '2025-01-20',\n },\n ];\n\n initializeNotices(notices);\n</script>\n\n<NoticeBanner />"
|
|
6733
|
+
},
|
|
6734
|
+
{
|
|
6735
|
+
title: "With Link",
|
|
6736
|
+
code: "<script>\n const notices = [\n {\n id: 'new-feature',\n message: 'Check out our new dashboard features!',\n variant: 'info',\n location: 'banner',\n link: {\n text: 'Learn more',\n href: '/whats-new',\n },\n },\n ];\n</script>\n\n<NoticeBanner />"
|
|
6737
|
+
},
|
|
6738
|
+
{
|
|
6739
|
+
title: "Page-Specific Notice",
|
|
6740
|
+
code: "<script>\n const notices = [\n {\n id: 'billing-update',\n message: 'Your payment method will expire soon.',\n variant: 'warning',\n location: 'banner',\n pages: ['/settings', '/billing'],\n },\n ];\n\n initializeNotices(notices);\n setCurrentPath('/billing'); // Notice will show\n</script>\n\n<NoticeBanner />"
|
|
6741
|
+
},
|
|
6742
|
+
{
|
|
6743
|
+
title: "In Layout",
|
|
6744
|
+
code: "<!-- +layout.svelte -->\n<NoticeBanner />\n\n<main>\n <slot />\n</main>"
|
|
6745
|
+
}
|
|
6746
|
+
],
|
|
6747
|
+
relatedComponents: [
|
|
6748
|
+
"NoticeCard",
|
|
6749
|
+
"Alert"
|
|
6750
|
+
]
|
|
6751
|
+
},
|
|
6752
|
+
{
|
|
6753
|
+
name: "NoticeCard",
|
|
6754
|
+
description: "Card-style component for displaying inline scheduled announcements",
|
|
6755
|
+
category: "feedback",
|
|
6756
|
+
importPath: "@classic-homes/theme-svelte",
|
|
6757
|
+
props: [
|
|
6758
|
+
{
|
|
6759
|
+
name: "class",
|
|
6760
|
+
type: "string",
|
|
6761
|
+
required: false,
|
|
6762
|
+
description: "Additional CSS classes"
|
|
6763
|
+
}
|
|
6764
|
+
],
|
|
6765
|
+
variants: [],
|
|
6766
|
+
slots: [
|
|
6767
|
+
{
|
|
6768
|
+
name: "children",
|
|
6769
|
+
description: "Main content",
|
|
6770
|
+
required: false
|
|
6771
|
+
}
|
|
6772
|
+
],
|
|
6773
|
+
events: [],
|
|
6774
|
+
examples: [
|
|
6775
|
+
{
|
|
6776
|
+
title: "Basic Usage",
|
|
6777
|
+
code: "<script>\n import { NoticeCard, initializeNotices, setCurrentPath } from '@classic-homes/theme-svelte';\n\n const notices = [\n {\n id: 'welcome',\n title: 'Welcome!',\n message: 'Thanks for signing up. Complete your profile to get started.',\n variant: 'info',\n location: 'card',\n dismissible: true,\n },\n ];\n\n initializeNotices(notices);\n setCurrentPath('/dashboard');\n</script>\n\n<NoticeCard />"
|
|
6778
|
+
},
|
|
6779
|
+
{
|
|
6780
|
+
title: "Welcome Message",
|
|
6781
|
+
code: "<script>\n const notices = [\n {\n id: 'onboarding',\n title: 'Complete Your Profile',\n message: 'Add a photo and bio to help others recognize you.',\n variant: 'info',\n location: 'card',\n link: {\n text: 'Edit profile',\n href: '/settings/profile',\n },\n },\n ];\n</script>\n\n<NoticeCard />"
|
|
6782
|
+
},
|
|
6783
|
+
{
|
|
6784
|
+
title: "Feature Announcement",
|
|
6785
|
+
code: `<script>
|
|
6786
|
+
const notices = [
|
|
6787
|
+
{
|
|
6788
|
+
id: 'new-charts',
|
|
6789
|
+
title: 'New Charts Available',
|
|
6790
|
+
message: "We've added 5 new chart types to your dashboard.",
|
|
6791
|
+
variant: 'success',
|
|
6792
|
+
location: 'card',
|
|
6793
|
+
startDate: '2025-01-01',
|
|
6794
|
+
endDate: '2025-01-31',
|
|
6795
|
+
},
|
|
6796
|
+
];
|
|
6797
|
+
</script>
|
|
6798
|
+
|
|
6799
|
+
<NoticeCard />`
|
|
6800
|
+
},
|
|
6801
|
+
{
|
|
6802
|
+
title: "Warning Notice",
|
|
6803
|
+
code: `<script>
|
|
6804
|
+
const notices = [
|
|
6805
|
+
{
|
|
6806
|
+
id: 'storage-limit',
|
|
6807
|
+
message: "You're approaching your storage limit. Upgrade to continue uploading.",
|
|
6808
|
+
variant: 'warning',
|
|
6809
|
+
location: 'card',
|
|
6810
|
+
pages: ['/dashboard', '/files'],
|
|
6811
|
+
link: {
|
|
6812
|
+
text: 'Upgrade plan',
|
|
6813
|
+
href: '/billing/upgrade',
|
|
6814
|
+
},
|
|
6815
|
+
},
|
|
6816
|
+
];
|
|
6817
|
+
</script>
|
|
6818
|
+
|
|
6819
|
+
<NoticeCard />`
|
|
6820
|
+
},
|
|
6821
|
+
{
|
|
6822
|
+
title: "In Page Content",
|
|
6823
|
+
code: '<div class="space-y-4">\n <NoticeCard />\n\n <Card>\n <CardHeader>\n <CardTitle>Dashboard</CardTitle>\n </CardHeader>\n <CardContent>\n <!-- Main content -->\n </CardContent>\n </Card>\n</div>'
|
|
6824
|
+
},
|
|
6825
|
+
{
|
|
6826
|
+
title: "Custom Styling",
|
|
6827
|
+
code: '<NoticeCard class="mb-6" />'
|
|
6828
|
+
}
|
|
6829
|
+
],
|
|
6830
|
+
relatedComponents: [
|
|
6831
|
+
"NoticeBanner",
|
|
6832
|
+
"Alert"
|
|
6833
|
+
]
|
|
6834
|
+
},
|
|
6835
|
+
{
|
|
6836
|
+
name: "NotificationBadge",
|
|
6837
|
+
description: "Unread notification count indicator for bell icons and buttons",
|
|
6838
|
+
category: "feedback",
|
|
6839
|
+
importPath: "@classic-homes/theme-svelte",
|
|
6840
|
+
props: [
|
|
6841
|
+
{
|
|
6842
|
+
name: "count",
|
|
6843
|
+
type: "number",
|
|
6844
|
+
required: false,
|
|
6845
|
+
description: "Number of unread notifications"
|
|
6846
|
+
},
|
|
6847
|
+
{
|
|
6848
|
+
name: "max",
|
|
6849
|
+
type: "number",
|
|
6850
|
+
default: "99",
|
|
6851
|
+
required: false,
|
|
6852
|
+
description: 'Maximum number to display (shows "N+" for more)'
|
|
6853
|
+
},
|
|
6854
|
+
{
|
|
6855
|
+
name: "showZero",
|
|
6856
|
+
type: "boolean",
|
|
6857
|
+
default: "false",
|
|
6858
|
+
required: false,
|
|
6859
|
+
description: "Whether to show the badge when count is 0"
|
|
6860
|
+
},
|
|
6861
|
+
{
|
|
6862
|
+
name: "size",
|
|
6863
|
+
type: "'sm' | 'md' | 'lg'",
|
|
6864
|
+
default: "'md'",
|
|
6865
|
+
required: false,
|
|
6866
|
+
description: "Size variant"
|
|
6867
|
+
},
|
|
6868
|
+
{
|
|
6869
|
+
name: "children",
|
|
6870
|
+
type: "Snippet",
|
|
6871
|
+
required: false,
|
|
6872
|
+
description: "Optional children (e.g., button or icon to wrap)"
|
|
6873
|
+
},
|
|
6874
|
+
{
|
|
6875
|
+
name: "class",
|
|
6876
|
+
type: "string",
|
|
6877
|
+
required: false,
|
|
6878
|
+
description: "Additional CSS classes"
|
|
6879
|
+
}
|
|
6880
|
+
],
|
|
6881
|
+
variants: [
|
|
6882
|
+
{
|
|
6883
|
+
name: "size",
|
|
6884
|
+
values: [
|
|
6885
|
+
"sm",
|
|
6886
|
+
"md",
|
|
6887
|
+
"lg"
|
|
6888
|
+
],
|
|
6889
|
+
default: "md"
|
|
6890
|
+
}
|
|
6891
|
+
],
|
|
6892
|
+
slots: [
|
|
6893
|
+
{
|
|
6894
|
+
name: "children",
|
|
6895
|
+
description: "Main content",
|
|
6896
|
+
required: false
|
|
6897
|
+
}
|
|
6898
|
+
],
|
|
6899
|
+
events: [],
|
|
6900
|
+
examples: [
|
|
6901
|
+
{
|
|
6902
|
+
title: "Basic Usage",
|
|
6903
|
+
code: "<NotificationBadge count={5} />"
|
|
6904
|
+
},
|
|
6905
|
+
{
|
|
6906
|
+
title: "In a Header",
|
|
6907
|
+
code: '<header class="flex items-center gap-4">\n <NotificationBadge count={unreadCount}>\n {#snippet children()}\n <button\n class="p-2 rounded-full hover:bg-muted"\n onclick={openNotifications}\n aria-label="View notifications"\n >\n <Icon name="bell" size={24} />\n </button>\n {/snippet}\n </NotificationBadge>\n</header>'
|
|
6908
|
+
},
|
|
6909
|
+
{
|
|
6910
|
+
title: "Dynamic Updates",
|
|
6911
|
+
code: "<script>\n import { notificationStore } from '@classic-homes/notifications/svelte';\n\n const unreadCount = $derived(notificationStore.notifications.filter((n) => !n.read).length);\n</script>\n\n<NotificationBadge count={unreadCount} />"
|
|
6912
|
+
}
|
|
6913
|
+
],
|
|
6914
|
+
relatedComponents: [
|
|
6915
|
+
"NotificationList",
|
|
6916
|
+
"NotificationDialog",
|
|
6917
|
+
"Badge"
|
|
6918
|
+
]
|
|
6919
|
+
},
|
|
6920
|
+
{
|
|
6921
|
+
name: "NotificationBulkActions",
|
|
6922
|
+
description: "Toolbar for selecting and performing bulk actions on notifications",
|
|
6923
|
+
category: "feedback",
|
|
6924
|
+
importPath: "@classic-homes/theme-svelte",
|
|
6925
|
+
props: [
|
|
6926
|
+
{
|
|
6927
|
+
name: "selectedCount",
|
|
6928
|
+
type: "number",
|
|
6929
|
+
required: false,
|
|
6930
|
+
description: "Number of currently selected notifications"
|
|
6931
|
+
},
|
|
6932
|
+
{
|
|
6933
|
+
name: "totalCount",
|
|
6934
|
+
type: "number",
|
|
6935
|
+
required: false,
|
|
6936
|
+
description: "Total number of notifications available"
|
|
6937
|
+
},
|
|
6938
|
+
{
|
|
6939
|
+
name: "allSelected",
|
|
6940
|
+
type: "boolean",
|
|
6941
|
+
default: "false",
|
|
6942
|
+
required: false,
|
|
6943
|
+
description: "Whether all notifications are selected"
|
|
6944
|
+
},
|
|
6945
|
+
{
|
|
6946
|
+
name: "onSelectAll",
|
|
6947
|
+
type: "(selected: boolean) => void",
|
|
6948
|
+
required: false,
|
|
6949
|
+
description: "Callback to select/deselect all"
|
|
6950
|
+
},
|
|
6951
|
+
{
|
|
6952
|
+
name: "onMarkRead",
|
|
6953
|
+
type: "() => void",
|
|
6954
|
+
required: false,
|
|
6955
|
+
description: "Callback to mark selected as read"
|
|
6956
|
+
},
|
|
6957
|
+
{
|
|
6958
|
+
name: "onMarkUnread",
|
|
6959
|
+
type: "() => void",
|
|
6960
|
+
required: false,
|
|
6961
|
+
description: "Callback to mark selected as unread"
|
|
6962
|
+
},
|
|
6963
|
+
{
|
|
6964
|
+
name: "onDelete",
|
|
6965
|
+
type: "() => void",
|
|
6966
|
+
required: false,
|
|
6967
|
+
description: "Callback to delete selected"
|
|
6968
|
+
},
|
|
6969
|
+
{
|
|
6970
|
+
name: "onClearSelection",
|
|
6971
|
+
type: "() => void",
|
|
6972
|
+
required: false,
|
|
6973
|
+
description: "Callback to clear selection"
|
|
6974
|
+
},
|
|
6975
|
+
{
|
|
6976
|
+
name: "class",
|
|
6977
|
+
type: "string",
|
|
6978
|
+
required: false,
|
|
6979
|
+
description: "Additional CSS classes"
|
|
6980
|
+
}
|
|
6981
|
+
],
|
|
6982
|
+
variants: [],
|
|
6983
|
+
slots: [
|
|
6984
|
+
{
|
|
6985
|
+
name: "children",
|
|
6986
|
+
description: "Main content",
|
|
6987
|
+
required: false
|
|
6988
|
+
}
|
|
6989
|
+
],
|
|
6990
|
+
events: [],
|
|
6991
|
+
examples: [
|
|
6992
|
+
{
|
|
6993
|
+
title: "Basic Usage",
|
|
6994
|
+
code: "<script>\n let selectedIds = $state(new Set<string>());\n const notifications = [...];\n</script>\n\n<NotificationBulkActions\n selectedCount={selectedIds.size}\n totalCount={notifications.length}\n allSelected={selectedIds.size === notifications.length}\n onSelectAll={(selected) => {\n /* ... */\n }}\n onMarkRead={() => {\n /* ... */\n }}\n onMarkUnread={() => {\n /* ... */\n }}\n onDelete={() => {\n /* ... */\n }}\n/>"
|
|
6995
|
+
},
|
|
6996
|
+
{
|
|
6997
|
+
title: "No Selection",
|
|
6998
|
+
description: 'When no items are selected, only the "Select all" checkbox is shown:',
|
|
6999
|
+
code: "<NotificationBulkActions selectedCount={0} totalCount={10} allSelected={false} />"
|
|
7000
|
+
},
|
|
7001
|
+
{
|
|
7002
|
+
title: "Partial Selection",
|
|
7003
|
+
description: "When some items are selected, action buttons appear:",
|
|
7004
|
+
code: '<NotificationBulkActions selectedCount={3} totalCount={10} allSelected={false} />\n<!-- Shows: "3 of 10 selected" with Clear button and action buttons -->'
|
|
7005
|
+
},
|
|
7006
|
+
{
|
|
7007
|
+
title: "All Selected",
|
|
7008
|
+
description: "When all items are selected:",
|
|
7009
|
+
code: "<NotificationBulkActions selectedCount={10} totalCount={10} allSelected={true} />"
|
|
7010
|
+
},
|
|
7011
|
+
{
|
|
7012
|
+
title: "Select All",
|
|
7013
|
+
description: "Toggle selection of all visible notifications:",
|
|
7014
|
+
code: "<script>\n function handleSelectAll(selected: boolean) {\n if (selected) {\n selectedIds = new Set(filteredNotifications().map(n => n.id));\n } else {\n selectedIds = new Set();\n }\n }\n</script>\n\n<NotificationBulkActions\n onSelectAll={handleSelectAll}\n {...}\n/>"
|
|
7015
|
+
},
|
|
7016
|
+
{
|
|
7017
|
+
title: "Mark as Read",
|
|
7018
|
+
description: "Mark all selected notifications as read:",
|
|
7019
|
+
code: "<script>\n function handleBulkMarkRead() {\n const count = selectedIds.size;\n notifications = notifications.map(n =>\n selectedIds.has(n.id)\n ? { ...n, read: true, readAt: new Date().toISOString() }\n : n\n );\n selectedIds = new Set();\n toastStore.success(`Marked ${count} notifications as read`);\n }\n</script>\n\n<NotificationBulkActions\n onMarkRead={handleBulkMarkRead}\n {...}\n/>"
|
|
7020
|
+
},
|
|
7021
|
+
{
|
|
7022
|
+
title: "Mark as Unread",
|
|
7023
|
+
description: "Mark all selected notifications as unread:",
|
|
7024
|
+
code: "<script>\n function handleBulkMarkUnread() {\n const count = selectedIds.size;\n notifications = notifications.map(n =>\n selectedIds.has(n.id)\n ? { ...n, read: false, readAt: undefined }\n : n\n );\n selectedIds = new Set();\n toastStore.info(`Marked ${count} notifications as unread`);\n }\n</script>\n\n<NotificationBulkActions\n onMarkUnread={handleBulkMarkUnread}\n {...}\n/>"
|
|
7025
|
+
},
|
|
7026
|
+
{
|
|
7027
|
+
title: "Delete",
|
|
7028
|
+
description: "Delete all selected notifications:",
|
|
7029
|
+
code: "<script>\n function handleBulkDelete() {\n const count = selectedIds.size;\n notifications = notifications.filter(n => !selectedIds.has(n.id));\n selectedIds = new Set();\n toastStore.info(`Deleted ${count} notifications`);\n }\n</script>\n\n<NotificationBulkActions\n onDelete={handleBulkDelete}\n {...}\n/>"
|
|
7030
|
+
},
|
|
7031
|
+
{
|
|
7032
|
+
title: "Complete Implementation",
|
|
7033
|
+
code: "<script>\n import {\n NotificationList,\n NotificationFilters,\n NotificationBulkActions,\n toastStore,\n } from '@classic-homes/theme-svelte';\n import type { Notification, NotificationFilter, NotificationCounts } from '@classic-homes/notifications/core';\n\n let notifications = $state<Notification[]>([...]);\n let filter = $state<NotificationFilter>('all');\n let selectedIds = $state(new Set<string>());\n\n const filteredNotifications = $derived(() => {\n switch (filter) {\n case 'unread': return notifications.filter(n => !n.read);\n case 'read': return notifications.filter(n => n.read);\n default: return notifications;\n }\n });\n\n const counts = $derived<NotificationCounts>({\n all: notifications.length,\n unread: notifications.filter(n => !n.read).length,\n read: notifications.filter(n => n.read).length,\n });\n\n const allSelected = $derived(\n filteredNotifications().length > 0 &&\n filteredNotifications().every(n => selectedIds.has(n.id))\n );\n\n function handleToggleSelect(id: string, selected: boolean) {\n const newSet = new Set(selectedIds);\n if (selected) newSet.add(id);\n else newSet.delete(id);\n selectedIds = newSet;\n }\n\n function handleSelectAll(selected: boolean) {\n if (selected) {\n selectedIds = new Set(filteredNotifications().map(n => n.id));\n } else {\n selectedIds = new Set();\n }\n }\n\n function handleClearSelection() {\n selectedIds = new Set();\n }\n\n function handleBulkMarkRead() {\n notifications = notifications.map(n =>\n selectedIds.has(n.id)\n ? { ...n, read: true, readAt: new Date().toISOString() }\n : n\n );\n selectedIds = new Set();\n toastStore.success('Marked as read');\n }\n\n function handleBulkMarkUnread() {\n notifications = notifications.map(n =>\n selectedIds.has(n.id)\n ? { ...n, read: false, readAt: undefined }\n : n\n );\n selectedIds = new Set();\n toastStore.info('Marked as unread');\n }\n\n function handleBulkDelete() {\n notifications = notifications.filter(n => !selectedIds.has(n.id));\n selectedIds = new Set();\n toastStore.info('Deleted');\n }\n</script>\n\n<NotificationFilters bind:filter {counts} onFilterChange={() => (selectedIds = new Set())} />\n\n{#if filteredNotifications().length > 0}\n <NotificationBulkActions\n selectedCount={selectedIds.size}\n totalCount={filteredNotifications().length}\n {allSelected}\n onSelectAll={handleSelectAll}\n onMarkRead={handleBulkMarkRead}\n onMarkUnread={handleBulkMarkUnread}\n onDelete={handleBulkDelete}\n onClearSelection={handleClearSelection}\n />\n{/if}\n\n<NotificationList\n notifications={filteredNotifications()}\n {selectedIds}\n selectable={true}\n onToggleSelect={handleToggleSelect}\n/>"
|
|
7034
|
+
}
|
|
7035
|
+
],
|
|
7036
|
+
relatedComponents: [
|
|
7037
|
+
"NotificationList",
|
|
7038
|
+
"NotificationFilters",
|
|
7039
|
+
"NotificationItem"
|
|
7040
|
+
]
|
|
7041
|
+
},
|
|
7042
|
+
{
|
|
7043
|
+
name: "NotificationDialog",
|
|
7044
|
+
description: "Modal dialog for viewing full notification details with actions",
|
|
7045
|
+
category: "feedback",
|
|
7046
|
+
importPath: "@classic-homes/theme-svelte",
|
|
7047
|
+
props: [
|
|
7048
|
+
{
|
|
7049
|
+
name: "notification",
|
|
7050
|
+
type: "Notification | null",
|
|
7051
|
+
required: false,
|
|
7052
|
+
description: "The notification to display"
|
|
7053
|
+
},
|
|
7054
|
+
{
|
|
7055
|
+
name: "open",
|
|
7056
|
+
type: "boolean",
|
|
7057
|
+
default: "false",
|
|
7058
|
+
required: false,
|
|
7059
|
+
description: "Whether the dialog is open (bindable)"
|
|
7060
|
+
},
|
|
7061
|
+
{
|
|
7062
|
+
name: "onClose",
|
|
7063
|
+
type: "() => void",
|
|
7064
|
+
required: false,
|
|
7065
|
+
description: "Callback when the dialog should close"
|
|
7066
|
+
},
|
|
7067
|
+
{
|
|
7068
|
+
name: "onMarkRead",
|
|
7069
|
+
type: "(id: string) => void",
|
|
7070
|
+
required: false,
|
|
7071
|
+
description: "Callback to mark notification as read"
|
|
7072
|
+
},
|
|
7073
|
+
{
|
|
7074
|
+
name: "onMarkUnread",
|
|
7075
|
+
type: "(id: string) => void",
|
|
7076
|
+
required: false,
|
|
7077
|
+
description: "Callback to mark as unread"
|
|
7078
|
+
},
|
|
7079
|
+
{
|
|
7080
|
+
name: "onDelete",
|
|
7081
|
+
type: "(id: string) => void",
|
|
7082
|
+
required: false,
|
|
7083
|
+
description: "Callback to delete notification"
|
|
7084
|
+
}
|
|
7085
|
+
],
|
|
7086
|
+
variants: [],
|
|
7087
|
+
slots: [
|
|
7088
|
+
{
|
|
7089
|
+
name: "children",
|
|
7090
|
+
description: "Main content",
|
|
7091
|
+
required: false
|
|
7092
|
+
}
|
|
7093
|
+
],
|
|
7094
|
+
events: [],
|
|
7095
|
+
examples: [
|
|
7096
|
+
{
|
|
7097
|
+
title: "Basic Usage",
|
|
7098
|
+
code: "<script>\n import type { Notification } from '@classic-homes/notifications/core';\n\n let notification = $state<Notification | null>(null);\n let open = $state(false);\n</script>\n\n<NotificationDialog {notification} bind:open />"
|
|
6706
7099
|
},
|
|
6707
7100
|
{
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
description: "Error message"
|
|
7101
|
+
title: "Mark as Read/Unread",
|
|
7102
|
+
description: "The dialog shows contextual buttons based on read status:",
|
|
7103
|
+
code: "<NotificationDialog\n {notification}\n bind:open\n onMarkRead={(id) => {\n notifications = notifications.map((n) =>\n n.id === id ? { ...n, read: true, readAt: new Date().toISOString() } : n\n );\n }}\n onMarkUnread={(id) => {\n notifications = notifications.map((n) =>\n n.id === id ? { ...n, read: false, readAt: undefined } : n\n );\n }}\n/>"
|
|
6712
7104
|
},
|
|
6713
7105
|
{
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
required: false,
|
|
6717
|
-
description: "Maximum selections allowed"
|
|
7106
|
+
title: "Delete",
|
|
7107
|
+
code: "<NotificationDialog\n {notification}\n bind:open\n onDelete={(id) => {\n notifications = notifications.filter((n) => n.id !== id);\n open = false;\n }}\n/>"
|
|
6718
7108
|
},
|
|
6719
7109
|
{
|
|
6720
|
-
|
|
6721
|
-
type: "
|
|
6722
|
-
default: "false",
|
|
6723
|
-
required: false,
|
|
6724
|
-
description: "Shows loading state"
|
|
7110
|
+
title: "Complete Implementation",
|
|
7111
|
+
code: "<script>\n import { NotificationList, NotificationDialog, toastStore } from '@classic-homes/theme-svelte';\n import type { Notification } from '@classic-homes/notifications/core';\n\n let notifications = $state<Notification[]>([...]);\n let selectedNotification = $state<Notification | null>(null);\n let dialogOpen = $state(false);\n\n function handleNotificationClick(notification: Notification) {\n selectedNotification = notification;\n dialogOpen = true;\n }\n\n function handleDialogClose() {\n dialogOpen = false;\n selectedNotification = null;\n }\n\n function markAsRead(id: string) {\n notifications = notifications.map(n =>\n n.id === id ? { ...n, read: true, readAt: new Date().toISOString() } : n\n );\n toastStore.success('Notification marked as read');\n }\n\n function markAsUnread(id: string) {\n notifications = notifications.map(n =>\n n.id === id ? { ...n, read: false, readAt: undefined } : n\n );\n toastStore.info('Notification marked as unread');\n }\n\n function deleteNotification(id: string) {\n notifications = notifications.filter(n => n.id !== id);\n handleDialogClose();\n toastStore.info('Notification deleted');\n }\n</script>\n\n<NotificationList {notifications} onNotificationClick={handleNotificationClick} />\n\n<NotificationDialog\n notification={selectedNotification}\n bind:open={dialogOpen}\n onClose={handleDialogClose}\n onMarkRead={markAsRead}\n onMarkUnread={markAsUnread}\n onDelete={deleteNotification}\n/>"
|
|
6725
7112
|
},
|
|
6726
7113
|
{
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
7114
|
+
title: "With Action Links",
|
|
7115
|
+
description: "Notifications with action URLs display a primary action button:",
|
|
7116
|
+
code: "<!-- Notification with actionUrl and actionLabel -->\n<NotificationDialog\n notification={{\n ...notification,\n actionUrl: '/settings/security',\n actionLabel: 'Review Activity',\n }}\n bind:open\n/>"
|
|
7117
|
+
}
|
|
7118
|
+
],
|
|
7119
|
+
relatedComponents: [
|
|
7120
|
+
"NotificationList",
|
|
7121
|
+
"NotificationItem",
|
|
7122
|
+
"Dialog"
|
|
7123
|
+
]
|
|
7124
|
+
},
|
|
7125
|
+
{
|
|
7126
|
+
name: "NotificationFilters",
|
|
7127
|
+
description: "Filter tabs for notification lists with counts",
|
|
7128
|
+
category: "feedback",
|
|
7129
|
+
importPath: "@classic-homes/theme-svelte",
|
|
7130
|
+
props: [
|
|
7131
|
+
{
|
|
7132
|
+
name: "filter",
|
|
7133
|
+
type: "NotificationFilter",
|
|
7134
|
+
default: "'all'",
|
|
6730
7135
|
required: false,
|
|
6731
|
-
description: "
|
|
7136
|
+
description: "Current active filter (bindable)"
|
|
6732
7137
|
},
|
|
6733
7138
|
{
|
|
6734
|
-
name: "
|
|
6735
|
-
type: "
|
|
7139
|
+
name: "counts",
|
|
7140
|
+
type: "NotificationCounts",
|
|
6736
7141
|
required: false,
|
|
6737
|
-
description: "
|
|
7142
|
+
description: "Counts for each filter tab"
|
|
6738
7143
|
},
|
|
6739
7144
|
{
|
|
6740
|
-
name: "
|
|
6741
|
-
type: "(
|
|
7145
|
+
name: "onFilterChange",
|
|
7146
|
+
type: "(filter: NotificationFilter) => void",
|
|
6742
7147
|
required: false,
|
|
6743
|
-
description: "Callback
|
|
7148
|
+
description: "Callback when filter changes"
|
|
6744
7149
|
},
|
|
6745
7150
|
{
|
|
6746
7151
|
name: "class",
|
|
@@ -6761,56 +7166,61 @@ var component_catalog_default = {
|
|
|
6761
7166
|
examples: [
|
|
6762
7167
|
{
|
|
6763
7168
|
title: "Basic Usage",
|
|
6764
|
-
code:
|
|
6765
|
-
let selected = $state([]);
|
|
6766
|
-
|
|
6767
|
-
const options = [
|
|
6768
|
-
{ value: 'react', label: 'React' },
|
|
6769
|
-
{ value: 'svelte', label: 'Svelte' },
|
|
6770
|
-
{ value: 'vue', label: 'Vue' },
|
|
6771
|
-
{ value: 'angular', label: 'Angular' },
|
|
6772
|
-
];
|
|
6773
|
-
</script>
|
|
6774
|
-
|
|
6775
|
-
<MultiSelect {options} bind:value={selected} placeholder="Select frameworks..." />`
|
|
7169
|
+
code: "<script>\n import type { NotificationFilter, NotificationCounts } from '@classic-homes/notifications/core';\n\n let filter = $state<NotificationFilter>('all');\n const counts: NotificationCounts = {\n all: 10,\n unread: 3,\n read: 7,\n };\n</script>\n\n<NotificationFilters bind:filter {counts} />"
|
|
6776
7170
|
},
|
|
6777
7171
|
{
|
|
6778
|
-
title: "
|
|
6779
|
-
code:
|
|
6780
|
-
let tags = $state([]);
|
|
6781
|
-
const tagOptions = [
|
|
6782
|
-
{ value: 'urgent', label: 'Urgent' },
|
|
6783
|
-
{ value: 'bug', label: 'Bug' },
|
|
6784
|
-
{ value: 'feature', label: 'Feature' },
|
|
6785
|
-
{ value: 'docs', label: 'Documentation' },
|
|
6786
|
-
];
|
|
6787
|
-
</script>
|
|
6788
|
-
|
|
6789
|
-
<MultiSelect
|
|
6790
|
-
label="Tags"
|
|
6791
|
-
hint="Add relevant tags"
|
|
6792
|
-
options={tagOptions}
|
|
6793
|
-
bind:value={tags}
|
|
6794
|
-
placeholder="Add tags..."
|
|
6795
|
-
/>`
|
|
7172
|
+
title: "With Notification List",
|
|
7173
|
+
code: "<script>\n import {\n NotificationFilters,\n NotificationList,\n } from '@classic-homes/theme-svelte';\n import type { Notification, NotificationFilter, NotificationCounts } from '@classic-homes/notifications/core';\n\n let notifications = $state<Notification[]>([...]);\n let filter = $state<NotificationFilter>('all');\n\n const counts = $derived<NotificationCounts>({\n all: notifications.length,\n unread: notifications.filter(n => !n.read).length,\n read: notifications.filter(n => n.read).length,\n });\n\n const filteredNotifications = $derived(() => {\n switch (filter) {\n case 'unread': return notifications.filter(n => !n.read);\n case 'read': return notifications.filter(n => n.read);\n default: return notifications;\n }\n });\n</script>\n\n<NotificationFilters bind:filter {counts} />\n\n<NotificationList\n notifications={filteredNotifications()}\n emptyTitle={filter === 'unread'\n ? 'No unread notifications'\n : filter === 'read'\n ? 'No read notifications'\n : 'No notifications'}\n/>"
|
|
6796
7174
|
},
|
|
6797
7175
|
{
|
|
6798
|
-
title: "
|
|
6799
|
-
code:
|
|
7176
|
+
title: "Reset Selection on Filter Change",
|
|
7177
|
+
code: "<script>\n let selectedIds = $state(new Set<string>());\n\n function handleFilterChange(newFilter: NotificationFilter) {\n filter = newFilter;\n selectedIds = new Set(); // Clear selection\n }\n</script>\n\n<NotificationFilters\n bind:filter\n {counts}\n onFilterChange={handleFilterChange}\n/>\n\n<NotificationBulkActions\n selectedCount={selectedIds.size}\n totalCount={filteredNotifications().length}\n {...}\n/>"
|
|
6800
7178
|
}
|
|
6801
7179
|
],
|
|
6802
7180
|
relatedComponents: [
|
|
6803
|
-
"
|
|
6804
|
-
"
|
|
6805
|
-
"
|
|
7181
|
+
"NotificationList",
|
|
7182
|
+
"NotificationBulkActions",
|
|
7183
|
+
"Tabs"
|
|
6806
7184
|
]
|
|
6807
7185
|
},
|
|
6808
7186
|
{
|
|
6809
|
-
name: "
|
|
6810
|
-
description: "
|
|
7187
|
+
name: "NotificationItem",
|
|
7188
|
+
description: "Single notification card with icon, title, message, and actions",
|
|
6811
7189
|
category: "feedback",
|
|
6812
7190
|
importPath: "@classic-homes/theme-svelte",
|
|
6813
7191
|
props: [
|
|
7192
|
+
{
|
|
7193
|
+
name: "notification",
|
|
7194
|
+
type: "Notification",
|
|
7195
|
+
required: false,
|
|
7196
|
+
description: "The notification object to display"
|
|
7197
|
+
},
|
|
7198
|
+
{
|
|
7199
|
+
name: "isSelected",
|
|
7200
|
+
type: "boolean",
|
|
7201
|
+
default: "false",
|
|
7202
|
+
required: false,
|
|
7203
|
+
description: "Whether this notification is selected"
|
|
7204
|
+
},
|
|
7205
|
+
{
|
|
7206
|
+
name: "selectable",
|
|
7207
|
+
type: "boolean",
|
|
7208
|
+
default: "false",
|
|
7209
|
+
required: false,
|
|
7210
|
+
description: "Whether selection mode is enabled"
|
|
7211
|
+
},
|
|
7212
|
+
{
|
|
7213
|
+
name: "onToggleSelect",
|
|
7214
|
+
type: "(id: string, selected: boolean) => void",
|
|
7215
|
+
required: false,
|
|
7216
|
+
description: "Callback when selection state changes"
|
|
7217
|
+
},
|
|
7218
|
+
{
|
|
7219
|
+
name: "onClick",
|
|
7220
|
+
type: "(notification: Notification) => void",
|
|
7221
|
+
required: false,
|
|
7222
|
+
description: "Callback when notification is clicked"
|
|
7223
|
+
},
|
|
6814
7224
|
{
|
|
6815
7225
|
name: "class",
|
|
6816
7226
|
type: "string",
|
|
@@ -6829,33 +7239,104 @@ var component_catalog_default = {
|
|
|
6829
7239
|
events: [],
|
|
6830
7240
|
examples: [
|
|
6831
7241
|
{
|
|
6832
|
-
title: "
|
|
6833
|
-
code: "<script>\n const
|
|
7242
|
+
title: "Basic Usage",
|
|
7243
|
+
code: "<script>\n import type { Notification } from '@classic-homes/notifications/core';\n\n const notification: Notification = {\n id: '1',\n userId: 'user-1',\n type: 'info',\n category: 'general',\n title: 'Welcome!',\n message: 'Thanks for signing up.',\n priority: 'normal',\n read: false,\n dismissed: false,\n createdAt: new Date().toISOString(),\n };\n</script>\n\n<NotificationItem {notification} />"
|
|
6834
7244
|
},
|
|
6835
7245
|
{
|
|
6836
|
-
title: "
|
|
6837
|
-
|
|
7246
|
+
title: "Unread",
|
|
7247
|
+
description: "Unread notifications have a light blue background and blue border:",
|
|
7248
|
+
code: "<NotificationItem notification={{ ...notification, read: false }} />"
|
|
6838
7249
|
},
|
|
6839
7250
|
{
|
|
6840
|
-
title: "
|
|
6841
|
-
|
|
7251
|
+
title: "Read",
|
|
7252
|
+
description: "Read notifications have a neutral card background:",
|
|
7253
|
+
code: "<NotificationItem notification={{ ...notification, read: true }} />"
|
|
6842
7254
|
},
|
|
6843
7255
|
{
|
|
6844
|
-
title: "
|
|
6845
|
-
|
|
7256
|
+
title: "Priority Badges",
|
|
7257
|
+
description: "Non-normal priorities display a badge:",
|
|
7258
|
+
code: `<!-- Shows "urgent" badge -->
|
|
7259
|
+
<NotificationItem notification={{ ...notification, priority: 'urgent' }} />
|
|
7260
|
+
|
|
7261
|
+
<!-- Shows "high" badge -->
|
|
7262
|
+
<NotificationItem notification={{ ...notification, priority: 'high' }} />`
|
|
7263
|
+
},
|
|
7264
|
+
{
|
|
7265
|
+
title: "In a List",
|
|
7266
|
+
code: "{#each notifications as notification (notification.id)}\n <NotificationItem\n {notification}\n selectable={true}\n isSelected={selectedIds.has(notification.id)}\n onToggleSelect={handleToggleSelect}\n onClick={handleNotificationClick}\n />\n{/each}"
|
|
6846
7267
|
}
|
|
6847
7268
|
],
|
|
6848
7269
|
relatedComponents: [
|
|
6849
|
-
"
|
|
6850
|
-
"
|
|
7270
|
+
"NotificationList",
|
|
7271
|
+
"NotificationDialog",
|
|
7272
|
+
"NotificationBadge"
|
|
6851
7273
|
]
|
|
6852
7274
|
},
|
|
6853
7275
|
{
|
|
6854
|
-
name: "
|
|
6855
|
-
description: "
|
|
7276
|
+
name: "NotificationList",
|
|
7277
|
+
description: "Container for displaying a list of notifications with empty states and loading skeletons",
|
|
6856
7278
|
category: "feedback",
|
|
6857
7279
|
importPath: "@classic-homes/theme-svelte",
|
|
6858
7280
|
props: [
|
|
7281
|
+
{
|
|
7282
|
+
name: "notifications",
|
|
7283
|
+
type: "Notification[]",
|
|
7284
|
+
required: false,
|
|
7285
|
+
description: "List of notifications to display"
|
|
7286
|
+
},
|
|
7287
|
+
{
|
|
7288
|
+
name: "selectedIds",
|
|
7289
|
+
type: "Set<string>",
|
|
7290
|
+
default: "new Set()",
|
|
7291
|
+
required: false,
|
|
7292
|
+
description: "Set of selected notification IDs"
|
|
7293
|
+
},
|
|
7294
|
+
{
|
|
7295
|
+
name: "selectable",
|
|
7296
|
+
type: "boolean",
|
|
7297
|
+
default: "false",
|
|
7298
|
+
required: false,
|
|
7299
|
+
description: "Whether selection mode is enabled"
|
|
7300
|
+
},
|
|
7301
|
+
{
|
|
7302
|
+
name: "onToggleSelect",
|
|
7303
|
+
type: "(id: string, selected: boolean) => void",
|
|
7304
|
+
required: false,
|
|
7305
|
+
description: "Callback when a notification's selection changes"
|
|
7306
|
+
},
|
|
7307
|
+
{
|
|
7308
|
+
name: "onNotificationClick",
|
|
7309
|
+
type: "(notification: Notification) => void",
|
|
7310
|
+
required: false,
|
|
7311
|
+
description: "Callback when a notification is clicked"
|
|
7312
|
+
},
|
|
7313
|
+
{
|
|
7314
|
+
name: "emptyState",
|
|
7315
|
+
type: "Snippet",
|
|
7316
|
+
required: false,
|
|
7317
|
+
description: "Custom empty state snippet"
|
|
7318
|
+
},
|
|
7319
|
+
{
|
|
7320
|
+
name: "emptyTitle",
|
|
7321
|
+
type: "string",
|
|
7322
|
+
default: "'No notifications'",
|
|
7323
|
+
required: false,
|
|
7324
|
+
description: "Empty state title"
|
|
7325
|
+
},
|
|
7326
|
+
{
|
|
7327
|
+
name: "emptyDescription",
|
|
7328
|
+
type: "string",
|
|
7329
|
+
default: `"You're all caught up!"`,
|
|
7330
|
+
required: false,
|
|
7331
|
+
description: "Empty state description"
|
|
7332
|
+
},
|
|
7333
|
+
{
|
|
7334
|
+
name: "loading",
|
|
7335
|
+
type: "boolean",
|
|
7336
|
+
default: "false",
|
|
7337
|
+
required: false,
|
|
7338
|
+
description: "Whether the list is loading"
|
|
7339
|
+
},
|
|
6859
7340
|
{
|
|
6860
7341
|
name: "class",
|
|
6861
7342
|
type: "string",
|
|
@@ -6875,62 +7356,39 @@ var component_catalog_default = {
|
|
|
6875
7356
|
examples: [
|
|
6876
7357
|
{
|
|
6877
7358
|
title: "Basic Usage",
|
|
6878
|
-
code: "<script>\n import {
|
|
6879
|
-
},
|
|
6880
|
-
{
|
|
6881
|
-
title: "Welcome Message",
|
|
6882
|
-
code: "<script>\n const notices = [\n {\n id: 'onboarding',\n title: 'Complete Your Profile',\n message: 'Add a photo and bio to help others recognize you.',\n variant: 'info',\n location: 'card',\n link: {\n text: 'Edit profile',\n href: '/settings/profile',\n },\n },\n ];\n</script>\n\n<NoticeCard />"
|
|
6883
|
-
},
|
|
6884
|
-
{
|
|
6885
|
-
title: "Feature Announcement",
|
|
6886
|
-
code: `<script>
|
|
6887
|
-
const notices = [
|
|
6888
|
-
{
|
|
6889
|
-
id: 'new-charts',
|
|
6890
|
-
title: 'New Charts Available',
|
|
6891
|
-
message: "We've added 5 new chart types to your dashboard.",
|
|
6892
|
-
variant: 'success',
|
|
6893
|
-
location: 'card',
|
|
6894
|
-
startDate: '2025-01-01',
|
|
6895
|
-
endDate: '2025-01-31',
|
|
6896
|
-
},
|
|
6897
|
-
];
|
|
6898
|
-
</script>
|
|
6899
|
-
|
|
6900
|
-
<NoticeCard />`
|
|
6901
|
-
},
|
|
6902
|
-
{
|
|
6903
|
-
title: "Warning Notice",
|
|
6904
|
-
code: `<script>
|
|
6905
|
-
const notices = [
|
|
6906
|
-
{
|
|
6907
|
-
id: 'storage-limit',
|
|
6908
|
-
message: "You're approaching your storage limit. Upgrade to continue uploading.",
|
|
6909
|
-
variant: 'warning',
|
|
6910
|
-
location: 'card',
|
|
6911
|
-
pages: ['/dashboard', '/files'],
|
|
6912
|
-
link: {
|
|
6913
|
-
text: 'Upgrade plan',
|
|
6914
|
-
href: '/billing/upgrade',
|
|
6915
|
-
},
|
|
6916
|
-
},
|
|
6917
|
-
];
|
|
6918
|
-
</script>
|
|
6919
|
-
|
|
6920
|
-
<NoticeCard />`
|
|
7359
|
+
code: "<script>\n import type { Notification } from '@classic-homes/notifications/core';\n\n let notifications = $state<Notification[]>([\n // ... notification objects\n ]);\n</script>\n\n<NotificationList {notifications} />"
|
|
6921
7360
|
},
|
|
6922
7361
|
{
|
|
6923
|
-
title: "
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
7362
|
+
title: "Custom Empty State",
|
|
7363
|
+
description: "Provide a completely custom empty state:",
|
|
7364
|
+
code: '<NotificationList notifications={[]}>\n {#snippet emptyState()}\n <div class="text-center py-12">\n <img src="/empty-inbox.svg" alt="" class="mx-auto mb-4" />\n <h3 class="text-lg font-medium">Inbox Zero!</h3>\n <p class="text-muted-foreground">You have no notifications</p>\n </div>\n {/snippet}\n</NotificationList>'
|
|
7365
|
+
},
|
|
7366
|
+
{
|
|
7367
|
+
title: "Complete Notification Center",
|
|
7368
|
+
code: "<script>\n import {\n NotificationList,\n NotificationFilters,\n NotificationBulkActions,\n NotificationDialog,\n } from '@classic-homes/theme-svelte';\n import type { Notification, NotificationFilter, NotificationCounts } from '@classic-homes/notifications/core';\n\n let notifications = $state<Notification[]>([...]);\n let filter = $state<NotificationFilter>('all');\n let selectedIds = $state(new Set<string>());\n let dialogOpen = $state(false);\n let selectedNotification = $state<Notification | null>(null);\n\n const filteredNotifications = $derived(() => {\n switch (filter) {\n case 'unread': return notifications.filter(n => !n.read);\n case 'read': return notifications.filter(n => n.read);\n default: return notifications;\n }\n });\n\n const counts: NotificationCounts = $derived({\n all: notifications.length,\n unread: notifications.filter(n => !n.read).length,\n read: notifications.filter(n => n.read).length,\n });\n</script>\n\n<NotificationFilters bind:filter {counts} />\n\n<NotificationBulkActions\n selectedCount={selectedIds.size}\n totalCount={filteredNotifications().length}\n onSelectAll={(selected) => {\n /* ... */\n }}\n onMarkRead={() => {\n /* ... */\n }}\n onDelete={() => {\n /* ... */\n }}\n/>\n\n<NotificationList\n notifications={filteredNotifications()}\n {selectedIds}\n selectable={true}\n onToggleSelect={handleToggleSelect}\n onNotificationClick={handleNotificationClick}\n/>\n\n<NotificationDialog notification={selectedNotification} bind:open={dialogOpen} />"
|
|
7369
|
+
},
|
|
7370
|
+
{
|
|
7371
|
+
title: "With Filter-Specific Empty States",
|
|
7372
|
+
code: `<NotificationList
|
|
7373
|
+
notifications={filteredNotifications()}
|
|
7374
|
+
emptyTitle={filter === 'unread'
|
|
7375
|
+
? 'No unread notifications'
|
|
7376
|
+
: filter === 'read'
|
|
7377
|
+
? 'No read notifications'
|
|
7378
|
+
: 'No notifications'}
|
|
7379
|
+
emptyDescription={filter === 'unread'
|
|
7380
|
+
? 'All caught up!'
|
|
7381
|
+
: filter === 'read'
|
|
7382
|
+
? 'No notifications have been read yet'
|
|
7383
|
+
: "You're all caught up!"}
|
|
7384
|
+
/>`
|
|
6929
7385
|
}
|
|
6930
7386
|
],
|
|
6931
7387
|
relatedComponents: [
|
|
6932
|
-
"
|
|
6933
|
-
"
|
|
7388
|
+
"NotificationItem",
|
|
7389
|
+
"NotificationFilters",
|
|
7390
|
+
"NotificationBulkActions",
|
|
7391
|
+
"NotificationDialog"
|
|
6934
7392
|
]
|
|
6935
7393
|
},
|
|
6936
7394
|
{
|
|
@@ -10584,7 +11042,7 @@ var token_definitions_default = {
|
|
|
10584
11042
|
name: "charcoal",
|
|
10585
11043
|
description: "Collection - Charcoal gray",
|
|
10586
11044
|
shades: {
|
|
10587
|
-
"50": "#
|
|
11045
|
+
"50": "#fafafa",
|
|
10588
11046
|
"100": "#e6e6e6",
|
|
10589
11047
|
"200": "#cccccc",
|
|
10590
11048
|
"300": "#b3b3b3",
|
|
@@ -11450,6 +11908,197 @@ var pattern_library_default = {
|
|
|
11450
11908
|
components: [],
|
|
11451
11909
|
example: "// +page.ts\nimport { requireAuth, requireRole, protectedLoad } from '@classic-homes/auth/svelte';\n\n// Simple auth requirement\nexport const load = requireAuth();\n\n// Role-based protection\nexport const load = requireRole('admin');\n\n// Custom protected load\nexport const load = protectedLoad(async (event, auth) => {\n const data = await fetchData(event.fetch, auth.user.id);\n return { user: auth.user, data };\n});"
|
|
11452
11910
|
}
|
|
11911
|
+
],
|
|
11912
|
+
notifications: [
|
|
11913
|
+
{
|
|
11914
|
+
id: "notification-center",
|
|
11915
|
+
name: "Notification Center",
|
|
11916
|
+
description: "Complete notification center with list, filters, bulk actions, and detail dialog",
|
|
11917
|
+
components: [
|
|
11918
|
+
"NotificationList",
|
|
11919
|
+
"NotificationItem",
|
|
11920
|
+
"NotificationFilters",
|
|
11921
|
+
"NotificationBulkActions",
|
|
11922
|
+
"NotificationDialog",
|
|
11923
|
+
"NotificationBadge"
|
|
11924
|
+
],
|
|
11925
|
+
example: `<script lang="ts">
|
|
11926
|
+
import {
|
|
11927
|
+
NotificationList,
|
|
11928
|
+
NotificationFilters,
|
|
11929
|
+
NotificationBulkActions,
|
|
11930
|
+
NotificationDialog,
|
|
11931
|
+
NotificationBadge,
|
|
11932
|
+
} from '@classic-homes/theme-svelte';
|
|
11933
|
+
import { notificationService } from '@classic-homes/notifications/core';
|
|
11934
|
+
import type { Notification, NotificationFilter } from '@classic-homes/notifications/core';
|
|
11935
|
+
|
|
11936
|
+
let notifications = $state<Notification[]>([]);
|
|
11937
|
+
let filter = $state<NotificationFilter>('all');
|
|
11938
|
+
let selectedIds = $state(new Set<string>());
|
|
11939
|
+
let selectedNotification = $state<Notification | null>(null);
|
|
11940
|
+
let dialogOpen = $state(false);
|
|
11941
|
+
|
|
11942
|
+
// Computed values
|
|
11943
|
+
let filteredNotifications = $derived(
|
|
11944
|
+
notifications.filter((n) => {
|
|
11945
|
+
if (filter === 'unread') return !n.read;
|
|
11946
|
+
if (filter === 'read') return n.read;
|
|
11947
|
+
return true;
|
|
11948
|
+
})
|
|
11949
|
+
);
|
|
11950
|
+
|
|
11951
|
+
let counts = $derived({
|
|
11952
|
+
all: notifications.length,
|
|
11953
|
+
unread: notifications.filter((n) => !n.read).length,
|
|
11954
|
+
read: notifications.filter((n) => n.read).length,
|
|
11955
|
+
});
|
|
11956
|
+
|
|
11957
|
+
// Load notifications
|
|
11958
|
+
$effect(() => {
|
|
11959
|
+
notificationService.list().then((result) => {
|
|
11960
|
+
notifications = result.notifications;
|
|
11961
|
+
});
|
|
11962
|
+
});
|
|
11963
|
+
|
|
11964
|
+
// Handlers
|
|
11965
|
+
function handleNotificationClick(notification: Notification) {
|
|
11966
|
+
selectedNotification = notification;
|
|
11967
|
+
dialogOpen = true;
|
|
11968
|
+
}
|
|
11969
|
+
|
|
11970
|
+
function handleToggleSelect(id: string, selected: boolean) {
|
|
11971
|
+
const newSet = new Set(selectedIds);
|
|
11972
|
+
if (selected) newSet.add(id);
|
|
11973
|
+
else newSet.delete(id);
|
|
11974
|
+
selectedIds = newSet;
|
|
11975
|
+
}
|
|
11976
|
+
|
|
11977
|
+
async function handleMarkRead() {
|
|
11978
|
+
await notificationService.markManyRead([...selectedIds]);
|
|
11979
|
+
notifications = notifications.map((n) =>
|
|
11980
|
+
selectedIds.has(n.id) ? { ...n, read: true } : n
|
|
11981
|
+
);
|
|
11982
|
+
selectedIds = new Set();
|
|
11983
|
+
}
|
|
11984
|
+
|
|
11985
|
+
async function handleBulkDelete() {
|
|
11986
|
+
await notificationService.bulkDelete([...selectedIds]);
|
|
11987
|
+
notifications = notifications.filter((n) => !selectedIds.has(n.id));
|
|
11988
|
+
selectedIds = new Set();
|
|
11989
|
+
}
|
|
11990
|
+
</script>
|
|
11991
|
+
|
|
11992
|
+
<div class="space-y-4">
|
|
11993
|
+
<NotificationFilters bind:filter {counts} />
|
|
11994
|
+
|
|
11995
|
+
{#if filteredNotifications.length > 0}
|
|
11996
|
+
<NotificationBulkActions
|
|
11997
|
+
selectedCount={selectedIds.size}
|
|
11998
|
+
totalCount={filteredNotifications.length}
|
|
11999
|
+
allSelected={selectedIds.size === filteredNotifications.length}
|
|
12000
|
+
onSelectAll={(selected) => {
|
|
12001
|
+
selectedIds = selected
|
|
12002
|
+
? new Set(filteredNotifications.map((n) => n.id))
|
|
12003
|
+
: new Set();
|
|
12004
|
+
}}
|
|
12005
|
+
onMarkRead={handleMarkRead}
|
|
12006
|
+
onDelete={handleBulkDelete}
|
|
12007
|
+
onClearSelection={() => (selectedIds = new Set())}
|
|
12008
|
+
/>
|
|
12009
|
+
{/if}
|
|
12010
|
+
|
|
12011
|
+
<NotificationList
|
|
12012
|
+
notifications={filteredNotifications}
|
|
12013
|
+
{selectedIds}
|
|
12014
|
+
selectable={true}
|
|
12015
|
+
onToggleSelect={handleToggleSelect}
|
|
12016
|
+
onNotificationClick={handleNotificationClick}
|
|
12017
|
+
/>
|
|
12018
|
+
|
|
12019
|
+
<NotificationDialog
|
|
12020
|
+
notification={selectedNotification}
|
|
12021
|
+
bind:open={dialogOpen}
|
|
12022
|
+
onClose={() => (dialogOpen = false)}
|
|
12023
|
+
onMarkRead={(id) => {
|
|
12024
|
+
notifications = notifications.map((n) =>
|
|
12025
|
+
n.id === id ? { ...n, read: true } : n
|
|
12026
|
+
);
|
|
12027
|
+
}}
|
|
12028
|
+
onDelete={(id) => {
|
|
12029
|
+
notifications = notifications.filter((n) => n.id !== id);
|
|
12030
|
+
dialogOpen = false;
|
|
12031
|
+
}}
|
|
12032
|
+
/>
|
|
12033
|
+
</div>`
|
|
12034
|
+
},
|
|
12035
|
+
{
|
|
12036
|
+
id: "notification-dropdown",
|
|
12037
|
+
name: "Notification Dropdown",
|
|
12038
|
+
description: "Notification bell icon with dropdown panel for header integration",
|
|
12039
|
+
components: [
|
|
12040
|
+
"NotificationBadge",
|
|
12041
|
+
"NotificationList",
|
|
12042
|
+
"NotificationItem",
|
|
12043
|
+
"DropdownMenu",
|
|
12044
|
+
"Button"
|
|
12045
|
+
],
|
|
12046
|
+
example: `<script lang="ts">
|
|
12047
|
+
import { NotificationBadge, NotificationList, Button, DropdownMenu } from '@classic-homes/theme-svelte';
|
|
12048
|
+
import { notificationService } from '@classic-homes/notifications/core';
|
|
12049
|
+
import type { Notification } from '@classic-homes/notifications/core';
|
|
12050
|
+
import { goto } from '$app/navigation';
|
|
12051
|
+
|
|
12052
|
+
let notifications = $state<Notification[]>([]);
|
|
12053
|
+
let unreadCount = $derived(notifications.filter((n) => !n.read).length);
|
|
12054
|
+
|
|
12055
|
+
$effect(() => {
|
|
12056
|
+
notificationService.list({ limit: 5 }).then((result) => {
|
|
12057
|
+
notifications = result.notifications;
|
|
12058
|
+
});
|
|
12059
|
+
});
|
|
12060
|
+
|
|
12061
|
+
function handleNotificationClick(notification: Notification) {
|
|
12062
|
+
if (notification.actionUrl) {
|
|
12063
|
+
goto(notification.actionUrl);
|
|
12064
|
+
}
|
|
12065
|
+
}
|
|
12066
|
+
</script>
|
|
12067
|
+
|
|
12068
|
+
<DropdownMenu.Root>
|
|
12069
|
+
<DropdownMenu.Trigger asChild let:builder>
|
|
12070
|
+
<Button builders={[builder]} variant="ghost" size="icon" class="relative">
|
|
12071
|
+
<NotificationBadge count={unreadCount} />
|
|
12072
|
+
</Button>
|
|
12073
|
+
</DropdownMenu.Trigger>
|
|
12074
|
+
|
|
12075
|
+
<DropdownMenu.Content class="w-80" align="end">
|
|
12076
|
+
<div class="flex items-center justify-between p-4 border-b">
|
|
12077
|
+
<h3 class="font-semibold">Notifications</h3>
|
|
12078
|
+
{#if unreadCount > 0}
|
|
12079
|
+
<Button variant="ghost" size="sm" onclick={() => notificationService.markAllRead()}>
|
|
12080
|
+
Mark all read
|
|
12081
|
+
</Button>
|
|
12082
|
+
{/if}
|
|
12083
|
+
</div>
|
|
12084
|
+
|
|
12085
|
+
<div class="max-h-96 overflow-y-auto">
|
|
12086
|
+
<NotificationList
|
|
12087
|
+
{notifications}
|
|
12088
|
+
onNotificationClick={handleNotificationClick}
|
|
12089
|
+
emptyTitle="No notifications"
|
|
12090
|
+
emptyDescription="You're all caught up!"
|
|
12091
|
+
/>
|
|
12092
|
+
</div>
|
|
12093
|
+
|
|
12094
|
+
<div class="p-2 border-t">
|
|
12095
|
+
<Button variant="ghost" class="w-full" onclick={() => goto('/notifications')}>
|
|
12096
|
+
View all notifications
|
|
12097
|
+
</Button>
|
|
12098
|
+
</div>
|
|
12099
|
+
</DropdownMenu.Content>
|
|
12100
|
+
</DropdownMenu.Root>`
|
|
12101
|
+
}
|
|
11453
12102
|
]
|
|
11454
12103
|
};
|
|
11455
12104
|
|
|
@@ -13177,7 +13826,10 @@ var SuggestPatternSchema = z3.object({
|
|
|
13177
13826
|
"login-with-mfa",
|
|
13178
13827
|
"sso-login",
|
|
13179
13828
|
"session-management",
|
|
13180
|
-
"protected-route"
|
|
13829
|
+
"protected-route",
|
|
13830
|
+
// Notification patterns
|
|
13831
|
+
"notification-center",
|
|
13832
|
+
"notification-dropdown"
|
|
13181
13833
|
]).describe("The use case you need a pattern for"),
|
|
13182
13834
|
requirements: z3.array(z3.string()).optional().describe("Additional requirements or constraints")
|
|
13183
13835
|
});
|
|
@@ -13191,12 +13843,18 @@ function registerSuggestPatternTool(server) {
|
|
|
13191
13843
|
const layout = patterns2.layouts.find((l) => l.id === useCase || l.useCase === useCase);
|
|
13192
13844
|
const form = patterns2.forms.find((f) => f.id === useCase);
|
|
13193
13845
|
const auth = patterns2.auth?.find((a) => a.id === useCase);
|
|
13194
|
-
const
|
|
13846
|
+
const notification = patterns2.notifications?.find((n) => n.id === useCase);
|
|
13847
|
+
const pattern = layout || form || auth || notification;
|
|
13195
13848
|
if (!pattern) {
|
|
13196
13849
|
const availablePatterns = [
|
|
13197
13850
|
...patterns2.layouts.map((l) => ({ id: l.id, type: "layout", name: l.name })),
|
|
13198
13851
|
...patterns2.forms.map((f) => ({ id: f.id, type: "form", name: f.name })),
|
|
13199
|
-
...patterns2.auth?.map((a) => ({ id: a.id, type: "auth", name: a.name })) || []
|
|
13852
|
+
...patterns2.auth?.map((a) => ({ id: a.id, type: "auth", name: a.name })) || [],
|
|
13853
|
+
...patterns2.notifications?.map((n) => ({
|
|
13854
|
+
id: n.id,
|
|
13855
|
+
type: "notification",
|
|
13856
|
+
name: n.name
|
|
13857
|
+
})) || []
|
|
13200
13858
|
];
|
|
13201
13859
|
return {
|
|
13202
13860
|
content: [
|