mountain-ui 1.0.110 → 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 (43) 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/projectRegistry/createProject.js +2 -0
  7. package/src/lib/registry/widgetGroupRegistry/components/EmptySlot.svelte +47 -0
  8. package/src/lib/registry/widgetGroupRegistry/components/GroupPreview.svelte +142 -0
  9. package/src/lib/registry/widgetGroupRegistry/components/NewWidgetGroup.svelte +122 -0
  10. package/src/lib/registry/widgetGroupRegistry/components/WidgetGroup.svelte +39 -0
  11. package/src/lib/registry/widgetGroupRegistry/createWidget.js +17 -0
  12. package/src/lib/registry/widgetGroupRegistry/createWidgetGroup.js +19 -0
  13. package/src/lib/registry/widgetGroupRegistry/registerWidgetGroups.js +37 -0
  14. package/src/lib/registry/widgetGroupRegistry/registry.svelte.js +47 -0
  15. package/src/lib/registry/widgetTypeRegistry/components/CreateWidgetDialog.svelte +25 -0
  16. package/src/lib/registry/widgetTypeRegistry/components/Widget.svelte +18 -0
  17. package/src/lib/registry/widgetTypeRegistry/components/WidgetConfig.svelte +16 -0
  18. package/src/lib/registry/widgetTypeRegistry/components/WidgetPreview.svelte +59 -0
  19. package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeButton.svelte +20 -0
  20. package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeSelector.svelte +32 -0
  21. package/src/lib/registry/widgetTypeRegistry/createWidgetType.js +20 -0
  22. package/src/lib/registry/widgetTypeRegistry/registerWidgetTypes.js +14 -0
  23. package/src/lib/registry/widgetTypeRegistry/registry.svelte.js +43 -0
  24. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/Bar.svelte +79 -0
  25. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/ConfigBar.svelte +176 -0
  26. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/index.js +13 -0
  27. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/text.js +21 -0
  28. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/ConfigEvolution.svelte +180 -0
  29. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/Evolution.svelte +81 -0
  30. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/index.js +13 -0
  31. package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/text.js +21 -0
  32. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/ConfigKPI.svelte +201 -0
  33. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/KPI.svelte +118 -0
  34. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/index.js +12 -0
  35. package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/text.js +22 -0
  36. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/ConfigList.svelte +199 -0
  37. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/List.svelte +97 -0
  38. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/index.js +12 -0
  39. package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/text.js +21 -0
  40. package/src/routes/exemple/[project_normalized_name]/+layout.svelte +1 -1
  41. package/src/routes/exemple/[project_normalized_name]/home/+page.svelte +61 -1
  42. package/src/routes/exemple/[project_normalized_name]/navigation/+page.svelte +28 -0
  43. package/src/routes/exemple/[project_normalized_name]/widgets/+page.svelte +92 -0
@@ -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">
@@ -1 +1,61 @@
1
- <h3>home</h3>
1
+ <script>
2
+ import WidgetGroup from '$lib/registry/widgetGroupRegistry/components/WidgetGroup.svelte';
3
+ import { registerWidgetGroups } from '$lib/registry/widgetGroupRegistry/registerWidgetGroups';
4
+ import { widgetGroupRegistry } from '$lib/registry/widgetGroupRegistry/registry.svelte';
5
+ import { IconButton, sendRequest, toast } from 'hamzus-ui';
6
+ import { onMount } from 'svelte';
7
+
8
+ const allWidgetGroup = widgetGroupRegistry.getAll();
9
+
10
+ onMount(() => {
11
+ registerWidgetGroups();
12
+ });
13
+
14
+ </script>
15
+
16
+ <div class="content">
17
+ <div class="container">
18
+ <div class="title">
19
+ <h3>Accueil</h3>
20
+ </div>
21
+ <div class="rows">
22
+ {#each $allWidgetGroup as widgetGroup}
23
+ <WidgetGroup id={widgetGroup.id} numberOfColumn={widgetGroup.column_number}></WidgetGroup>
24
+ {/each}
25
+ </div>
26
+ </div>
27
+ </div>
28
+
29
+ <style>
30
+ .content {
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ padding: 60px var(--pad-m);
35
+ }
36
+
37
+ .container {
38
+ display: flex;
39
+ flex-direction: column;
40
+ align-items: center;
41
+ width: min(100%, 1000px);
42
+ }
43
+
44
+ .title {
45
+ width: 100%;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: space-between;
49
+ padding: var(--pad-s);
50
+ border-bottom: 1px solid var(--bg-2);
51
+ }
52
+
53
+ .rows {
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: center;
57
+ width: 100%;
58
+ row-gap: var(--pad-s);
59
+ padding: var(--pad-s);
60
+ }
61
+ </style>
@@ -16,6 +16,7 @@
16
16
 
17
17
  let newGroupIsOpen = $state(false);
18
18
 
19
+
19
20
  function handleChangeDragedElement(id) {
20
21
  dragedElementEntityId = id;
21
22
  }
@@ -54,6 +55,31 @@
54
55
 
55
56
  await registerNavigation();
56
57
  }
