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.
- package/index.d.ts +29 -0
- package/index.js +29 -0
- package/package.json +1 -1
- package/src/lib/registry/navigationRegistry/components/NavigationGroupRow.svelte +30 -32
- package/src/lib/registry/navigationRegistry/components/NewNavbarGroupDialog.svelte +43 -39
- package/src/lib/registry/navigationRegistry/registerNavigation.js +1 -3
- package/src/lib/registry/projectRegistry/createProject.js +2 -0
- package/src/lib/registry/widgetGroupRegistry/components/EmptySlot.svelte +47 -0
- package/src/lib/registry/widgetGroupRegistry/components/GroupPreview.svelte +142 -0
- package/src/lib/registry/widgetGroupRegistry/components/NewWidgetGroup.svelte +122 -0
- package/src/lib/registry/widgetGroupRegistry/components/WidgetGroup.svelte +39 -0
- package/src/lib/registry/widgetGroupRegistry/createWidget.js +17 -0
- package/src/lib/registry/widgetGroupRegistry/createWidgetGroup.js +19 -0
- package/src/lib/registry/widgetGroupRegistry/registerWidgetGroups.js +37 -0
- package/src/lib/registry/widgetGroupRegistry/registry.svelte.js +47 -0
- package/src/lib/registry/widgetTypeRegistry/components/CreateWidgetDialog.svelte +25 -0
- package/src/lib/registry/widgetTypeRegistry/components/Widget.svelte +18 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetConfig.svelte +16 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetPreview.svelte +59 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeButton.svelte +20 -0
- package/src/lib/registry/widgetTypeRegistry/components/WidgetTypeSelector.svelte +32 -0
- package/src/lib/registry/widgetTypeRegistry/createWidgetType.js +20 -0
- package/src/lib/registry/widgetTypeRegistry/registerWidgetTypes.js +14 -0
- package/src/lib/registry/widgetTypeRegistry/registry.svelte.js +43 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/Bar.svelte +79 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/ConfigBar.svelte +176 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/index.js +13 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Bar/text.js +21 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/ConfigEvolution.svelte +180 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/Evolution.svelte +81 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/index.js +13 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/Evolution/text.js +21 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/ConfigKPI.svelte +201 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/KPI.svelte +118 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/index.js +12 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/KPI/text.js +22 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/ConfigList.svelte +199 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/List.svelte +97 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/index.js +12 -0
- package/src/lib/registry/widgetTypeRegistry/widgetTypes/List/text.js +21 -0
- package/src/routes/exemple/[project_normalized_name]/+layout.svelte +1 -1
- package/src/routes/exemple/[project_normalized_name]/home/+page.svelte +61 -1
- package/src/routes/exemple/[project_normalized_name]/navigation/+page.svelte +28 -0
- package/src/routes/exemple/[project_normalized_name]/widgets/+page.svelte +92 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { IconButton } from 'hamzus-ui';
|
|
3
|
+
|
|
4
|
+
let {onCreate = (numberColumn) =>{}} = $props()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="group">
|
|
8
|
+
<h4>Nouvelle rangée</h4>
|
|
9
|
+
<div class="btn">
|
|
10
|
+
<IconButton onClick={()=>{onCreate(1)}} size="48px" style="border-radius:var(--radius-l);" variant="outline">
|
|
11
|
+
<svg
|
|
12
|
+
width="24"
|
|
13
|
+
height="24"
|
|
14
|
+
viewBox="0 0 24 24"
|
|
15
|
+
fill="none"
|
|
16
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
+
>
|
|
18
|
+
<path
|
|
19
|
+
d="M19.9 7.75H4.1C2.6 7.75 2 8.39 2 9.98V14.02C2 15.61 2.6 16.25 4.1 16.25H19.9C21.4 16.25 22 15.61 22 14.02V9.98C22 8.39 21.4 7.75 19.9 7.75Z"
|
|
20
|
+
fill="#292D32"
|
|
21
|
+
/>
|
|
22
|
+
</svg>
|
|
23
|
+
</IconButton>
|
|
24
|
+
<IconButton onClick={()=>{onCreate(2)}} size="48px" style="border-radius:var(--radius-l);" variant="outline"
|
|
25
|
+
><svg
|
|
26
|
+
width="24"
|
|
27
|
+
height="24"
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
fill="none"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
opacity="0.4"
|
|
34
|
+
d="M13.5 4.1V19.9C13.5 21.4 14.14 22 15.73 22H19.77C21.36 22 22 21.4 22 19.9V4.1C22 2.6 21.36 2 19.77 2H15.73C14.14 2 13.5 2.6 13.5 4.1Z"
|
|
35
|
+
fill="#292D32"
|
|
36
|
+
/>
|
|
37
|
+
<path
|
|
38
|
+
d="M2 4.1V19.9C2 21.4 2.64 22 4.23 22H8.27C9.86 22 10.5 21.4 10.5 19.9V4.1C10.5 2.6 9.86 2 8.27 2H4.23C2.64 2 2 2.6 2 4.1Z"
|
|
39
|
+
fill="#292D32"
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
</IconButton>
|
|
43
|
+
<IconButton onClick={()=>{onCreate(3)}} size="48px" style="border-radius:var(--radius-l);" variant="outline"
|
|
44
|
+
><svg
|
|
45
|
+
width="24"
|
|
46
|
+
height="24"
|
|
47
|
+
viewBox="0 0 24 24"
|
|
48
|
+
fill="none"
|
|
49
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
50
|
+
>
|
|
51
|
+
<path
|
|
52
|
+
d="M2 4.1V19.9C2 21.4 2.45147 22 3.57309 22H6.423C7.54462 22 7.99609 21.4 7.99609 19.9V4.1C7.99609 2.6 7.54462 2 6.423 2H3.57309C2.45147 2 2 2.6 2 4.1Z"
|
|
53
|
+
fill="#292D32"
|
|
54
|
+
/>
|
|
55
|
+
<path
|
|
56
|
+
opacity="0.4"
|
|
57
|
+
d="M9.00195 4.1V19.9C9.00195 21.4 9.45342 22 10.575 22H13.425C14.5466 22 14.998 21.4 14.998 19.9V4.1C14.998 2.6 14.5466 2 13.425 2H10.575C9.45342 2 9.00195 2.6 9.00195 4.1Z"
|
|
58
|
+
fill="#292D32"
|
|
59
|
+
/>
|
|
60
|
+
<path
|
|
61
|
+
d="M16.0039 4.1V19.9C16.0039 21.4 16.4554 22 17.577 22H20.4269C21.5485 22 22 21.4 22 19.9V4.1C22 2.6 21.5485 2 20.4269 2H17.577C16.4554 2 16.0039 2.6 16.0039 4.1Z"
|
|
62
|
+
fill="#292D32"
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
</IconButton>
|
|
66
|
+
<IconButton onClick={()=>{onCreate(4)}} size="48px" style="border-radius:var(--radius-l);" variant="outline"
|
|
67
|
+
><svg
|
|
68
|
+
width="24"
|
|
69
|
+
height="24"
|
|
70
|
+
viewBox="0 0 24 24"
|
|
71
|
+
fill="none"
|
|
72
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
73
|
+
>
|
|
74
|
+
<path
|
|
75
|
+
d="M2.21875 4.1V19.9C2.21875 21.4 2.51366 22 3.24633 22H5.10795C5.84062 22 6.13553 21.4 6.13553 19.9V4.1C6.13553 2.6 5.84062 2 5.10795 2H3.24633C2.51366 2 2.21875 2.6 2.21875 4.1Z"
|
|
76
|
+
fill="#292D32"
|
|
77
|
+
/>
|
|
78
|
+
<path
|
|
79
|
+
opacity="0.4"
|
|
80
|
+
d="M7.43359 4.1V19.9C7.43359 21.4 7.7285 22 8.46117 22H10.3228C11.0555 22 11.3504 21.4 11.3504 19.9V4.1C11.3504 2.6 11.0555 2 10.3228 2H8.46117C7.7285 2 7.43359 2.6 7.43359 4.1Z"
|
|
81
|
+
fill="#292D32"
|
|
82
|
+
/>
|
|
83
|
+
<path
|
|
84
|
+
d="M12.6484 4.1V19.9C12.6484 21.4 12.9433 22 13.676 22H15.5376C16.2703 22 16.5652 21.4 16.5652 19.9V4.1C16.5652 2.6 16.2703 2 15.5376 2H13.676C12.9433 2 12.6484 2.6 12.6484 4.1Z"
|
|
85
|
+
fill="#292D32"
|
|
86
|
+
/>
|
|
87
|
+
<path
|
|
88
|
+
opacity="0.4"
|
|
89
|
+
d="M17.8652 4.1V19.9C17.8652 21.4 18.1601 22 18.8928 22H20.7544C21.4871 22 21.782 21.4 21.782 19.9V4.1C21.782 2.6 21.4871 2 20.7544 2H18.8928C18.1601 2 17.8652 2.6 17.8652 4.1Z"
|
|
90
|
+
fill="#292D32"
|
|
91
|
+
/>
|
|
92
|
+
</svg>
|
|
93
|
+
</IconButton>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<style>
|
|
98
|
+
.group {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
flex-direction: column;
|
|
103
|
+
gap: var(--pad-m);
|
|
104
|
+
padding: 50px var(--pad-xl);
|
|
105
|
+
border-radius: var(--radius-xl);
|
|
106
|
+
background-color: var(--bg-blur);
|
|
107
|
+
border: 5px solid var(--bg-1);
|
|
108
|
+
outline: 1px solid var(--bg-2);
|
|
109
|
+
transition: outline 0.2s ease-out;
|
|
110
|
+
width: 100%;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.group:hover {
|
|
114
|
+
outline: 1px solid var(--stroke);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.btn {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
column-gap: var(--pad-m);
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { handlers } from 'svelte/legacy';
|
|
3
|
+
import EmptySlot from './EmptySlot.svelte';
|
|
4
|
+
import CreateWidgetDialog from '$lib/registry/widgetTypeRegistry/components/CreateWidgetDialog.svelte';
|
|
5
|
+
import { sendRequest, toast } from 'hamzus-ui';
|
|
6
|
+
import { registerWidgetGroups } from '../registerWidgetGroups';
|
|
7
|
+
import { widgetGroupRegistry } from '../registry.svelte';
|
|
8
|
+
import Widget from '$lib/registry/widgetTypeRegistry/components/Widget.svelte';
|
|
9
|
+
|
|
10
|
+
let { id = null, numberOfColumn = 1, children = [] } = $props();
|
|
11
|
+
|
|
12
|
+
const group = $derived(widgetGroupRegistry.get(id))
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
{#if group && group.children && group.children.length > 0}
|
|
16
|
+
<div class="group-container" style="grid-template-columns:repeat({numberOfColumn}, minmax(0, 1fr));">
|
|
17
|
+
{#each Array.from({ length: numberOfColumn }) as column, index}
|
|
18
|
+
{const child = group.getChild(index + 1)}
|
|
19
|
+
{#if child}
|
|
20
|
+
<Widget type={child.type} {...child.props}></Widget>
|
|
21
|
+
{:else}
|
|
22
|
+
<div class="empty">
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
{/if}
|
|
26
|
+
{/each}
|
|
27
|
+
</div>
|
|
28
|
+
{/if}
|
|
29
|
+
|
|
30
|
+
<style>
|
|
31
|
+
.group-container {
|
|
32
|
+
width: 100%;
|
|
33
|
+
display: grid;
|
|
34
|
+
padding: var(--pad-xl);
|
|
35
|
+
column-gap: var(--pad-m);
|
|
36
|
+
min-height: 150px;
|
|
37
|
+
transition: border 0.2s ease-out;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sendRequest } from "hamzus-ui";
|
|
2
|
+
import { widgetGroupRegistry } from "./registry.svelte";
|
|
3
|
+
|
|
4
|
+
export function createWidgetGroup(config = {}) {
|
|
5
|
+
const widgetGroup = {
|
|
6
|
+
id: null,
|
|
7
|
+
column_number:1,
|
|
8
|
+
position:1,
|
|
9
|
+
children:[],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
Object.assign(widgetGroup, config);
|
|
13
|
+
|
|
14
|
+
widgetGroup.getChild = (position) =>{
|
|
15
|
+
return widgetGroup.children.find(c=>c.position === position)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return widgetGroup;
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sendRequest } from "hamzus-ui";
|
|
2
|
+
import { widgetGroupRegistry } from "./registry.svelte";
|
|
3
|
+
import { createWidgetGroup } from "./createWidgetGroup";
|
|
4
|
+
import { createWidget } from "./createWidget";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export async function registerWidgetGroups() {
|
|
8
|
+
|
|
9
|
+
widgetGroupRegistry.unregisterAll()
|
|
10
|
+
|
|
11
|
+
const request = await sendRequest({
|
|
12
|
+
path:"/get-all-widget-groups",
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
for (const group of request.data) {
|
|
16
|
+
let config = {
|
|
17
|
+
id: group.id,
|
|
18
|
+
column_number:group.column_number,
|
|
19
|
+
position:group.position,
|
|
20
|
+
children:[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const child of group.children) {
|
|
24
|
+
config.children.push(createWidget({
|
|
25
|
+
id:child.id,
|
|
26
|
+
group_id:child.group_id,
|
|
27
|
+
position:child.position,
|
|
28
|
+
type:child.type,
|
|
29
|
+
title:child.title,
|
|
30
|
+
props:child.props,
|
|
31
|
+
}))
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
widgetGroupRegistry.register(createWidgetGroup(config))
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { writable, derived, get } from 'svelte/store';
|
|
2
|
+
|
|
3
|
+
function createWidgetGroupRegistry() {
|
|
4
|
+
const store = writable({});
|
|
5
|
+
|
|
6
|
+
const all = derived(store, ($widgetGroups) => Object.values($widgetGroups));
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
subscribe: store.subscribe,
|
|
10
|
+
|
|
11
|
+
register(widgetGroup) {
|
|
12
|
+
store.update((widgetGroups) => ({
|
|
13
|
+
...widgetGroups,
|
|
14
|
+
[widgetGroup.id]: widgetGroup
|
|
15
|
+
}));
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
unregisterAll() {
|
|
19
|
+
store.update((widgetGroups) => {
|
|
20
|
+
return {};
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
unregister(id) {
|
|
24
|
+
store.update((widgetGroups) => {
|
|
25
|
+
const copy = { ...widgetGroups };
|
|
26
|
+
|
|
27
|
+
delete copy[id];
|
|
28
|
+
|
|
29
|
+
return copy;
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
get(id) {
|
|
34
|
+
return get(store)[id];
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
select(id) {
|
|
38
|
+
return derived(store, ($widgetGroups) => $widgetGroups[id]);
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
getAll() {
|
|
42
|
+
return all;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const widgetGroupRegistry = createWidgetGroupRegistry();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { AlertCard, Button, Dialog } from "hamzus-ui";
|
|
3
|
+
import WidgetTypeSelector from "./WidgetTypeSelector.svelte";
|
|
4
|
+
import WidgetConfig from "./WidgetConfig.svelte";
|
|
5
|
+
|
|
6
|
+
let {isOpen = $bindable(false), save = ()=>{}, ...props} = $props()
|
|
7
|
+
|
|
8
|
+
let type = $state(null)
|
|
9
|
+
|
|
10
|
+
async function handleSave(data) {
|
|
11
|
+
await save(data)
|
|
12
|
+
|
|
13
|
+
isOpen = false
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<Dialog bind:isOpen>
|
|
18
|
+
<div style="display:flex;row-gap:var(--pad-m);flex-direction:column;">
|
|
19
|
+
<h3>Créer un nouveau widget</h3>
|
|
20
|
+
<WidgetTypeSelector onChange={(newType)=>{type = newType}}></WidgetTypeSelector>
|
|
21
|
+
{#if type}
|
|
22
|
+
<WidgetConfig save={handleSave} {type}></WidgetConfig>
|
|
23
|
+
{/if}
|
|
24
|
+
</div>
|
|
25
|
+
</Dialog>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { widgetTypeRegistry } from "../registry.svelte";
|
|
3
|
+
|
|
4
|
+
let {type, ...props} = $props()
|
|
5
|
+
|
|
6
|
+
const widgetType = $derived(widgetTypeRegistry.get(type))
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="widget-case">
|
|
10
|
+
<svelte:component this={widgetType.components.component} {...props}></svelte:component>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.widget-case {
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { widgetTypeRegistry } from "../registry.svelte";
|
|
3
|
+
|
|
4
|
+
let {type, save = (data)=>{}, ...props} = $props()
|
|
5
|
+
|
|
6
|
+
const widgetType = $derived(widgetTypeRegistry.get(type))
|
|
7
|
+
|
|
8
|
+
function handleSave(data) {
|
|
9
|
+
save({
|
|
10
|
+
...data,
|
|
11
|
+
type:widgetType.type
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<svelte:component this={widgetType.components.config} save={handleSave} {...props}></svelte:component>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { IconButton } from 'hamzus-ui';
|
|
3
|
+
import { widgetTypeRegistry } from '../registry.svelte';
|
|
4
|
+
|
|
5
|
+
let { type, onDelete = () => {}, ...props } = $props();
|
|
6
|
+
|
|
7
|
+
const widgetType = $derived(widgetTypeRegistry.get(type));
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div class="widget-case">
|
|
11
|
+
<svelte:component this={widgetType.components.component} {...props}></svelte:component>
|
|
12
|
+
<div class="btn">
|
|
13
|
+
<IconButton variant="secondary" onClick={onDelete}>
|
|
14
|
+
<svg
|
|
15
|
+
width="24"
|
|
16
|
+
height="24"
|
|
17
|
+
viewBox="0 0 24 24"
|
|
18
|
+
fill="none"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
>
|
|
21
|
+
<path
|
|
22
|
+
d="M20.9997 6.72998C20.9797 6.72998 20.9497 6.72998 20.9197 6.72998C15.6297 6.19998 10.3497 5.99998 5.11967 6.52998L3.07967 6.72998C2.65967 6.76998 2.28967 6.46998 2.24967 6.04998C2.20967 5.62998 2.50967 5.26998 2.91967 5.22998L4.95967 5.02998C10.2797 4.48998 15.6697 4.69998 21.0697 5.22998C21.4797 5.26998 21.7797 5.63998 21.7397 6.04998C21.7097 6.43998 21.3797 6.72998 20.9997 6.72998Z"
|
|
23
|
+
fill="#292D32"
|
|
24
|
+
/>
|
|
25
|
+
<path
|
|
26
|
+
d="M8.50074 5.72C8.46074 5.72 8.42074 5.72 8.37074 5.71C7.97074 5.64 7.69074 5.25 7.76074 4.85L7.98074 3.54C8.14074 2.58 8.36074 1.25 10.6907 1.25H13.3107C15.6507 1.25 15.8707 2.63 16.0207 3.55L16.2407 4.85C16.3107 5.26 16.0307 5.65 15.6307 5.71C15.2207 5.78 14.8307 5.5 14.7707 5.1L14.5507 3.8C14.4107 2.93 14.3807 2.76 13.3207 2.76H10.7007C9.64074 2.76 9.62074 2.9 9.47074 3.79L9.24074 5.09C9.18074 5.46 8.86074 5.72 8.50074 5.72Z"
|
|
27
|
+
fill="#292D32"
|
|
28
|
+
/>
|
|
29
|
+
<path
|
|
30
|
+
d="M15.2104 22.7501H8.79039C5.30039 22.7501 5.16039 20.8201 5.05039 19.2601L4.40039 9.19007C4.37039 8.78007 4.69039 8.42008 5.10039 8.39008C5.52039 8.37008 5.87039 8.68008 5.90039 9.09008L6.55039 19.1601C6.66039 20.6801 6.70039 21.2501 8.79039 21.2501H15.2104C17.3104 21.2501 17.3504 20.6801 17.4504 19.1601L18.1004 9.09008C18.1304 8.68008 18.4904 8.37008 18.9004 8.39008C19.3104 8.42008 19.6304 8.77007 19.6004 9.19007L18.9504 19.2601C18.8404 20.8201 18.7004 22.7501 15.2104 22.7501Z"
|
|
31
|
+
fill="#292D32"
|
|
32
|
+
/>
|
|
33
|
+
<path
|
|
34
|
+
d="M13.6601 17.25H10.3301C9.92008 17.25 9.58008 16.91 9.58008 16.5C9.58008 16.09 9.92008 15.75 10.3301 15.75H13.6601C14.0701 15.75 14.4101 16.09 14.4101 16.5C14.4101 16.91 14.0701 17.25 13.6601 17.25Z"
|
|
35
|
+
fill="#292D32"
|
|
36
|
+
/>
|
|
37
|
+
<path
|
|
38
|
+
d="M14.5 13.25H9.5C9.09 13.25 8.75 12.91 8.75 12.5C8.75 12.09 9.09 11.75 9.5 11.75H14.5C14.91 11.75 15.25 12.09 15.25 12.5C15.25 12.91 14.91 13.25 14.5 13.25Z"
|
|
39
|
+
fill="#292D32"
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
</IconButton>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<style>
|
|
47
|
+
.widget-case {
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
position: relative;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.btn {
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: var(--pad-s);
|
|
56
|
+
right: var(--pad-s);
|
|
57
|
+
z-index: 3;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Button } from "hamzus-ui";
|
|
3
|
+
import { widgetTypeRegistry } from "../registry.svelte";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
type="",
|
|
7
|
+
style="",
|
|
8
|
+
variant="ghost",
|
|
9
|
+
...props
|
|
10
|
+
} = $props()
|
|
11
|
+
|
|
12
|
+
const widgetType = $derived(widgetTypeRegistry.get(type))
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
<Button {variant} style="width:100%;{style}" {...props}>
|
|
17
|
+
<h5>{widgetType.name}</h5>
|
|
18
|
+
</Button>
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Button, DropdownMenu } from 'hamzus-ui';
|
|
3
|
+
import { widgetTypeRegistry } from '../registry.svelte';
|
|
4
|
+
import WidgetTypeButton from './WidgetTypeButton.svelte';
|
|
5
|
+
|
|
6
|
+
let { value = $bindable(null), onChange = (type) => {} } = $props();
|
|
7
|
+
|
|
8
|
+
const widgetTypes = widgetTypeRegistry.getAll();
|
|
9
|
+
|
|
10
|
+
function handleClick(type) {
|
|
11
|
+
value = type;
|
|
12
|
+
onChange(type);
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<DropdownMenu.Root direction="bottom">
|
|
17
|
+
<DropdownMenu.Trigger slot="trigger">
|
|
18
|
+
<Button variant="secondary">
|
|
19
|
+
{#if value}
|
|
20
|
+
{@const widgetType = widgetTypeRegistry.get(value)}
|
|
21
|
+
<h5>{widgetType.name}</h5>
|
|
22
|
+
{:else}
|
|
23
|
+
<h5>séléctionner</h5>
|
|
24
|
+
{/if}
|
|
25
|
+
</Button>
|
|
26
|
+
</DropdownMenu.Trigger>
|
|
27
|
+
<DropdownMenu.Content slot="content" width="250px">
|
|
28
|
+
{#each $widgetTypes as widgetType}
|
|
29
|
+
<WidgetTypeButton type={widgetType.type} onClick={() => {handleClick(widgetType.type)}}></WidgetTypeButton>
|
|
30
|
+
{/each}
|
|
31
|
+
</DropdownMenu.Content>
|
|
32
|
+
</DropdownMenu.Root>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { sendRequest } from "hamzus-ui";
|
|
2
|
+
import { widgetTypeRegistry } from "./registry.svelte";
|
|
3
|
+
|
|
4
|
+
export function createWidgetType(config = {}) {
|
|
5
|
+
const widgetType = {
|
|
6
|
+
type: null,
|
|
7
|
+
name: null,
|
|
8
|
+
default_props:{},
|
|
9
|
+
components:{
|
|
10
|
+
config:null,
|
|
11
|
+
preview:null,
|
|
12
|
+
component:null,
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
Object.assign(widgetType, config);
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
return widgetType;
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sendRequest } from "hamzus-ui";
|
|
2
|
+
import { widgetTypeRegistry } from "./registry.svelte";
|
|
3
|
+
import Bar from "./widgetTypes/Bar";
|
|
4
|
+
import Evolution from "./widgetTypes/Evolution";
|
|
5
|
+
import KPI from "./widgetTypes/KPI";
|
|
6
|
+
import List from "./widgetTypes/List";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export async function registerWidgetTypes() {
|
|
10
|
+
widgetTypeRegistry.register(Bar)
|
|
11
|
+
widgetTypeRegistry.register(Evolution)
|
|
12
|
+
widgetTypeRegistry.register(KPI)
|
|
13
|
+
widgetTypeRegistry.register(List)
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { writable, derived, get } from 'svelte/store';
|
|
2
|
+
|
|
3
|
+
function createWidgetTypeRegistry() {
|
|
4
|
+
const store = writable({});
|
|
5
|
+
|
|
6
|
+
const all = derived(store, ($widgetTypes) => Object.values($widgetTypes));
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
subscribe: store.subscribe,
|
|
10
|
+
|
|
11
|
+
register(widgetGroup) {
|
|
12
|
+
store.update((widgetTypes) => ({
|
|
13
|
+
...widgetTypes,
|
|
14
|
+
[widgetGroup.type]: widgetGroup
|
|
15
|
+
}));
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
unregister(type) {
|
|
19
|
+
store.update((widgetTypes) => {
|
|
20
|
+
const copy = { ...widgetTypes };
|
|
21
|
+
|
|
22
|
+
delete copy[type];
|
|
23
|
+
|
|
24
|
+
return copy;
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
get(type) {
|
|
29
|
+
return get(store)[type];
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
select(type) {
|
|
33
|
+
return derived(store, ($widgetTypes) => $widgetTypes[type]);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
getAll() {
|
|
37
|
+
return all;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const widgetTypeRegistry = createWidgetTypeRegistry();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { ChartBar, ChartLine, sendRequest, Skeleton } from 'hamzus-ui';
|
|
3
|
+
import { frequencyText, operationText } from './text';
|
|
4
|
+
import { onMount } from 'svelte';
|
|
5
|
+
|
|
6
|
+
let {id = '', title = '', entityId = '', frequency = '', valueFieldId = '', dateFieldId = '', operation = ''} = $props()
|
|
7
|
+
|
|
8
|
+
let data = $state(null);
|
|
9
|
+
let previousTotal = $state(null);
|
|
10
|
+
|
|
11
|
+
onMount(async () => {
|
|
12
|
+
const request = await sendRequest({
|
|
13
|
+
path: '/get-widget-data',
|
|
14
|
+
data: {
|
|
15
|
+
widgetLinkId: id
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
data = request.data
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function getRandomSizes() {
|
|
24
|
+
const sizes = [60, 120, 80];
|
|
25
|
+
|
|
26
|
+
return sizes[Math.floor(Math.random() * sizes.length)];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getPercent() {
|
|
30
|
+
if (previousTotal === 0) {
|
|
31
|
+
if (total === 0) return 0;
|
|
32
|
+
return null; // augmentation non calculable
|
|
33
|
+
}
|
|
34
|
+
return ((total - previousTotal) / previousTotal) * 100;
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class="kpi-container">
|
|
39
|
+
<div class="kpi">
|
|
40
|
+
<h4>{title}</h4>
|
|
41
|
+
{#if data === null}
|
|
42
|
+
<Skeleton style="width:{getRandomSizes()}px;height:32px;"></Skeleton>
|
|
43
|
+
{:else}
|
|
44
|
+
<ChartBar {data}
|
|
45
|
+
></ChartBar>
|
|
46
|
+
{/if}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<style>
|
|
51
|
+
.kpi-container {
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
padding: var(--pad-m);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.kpi {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
row-gap: var(--pad-m);
|
|
61
|
+
padding: var(--pad-xxl);
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 100%;
|
|
64
|
+
background-color: var(--bg-blur);
|
|
65
|
+
border-radius: var(--radius-m);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.bottom {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.right {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
column-gap: var(--pad-m);
|
|
78
|
+
}
|
|
79
|
+
</style>
|