Skip to content

Commit 66c2bb7

Browse files
committed
fix(ui): adjust text progress rendering
- measure real character width for bar length - avoid clipping progress bar text
1 parent d6ad300 commit 66c2bb7

File tree

6 files changed

+585
-11824
lines changed

6 files changed

+585
-11824
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ logs
2525
tmp
2626

2727
# 忽略下载的文件 downloads 下的所有文件
28-
downloads
28+
downloads
29+
30+
# 忽略 npm/yarn lock 文件
31+
package-lock.json
32+
pnpm-lock.yaml
33+
yarn.lock

components/LayerProgress.vue

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,30 @@
55
enter-from-class="opacity-0 -translate-y-4"
66
enter-to-class="opacity-100 translate-y-0"
77
>
8-
<div class="mt-5 p-3 bg-gray-50 border-2 border-gray-300 rounded-lg font-mono">
8+
<div class="mt-5 p-3 bg-gray-50 border-2 border-gray-300 rounded-lg">
99
<div
1010
v-for="(progress, digest) in progressData"
1111
:key="digest"
1212
class="py-1"
1313
>
14-
<div class="flex items-center whitespace-pre">
14+
<div class="flex items-center">
1515
<span class="w-32 text-gray-600 shrink-0">{{ formatDigest(digest) }}:</span>
16-
<div class="flex-1 flex items-center">
17-
<span class="progress-bar">{{ formatProgressBar(progress) }}</span>
18-
<span class="ml-2 text-gray-600 shrink-0">{{ formatSize(progress) }}</span>
16+
<div class="flex-1 flex items-center gap-2 min-w-0">
17+
<span ref="barContainer" class="progress-bar font-mono">
18+
{{ formatProgressBar(progress) }}
19+
</span>
20+
<span class="text-gray-600 shrink-0 font-mono">{{ formatSize(progress) }}</span>
1921
</div>
2022
</div>
2123
</div>
24+
<span ref="charMeasure" class="absolute opacity-0 pointer-events-none font-mono">0</span>
2225
</div>
2326
</Transition>
2427
</template>
2528

2629
<script setup lang="ts">
30+
import { ref, computed } from "vue";
31+
import { useElementSize } from "@vueuse/core";
2732
import type { DownloadProgress } from "~/types/docker";
2833
2934
const props = defineProps<{
@@ -33,10 +38,28 @@ const props = defineProps<{
3338
const formatDigest = (digest: string): string =>
3439
digest.replace("sha256:", "").substring(0, 12);
3540
41+
const barContainer = ref<HTMLElement | null>(null);
42+
const charMeasure = ref<HTMLElement | null>(null);
43+
const { width: barWidth } = useElementSize(barContainer);
44+
const { width: charWidth } = useElementSize(charMeasure);
45+
46+
const barLength = computed(() => {
47+
const containerWidth = barWidth.value || 0;
48+
const singleChar = charWidth.value || 0;
49+
if (containerWidth <= 0 || singleChar <= 0) return 30;
50+
const available = Math.floor(containerWidth / singleChar) - 4;
51+
return Math.max(10, available);
52+
});
53+
3654
const formatProgressBar = (progress: DownloadProgress): string => {
37-
const bar = "=".repeat(Math.floor(progress.percentage / 2));
38-
const space = " ".repeat(50 - Math.floor(progress.percentage / 2));
39-
return `[${bar}>${space}]`;
55+
const total = barLength.value;
56+
const filled = Math.floor((progress.percentage / 100) * total);
57+
const clamped = Math.min(Math.max(filled, 0), total);
58+
if (clamped >= total) {
59+
return `[${"=".repeat(total)}]`;
60+
}
61+
const empty = Math.max(total - clamped - 1, 0);
62+
return `[${"=".repeat(clamped)}>${" ".repeat(empty)}]`;
4063
};
4164
4265
const formatSize = (progress: DownloadProgress): string => {
@@ -48,7 +71,9 @@ const formatSize = (progress: DownloadProgress): string => {
4871

4972
<style scoped>
5073
.progress-bar {
51-
font-family: monospace;
74+
display: block;
75+
flex: 1;
76+
min-width: 0;
5277
white-space: pre;
5378
}
54-
</style>
79+
</style>

0 commit comments

Comments
 (0)