mountain-ui 1.0.109 → 1.0.111

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.
Files changed (44) hide show
  1. package/index.d.ts +29 -0
  2. package/index.js +29 -0
  3. package/package.json +1 -1
  4. package/src/lib/registry/navigationRegistry/components/NavigationGroupRow.svelte +30 -32
  5. package/src/lib/registry/navigationRegistry/components/NewNavbarGroupDialog.svelte +43 -39
  6. package/src/lib/registry/navigationRegistry/registerNavigation.js +1 -3
  7. package/src/lib/registry/projectRegistry/createProject.js +2 -0
  8. package/src/lib/registry/widgetGroupRegistry/components/EmptySlot.svelte +47 -0
  9. package/src/lib/registry/widgetGroupRegistry/components/GroupPreview.svelte +142 -0
  10. package/src/lib/registry/widgetGroupRegistry/components/NewWidgetGroup.svelte +122 -0
  11. package/src/lib/registry/widgetGroupRegistry/components/WidgetGroup.svelte +39 -0
  12. package/src/lib/registry/widgetGroupRegistry/createWidget.js +17 -0
  13. package/src/lib/registry/widgetGroupRegistry/createWidgetGroup.js +19 -0
  14. package/src/lib/registry/widgetGroupRegistry/registerWidgetGroups.js +37 -0
  15. package/src/lib/registry/widgetGroupRegistry/registry.svelte.js +47 -0
  16. package/src/lib/registry/widgetTypeRegistry/components/CreateWidgetDialog.svelte +25 -0
  17. package/src/lib/registry/widgetTypeRegistry/components/Widget.svelte +18 -0
  18. package/src/lib/registry/widgetTypeRegistry/components/WidgetConfig.svelte +16 -0
  19. package/src/lib/registry/widgetTypeRegistry/components/WidgetPreview.svelte +59 -0
  20. package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeButton.svelte +20 -0
  21. package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeSelector.svelte +32 -0
  22. package/src/lib/registry/widgetTypeRegistry/createWidgetType.js +20 -0
  23. package/src/lib/registry/widgetTypeRegistry/registerWidgetTypes.js +14 -0
  24. package/src/lib/registry/widgetTypeRegistry/registry.svelte.js +43 -0
  25. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/Bar.svelte +79 -0
  26. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/ConfigBar.svelte +176 -0
  27. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/index.js +13 -0
  28. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/text.js +21 -0
  29. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/ConfigEvolution.svelte +180 -0
  30. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/Evolution.svelte +81 -0
  31. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/index.js +13 -0
  32. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/text.js +21 -0
  33. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/ConfigKPI.svelte +201 -0
  34. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/KPI.svelte +118 -0
  35. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/index.js +12 -0
  36. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/text.js +22 -0
  37. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/ConfigList.svelte +199 -0
  38. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/List.svelte +97 -0
  39. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/index.js +12 -0
  40. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/text.js +21 -0
  41. package/src/routes/exemple/[project_normalized_name]/+layout.svelte +1 -1
  42. package/src/routes/exemple/[project_normalized_name]/home/+page.svelte +61 -1
  43. package/src/routes/exemple/[project_normalized_name]/navigation/+page.svelte +28 -0
  44. package/src/routes/exemple/[project_normalized_name]/widgets/+page.svelte +92 -0
