urpanels-ui-pack 0.0.4 → 0.0.11
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/BasePageService/BasePageService.d.ts +121 -0
- package/dist/BasePageService/BasePageService.js +191 -0
- package/dist/BasePageService/index.d.ts +2 -0
- package/dist/BasePageService/index.js +1 -0
- package/dist/Button/Button.svelte +1 -0
- package/dist/DataTableLite/DataTableLite.svelte +56 -0
- package/dist/DataTableLite/DataTableLite.svelte.d.ts +15 -0
- package/dist/DataTableLite/index.d.ts +1 -0
- package/dist/DataTableLite/index.js +1 -0
- package/dist/FilterBar/FilterBar.svelte +124 -0
- package/dist/FilterBar/FilterBar.svelte.d.ts +14 -0
- package/dist/FilterBar/index.d.ts +2 -0
- package/dist/FilterBar/index.js +1 -0
- package/dist/FilterBar/types.d.ts +35 -0
- package/dist/FilterBar/types.js +1 -0
- package/dist/ImageEditorModal/ImageEditorModal.svelte +330 -0
- package/dist/ImageEditorModal/ImageEditorModal.svelte.d.ts +23 -0
- package/dist/ImageEditorModal/index.d.ts +1 -0
- package/dist/ImageEditorModal/index.js +1 -0
- package/dist/InfoCard/InfoCard.svelte +61 -30
- package/dist/InputCheckboxModal/InputCheckboxModal.svelte +235 -0
- package/dist/InputCheckboxModal/InputCheckboxModal.svelte.d.ts +23 -0
- package/dist/InputCheckboxModal/index.d.ts +1 -0
- package/dist/InputCheckboxModal/index.js +1 -0
- package/dist/InputMultiSelectModal/InputMultiSelectModal.svelte +285 -0
- package/dist/InputMultiSelectModal/InputMultiSelectModal.svelte.d.ts +25 -0
- package/dist/InputMultiSelectModal/index.d.ts +1 -0
- package/dist/InputMultiSelectModal/index.js +1 -0
- package/dist/InputQuantityModal/InputQuantityModal.svelte +431 -0
- package/dist/InputQuantityModal/InputQuantityModal.svelte.d.ts +29 -0
- package/dist/InputQuantityModal/index.d.ts +1 -0
- package/dist/InputQuantityModal/index.js +1 -0
- package/dist/InputSelectModal/InputSelectModal.svelte +118 -0
- package/dist/InputSelectModal/InputSelectModal.svelte.d.ts +19 -0
- package/dist/InputSelectModal/index.d.ts +1 -0
- package/dist/InputSelectModal/index.js +1 -0
- package/dist/InputSelectModalV2/InputSelectModalV2.svelte +340 -0
- package/dist/InputSelectModalV2/InputSelectModalV2.svelte.d.ts +48 -0
- package/dist/InputSelectModalV2/index.d.ts +1 -0
- package/dist/InputSelectModalV2/index.js +1 -0
- package/dist/KpiStatsGrid/KpiStatsGrid.svelte +50 -0
- package/dist/KpiStatsGrid/KpiStatsGrid.svelte.d.ts +14 -0
- package/dist/KpiStatsGrid/index.d.ts +1 -0
- package/dist/KpiStatsGrid/index.js +1 -0
- package/dist/LoadingSpinner/LoadingSpinner.svelte +1 -1
- package/dist/Modal/Modal.svelte +108 -19
- package/dist/Modal/Modal.svelte.d.ts +11 -2
- package/dist/PageLayout/ActionButton.svelte +12 -4
- package/dist/PageLayout/PageContent.svelte +1 -1
- package/dist/PageLayout/PageHeader.svelte +89 -14
- package/dist/PageLayout/PageHeader.svelte.d.ts +10 -1
- package/dist/PageLayout/SearchBar.svelte +1 -1
- package/dist/PageLayout/ViewToggle.svelte +1 -1
- package/dist/Pagination/Pagination.svelte +1 -1
- package/dist/RecentActivityList/RecentActivityList.svelte +64 -0
- package/dist/RecentActivityList/RecentActivityList.svelte.d.ts +18 -0
- package/dist/RecentActivityList/index.d.ts +1 -0
- package/dist/RecentActivityList/index.js +1 -0
- package/dist/RichTextEditor/RichTextEditor.svelte +181 -1
- package/dist/RichTextEditor/RichTextEditor.svelte.d.ts +3 -0
- package/dist/RichTextRenderer/RichTextRenderer.svelte +169 -0
- package/dist/RichTextRenderer/RichTextRenderer.svelte.d.ts +11 -0
- package/dist/RichTextRenderer/index.d.ts +1 -0
- package/dist/RichTextRenderer/index.js +1 -0
- package/dist/StatusPill/StatusPill.svelte +26 -0
- package/dist/StatusPill/StatusPill.svelte.d.ts +10 -0
- package/dist/StatusPill/index.d.ts +1 -0
- package/dist/StatusPill/index.js +1 -0
- package/dist/TimelineList/TimelineList.svelte +207 -0
- package/dist/TimelineList/TimelineList.svelte.d.ts +4 -0
- package/dist/TimelineList/TimelineList.types.d.ts +70 -0
- package/dist/TimelineList/TimelineList.types.js +1 -0
- package/dist/TimelineList/index.d.ts +2 -0
- package/dist/TimelineList/index.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/inputs/InputNumber/InputNumber.svelte +140 -0
- package/dist/inputs/InputNumber/InputNumber.svelte.d.ts +27 -0
- package/dist/inputs/InputNumber/index.d.ts +2 -0
- package/dist/inputs/InputNumber/index.js +2 -0
- package/dist/inputs/InputSelect/InputSelect.svelte +73 -0
- package/dist/inputs/InputSelect/InputSelect.svelte.d.ts +18 -0
- package/dist/inputs/InputSelect/index.d.ts +2 -0
- package/dist/inputs/InputSelect/index.js +2 -0
- package/dist/inputs/InputText/InputText.svelte +126 -0
- package/dist/inputs/InputText/InputText.svelte.d.ts +49 -0
- package/dist/inputs/InputText/index.d.ts +2 -0
- package/dist/inputs/InputText/index.js +2 -0
- package/dist/inputs/TextArea/TextArea.svelte +113 -0
- package/dist/inputs/TextArea/TextArea.svelte.d.ts +21 -0
- package/dist/inputs/TextArea/index.d.ts +2 -0
- package/dist/inputs/TextArea/index.js +2 -0
- package/dist/inputs/index.d.ts +3 -0
- package/dist/inputs/index.js +4 -0
- package/dist/sections/PreviewSelector/PreviewSelector.svelte +164 -0
- package/dist/sections/PreviewSelector/PreviewSelector.svelte.d.ts +25 -0
- package/dist/sections/PreviewSelector/index.d.ts +2 -0
- package/dist/sections/PreviewSelector/index.js +1 -0
- package/dist/sections/index.d.ts +2 -5
- package/dist/sections/index.js +6 -3
- package/package.json +17 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { PageService, type PageOts } from "@urga-panel/ur-panels-core/dist/services/abstract/pageServices/PageServices";
|
|
2
|
+
/**
|
|
3
|
+
* View mode types for list display
|
|
4
|
+
*/
|
|
5
|
+
export type ViewMode = 'card' | 'table';
|
|
6
|
+
/**
|
|
7
|
+
* Local settings interface - extend this for custom settings
|
|
8
|
+
*/
|
|
9
|
+
export interface BaseLocalSettings {
|
|
10
|
+
viewMode?: ViewMode;
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Base Page Service with common loading state management and local settings
|
|
16
|
+
* All page services should extend this instead of PageService directly
|
|
17
|
+
*
|
|
18
|
+
* IMPORTANT: Child classes MUST implement isLoading with $state()
|
|
19
|
+
* Example: public isLoading: boolean = $state(true);
|
|
20
|
+
*
|
|
21
|
+
* For viewMode reactivity, child class should implement:
|
|
22
|
+
* public viewMode: ViewMode = $state(this.getLocalSetting('viewMode') || 'card');
|
|
23
|
+
*/
|
|
24
|
+
export declare abstract class BasePageService extends PageService {
|
|
25
|
+
/**
|
|
26
|
+
* Loading state - MUST be implemented in child class with $state()
|
|
27
|
+
* Example: public isLoading: boolean = $state(true);
|
|
28
|
+
*/
|
|
29
|
+
abstract isLoading: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Unique key for localStorage - override in child class
|
|
32
|
+
* Default uses class name, but should be overridden for uniqueness
|
|
33
|
+
*/
|
|
34
|
+
protected get localStorageKey(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Default settings - override in child class to set defaults
|
|
37
|
+
*/
|
|
38
|
+
protected get defaultSettings(): BaseLocalSettings;
|
|
39
|
+
constructor(ots: PageOts);
|
|
40
|
+
/**
|
|
41
|
+
* Wraps an async function with loading state management
|
|
42
|
+
* Automatically sets isLoading to true before execution and false after
|
|
43
|
+
*
|
|
44
|
+
* @param fn - Async function to execute
|
|
45
|
+
* @returns Promise with the result of the function
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* await service.withLoading(async () => {
|
|
49
|
+
* await loadData();
|
|
50
|
+
* });
|
|
51
|
+
*/
|
|
52
|
+
withLoading<T>(fn: () => Promise<T>): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Sets loading state manually
|
|
55
|
+
* Use this when you need more granular control
|
|
56
|
+
*
|
|
57
|
+
* @param loading - Loading state
|
|
58
|
+
*/
|
|
59
|
+
protected setLoading(loading: boolean): void;
|
|
60
|
+
/**
|
|
61
|
+
* Gets all local settings from localStorage
|
|
62
|
+
* @returns Current settings merged with defaults
|
|
63
|
+
*/
|
|
64
|
+
getLocalSettings<T extends BaseLocalSettings = BaseLocalSettings>(): T;
|
|
65
|
+
/**
|
|
66
|
+
* Gets a specific setting value
|
|
67
|
+
* @param key - Setting key
|
|
68
|
+
* @returns Setting value or default
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const viewMode = this.getLocalSetting('viewMode'); // 'card' | 'table'
|
|
72
|
+
*/
|
|
73
|
+
getLocalSetting<K extends keyof BaseLocalSettings>(key: K): BaseLocalSettings[K];
|
|
74
|
+
/**
|
|
75
|
+
* Saves a specific setting to localStorage
|
|
76
|
+
* @param key - Setting key
|
|
77
|
+
* @param value - Setting value
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* this.saveLocalSetting('viewMode', 'table');
|
|
81
|
+
*/
|
|
82
|
+
saveLocalSetting<K extends keyof BaseLocalSettings>(key: K, value: BaseLocalSettings[K]): void;
|
|
83
|
+
/**
|
|
84
|
+
* Saves multiple settings at once
|
|
85
|
+
* @param settings - Partial settings object
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* this.saveLocalSettings({ viewMode: 'table', pageSize: 50 });
|
|
89
|
+
*/
|
|
90
|
+
saveLocalSettings(settings: Partial<BaseLocalSettings>): void;
|
|
91
|
+
/**
|
|
92
|
+
* Clears all local settings for this page
|
|
93
|
+
*/
|
|
94
|
+
clearLocalSettings(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Gets the current view mode from local settings
|
|
97
|
+
* @returns 'card' or 'table'
|
|
98
|
+
*/
|
|
99
|
+
getViewMode(): ViewMode;
|
|
100
|
+
/**
|
|
101
|
+
* Saves view mode preference
|
|
102
|
+
* NOTE: Child class should also update its $state viewMode property
|
|
103
|
+
* @param mode - 'card' or 'table'
|
|
104
|
+
*/
|
|
105
|
+
saveViewMode(mode: ViewMode): void;
|
|
106
|
+
/**
|
|
107
|
+
* Toggles between card and table view
|
|
108
|
+
* @returns The new view mode
|
|
109
|
+
*/
|
|
110
|
+
toggleViewMode(): ViewMode;
|
|
111
|
+
/**
|
|
112
|
+
* Gets the saved page size
|
|
113
|
+
* @returns Page size number
|
|
114
|
+
*/
|
|
115
|
+
getPageSize(): number;
|
|
116
|
+
/**
|
|
117
|
+
* Saves page size preference
|
|
118
|
+
* @param size - Number of items per page
|
|
119
|
+
*/
|
|
120
|
+
savePageSize(size: number): void;
|
|
121
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { PageService } from "@urga-panel/ur-panels-core/dist/services/abstract/pageServices/PageServices";
|
|
3
|
+
/**
|
|
4
|
+
* Base Page Service with common loading state management and local settings
|
|
5
|
+
* All page services should extend this instead of PageService directly
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Child classes MUST implement isLoading with $state()
|
|
8
|
+
* Example: public isLoading: boolean = $state(true);
|
|
9
|
+
*
|
|
10
|
+
* For viewMode reactivity, child class should implement:
|
|
11
|
+
* public viewMode: ViewMode = $state(this.getLocalSetting('viewMode') || 'card');
|
|
12
|
+
*/
|
|
13
|
+
export class BasePageService extends PageService {
|
|
14
|
+
/**
|
|
15
|
+
* Unique key for localStorage - override in child class
|
|
16
|
+
* Default uses class name, but should be overridden for uniqueness
|
|
17
|
+
*/
|
|
18
|
+
get localStorageKey() {
|
|
19
|
+
return `urpanels_page_${this.constructor.name}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Default settings - override in child class to set defaults
|
|
23
|
+
*/
|
|
24
|
+
get defaultSettings() {
|
|
25
|
+
return {
|
|
26
|
+
viewMode: 'card',
|
|
27
|
+
pageSize: 20
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
constructor(ots) {
|
|
31
|
+
super(ots);
|
|
32
|
+
}
|
|
33
|
+
// ==================== Loading State Management ====================
|
|
34
|
+
/**
|
|
35
|
+
* Wraps an async function with loading state management
|
|
36
|
+
* Automatically sets isLoading to true before execution and false after
|
|
37
|
+
*
|
|
38
|
+
* @param fn - Async function to execute
|
|
39
|
+
* @returns Promise with the result of the function
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* await service.withLoading(async () => {
|
|
43
|
+
* await loadData();
|
|
44
|
+
* });
|
|
45
|
+
*/
|
|
46
|
+
async withLoading(fn) {
|
|
47
|
+
this.isLoading = true;
|
|
48
|
+
try {
|
|
49
|
+
return await fn();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
this.isLoading = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sets loading state manually
|
|
57
|
+
* Use this when you need more granular control
|
|
58
|
+
*
|
|
59
|
+
* @param loading - Loading state
|
|
60
|
+
*/
|
|
61
|
+
setLoading(loading) {
|
|
62
|
+
this.isLoading = loading;
|
|
63
|
+
}
|
|
64
|
+
// ==================== Local Settings Management ====================
|
|
65
|
+
/**
|
|
66
|
+
* Gets all local settings from localStorage
|
|
67
|
+
* @returns Current settings merged with defaults
|
|
68
|
+
*/
|
|
69
|
+
getLocalSettings() {
|
|
70
|
+
if (typeof window === 'undefined') {
|
|
71
|
+
return this.defaultSettings;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const stored = localStorage.getItem(this.localStorageKey);
|
|
75
|
+
if (stored) {
|
|
76
|
+
const parsed = JSON.parse(stored);
|
|
77
|
+
return { ...this.defaultSettings, ...parsed };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.warn('Failed to parse local settings:', e);
|
|
82
|
+
}
|
|
83
|
+
return this.defaultSettings;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Gets a specific setting value
|
|
87
|
+
* @param key - Setting key
|
|
88
|
+
* @returns Setting value or default
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const viewMode = this.getLocalSetting('viewMode'); // 'card' | 'table'
|
|
92
|
+
*/
|
|
93
|
+
getLocalSetting(key) {
|
|
94
|
+
var _a;
|
|
95
|
+
const settings = this.getLocalSettings();
|
|
96
|
+
return (_a = settings[key]) !== null && _a !== void 0 ? _a : this.defaultSettings[key];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Saves a specific setting to localStorage
|
|
100
|
+
* @param key - Setting key
|
|
101
|
+
* @param value - Setting value
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* this.saveLocalSetting('viewMode', 'table');
|
|
105
|
+
*/
|
|
106
|
+
saveLocalSetting(key, value) {
|
|
107
|
+
if (typeof window === 'undefined')
|
|
108
|
+
return;
|
|
109
|
+
try {
|
|
110
|
+
const current = this.getLocalSettings();
|
|
111
|
+
current[key] = value;
|
|
112
|
+
localStorage.setItem(this.localStorageKey, JSON.stringify(current));
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
console.warn('Failed to save local setting:', e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Saves multiple settings at once
|
|
120
|
+
* @param settings - Partial settings object
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* this.saveLocalSettings({ viewMode: 'table', pageSize: 50 });
|
|
124
|
+
*/
|
|
125
|
+
saveLocalSettings(settings) {
|
|
126
|
+
if (typeof window === 'undefined')
|
|
127
|
+
return;
|
|
128
|
+
try {
|
|
129
|
+
const current = this.getLocalSettings();
|
|
130
|
+
const updated = { ...current, ...settings };
|
|
131
|
+
localStorage.setItem(this.localStorageKey, JSON.stringify(updated));
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
console.warn('Failed to save local settings:', e);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Clears all local settings for this page
|
|
139
|
+
*/
|
|
140
|
+
clearLocalSettings() {
|
|
141
|
+
if (typeof window === 'undefined')
|
|
142
|
+
return;
|
|
143
|
+
try {
|
|
144
|
+
localStorage.removeItem(this.localStorageKey);
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
console.warn('Failed to clear local settings:', e);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ==================== View Mode Helpers ====================
|
|
151
|
+
/**
|
|
152
|
+
* Gets the current view mode from local settings
|
|
153
|
+
* @returns 'card' or 'table'
|
|
154
|
+
*/
|
|
155
|
+
getViewMode() {
|
|
156
|
+
return this.getLocalSetting('viewMode') || 'card';
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Saves view mode preference
|
|
160
|
+
* NOTE: Child class should also update its $state viewMode property
|
|
161
|
+
* @param mode - 'card' or 'table'
|
|
162
|
+
*/
|
|
163
|
+
saveViewMode(mode) {
|
|
164
|
+
this.saveLocalSetting('viewMode', mode);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Toggles between card and table view
|
|
168
|
+
* @returns The new view mode
|
|
169
|
+
*/
|
|
170
|
+
toggleViewMode() {
|
|
171
|
+
const current = this.getViewMode();
|
|
172
|
+
const newMode = current === 'card' ? 'table' : 'card';
|
|
173
|
+
this.saveViewMode(newMode);
|
|
174
|
+
return newMode;
|
|
175
|
+
}
|
|
176
|
+
// ==================== Page Size Helpers ====================
|
|
177
|
+
/**
|
|
178
|
+
* Gets the saved page size
|
|
179
|
+
* @returns Page size number
|
|
180
|
+
*/
|
|
181
|
+
getPageSize() {
|
|
182
|
+
return this.getLocalSetting('pageSize') || 20;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Saves page size preference
|
|
186
|
+
* @param size - Number of items per page
|
|
187
|
+
*/
|
|
188
|
+
savePageSize(size) {
|
|
189
|
+
this.saveLocalSetting('pageSize', size);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BasePageService } from './BasePageService.js';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export type TableColumn = {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
align?: 'left' | 'center' | 'right';
|
|
6
|
+
width?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
columns: TableColumn[];
|
|
11
|
+
rows: Record<string, any>[];
|
|
12
|
+
rowKey?: string;
|
|
13
|
+
emptyText?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { columns = [], rows = [], rowKey = 'id', emptyText = '-' }: Props = $props();
|
|
17
|
+
|
|
18
|
+
const alignClass = (align?: string) => {
|
|
19
|
+
if (align === 'center') return 'text-center';
|
|
20
|
+
if (align === 'right') return 'text-right';
|
|
21
|
+
return 'text-left';
|
|
22
|
+
};
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<div class="overflow-x-auto" data-component-name="DataTableLite">
|
|
26
|
+
<table class="min-w-full border-collapse">
|
|
27
|
+
<thead>
|
|
28
|
+
<tr>
|
|
29
|
+
{#each columns as col}
|
|
30
|
+
<th class="px-3 py-2.5 text-xs font-semibold text-gray-700 bg-gray-50 border-b border-gray-200 {alignClass(col.align)}" style:width={col.width || undefined}>
|
|
31
|
+
{col.label}
|
|
32
|
+
</th>
|
|
33
|
+
{/each}
|
|
34
|
+
</tr>
|
|
35
|
+
</thead>
|
|
36
|
+
<tbody>
|
|
37
|
+
{#if rows.length === 0}
|
|
38
|
+
<tr>
|
|
39
|
+
<td colspan={columns.length} class="px-3 py-6 text-center text-sm text-gray-400">
|
|
40
|
+
{emptyText}
|
|
41
|
+
</td>
|
|
42
|
+
</tr>
|
|
43
|
+
{:else}
|
|
44
|
+
{#each rows as row (row[rowKey] || Math.random())}
|
|
45
|
+
<tr class="hover:bg-gray-50">
|
|
46
|
+
{#each columns as col}
|
|
47
|
+
<td class="px-3 py-2.5 text-sm text-gray-800 border-b border-gray-100 {alignClass(col.align)}">
|
|
48
|
+
{row[col.key] ?? '-'}
|
|
49
|
+
</td>
|
|
50
|
+
{/each}
|
|
51
|
+
</tr>
|
|
52
|
+
{/each}
|
|
53
|
+
{/if}
|
|
54
|
+
</tbody>
|
|
55
|
+
</table>
|
|
56
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type TableColumn = {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
align?: 'left' | 'center' | 'right';
|
|
5
|
+
width?: string;
|
|
6
|
+
};
|
|
7
|
+
interface Props {
|
|
8
|
+
columns: TableColumn[];
|
|
9
|
+
rows: Record<string, any>[];
|
|
10
|
+
rowKey?: string;
|
|
11
|
+
emptyText?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const DataTableLite: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type DataTableLite = ReturnType<typeof DataTableLite>;
|
|
15
|
+
export default DataTableLite;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as DataTableLite } from './DataTableLite.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as DataTableLite } from './DataTableLite.svelte';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { FilterGroup, ActiveFilters } from './types';
|
|
3
|
+
import { t } from '../utils/translations.svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
/** Array of filter group definitions */
|
|
7
|
+
groups: FilterGroup[];
|
|
8
|
+
/** Current active filter values (bindable) */
|
|
9
|
+
activeFilters?: ActiveFilters;
|
|
10
|
+
/** Called when any filter changes */
|
|
11
|
+
onFilterChange?: (filters: ActiveFilters) => void;
|
|
12
|
+
/** Compact mode - smaller chips */
|
|
13
|
+
compact?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
groups,
|
|
18
|
+
activeFilters = $bindable({}),
|
|
19
|
+
onFilterChange,
|
|
20
|
+
compact = false
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
function isActive(groupKey: string, optionValue: string): boolean {
|
|
24
|
+
const current = activeFilters[groupKey];
|
|
25
|
+
if (current === null || current === undefined) return false;
|
|
26
|
+
if (Array.isArray(current)) return current.includes(optionValue);
|
|
27
|
+
return current === optionValue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isAllActive(groupKey: string): boolean {
|
|
31
|
+
const current = activeFilters[groupKey];
|
|
32
|
+
return current === null || current === undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleSelect(group: FilterGroup, optionValue: string) {
|
|
36
|
+
if (group.type === 'single') {
|
|
37
|
+
// Single select: toggle between this option and "all"
|
|
38
|
+
if (activeFilters[group.key] === optionValue) {
|
|
39
|
+
activeFilters[group.key] = null;
|
|
40
|
+
} else {
|
|
41
|
+
activeFilters[group.key] = optionValue;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
// Multi select: toggle option in array
|
|
45
|
+
const current = activeFilters[group.key];
|
|
46
|
+
let arr: string[] = Array.isArray(current) ? [...current] : [];
|
|
47
|
+
|
|
48
|
+
if (arr.includes(optionValue)) {
|
|
49
|
+
arr = arr.filter(v => v !== optionValue);
|
|
50
|
+
} else {
|
|
51
|
+
arr.push(optionValue);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
activeFilters[group.key] = arr.length > 0 ? arr : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onFilterChange?.(activeFilters);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function handleSelectAll(groupKey: string) {
|
|
61
|
+
activeFilters[groupKey] = null;
|
|
62
|
+
onFilterChange?.(activeFilters);
|
|
63
|
+
}
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div class="flex flex-wrap gap-3" data-component-name="FilterBar">
|
|
67
|
+
{#each groups as group}
|
|
68
|
+
<div class="flex items-center gap-1.5">
|
|
69
|
+
{#if group.label}
|
|
70
|
+
<span class="text-xs font-medium text-gray-500 mr-1 hidden sm:inline">{group.label}:</span>
|
|
71
|
+
{/if}
|
|
72
|
+
|
|
73
|
+
<div class="flex flex-wrap items-center bg-gray-100 rounded-xl p-1 {compact ? 'gap-0.5' : 'gap-1'}">
|
|
74
|
+
<!-- "All" option -->
|
|
75
|
+
{#if group.allLabel !== null}
|
|
76
|
+
<button
|
|
77
|
+
onclick={() => handleSelectAll(group.key)}
|
|
78
|
+
class="
|
|
79
|
+
{compact ? 'px-2.5 py-1.5 text-xs' : 'px-3 py-1.5 text-sm'}
|
|
80
|
+
rounded-lg font-medium transition-all cursor-pointer
|
|
81
|
+
{isAllActive(group.key)
|
|
82
|
+
? 'bg-white text-blue-600 shadow-sm'
|
|
83
|
+
: 'text-gray-600 hover:text-gray-900'}
|
|
84
|
+
"
|
|
85
|
+
>
|
|
86
|
+
{group.allLabel || t('common.all') || 'Tümü'}
|
|
87
|
+
</button>
|
|
88
|
+
{/if}
|
|
89
|
+
|
|
90
|
+
<!-- Filter options -->
|
|
91
|
+
{#each group.options as option}
|
|
92
|
+
<button
|
|
93
|
+
onclick={() => handleSelect(group, option.value)}
|
|
94
|
+
class="
|
|
95
|
+
flex items-start gap-1.5 text-left
|
|
96
|
+
{compact ? 'px-2.5 py-1.5 text-xs' : 'px-3 py-1.5 text-sm'}
|
|
97
|
+
max-w-[10rem] sm:max-w-[14rem]
|
|
98
|
+
rounded-lg font-medium transition-all cursor-pointer
|
|
99
|
+
{isActive(group.key, option.value)
|
|
100
|
+
? 'bg-white text-blue-600 shadow-sm'
|
|
101
|
+
: 'text-gray-600 hover:text-gray-900'}
|
|
102
|
+
"
|
|
103
|
+
>
|
|
104
|
+
{#if option.icon}
|
|
105
|
+
<span class="text-sm">{option.icon}</span>
|
|
106
|
+
{/if}
|
|
107
|
+
<span class="whitespace-normal break-words leading-tight">{option.label}</span>
|
|
108
|
+
{#if option.count !== undefined}
|
|
109
|
+
<span class="
|
|
110
|
+
{compact ? 'text-[10px] px-1' : 'text-xs px-1.5'}
|
|
111
|
+
py-0.5 rounded-full
|
|
112
|
+
{isActive(group.key, option.value)
|
|
113
|
+
? 'bg-blue-100 text-blue-700'
|
|
114
|
+
: 'bg-gray-200 text-gray-600'}
|
|
115
|
+
">
|
|
116
|
+
{option.count}
|
|
117
|
+
</span>
|
|
118
|
+
{/if}
|
|
119
|
+
</button>
|
|
120
|
+
{/each}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
{/each}
|
|
124
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FilterGroup, ActiveFilters } from './types';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Array of filter group definitions */
|
|
4
|
+
groups: FilterGroup[];
|
|
5
|
+
/** Current active filter values (bindable) */
|
|
6
|
+
activeFilters?: ActiveFilters;
|
|
7
|
+
/** Called when any filter changes */
|
|
8
|
+
onFilterChange?: (filters: ActiveFilters) => void;
|
|
9
|
+
/** Compact mode - smaller chips */
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const FilterBar: import("svelte").Component<Props, {}, "activeFilters">;
|
|
13
|
+
type FilterBar = ReturnType<typeof FilterBar>;
|
|
14
|
+
export default FilterBar;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as FilterBar } from './FilterBar.svelte';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single filter option within a filter group
|
|
3
|
+
*/
|
|
4
|
+
export interface FilterOption {
|
|
5
|
+
/** Unique value for this option */
|
|
6
|
+
value: string;
|
|
7
|
+
/** Display label */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Optional icon (emoji or SVG path) */
|
|
10
|
+
icon?: string;
|
|
11
|
+
/** Optional count badge */
|
|
12
|
+
count?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A group of related filter options
|
|
16
|
+
* Each group represents a filter dimension (e.g., type, category, status)
|
|
17
|
+
*/
|
|
18
|
+
export interface FilterGroup {
|
|
19
|
+
/** Unique key for this filter group (used in activeFilters map) */
|
|
20
|
+
key: string;
|
|
21
|
+
/** Display label for the group */
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Available options */
|
|
24
|
+
options: FilterOption[];
|
|
25
|
+
/** Selection mode: single = radio-like, multi = checkbox-like */
|
|
26
|
+
type: 'single' | 'multi';
|
|
27
|
+
/** Custom label for the "all" option. Set to null to hide "all" option (only for multi) */
|
|
28
|
+
allLabel?: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Map of active filter values
|
|
32
|
+
* key = FilterGroup.key
|
|
33
|
+
* value = null (all), string (single selection), string[] (multi selection)
|
|
34
|
+
*/
|
|
35
|
+
export type ActiveFilters = Record<string, string | string[] | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|