|
1 | 1 | <script> |
2 | 2 | export let progress = 0; |
| 3 | + export let mt = 4; |
3 | 4 |
|
4 | | - let percentage = 0; |
5 | | - let offset = 0; |
| 5 | + let textElement; |
| 6 | + let progressContainer; |
| 7 | + let marginLeft = 0; |
6 | 8 |
|
7 | 9 | $: normalizedProgress = Math.min(progress, 100); |
8 | | - $: offset = percentage.offsetWidth / 2; |
| 10 | +
|
| 11 | + function calculateMargin() { |
| 12 | + if (!textElement || !progressContainer) return 0; |
| 13 | +
|
| 14 | + const containerWidth = progressContainer.offsetWidth; |
| 15 | + const textWidth = textElement.offsetWidth; |
| 16 | +
|
| 17 | + if (containerWidth === 0 || textWidth === 0) return 0; |
| 18 | +
|
| 19 | + // Calculate target position (center text on progress end) |
| 20 | + const targetPixels = (normalizedProgress / 100) * containerWidth - textWidth / 2; |
| 21 | +
|
| 22 | + // Keep within bounds |
| 23 | + const minPixels = 0; |
| 24 | + const maxPixels = containerWidth - textWidth; |
| 25 | + const constrainedPixels = Math.min(Math.max(targetPixels, minPixels), maxPixels); |
| 26 | +
|
| 27 | + // Convert to percentage |
| 28 | + return (constrainedPixels / containerWidth) * 100; |
| 29 | + } |
| 30 | +
|
| 31 | + $: { |
| 32 | + normalizedProgress; |
| 33 | + if (textElement && progressContainer) { |
| 34 | + marginLeft = calculateMargin(); |
| 35 | + } |
| 36 | + } |
9 | 37 | </script> |
10 | 38 |
|
11 | | -<div class="progress-bar-container relative mt-4"> |
| 39 | +<div class="progress-bar-container mt-{mt}" bind:this={progressContainer}> |
12 | 40 | <div class="progress-bar"> |
13 | 41 | <div class="progress" style="width: {normalizedProgress}%" /> |
14 | 42 | </div> |
15 | | - <div |
16 | | - bind:this={percentage} |
17 | | - class="progress-bar-text" |
18 | | - style="left: min(max(calc({normalizedProgress}% - {offset}px), 0px), calc(100% - {percentage?.offsetWidth || 0}px))" |
19 | | - > |
| 43 | + <div bind:this={textElement} class="progress-bar-text" style="margin-left: {marginLeft}%"> |
20 | 44 | {normalizedProgress}% |
21 | 45 | </div> |
22 | 46 | </div> |
23 | 47 |
|
24 | 48 | <style lang="postcss"> |
25 | | - /* dark:bg-mine-shaft-950 dark:text-spring-wood-50 */ |
26 | | - .progress-bar { |
27 | | - @apply h-4 w-full overflow-hidden rounded-full bg-mine-shaft-100 dark:bg-mine-shaft-800; |
| 49 | + .progress-bar-container { |
| 50 | + @apply flex flex-col gap-[2px]; |
28 | 51 | } |
29 | 52 |
|
30 | | - .progress-bar-text { |
31 | | - @apply absolute left-0 top-5 text-center text-sm; |
| 53 | + .progress-bar { |
| 54 | + @apply h-2 w-full overflow-hidden rounded-full bg-mine-shaft-100 dark:bg-mine-shaft-800; |
32 | 55 | } |
33 | 56 |
|
34 | 57 | .progress { |
35 | 58 | @apply h-full bg-red-berry-800 transition-all duration-500 dark:bg-red-berry-900; |
36 | 59 | } |
| 60 | +
|
| 61 | + .progress-bar-text { |
| 62 | + @apply text-xs text-mine-shaft-600 dark:text-mine-shaft-400 transition-all duration-300 inline-block w-fit; |
| 63 | + } |
37 | 64 | </style> |
0 commit comments