@@ -0,0 +1,201 @@
1
+ <script>
2
+ import { Button, DropdownMenu, Input, sendRequest } from 'hamzus-ui';
3
+ import { frequencyText, frequencyTextForConfig } from './text';
4
+ import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
5
+
6
+ let { id = null, save = () => {} } = $props();
7
+
8
+ let title = $state('');
9
+
10
+ const entities = entityRegistry.getAll()
11
+
12
+ let entityId = $state(null);
13
+ const entity = $derived(entityRegistry.get(entityId));
14
+
15
+ let frequency = $state('month'); // day | month | year
16
+ const frequencies = ['day', 'month', 'year'];
17
+
18
+ let valueFieldId = $state(null);
19
+ const valueField = $derived(entityRegistry.getField(valueFieldId));
20
+
21
+ let dateFieldId = $state(null);
22
+ const dateField = $derived(entityRegistry.getField(dateFieldId));
23
+ const dateFieldTypes = ['time-created_at', 'time-datetime', 'time-updated_at'];
24
+
25
+ let operation = $state('count'); // count | sum | avg | min | max
26
+ const operations = ['count', 'sum', 'avg', 'min', 'max'];
27
+
28
+ let size = $state('4/1');
29
+ const sizes = ['4/1', '6/1', '8/1', '12/1'];
30
+
31
+ function handleSelectEntity(entity) {
32
+ entityId = entity.id;
33
+
34
+ // parcourir les fields pour set auto le field de value et de date
35
+ for (const field of entity.fields) {
36
+ if (field.type.startsWith('number-') || field.type.startsWith('calculation-')) {
37
+ valueFieldId = field.id;
38
+ }
39
+ if (dateFieldTypes.includes(field.type)) {
40
+ dateFieldId = field.id;
41
+ }
42
+ }
43
+ }
44
+
45
+ async function handleSave() {
46
+ save({
47
+ id,
48
+ title,
49
+ entityId,
50
+ frequency,
51
+ valueFieldId,
52
+ dateFieldId,
53
+ operation,
54
+ size
55
+ });
56
+ }
57
+ </script>
58
+
59
+ <div class="config">
60
+ <Input label="titre" bind:value={title} placeholder="exemple"></Input>
61
+ <h5>opération</h5>
62
+ <DropdownMenu.Root direction="bottom">
63
+ <DropdownMenu.Trigger slot="trigger">
64
+ <Button variant="secondary">
65
+ <h5>{operation ?? 'choisissez une opération'}</h5>
66
+ </Button>
67
+ </DropdownMenu.Trigger>
68
+ <DropdownMenu.Content slot="content" width="250px">
69
+ {#each operations as operationEl}
70
+ <Button
71
+ onClick={() => {
72
+ operation = operationEl;
73
+ }}
74
+ variant="ghost"
75
+ style="width:100%;"><h5>{operationEl}</h5></Button
76
+ >
77
+ {/each}
78
+ </DropdownMenu.Content>
79
+ </DropdownMenu.Root>
80
+ <h5>Entité</h5>
81
+ <DropdownMenu.Root direction="bottom">
82
+ <DropdownMenu.Trigger slot="trigger">
83
+ <Button variant="secondary">
84
+ <h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
85
+ </Button>
86
+ </DropdownMenu.Trigger>
87
+ <DropdownMenu.Content slot="content" width="250px">
88
+ {#each $entities as entity}
89
+ <Button
90
+ onClick={() => {
91
+ handleSelectEntity(entity);
92
+ }}
93
+ variant="ghost"
94
+ style="width:100%;"><h5>{entity.plural_name}</h5></Button
95
+ >
96
+ {/each}
97
+ </DropdownMenu.Content>
98
+ </DropdownMenu.Root>
99
+ {#if entity}
100
+ {@const availedValueFields = entity.fields.filter(
101
+ (field) => field.type.startsWith('number-') || field.type.startsWith('calculation-')
102
+ )}
103
+ {@const availedDateFields = entity.fields.filter((field) =>
104
+ dateFieldTypes.includes(field.type)
105
+ )}
106
+ {#if operation !== 'count'}
107
+ <h5>Champs pour valeurs</h5>
108
+ <DropdownMenu.Root direction="bottom">
109
+ <DropdownMenu.Trigger slot="trigger">
110
+ <Button variant="secondary">
111
+ <h5>{valueField?.name ?? 'choisissez un champ pour valeur'}</h5>
112
+ </Button>
113
+ </DropdownMenu.Trigger>
114
+ <DropdownMenu.Content slot="content" width="250px">
115
+ {#if availedValueFields.length > 0}
116
+ {#each availedValueFields as field}
117
+ <Button
118
+ onClick={() => {
119
+ valueFieldId = field.id;
120
+ }}
121
+ variant="ghost"
122
+ style="width:100%;"><h5>{field.name}</h5></Button
123
+ >
124
+ {/each}
125
+ {:else}
126
+ <div class="nothing">
127
+ <h3>Aucun champs de valeur disponible</h3>
128
+ <p>
129
+ L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
130
+ </p>
131
+ </div>
132
+ {/if}
133
+ </DropdownMenu.Content>
134
+ </DropdownMenu.Root>
135
+ {/if}
136
+ <h5>Champs pour date</h5>
137
+ <DropdownMenu.Root direction="bottom">
138
+ <DropdownMenu.Trigger slot="trigger">
139
+ <Button variant="secondary">
140
+ <h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
141
+ </Button>
142
+ </DropdownMenu.Trigger>
143
+ <DropdownMenu.Content slot="content" width="250px">
144
+ {#if availedDateFields.length > 0}
145
+ {#each availedDateFields as field}
146
+ <Button
147
+ onClick={() => {
148
+ dateFieldId = field.id;
149
+ }}
150
+ variant="ghost"
151
+ style="width:100%;"><h5>{field.name}</h5></Button
152
+ >
153
+ {/each}
154
+ {:else}
155
+ <div class="nothing">
156
+ <h3>Aucun champs de date disponible</h3>
157
+ <p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
158
+ </div>
159
+ {/if}
160
+ </DropdownMenu.Content>
161
+ </DropdownMenu.Root>
162
+ <h5>fréquence</h5>
163
+ <DropdownMenu.Root direction="bottom">
164
+ <DropdownMenu.Trigger slot="trigger">
165
+ <Button variant="secondary">
166
+ <h5>{frequency ? frequencyTextForConfig[frequency] : 'choisissez une fréquence'}</h5>
167
+ </Button>
168
+ </DropdownMenu.Trigger>
169
+ <DropdownMenu.Content slot="content" width="250px">
170
+ {#each frequencies as frequencyEl}
171
+ <Button
172
+ onClick={() => {
173
+ frequency = frequencyEl;
174
+ }}
175
+ variant="ghost"
176
+ style="width:100%;"><h5>{frequencyTextForConfig[frequencyEl]}</h5></Button
177
+ >
178
+ {/each}
179
+ </DropdownMenu.Content>
180
+ </DropdownMenu.Root>
181
+ {/if}
182
+
183
+ <Button onClick={handleSave}>
184
+ <h5>enregistrer</h5>
185
+ </Button>
186
+ </div>
187
+
188
+ <style>
189
+ .config {
190
+ display: flex;
191
+ flex-direction: column;
192
+ row-gap: var(--pad-m);
193
+ }
194
+
195
+ .nothing {
196
+ display: flex;
197
+ flex-direction: column;
198
+ row-gap: var(--pad-m);
199
+ padding: var(--pad-m);
200
+ }
201
+ </style>
@@ -0,0 +1,118 @@
1
+ <script>
2
+ import { sendRequest, Skeleton } from 'hamzus-ui';
3
+ import { frequencyText, operationText } from './text';
4
+ import { onMount } from 'svelte';
5
+
6
+ let {
7
+ id = '',
8
+ title = '',
9
+ entityId = '',
10
+ frequency = '',
11
+ valueFieldId = '',
12
+ dateFieldId = '',
13
+ operation = '',
14
+ } = $props()
15
+
16
+ let total = $state(null);
17
+ let previousTotal = $state(null);
18
+
19
+ onMount(async () => {
20
+ const request = await sendRequest({
21
+ path: '/get-widget-data',
22
+ data: {
23
+ widgetLinkId: id
24
+ }
25
+ });
26
+
27
+ total = request.data[0];
28
+ previousTotal = request.data[1];
29
+ });
30
+
31
+ function getRandomSizes() {
32
+ const sizes = [60, 120, 80];
33
+
34
+ return sizes[Math.floor(Math.random() * sizes.length)];
35
+ }
36
+
37
+ function getPercent() {
38
+ if (previousTotal === 0) {
39
+ if (total === 0) return 0;
40
+ return null; // augmentation non calculable
41
+ }
42
+ return ((total - previousTotal) / previousTotal) * 100;
43
+ }
44
+ </script>
45
+
46
+ <div class="kpi-container">
47
+ <div class="kpi">
48
+ <h4>{title}</h4>
49
+ {#if total === null}
50
+ <Skeleton style="width:{getRandomSizes()}px;height:32px;"></Skeleton>
51
+ {:else}
52
+ <h3>{total}</h3>
53
+ {/if}
54
+ <div class="bottom">
55
+ <h5>{frequencyText[frequency] ?? '-'} | {operationText[operation] ?? '-'}</h5>
56
+ <div class="right">
57
+ {#if total === null}
58
+ <h4 style="color: var(--green);">+</h4>
59
+ <Skeleton style="width:24px;height:16px;" />
60
+ <h4 style="color: var(--green);">%</h4>
61
+ {:else}
62
+ {@const percent = getPercent()}
63
+ {#if percent !== null}
64
+ <h4 style="color: var(--green);">+{getPercent()} %</h4>
65
+ <svg
66
+ width="24"
67
+ height="24"
68
+ viewBox="0 0 24 24"
69
+ fill="none"
70
+ xmlns="http://www.w3.org/2000/svg"
71
+ >
72
+ <path
73
+ opacity="0.4"
74
+ d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
75
+ fill="#34C759"
76
+ />
77
+ <path
78
+ d="M15.5295 10.9699L12.5295 7.96994C12.2395 7.67994 11.7595 7.67994 11.4695 7.96994L8.46945 10.9699C8.17945 11.2599 8.17945 11.7399 8.46945 12.0299C8.75945 12.3199 9.23945 12.3199 9.52945 12.0299L11.2495 10.3099V15.4999C11.2495 15.9099 11.5895 16.2499 11.9995 16.2499C12.4095 16.2499 12.7495 15.9099 12.7495 15.4999V10.3099L14.4695 12.0299C14.6195 12.1799 14.8095 12.2499 14.9995 12.2499C15.1895 12.2499 15.3795 12.1799 15.5295 12.0299C15.8195 11.7399 15.8195 11.2599 15.5295 10.9699Z"
79
+ fill="#34C759"
80
+ />
81
+ </svg>
82
+ {/if}
83
+ {/if}
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <style>
90
+ .kpi-container {
91
+ width: 100%;
92
+ height: 100%;
93
+ padding: var(--pad-m);
94
+ }
95
+
96
+ .kpi {
97
+ display: flex;
98
+ flex-direction: column;
99
+ row-gap: var(--pad-m);
100
+ padding: var(--pad-xxl);
101
+ width: 100%;
102
+ height: 100%;
103
+ background-color: var(--bg-blur);
104
+ border-radius: var(--radius-m);
105
+ }
106
+
107
+ .bottom {
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: space-between;
111
+ }
112
+
113
+ .right {
114
+ display: flex;
115
+ align-items: center;
116
+ column-gap: var(--pad-m);
117
+ }
118
+ </style>
@@ -0,0 +1,12 @@
1
+ import ConfigKPI from "./ConfigKPI.svelte";
2
+ import KPI from "./KPI.svelte";
3
+ import { createWidgetType } from "../../createWidgetType";
4
+
5
+ export default createWidgetType({
6
+ type: "KPI",
7
+ name: "KPI",
8
+ components: {
9
+ config: ConfigKPI,
10
+ component: KPI,
11
+ }
12
+ })
@@ -0,0 +1,22 @@
1
+
2
+
3
+ export const frequencyText = {
4
+ 'day': 'aujourd\'hui',
5
+ 'month': 'ce mois-ci',
6
+ 'year': 'cette année'
7
+ }
8
+
9
+ export const frequencyTextForConfig = {
10
+ 'day': 'par jour',
11
+ 'month': 'par mois',
12
+ 'year': 'par an'
13
+ }
14
+
15
+
16
+ export const operationText = {
17
+ 'count': 'nombre d\'entrée',
18
+ 'sum': 'somme',
19
+ 'avg': 'moyenne',
20
+ 'min': "min",
21
+ 'max': "max"
22
+ }
@@ -0,0 +1,199 @@
1
+ <script>
2
+ import { Button, DropdownMenu, Input, sendRequest } from 'hamzus-ui';
3
+ import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
4
+
5
+ let {
6
+ id = null,
7
+ save = () => {},
8
+ } = $props()
9
+
10
+ let title = $state('');
11
+
12
+ const entities = entityRegistry.getAll()
13
+
14
+ let entityId = $state(null);
15
+ const entity = $derived(entityRegistry.get(entityId));
16
+
17
+
18
+ let valueFieldId = $state(null);
19
+ const valueField = $derived(entityRegistry.getField(valueFieldId));
20
+ let selectedValueOfValueField = $state(null);
21
+
22
+ let sortFieldId = $state(null);
23
+ const dateField = $derived(entityRegistry.getField(sortFieldId));
24
+ const dateFieldTypes = ['time-created_at', 'time-datetime', 'time-updated_at', 'primary'];
25
+
26
+ let operation = $state('count'); // count | sum | avg | min | max
27
+ const operations = ['count', 'sum', 'avg', 'min', 'max'];
28
+
29
+ let size = $state('12/2');
30
+ const sizes = ['8/2', '12/2'];
31
+
32
+ function handleSelectEntity(entity) {
33
+ entityId = entity.id;
34
+
35
+ // parcourir les fields pour set auto le field de value et de date
36
+ for (const field of entity.fields) {
37
+ // if (field.type.startsWith('number-') || field.type.startsWith('calculation-')) {
38
+ // valueFieldId = field.id;
39
+ // }
40
+ if (dateFieldTypes.includes(field.type)) {
41
+ sortFieldId = field.id;
42
+ }
43
+ }
44
+ }
45
+
46
+ async function handleSave() {
47
+ save({
48
+ id,
49
+ title,
50
+ entityId,
51
+ valueFieldId,
52
+ selectedValueOfValueField,
53
+ sortFieldId,
54
+ operation,
55
+ size
56
+ });
57
+ }
58
+ </script>
59
+
60
+ <div class="config">
61
+ <Input label="titre" bind:value={title} placeholder="exemple"></Input>
62
+ <h5>Entité</h5>
63
+ <DropdownMenu.Root direction="bottom">
64
+ <DropdownMenu.Trigger slot="trigger">
65
+ <Button variant="secondary">
66
+ <h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
67
+ </Button>
68
+ </DropdownMenu.Trigger>
69
+ <DropdownMenu.Content slot="content" width="250px">
70
+ {#each $entities as entity}
71
+ <Button
72
+ onClick={() => {
73
+ handleSelectEntity(entity);
74
+ }}
75
+ variant="ghost"
76
+ style="width:100%;"><h5>{entity.plural_name}</h5></Button
77
+ >
78
+ {/each}
79
+ </DropdownMenu.Content>
80
+ </DropdownMenu.Root>
81
+ {#if entity}
82
+ {@const availedValueFields = entity.fields.filter((field) => field.type === 'list-radio')}
83
+ {@const availedDateFields = entity.fields.filter((field) =>
84
+ dateFieldTypes.includes(field.type)
85
+ )}
86
+ <h5>Précisé un status</h5>
87
+ <DropdownMenu.Root direction="bottom">
88
+ <DropdownMenu.Trigger slot="trigger">
89
+ <Button variant="secondary">
90
+ <h5>{valueField?.name ?? 'choisissez un champ pour status'}</h5>
91
+ </Button>
92
+ </DropdownMenu.Trigger>
93
+ <DropdownMenu.Content slot="content" width="250px">
94
+ {#if availedValueFields.length > 0}
95
+ {#each availedValueFields as field}
96
+ <Button
97
+ onClick={() => {
98
+ valueFieldId = field.id;
99
+ }}
100
+ variant="ghost"
101
+ style="width:100%;"><h5>{field.name}</h5></Button
102
+ >
103
+ {/each}
104
+ {:else}
105
+ <div class="nothing">
106
+ <h3>Aucun champs de status disponible</h3>
107
+ <p>
108
+ L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
109
+ </p>
110
+ </div>
111
+ {/if}
112
+ </DropdownMenu.Content>
113
+ </DropdownMenu.Root>
114
+ {#if valueField}
115
+ <h5>status</h5>
116
+ <DropdownMenu.Root direction="bottom">
117
+ <DropdownMenu.Trigger slot="trigger">
118
+ <Button variant="secondary">
119
+ <h5>{selectedValueOfValueField ?? 'choisissez un status'}</h5>
120
+ </Button>
121
+ </DropdownMenu.Trigger>
122
+ <DropdownMenu.Content slot="content" width="250px">
123
+ {#if valueField.props.choices.length > 0}
124
+ <Button
125
+ onClick={() => {
126
+ selectedValueOfValueField = null;
127
+ }}
128
+ variant="ghost"
129
+ style="width:100%;">aucun</Button
130
+ >
131
+ {#each valueField.props.choices as choice}
132
+ <Button
133
+ onClick={() => {
134
+ selectedValueOfValueField = choice.value;
135
+ }}
136
+ variant="ghost"
137
+ style="width:100%;">
138
+ <h5 style="color: var({choice.color});">{choice.value}</h5></Button
139
+ >
140
+ {/each}
141
+ {:else}
142
+ <div class="nothing">
143
+ <h3>Aucun champs de status disponible</h3>
144
+ <p>
145
+ L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
146
+ </p>
147
+ </div>
148
+ {/if}
149
+ </DropdownMenu.Content>
150
+ </DropdownMenu.Root>
151
+ {/if}
152
+ <h5>Trié par</h5>
153
+ <DropdownMenu.Root direction="bottom">
154
+ <DropdownMenu.Trigger slot="trigger">
155
+ <Button variant="secondary">
156
+ <h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
157
+ </Button>
158
+ </DropdownMenu.Trigger>
159
+ <DropdownMenu.Content slot="content" width="250px">
160
+ {#if availedDateFields.length > 0}
161
+ {#each availedDateFields as field}
162
+ <Button
163
+ onClick={() => {
164
+ sortFieldId = field.id;
165
+ }}
166
+ variant="ghost"
167
+ style="width:100%;">
168
+ <h5>{field.name}</h5></Button
169
+ >
170
+ {/each}
171
+ {:else}
172
+ <div class="nothing">
173
+ <h3>Aucun champs de date disponible</h3>
174
+ <p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
175
+ </div>
176
+ {/if}
177
+ </DropdownMenu.Content>
178
+ </DropdownMenu.Root>
179
+ {/if}
180
+
181
+ <Button onClick={handleSave}>
182
+ <h5>enregistrer</h5>
183
+ </Button>
184
+ </div>
185
+
186
+ <style>
187
+ .config {
188
+ display: flex;
189
+ flex-direction: column;
190
+ row-gap: var(--pad-m);
191
+ }
192
+
193
+ .nothing {
194
+ display: flex;
195
+ flex-direction: column;
196
+ row-gap: var(--pad-m);
197
+ padding: var(--pad-m);
198
+ }
199
+ </style>
@@ -0,0 +1,97 @@
1
+ <script>
2
+ import { ChartLine, sendRequest, Skeleton } from 'hamzus-ui';
3
+ import { frequencyText, operationText } from './text';
4
+ import { onMount } from 'svelte';
5
+ import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
6
+ import ViewEntriesTypeComponent from '$lib/registry/viewEntriesTypeRegistry/components/ViewEntriesTypeComponent.svelte';
7
+
8
+ let {
9
+ id = '',
10
+ title = '',
11
+ entityId = '',
12
+ valueFieldId = '',
13
+ selectedValueOfValueField = '',
14
+ sortFieldId = '',
15
+ size = ''
16
+ } = $props();
17
+
18
+ let entity = $state(null);
19
+ let filters = $state(null);
20
+
21
+ onMount(async () => {
22
+ entity = entityRegistry.get(entityId);
23
+
24
+ let newFilters = {};
25
+ if (valueFieldId) {
26
+ const filterFieldName = entityRegistry.getField(valueFieldId);
27
+ newFilters = {
28
+ [filterFieldName.normalized_name]: selectedValueOfValueField
29
+ };
30
+ }
31
+ filters = { ...newFilters };
32
+ });
33
+
34
+ function getRandomSizes() {
35
+ const sizes = [60, 120, 80];
36
+
37
+ return sizes[Math.floor(Math.random() * sizes.length)];
38
+ }
39
+
40
+ function getPercent() {
41
+ if (previousTotal === 0) {
42
+ if (total === 0) return 0;
43
+ return null; // augmentation non calculable
44
+ }
45
+ return ((total - previousTotal) / previousTotal) * 100;
46
+ }
47
+ </script>
48
+
49
+ <div class="kpi-container">
50
+ <div class="kpi">
51
+ {#if filters}
52
+ <ViewEntriesTypeComponent invisibleFilters={filters} type="table" entityId={82}>
53
+ <h4 slot="actions">{title}</h4>
54
+ </ViewEntriesTypeComponent>
55
+ {:else}
56
+ <div class="title">
57
+ <h4>{title}</h4>
58
+ </div>
59
+ {/if}
60
+ </div>
61
+ </div>
62
+
63
+ <style>
64
+ .kpi-container {
65
+ width: 100%;
66
+ height: 100%;
67
+ min-height: 250px;
68
+ }
69
+
70
+ .kpi {
71
+ display: flex;
72
+ flex-direction: column;
73
+ row-gap: var(--pad-m);
74
+ padding-bottom: var(--pad-m);
75
+ width: 100%;
76
+ height: 100%;
77
+ border: 1px solid var(--stroke);
78
+ border-radius: var(--radius-m);
79
+ overflow: auto;
80
+ }
81
+
82
+ .title {
83
+ padding: var(--pad-m);
84
+ }
85
+
86
+ .bottom {
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ }
91
+
92
+ .right {
93
+ display: flex;
94
+ align-items: center;
95
+ column-gap: var(--pad-m);
96
+ }
97
+ </style>
@@ -0,0 +1,12 @@
1
+ import ConfigList from "./ConfigList.svelte";
2
+ import List from "./List.svelte";
3
+ import { createWidgetType } from "../../createWidgetType";
4
+
5
+ export default createWidgetType({
6
+ type: "List",
7
+ name: "Liste d'entrée",
8
+ components: {
9
+ config: ConfigList,
10
+ component: List,
11
+ }
12
+ })
@@ -0,0 +1,21 @@
1
+
2
+
3
+ export const frequencyText = {
4
+ 'day': 'aujourd\'hui',
5
+ 'month': 'ce mois-ci',
6
+ 'year': 'cette année'
7
+ }
8
+
9
+ export const frequencyTextForConfig = {
10
+ 'day': 'par jour',
11
+ 'month': 'par mois',
12
+ 'year': 'par an'
13
+ }
14
+
15
+ export const operationText = {
16
+ 'count': 'nombre d\'entrée',
17
+ 'sum': 'somme',
18
+ 'avg': 'moyenne',
19
+ 'min': "min",
20
+ 'max': "max"
21
+ }
@@ -85,7 +85,7 @@
85
85
  <NavbarBtn href="{$targetProjectHref}/navigation" text="Navigation">
86
86
  <NavbarIcon slot="endContent" color="var(--font-2)" icon="Grid|grid-4"></NavbarIcon>
87
87
  </NavbarBtn>
88
- <NavbarBtn text="Accueil">
88
+ <NavbarBtn href="{$targetProjectHref}/widgets" text="Accueil">
89
89
  <NavbarIcon slot="endContent" color="var(--font-2)" icon="Essetionnal|home-2"></NavbarIcon>
90
90
  </NavbarBtn>
91
91
  <NavbarBtn text="Constantes">