hamzus-ui 0.0.194 → 0.0.196

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.
@@ -0,0 +1,331 @@
1
+ <script>
2
+ import Button from '../Button/Button.svelte';
3
+ import * as DropdownMenu from '../DropdownMenu';
4
+ import IconButton from '../IconButton/IconButton.svelte';
5
+ import Switch from '../Switch/Switch.svelte';
6
+ import * as Popover from '../Popover';
7
+ import { tableData } from './table';
8
+ import MonthPicker from '../MonthOfYearPicker/MonthOfYearPicker.svelte';
9
+ import DatePicker from '../DatePicker/DatePicker.svelte';
10
+ import Input from '../Input/Input.svelte';
11
+ import Checkbox from '../Checkboxes/Checkbox/Checkbox.svelte';
12
+
13
+ export let tableId;
14
+
15
+ function handleChangeSkipLine(columnName, newValue) {
16
+ tableData.update((actualValue) => {
17
+ for (let i = 0; i < actualValue[tableId].columns.length; i++) {
18
+ const element = actualValue[tableId].columns[i];
19
+ if (element.name === columnName) {
20
+ actualValue[tableId].columns[i].skipLine = newValue;
21
+ break;
22
+ }
23
+ }
24
+
25
+ return actualValue;
26
+ });
27
+
28
+ document.dispatchEvent(new Event('saveTableData'));
29
+ }
30
+ function handleFilter(columnName, newValue, position) {
31
+
32
+ let foundedColumn = false;
33
+ tableData.update((actualValue) => {
34
+ for (let i = 0; i < actualValue[tableId].columns.length; i++) {
35
+ const element = actualValue[tableId].columns[i];
36
+ if (element.name === columnName) {
37
+ if (newValue === null || newValue === undefined || newValue === '') {
38
+ actualValue[tableId].columns[i].filter = newValue;
39
+ actualValue[tableId].columns[i].filterAfter = newValue;
40
+ actualValue[tableId].columns[i].filterBefore = newValue;
41
+ delete actualValue[tableId].filters[columnName];
42
+ foundedColumn = true;
43
+ break;
44
+ }
45
+
46
+ switch (position) {
47
+ case 'after':
48
+ // filtre datetime apres le
49
+ actualValue[tableId].columns[i].filterAfter = newValue;
50
+
51
+ break;
52
+ case 'before':
53
+ // filtre datetime apres le
54
+ actualValue[tableId].columns[i].filterBefore = newValue;
55
+ break;
56
+
57
+ default:
58
+ // filtre standart (recherche textuelle)
59
+ actualValue[tableId].columns[i].filter = newValue;
60
+ break;
61
+ }
62
+
63
+ actualValue[tableId].offset = 0;
64
+ actualValue[tableId].filters[columnName] = newValue;
65
+ foundedColumn = true;
66
+ break;
67
+ }
68
+ }
69
+
70
+ return actualValue;
71
+ });
72
+
73
+ if (foundedColumn) {
74
+ // emmetre un event
75
+ document.dispatchEvent(new Event('updateTableResult'));
76
+ }
77
+ }
78
+ function handleSort(columnName) {
79
+ tableData.update((actualValue) => {
80
+ const actualSort = actualValue[tableId].sort;
81
+
82
+ // si la colonne est different alors on set la direction en desc
83
+ let newDirection = '';
84
+ if (actualSort.columnName != columnName) {
85
+ newDirection = 'DESC';
86
+ } else {
87
+ // modifier la direction
88
+ switch (actualSort.direction) {
89
+ case '':
90
+ newDirection = 'DESC';
91
+ break;
92
+ case 'DESC':
93
+ newDirection = 'ASC';
94
+ break;
95
+ default:
96
+ // if "ASC" -> remove filter
97
+ newDirection = '';
98
+ break;
99
+ }
100
+ }
101
+
102
+ actualValue[tableId].sort = {
103
+ columnName: columnName,
104
+ direction: newDirection
105
+ };
106
+
107
+ return actualValue;
108
+ });
109
+ document.dispatchEvent(new Event('updateTableResult'));
110
+ }
111
+ function focusInput(columnName) {
112
+ // selectionner l input si il y en a
113
+
114
+ if (document.querySelector(`.input-column-hamzus-${columnName}`)) {
115
+ document.querySelector(`.input-column-hamzus-${columnName} input`).focus();
116
+ }
117
+ }
118
+ function unfocusInput() {
119
+ // selectionner l input si il y en a
120
+
121
+ if (document.querySelector(`input:focus`)) {
122
+ document.querySelector(`input:focus`).blur();
123
+ }
124
+ }
125
+ function handleSelectAll() {
126
+ tableData.update((actualValue) => {
127
+ if (actualValue[tableId].selection.length !== actualValue[tableId].rows.length) {
128
+ let allRows = actualValue[tableId].rows;
129
+ actualValue[tableId].selection = allRows;
130
+ return actualValue;
131
+ }
132
+
133
+ actualValue[tableId].selection = [];
134
+
135
+ return actualValue;
136
+ });
137
+ }
138
+ </script>
139
+
140
+ {#if $tableData[tableId].actions.length > 0}
141
+ <div
142
+ style="--width:50px"
143
+ class="selector column {$tableData[tableId].selection.length > 0 ? 'active' : ''}"
144
+ >
145
+ <Checkbox
146
+ size={24}
147
+ checked={$tableData[tableId].selection.length === $tableData[tableId].rows.length}
148
+ onChange={handleSelectAll}
149
+ ></Checkbox>
150
+ </div>
151
+ {/if}
152
+ <DropdownMenu.Root>
153
+ <DropdownMenu.Trigger slot="trigger">
154
+ <IconButton variant="outline" style="margin:7px 0px;">
155
+ <svg
156
+ width="24"
157
+ height="24"
158
+ viewBox="0 0 24 24"
159
+ fill="none"
160
+ xmlns="http://www.w3.org/2000/svg"
161
+ >
162
+ <path
163
+ d="M10.9308 22.75C10.4508 22.75 9.97082 22.63 9.53082 22.39C8.64082 21.89 8.11078 21 8.11078 19.99V14.64C8.11078 14.13 7.78076 13.38 7.47076 12.99L3.67078 9.00003C3.04078 8.37003 2.55078 7.27002 2.55078 6.46002V4.14005C2.55078 2.53005 3.7708 1.27002 5.3208 1.27002H18.6608C20.1908 1.27002 21.4308 2.51004 21.4308 4.04004V6.26004C21.4308 7.31004 20.8008 8.52002 20.2008 9.11002C19.9108 9.40002 19.4308 9.40002 19.1408 9.11002C18.8508 8.82002 18.8508 8.34002 19.1408 8.05002C19.5108 7.68002 19.9308 6.85004 19.9308 6.26004V4.04004C19.9308 3.34004 19.3608 2.77002 18.6608 2.77002H5.3208C4.6108 2.77002 4.05078 3.37005 4.05078 4.14005V6.46002C4.05078 6.83002 4.35078 7.56004 4.74078 7.95004L8.59082 12C9.10082 12.63 9.60077 13.69 9.60077 14.64V19.99C9.60077 20.65 10.0508 20.97 10.2508 21.08C10.6808 21.32 11.1908 21.31 11.5908 21.07L12.9908 20.17C13.2808 20 13.5608 19.45 13.5608 19.08C13.5608 18.67 13.9008 18.33 14.3108 18.33C14.7208 18.33 15.0608 18.67 15.0608 19.08C15.0608 19.98 14.5008 21.01 13.7908 21.44L12.4008 22.34C11.9508 22.61 11.4408 22.75 10.9308 22.75Z"
164
+ fill="#292D32"
165
+ />
166
+ <path
167
+ d="M16.0711 17.2701C13.8911 17.2701 12.1211 15.5001 12.1211 13.3201C12.1211 11.1401 13.8911 9.37012 16.0711 9.37012C18.2511 9.37012 20.0211 11.1401 20.0211 13.3201C20.0211 15.5001 18.2511 17.2701 16.0711 17.2701ZM16.0711 10.8701C14.7211 10.8701 13.6211 11.9701 13.6211 13.3201C13.6211 14.6701 14.7211 15.7701 16.0711 15.7701C17.4211 15.7701 18.5211 14.6701 18.5211 13.3201C18.5211 11.9701 17.4211 10.8701 16.0711 10.8701Z"
168
+ fill="#292D32"
169
+ />
170
+ <path
171
+ d="M19.8705 17.8701C19.6805 17.8701 19.4905 17.8001 19.3405 17.6501L18.3405 16.6501C18.0505 16.3601 18.0505 15.8801 18.3405 15.5901C18.6305 15.3001 19.1105 15.3001 19.4005 15.5901L20.4005 16.5901C20.6905 16.8801 20.6905 17.3601 20.4005 17.6501C20.2605 17.7901 20.0605 17.8701 19.8705 17.8701Z"
172
+ fill="#292D32"
173
+ />
174
+ </svg>
175
+ </IconButton>
176
+ </DropdownMenu.Trigger>
177
+ <DropdownMenu.Content slot="content">
178
+ {#each $tableData[tableId].columns as column, index}
179
+ {#if !column.hidden}
180
+ {#if column.isSearchable}
181
+ <DropdownMenu.Root
182
+ triggerFullWidth
183
+ onOpen={() => {
184
+ focusInput(column.name);
185
+ }}
186
+ onClose={unfocusInput}
187
+ >
188
+ <DropdownMenu.Trigger slot="trigger">
189
+ <Button style="width:100%;" avoidRipple={!column.isSearchable} variant="ghost">
190
+ <h4>{column.label}</h4>
191
+ <h4>
192
+ {$tableData[tableId].sort &&
193
+ $tableData[tableId].sort.columnName === column.name &&
194
+ $tableData[tableId].sort.direction !== ''
195
+ ? $tableData[tableId].sort.direction === 'DESC'
196
+ ? '⬇️'
197
+ : '⬆️'
198
+ : ''}
199
+ </h4>
200
+ <h4>
201
+ {$tableData[tableId].filters &&
202
+ ($tableData[tableId].filters[column.name] != '') &
203
+ ($tableData[tableId].filters[column.name] != undefined)
204
+ ? '🔍'
205
+ : ''}
206
+ </h4>
207
+ </Button>
208
+ </DropdownMenu.Trigger>
209
+ <DropdownMenu.Content slot="content">
210
+ <DropdownMenu.Label>{column.label}</DropdownMenu.Label>
211
+ {#if !column.searchChoices}
212
+ {#if column.monthPicker}
213
+ <div class="input-column-hamzus-{column.name}">
214
+ <MonthPicker
215
+ label="mois"
216
+ value={column.filter ?? ''}
217
+ onChange={(newValue) => {
218
+ handleFilter(column.name, newValue);
219
+ }}
220
+ ></MonthPicker>
221
+ </div>
222
+ {:else if column.datePicker}
223
+ <div class="input-column-hamzus-{column.name}">
224
+ <DatePicker
225
+ label="à partir du"
226
+ value={column.filterAfter ?? ''}
227
+ onChange={(newValue) => {
228
+ handleFilter(column.name, newValue, 'after');
229
+ }}
230
+ ></DatePicker>
231
+ <DatePicker
232
+ label="jusqu'au"
233
+ value={column.filterBefore ?? ''}
234
+ onChange={(newValue) => {
235
+ handleFilter(column.name, newValue, 'before');
236
+ }}
237
+ ></DatePicker>
238
+ </div>
239
+ {:else}
240
+ <div class="input-column-hamzus-{column.name}">
241
+ <Input
242
+ placeholder="filtre"
243
+ value={column.filter ?? ''}
244
+ onChange={(newValue) => {
245
+ handleFilter(column.name, newValue);
246
+ }}
247
+ ></Input>
248
+ </div>
249
+ {/if}
250
+ {:else}
251
+ <Popover.Root direction="right" triggerFullWidth>
252
+ <Popover.Trigger slot="trigger">
253
+ <Button style="width:100%;justify-content:space-between;" variant="ghost">
254
+ <h4>filtre</h4>
255
+ <svg
256
+ width="24"
257
+ height="24"
258
+ viewBox="0 0 24 24"
259
+ fill="none"
260
+ xmlns="http://www.w3.org/2000/svg"
261
+ >
262
+ <path
263
+ d="M14.4291 18.8201C14.2391 18.8201 14.0491 18.7501 13.8991 18.6001C13.6091 18.3101 13.6091 17.8301 13.8991 17.5401L19.4391 12.0001L13.8991 6.46012C13.6091 6.17012 13.6091 5.69012 13.8991 5.40012C14.1891 5.11012 14.6691 5.11012 14.9591 5.40012L21.0291 11.4701C21.3191 11.7601 21.3191 12.2401 21.0291 12.5301L14.9591 18.6001C14.8091 18.7501 14.6191 18.8201 14.4291 18.8201Z"
264
+ fill="#292D32"
265
+ />
266
+ <path
267
+ d="M20.33 12.75H3.5C3.09 12.75 2.75 12.41 2.75 12C2.75 11.59 3.09 11.25 3.5 11.25H20.33C20.74 11.25 21.08 11.59 21.08 12C21.08 12.41 20.74 12.75 20.33 12.75Z"
268
+ fill="#292D32"
269
+ />
270
+ </svg>
271
+ </Button>
272
+ </Popover.Trigger>
273
+ <Popover.Content slot="content">
274
+ <Popover.Button
275
+ label="aucun"
276
+ onClick={() => {
277
+ handleFilter(column.name, null);
278
+ }}
279
+ ></Popover.Button>
280
+ {#each column.searchChoices as choice}
281
+ <Popover.Button
282
+ label={choice.label}
283
+ onClick={() => {
284
+ handleFilter(column.name, choice.value);
285
+ }}
286
+ ></Popover.Button>
287
+ {/each}
288
+ </Popover.Content>
289
+ </Popover.Root>
290
+ {/if}
291
+ <DropdownMenu.Separator></DropdownMenu.Separator>
292
+ <DropdownMenu.Button variant="ghost" style="padding:0;">
293
+ <label
294
+ style="display:flex;align-items:center;justify-content:space-between;width:100%;padding:3px 7px;"
295
+ >
296
+ <h4>ne pas passer a la ligne</h4>
297
+ <Switch
298
+ checked={column.skipLine}
299
+ onChange={(newValue) => {
300
+ handleChangeSkipLine(column.name, newValue);
301
+ }}
302
+ size={16}
303
+ ></Switch>
304
+ </label>
305
+ </DropdownMenu.Button>
306
+ {#if column.isSortable !== false}
307
+ <DropdownMenu.Separator></DropdownMenu.Separator>
308
+ <DropdownMenu.Button
309
+ onClick={() => {
310
+ handleSort(column.name);
311
+ }}
312
+ variant="ghost"
313
+ label="trier"
314
+ ></DropdownMenu.Button>
315
+ {/if}
316
+ </DropdownMenu.Content>
317
+ </DropdownMenu.Root>
318
+ {:else}
319
+ <div style="width:100%;">
320
+ <Button
321
+ style="width:100%;"
322
+ avoidRipple={!column.isSearchable}
323
+ variant="ghost"
324
+ label={column.label}
325
+ ></Button>
326
+ </div>
327
+ {/if}
328
+ {/if}
329
+ {/each}
330
+ </DropdownMenu.Content>
331
+ </DropdownMenu.Root>
@@ -0,0 +1,166 @@
1
+ <script>
2
+ // import
3
+ import { onDestroy, onMount } from 'svelte';
4
+ import TableLoader from './TableLoader.svelte';
5
+
6
+ // props
7
+ export let tableId = 0;
8
+ export let columnDateFilter = "created_at";
9
+ export let columns = [];
10
+ export let filters = {};
11
+ export let sort = {};
12
+ export let totalOfRows = 0;
13
+ export let limit = 20;
14
+ export let offset = 0;
15
+ export let version = 1;
16
+ export let onClick = undefined;
17
+ export let getRows = (filters, sort, limit, offset) => {};
18
+
19
+ export let ctx = {
20
+ tableId:`${tableId}_calendar_hamzus_ui`,
21
+ columnDateFilter,
22
+ columns,
23
+ filters,
24
+ sort,
25
+ totalOfRows,
26
+ limit,
27
+ offset,
28
+ version,
29
+ onClick,
30
+ getRows:handleGetRows,
31
+ };
32
+
33
+
34
+ // locale var
35
+ let mounted = false;
36
+ let loading = false;
37
+ let rows = [];
38
+ let defaultColumns = [...columns];
39
+
40
+ // life component
41
+ onMount(async () => {
42
+
43
+
44
+ // verifier si l utilisateur possede une ocnfigursation enregistre dans le localsotrage
45
+ const savedConfiguration = localStorage.getItem(ctx.tableId);
46
+
47
+ if (savedConfiguration) {
48
+ try {
49
+ const overrideConfig = JSON.parse(savedConfiguration);
50
+
51
+ const upToDate = version === (overrideConfig.version ?? null)
52
+
53
+ // si il n'est pas a jour alors il doit étre surpimmer le localstorage et le mettre a jour
54
+ if (!upToDate) {
55
+ localStorage.removeItem(ctx.tableId)
56
+ }else{
57
+ columns = overrideConfig.columns;
58
+ }
59
+ filters = overrideConfig.filters;
60
+ } catch (error) {
61
+ // suprimmer ce localstorage car il ne peut pas etre decoder
62
+ localStorage.removeItem(ctx.tableId);
63
+ }
64
+ }
65
+
66
+ // aller chercher les rows
67
+ const request = await getRows(filters, sort, limit, offset)
68
+ totalOfRows = request.totalOfRows
69
+ rows = request.rows;
70
+ });
71
+
72
+ onDestroy(()=>{
73
+ mounted = false;
74
+ })
75
+
76
+ async function handleUpdateResult() {
77
+ if (!mounted || loading) {
78
+ return
79
+ }
80
+ loading = true
81
+
82
+ const actualTableData = ctx;
83
+
84
+ let filters = {
85
+ ...actualTableData.filters
86
+ }
87
+
88
+ // vertifier si il n y a pas de filtre special style datepicker pour interval de temsp
89
+ for (const column of actualTableData.columns) {
90
+ if (!column.datePicker ) {
91
+ continue;
92
+ }
93
+ if (filters[column.name]) {
94
+ delete filters[column.name]
95
+ }
96
+ if (column.filterAfter) {
97
+ filters = {
98
+ ...filters,
99
+ [column.name + "_after"]:column.filterAfter
100
+ }
101
+ }
102
+ if (column.filterBefore) {
103
+ filters = {
104
+ ...filters,
105
+ [column.name + "_before"]:column.filterBefore
106
+ }
107
+ }
108
+ }
109
+
110
+ const request = await handleGetRows(
111
+ filters,
112
+ actualTableData.sort,
113
+ actualTableData.limit,
114
+ actualTableData.offset
115
+ )
116
+
117
+ saveDataActualData();
118
+
119
+ loading = false
120
+ }
121
+ async function saveDataActualData() {
122
+ if (!mounted) {
123
+ return;
124
+ }
125
+ localStorage.setItem(ctx.tableId, JSON.stringify(ctx));
126
+ }
127
+ function handleResetSettings() {
128
+ ctx.columns = structuredClone(defaultColumns);
129
+ saveDataActualData()
130
+ }
131
+
132
+ async function handleGetRows(filters, sort, limit, offset) {
133
+ loading = true;
134
+ const request = await getRows(filters, sort, limit, offset)
135
+ totalOfRows = request.totalOfRows
136
+ rows = request.rows;
137
+ loading = false;
138
+ }
139
+ </script>
140
+
141
+ {#if mounted}
142
+ <div class="table">
143
+ <div class="top-bar">
144
+ <slot name="actions-bar" {ctx}></slot>
145
+ </div>
146
+ {#if loading}
147
+ <TableLoader></TableLoader>
148
+ {:else}
149
+ <slot name="content" {ctx}></slot>
150
+ {/if}
151
+ </div>
152
+ {/if}
153
+
154
+ <style>
155
+ .table {
156
+ display: flex;
157
+ flex-direction: column;
158
+ width: 100%;
159
+ }
160
+ .top-bar{
161
+ position: sticky;
162
+ top: 0;
163
+ background-color: var(--bg-1);
164
+ z-index: 1;
165
+ }
166
+ </style>
@@ -0,0 +1,15 @@
1
+ <script>
2
+ import Skeleton from '../Skeleton/Skeleton.svelte';
3
+ </script>
4
+
5
+ <div class="result">
6
+ <h1>Chargement...</h1>
7
+ </div>
8
+
9
+ <style>
10
+ .result{
11
+ display: flex;
12
+ flex-direction: column;
13
+ row-gap: var(--pad-xs);
14
+ }
15
+ </style>
@@ -0,0 +1,3 @@
1
+ export { default as Root } from './Root.svelte';//main logic
2
+ export { default as ActionsBar } from './ActionsBar.svelte';//search, active filters, columns list,...
3
+ export { default as Content } from './Content.svelte';//table rows