58
+
59
+ async function handleEditGroup(id, icon, color, name) {
60
+ const request = await sendRequest({
61
+ path: '/edit-group-navigation',
62
+ data: {
63
+ id,
64
+ icon,
65
+ color,
66
+ name
67
+ }
68
+ });
69
+
70
+ await registerNavigation();
71
+
72
+ }
73
+ async function handleDeleteGroup(id) {
74
+ const request = await sendRequest({
75
+ path: '/delete-group-navigation',
76
+ data: {
77
+ groupId:id,
78
+ }
79
+ });
80
+
81
+ await registerNavigation();
82
+ }
57
83
  </script>
58
84
 
59
85
  <NewNavbarGroupDialog onCreate={handleCreate} bind:isOpen={newGroupIsOpen}></NewNavbarGroupDialog>
@@ -93,6 +119,8 @@
93
119
  groupIsOpen[group.id] = value;
94
120
  console.log(value);
95
121
  }}
122
+ onEdit={handleEditGroup}
123
+ onDelete={handleDeleteGroup}
96
124
  activeDrag={dragedElementEntityId}
97
125
  onDrop={handleDropElementOnGroup}
98
126
  id={group.id}
@@ -0,0 +1,92 @@
1
+ <script>
2
+ import { entityRegistry } from '$lib/registry/entityRegistry/registry.svelte';
3
+ import NavigationGroupRow from '$lib/registry/navigationRegistry/components/NavigationGroupRow.svelte';
4
+ import NavigationRow from '$lib/registry/navigationRegistry/components/NavigationRow.svelte';
5
+ import NewNavbarGroupDialog from '$lib/registry/navigationRegistry/components/NewNavbarGroupDialog.svelte';
6
+ import { registerNavigation } from '$lib/registry/navigationRegistry/registerNavigation';
7
+ import { navigationRegistry } from '$lib/registry/navigationRegistry/registry.svelte';
8
+ import GroupPreview from '$lib/registry/widgetGroupRegistry/components/GroupPreview.svelte';
9
+ import NewWidgetGroup from '$lib/registry/widgetGroupRegistry/components/NewWidgetGroup.svelte';
10
+ import { registerWidgetGroups } from '$lib/registry/widgetGroupRegistry/registerWidgetGroups';
11
+ import { widgetGroupRegistry } from '$lib/registry/widgetGroupRegistry/registry.svelte';
12
+ import { IconButton, sendRequest, toast } from 'hamzus-ui';
13
+ import { onMount } from 'svelte';
14
+
15
+ const allWidgetGroup = widgetGroupRegistry.getAll();
16
+
17
+ onMount(() => {
18
+ registerWidgetGroups();
19
+ });
20
+
21
+ async function handleCreate(numberOfColumns) {
22
+ const request = await sendRequest({
23
+ path: '/create-group-widget',
24
+ data: {
25
+ numberOfColumns
26
+ }
27
+ });
28
+
29
+ if (request.statusType === 'error') {
30
+ toast.error({
31
+ title: 'Erreur !',
32
+ description: request.message
33
+ });
34
+ return;
35
+ }
36
+
37
+ toast.success({
38
+ title: 'Succès !',
39
+ description: request.message
40
+ });
41
+
42
+ registerWidgetGroups()
43
+ }
44
+ </script>
45
+
46
+ <div class="content">
47
+ <div class="container">
48
+ <div class="title">
49
+ <h3>Accueil</h3>
50
+ </div>
51
+ <div class="rows">
52
+ {#each $allWidgetGroup as widgetGroup}
53
+ <GroupPreview id={widgetGroup.id} numberOfColumn={widgetGroup.column_number}></GroupPreview>
54
+ {/each}
55
+ <NewWidgetGroup onCreate={handleCreate}></NewWidgetGroup>
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <style>
61
+ .content {
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ padding: 60px var(--pad-m);
66
+ }
67
+
68
+ .container {
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ width: min(100%, 1000px);
73
+ }
74
+
75
+ .title {
76
+ width: 100%;
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: space-between;
80
+ padding: var(--pad-s);
81
+ border-bottom: 1px solid var(--bg-2);
82
+ }
83
+
84
+ .rows {
85
+ display: flex;
86
+ flex-direction: column;
87
+ align-items: center;
88
+ width: 100%;
89
+ row-gap: var(--pad-s);
90
+ padding: var(--pad-s);
91
+ }
92
+ </style>