hamzus-ui 0.0.12 → 0.0.13
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
CHANGED
|
@@ -21,6 +21,9 @@ export { default as TextArea } from "./src/components/hamzus-ui/TextArea/TextAre
|
|
|
21
21
|
export { default as Checkbox } from "./src/components/hamzus-ui/Checkboxes/Checkbox/Checkbox.svelte"
|
|
22
22
|
export { default as Switch } from "./src/components/hamzus-ui/Swicth/Swicth.svelte"
|
|
23
23
|
|
|
24
|
+
// data
|
|
25
|
+
export { default as ProgressCircle } from "./src/components/hamzus-ui/ProgressCircle/ProgressCircle.svelte"
|
|
26
|
+
|
|
24
27
|
|
|
25
28
|
export * as DropdownMenu from "./src/components/hamzus-ui/DropdownMenu";
|
|
26
29
|
export * as Popover from "./src/components/hamzus-ui/Popover";
|
package/index.js
CHANGED
|
@@ -16,7 +16,8 @@ export { default as DatePicker } from "./src/components/hamzus-ui/DatePicker/Dat
|
|
|
16
16
|
export { default as TextArea } from "./src/components/hamzus-ui/TextArea/TextArea.svelte"
|
|
17
17
|
export { default as Checkbox } from "./src/components/hamzus-ui/Checkboxes/Checkbox/Checkbox.svelte"
|
|
18
18
|
export { default as Switch } from "./src/components/hamzus-ui/Swicth/Swicth.svelte"
|
|
19
|
-
|
|
19
|
+
// data
|
|
20
|
+
export { default as ProgressCircle } from "./src/components/hamzus-ui/ProgressCircle/ProgressCircle.svelte"
|
|
20
21
|
|
|
21
22
|
export * as DropdownMenu from "./src/components/hamzus-ui/DropdownMenu"
|
|
22
23
|
export * as Popover from "./src/components/hamzus-ui/Popover"
|
package/package.json
CHANGED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
|
|
4
|
+
export let size = 100;
|
|
5
|
+
export let thickness = 10;
|
|
6
|
+
export let progress = 100; // 0–100
|
|
7
|
+
export let gapPixels = 4; // Écart visuel minimal
|
|
8
|
+
export let color = null;
|
|
9
|
+
export let colorPercentBased = {
|
|
10
|
+
0: 'var(--red)',
|
|
11
|
+
40: 'var(--orange)',
|
|
12
|
+
60: 'var(--green)'
|
|
13
|
+
};
|
|
14
|
+
export let bgColor = 'var(--bg-2)';
|
|
15
|
+
export let showLabel = false;
|
|
16
|
+
export let animated = true;
|
|
17
|
+
export let linecap = 'round';
|
|
18
|
+
|
|
19
|
+
const r = (size - thickness) / 2;
|
|
20
|
+
const cx = size / 2;
|
|
21
|
+
const cy = size / 2;
|
|
22
|
+
const circumference = 2 * Math.PI * r;
|
|
23
|
+
|
|
24
|
+
let dynamicColor = color === null;
|
|
25
|
+
let copyColor = dynamicColor
|
|
26
|
+
? animated
|
|
27
|
+
? colorPercentBased[0]
|
|
28
|
+
: getCorrectColor(progress)
|
|
29
|
+
: color;
|
|
30
|
+
let copyProgress = animated ? 0 : progress === 100 ? 99.99 : progress;
|
|
31
|
+
|
|
32
|
+
// Fonction ease-out (courbe cubic)
|
|
33
|
+
function easeOutCubic(t) {
|
|
34
|
+
return 1 - Math.pow(1 - t, 3);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onMount(() => {
|
|
38
|
+
if (!animated) return;
|
|
39
|
+
|
|
40
|
+
const duration = 800; // en ms
|
|
41
|
+
const start = performance.now();
|
|
42
|
+
|
|
43
|
+
function animate(now) {
|
|
44
|
+
const elapsed = now - start;
|
|
45
|
+
const t = Math.min(elapsed / duration, 1); // clamp entre 0 et 1
|
|
46
|
+
|
|
47
|
+
const eased = easeOutCubic(t);
|
|
48
|
+
|
|
49
|
+
let newValue = Math.round(progress * eased);
|
|
50
|
+
|
|
51
|
+
copyProgress = newValue === 100 ? 99.99 : newValue;
|
|
52
|
+
|
|
53
|
+
// determiner la couleur si il y a dynamic color
|
|
54
|
+
if (dynamicColor) {
|
|
55
|
+
let finalColor = colorPercentBased[0];
|
|
56
|
+
for (const step in colorPercentBased) {
|
|
57
|
+
const color = colorPercentBased[step];
|
|
58
|
+
|
|
59
|
+
if (copyProgress > step) {
|
|
60
|
+
finalColor = color;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
copyColor = finalColor;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (t < 1) {
|
|
71
|
+
requestAnimationFrame(animate);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
requestAnimationFrame(animate);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
function getCorrectColor(progress) {
|
|
79
|
+
let finalColor = colorPercentBased[0];
|
|
80
|
+
for (const step in colorPercentBased) {
|
|
81
|
+
const color = colorPercentBased[step];
|
|
82
|
+
|
|
83
|
+
if (progress > step) {
|
|
84
|
+
finalColor = color;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return finalColor;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Progrès en angle
|
|
95
|
+
$: progressAngle = (copyProgress / 100) * 360;
|
|
96
|
+
|
|
97
|
+
// ➕ Compensation du stroke-linecap (ajoute une demi-thickness de chaque côté de l'arc)
|
|
98
|
+
const capVisualOverlap = thickness; // total débordement = thickness (2 * thickness/2)
|
|
99
|
+
|
|
100
|
+
$: totalGapPx = gapPixels + capVisualOverlap;
|
|
101
|
+
$: gapAngle = (totalGapPx / circumference) * 360;
|
|
102
|
+
|
|
103
|
+
$: startAngleProgress = -90;
|
|
104
|
+
$: endAngleProgress = startAngleProgress + progressAngle;
|
|
105
|
+
|
|
106
|
+
$: startAngleBg = endAngleProgress + gapAngle;
|
|
107
|
+
$: endAngleBg = 270 - gapAngle;
|
|
108
|
+
|
|
109
|
+
function polarToCartesian(cx, cy, r, angleDeg) {
|
|
110
|
+
const angleRad = (angleDeg * Math.PI) / 180;
|
|
111
|
+
return {
|
|
112
|
+
x: cx + r * Math.cos(angleRad),
|
|
113
|
+
y: cy + r * Math.sin(angleRad)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function describeArc(cx, cy, r, startAngle, endAngle) {
|
|
118
|
+
const start = polarToCartesian(cx, cy, r, endAngle);
|
|
119
|
+
const end = polarToCartesian(cx, cy, r, startAngle);
|
|
120
|
+
const largeArcFlag = endAngle - startAngle > 180 ? 1 : 0;
|
|
121
|
+
|
|
122
|
+
return ['M', start.x, start.y, 'A', r, r, 0, largeArcFlag, 0, end.x, end.y].join(' ');
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<svg class="progress-circle" width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
|
|
127
|
+
<!-- Arc de progression -->
|
|
128
|
+
<path
|
|
129
|
+
d={describeArc(cx, cy, r, startAngleProgress, endAngleProgress)}
|
|
130
|
+
stroke={copyColor}
|
|
131
|
+
stroke-width={thickness}
|
|
132
|
+
fill="none"
|
|
133
|
+
stroke-linecap={linecap}
|
|
134
|
+
/>
|
|
135
|
+
|
|
136
|
+
{#if showLabel}
|
|
137
|
+
<text
|
|
138
|
+
x="50%"
|
|
139
|
+
y="50%"
|
|
140
|
+
text-anchor="middle"
|
|
141
|
+
dominant-baseline="central"
|
|
142
|
+
fill={copyColor}
|
|
143
|
+
style="font-size: {size / 3.5}px;"
|
|
144
|
+
class="h4">{Math.round(copyProgress)}%</text
|
|
145
|
+
>
|
|
146
|
+
{/if}
|
|
147
|
+
|
|
148
|
+
<!-- Arc de fond, après le progress + gap -->
|
|
149
|
+
{#if copyProgress < 96}
|
|
150
|
+
<path
|
|
151
|
+
d={describeArc(cx, cy, r, startAngleBg, endAngleBg)}
|
|
152
|
+
stroke={bgColor}
|
|
153
|
+
stroke-width={thickness}
|
|
154
|
+
fill="none"
|
|
155
|
+
stroke-linecap={linecap}
|
|
156
|
+
/>
|
|
157
|
+
{/if}
|
|
158
|
+
</svg>
|
|
159
|
+
|
|
160
|
+
<style>
|
|
161
|
+
.progress-circle path {
|
|
162
|
+
transition: stroke 0.3s ease-out;
|
|
163
|
+
}
|
|
164
|
+
.progress-circle text {
|
|
165
|
+
transition: color 0.3s ease-out;
|
|
166
|
+
}
|
|
167
|
+
</style>
|