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,176 @@
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 = 'count'; // count | sum | avg | min | max
26
+ const operations = ['count', 'sum', 'avg', 'min', 'max'];
27
+
28
+ function handleSelectEntity(entity) {
29
+ entityId = entity.id;
30
+
31
+ // parcourir les fields pour set auto le field de value et de date
32
+ for (const field of entity.fields) {
33
+ if (field.type.startsWith('number-') || field.type.startsWith('calculation-')) {
34
+ valueFieldId = field.id;
35
+ }
36
+ if (dateFieldTypes.includes(field.type)) {
37
+ dateFieldId = field.id;
38
+ }
39
+ }
40
+ }
41
+
42
+ async function handleSave() {
43
+ save({
44
+ id,
45
+ title,
46
+ entityId,
47
+ frequency,
48
+ valueFieldId,
49
+ dateFieldId,
50
+ operation
51
+ });
52
+ }
53
+ </script>
54
+
55
+ <div class="config">
56
+ <Input label="titre" bind:value={title} placeholder="exemple"></Input>
57
+ <h5>Entité</h5>
58
+ <DropdownMenu.Root direction="bottom">
59
+ <DropdownMenu.Trigger slot="trigger">
60
+ <Button variant="secondary">
61
+ <h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
62
+ </Button>
63
+ </DropdownMenu.Trigger>
64
+ <DropdownMenu.Content slot="content" width="250px">
65
+ {#each $entities as entity}
66
+ <Button
67
+ onClick={() => {
68
+ handleSelectEntity(entity);
69
+ }}
70
+ variant="ghost"
71
+ style="width:100%;"><h5>{entity.plural_name}</h5></Button
72
+ >
73
+ {/each}
74
+ </DropdownMenu.Content>
75
+ </DropdownMenu.Root>
76
+ {#if entity}
77
+ {@const availedValueFields = entity.fields.filter(
78
+ (field) => field.type.startsWith('number-') || field.type.startsWith('calculation-')
79
+ )}
80
+ {@const availedDateFields = entity.fields.filter((field) =>
81
+ dateFieldTypes.includes(field.type)
82
+ )}
83
+ <h5>Champs pour valeurs</h5>
84
+ <DropdownMenu.Root direction="bottom">
85
+ <DropdownMenu.Trigger slot="trigger">
86
+ <Button variant="secondary">
87
+ <h5>{valueField?.name ?? 'choisissez un champ pour valeur'}</h5>
88
+ </Button>
89
+ </DropdownMenu.Trigger>
90
+ <DropdownMenu.Content slot="content" width="250px">
91
+ {#if availedValueFields.length > 0}
92
+ {#each availedValueFields as field}
93
+ <Button
94
+ onClick={() => {
95
+ valueFieldId = field.id;
96
+ }}
97
+ variant="ghost"
98
+ style="width:100%;"><h5>{field.name}</h5></Button
99
+ >
100
+ {/each}
101
+ {:else}
102
+ <div class="nothing">
103
+ <h3>Aucun champs de valeur disponible</h3>
104
+ <p>
105
+ L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
106
+ </p>
107
+ </div>
108
+ {/if}
109
+ </DropdownMenu.Content>
110
+ </DropdownMenu.Root>
111
+ <h5>Champs pour date</h5>
112
+ <DropdownMenu.Root direction="bottom">
113
+ <DropdownMenu.Trigger slot="trigger">
114
+ <Button variant="secondary">
115
+ <h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
116
+ </Button>
117
+ </DropdownMenu.Trigger>
118
+ <DropdownMenu.Content slot="content" width="250px">
119
+ {#if availedDateFields.length > 0}
120
+ {#each availedDateFields as field}
121
+ <Button
122
+ onClick={() => {
123
+ dateFieldId = field.id;
124
+ }}
125
+ variant="ghost"
126
+ style="width:100%;"><h5>{field.name}</h5></Button
127
+ >
128
+ {/each}
129
+ {:else}
130
+ <div class="nothing">
131
+ <h3>Aucun champs de date disponible</h3>
132
+ <p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
133
+ </div>
134
+ {/if}
135
+ </DropdownMenu.Content>
136
+ </DropdownMenu.Root>
137
+ <h5>fréquence</h5>
138
+ <DropdownMenu.Root direction="bottom">
139
+ <DropdownMenu.Trigger slot="trigger">
140
+ <Button variant="secondary">
141
+ <h5>{frequency ? frequencyTextForConfig[frequency] : 'choisissez une fréquence'}</h5>
142
+ </Button>
143
+ </DropdownMenu.Trigger>
144
+ <DropdownMenu.Content slot="content" width="250px">
145
+ {#each frequencies as frequencyEl}
146
+ <Button
147
+ onClick={() => {
148
+ frequency = frequencyEl;
149
+ }}
150
+ variant="ghost"
151
+ style="width:100%;"><h5>{frequencyTextForConfig[frequencyEl]}</h5></Button
152
+ >
153
+ {/each}
154
+ </DropdownMenu.Content>
155
+ </DropdownMenu.Root>
156
+ {/if}
157
+
158
+ <Button onClick={handleSave}>
159
+ <h5>enregistrer</h5>
160
+ </Button>
161
+ </div>
162
+
163
+ <style>
164
+ .config {
165
+ display: flex;
166
+ flex-direction: column;
167
+ row-gap: var(--pad-m);
168
+ }
169
+
170
+ .nothing {
171
+ display: flex;
172
+ flex-direction: column;
173
+ row-gap: var(--pad-m);
174
+ padding: var(--pad-m);
175
+ }
176
+ </style>
@@ -0,0 +1,13 @@
1
+ import ConfigBar from "./ConfigBar.svelte";
2
+ import Bar from "./Bar.svelte";
3
+ import { createWidgetType } from "../../createWidgetType";
4
+
5
+
6
+ export default createWidgetType({
7
+ type:"Bar",
8
+ name:"Graphique en bar",
9
+ components:{
10
+ config:ConfigBar,
11
+ component:Bar,
12
+ }
13
+ })
@@ -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
+ }
@@ -0,0 +1,180 @@
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 = 'count'; // count | sum | avg | min | max
26
+ const operations = ['count', 'sum', 'avg', 'min', 'max'];
27
+
28
+ let size = $state('4/2');
29
+ const sizes = ['4/2', '6/2', '8/2', '12/2'];
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>Entité</h5>
62
+ <DropdownMenu.Root direction="bottom">
63
+ <DropdownMenu.Trigger slot="trigger">
64
+ <Button variant="secondary">
65
+ <h5>{entity?.plural_name ?? 'choisissez une entité'}</h5>
66
+ </Button>
67
+ </DropdownMenu.Trigger>
68
+ <DropdownMenu.Content slot="content" width="250px">
69
+ {#each $entities as entity}
70
+ <Button
71
+ onClick={() => {
72
+ handleSelectEntity(entity);
73
+ }}
74
+ variant="ghost"
75
+ style="width:100%;"><h5>{entity.plural_name}</h5></Button
76
+ >
77
+ {/each}
78
+ </DropdownMenu.Content>
79
+ </DropdownMenu.Root>
80
+ {#if entity}
81
+ {@const availedValueFields = entity.fields.filter(
82
+ (field) => field.type.startsWith('number-') || field.type.startsWith('calculation-')
83
+ )}
84
+ {@const availedDateFields = entity.fields.filter((field) =>
85
+ dateFieldTypes.includes(field.type)
86
+ )}
87
+ <h5>Champs pour valeurs</h5>
88
+ <DropdownMenu.Root direction="bottom">
89
+ <DropdownMenu.Trigger slot="trigger">
90
+ <Button variant="secondary">
91
+ <h5>{valueField?.name ?? 'choisissez un champ pour valeur'}</h5>
92
+ </Button>
93
+ </DropdownMenu.Trigger>
94
+ <DropdownMenu.Content slot="content" width="250px">
95
+ {#if availedValueFields.length > 0}
96
+ {#each availedValueFields as field}
97
+ <Button
98
+ onClick={() => {
99
+ valueFieldId = field.id;
100
+ }}
101
+ variant="ghost"
102
+ style="width:100%;"><h5>{field.name}</h5></Button
103
+ >
104
+ {/each}
105
+ {:else}
106
+ <div class="nothing">
107
+ <h3>Aucun champs de valeur disponible</h3>
108
+ <p>
109
+ L'entité {entity?.plural_name} ne contient pas de champs nombre, permettant les calculs.
110
+ </p>
111
+ </div>
112
+ {/if}
113
+ </DropdownMenu.Content>
114
+ </DropdownMenu.Root>
115
+ <h5>Champs pour date</h5>
116
+ <DropdownMenu.Root direction="bottom">
117
+ <DropdownMenu.Trigger slot="trigger">
118
+ <Button variant="secondary">
119
+ <h5>{dateField?.name ?? 'choisissez un champ pour date'}</h5>
120
+ </Button>
121
+ </DropdownMenu.Trigger>
122
+ <DropdownMenu.Content slot="content" width="250px">
123
+ {#if availedDateFields.length > 0}
124
+ {#each availedDateFields as field}
125
+ <Button
126
+ onClick={() => {
127
+ dateFieldId = field.id;
128
+ }}
129
+ variant="ghost"
130
+ style="width:100%;"><h5>{field.name}</h5></Button
131
+ >
132
+ {/each}
133
+ {:else}
134
+ <div class="nothing">
135
+ <h3>Aucun champs de date disponible</h3>
136
+ <p>L'entité {entity?.plural_name} ne contient pas de champs de date.</p>
137
+ </div>
138
+ {/if}
139
+ </DropdownMenu.Content>
140
+ </DropdownMenu.Root>
141
+ <h5>fréquence</h5>
142
+ <DropdownMenu.Root direction="bottom">
143
+ <DropdownMenu.Trigger slot="trigger">
144
+ <Button variant="secondary">
145
+ <h5>{frequency ? frequencyTextForConfig[frequency] : 'choisissez une fréquence'}</h5>
146
+ </Button>
147
+ </DropdownMenu.Trigger>
148
+ <DropdownMenu.Content slot="content" width="250px">
149
+ {#each frequencies as frequencyEl}
150
+ <Button
151
+ onClick={() => {
152
+ frequency = frequencyEl;
153
+ }}
154
+ variant="ghost"
155
+ style="width:100%;"><h5>{frequencyTextForConfig[frequencyEl]}</h5></Button
156
+ >
157
+ {/each}
158
+ </DropdownMenu.Content>
159
+ </DropdownMenu.Root>
160
+ {/if}
161
+
162
+ <Button onClick={handleSave}>
163
+ <h5>enregistrer</h5>
164
+ </Button>
165
+ </div>
166
+
167
+ <style>
168
+ .config {
169
+ display: flex;
170
+ flex-direction: column;
171
+ row-gap: var(--pad-m);
172
+ }
173
+
174
+ .nothing {
175
+ display: flex;
176
+ flex-direction: column;
177
+ row-gap: var(--pad-m);
178
+ padding: var(--pad-m);
179
+ }
180
+ </style>
@@ -0,0 +1,81 @@
1
+ <script>
2
+ import { ChartLine, sendRequest, Skeleton } from 'hamzus-ui';
3
+ import { frequencyText, operationText } from './text';
4
+ import { onMount } from 'svelte';
5
+
6
+ let {
7
+ id = '',title = '',entityId = '',frequency = '',valueFieldId = '',dateFieldId = '',operation = '',
8
+ } = $props()
9
+
10
+ let data = $state(null);
11
+ let previousTotal = $state(null);
12
+
13
+ onMount(async () => {
14
+ const request = await sendRequest({
15
+ path: '/get-widget-data',
16
+ data: {
17
+ widgetLinkId: id
18
+ }
19
+ });
20
+
21
+
22
+ data = request.data
23
+ });
24
+
25
+ function getRandomSizes() {
26
+ const sizes = [60, 120, 80];
27
+
28
+ return sizes[Math.floor(Math.random() * sizes.length)];
29
+ }
30
+
31
+ function getPercent() {
32
+ if (previousTotal === 0) {
33
+ if (total === 0) return 0;
34
+ return null; // augmentation non calculable
35
+ }
36
+ return ((total - previousTotal) / previousTotal) * 100;
37
+ }
38
+ </script>
39
+
40
+ <div class="kpi-container">
41
+ <div class="kpi">
42
+ <h4>{title}</h4>
43
+ {#if data === null}
44
+ <Skeleton style="width:{getRandomSizes()}px;height:32px;"></Skeleton>
45
+ {:else}
46
+ <ChartLine {data}
47
+ ></ChartLine>
48
+ {/if}
49
+ </div>
50
+ </div>
51
+
52
+ <style>
53
+ .kpi-container {
54
+ width: 100%;
55
+ height: 100%;
56
+ padding: var(--pad-m);
57
+ }
58
+
59
+ .kpi {
60
+ display: flex;
61
+ flex-direction: column;
62
+ row-gap: var(--pad-m);
63
+ padding: var(--pad-xxl);
64
+ width: 100%;
65
+ height: 100%;
66
+ background-color: var(--bg-blur);
67
+ border-radius: var(--radius-m);
68
+ }
69
+
70
+ .bottom {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: space-between;
74
+ }
75
+
76
+ .right {
77
+ display: flex;
78
+ align-items: center;
79
+ column-gap: var(--pad-m);
80
+ }
81
+ </style>
@@ -0,0 +1,13 @@
1
+ import ConfigEvolution from "./ConfigEvolution.svelte";
2
+ import Evolution from "./Evolution.svelte";
3
+ import { createWidgetType } from "../../createWidgetType";
4
+
5
+
6
+ export default createWidgetType({
7
+ type: "Evolution",
8
+ name: "Graphique d'évolution",
9
+ components: {
10
+ config: ConfigEvolution,
11
+ component: Evolution,
12
+ }
13
+ })
@@ -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
+ }