feat: redesign admin download overlay - ring progress + % inside + cancel btn bottom-right
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
mini
2026-02-19 01:31:05 +08:00
parent 94eac4a0c2
commit bc5662bc5f

View File

@@ -31,7 +31,19 @@
<span>{{ platformIcon(v.platform || v.url) }}</span>
</div>
<div v-if="v.status === 'downloading'" class="thumb-overlay"></div>
<!-- Downloading overlay: progress ring + cancel -->
<div v-if="v.status === 'downloading'" class="thumb-overlay dl-overlay">
<!-- Circular progress ring with percentage inside -->
<svg class="dl-ring" viewBox="0 0 48 48">
<circle class="dl-ring-bg" cx="24" cy="24" r="20" />
<circle class="dl-ring-fill" cx="24" cy="24" r="20"
:stroke-dasharray="`${(v.progress > 1 ? v.progress : 0) / 100 * 125.7} 125.7`"
:class="{ 'dl-ring-spin': v.progress <= 1 }" />
</svg>
<span class="dl-ring-pct">{{ v.progress > 1 ? v.progress + '%' : '…' }}</span>
<!-- Cancel button: bottom-right -->
<button class="dl-cancel" @click.stop="cancelDownload(v)" title="Cancel">✕</button>
</div>
<div v-else-if="v.status === 'pending'" class="thumb-overlay">🕐</div>
<div v-else-if="v.status === 'error'" class="thumb-overlay err-overlay">✕</div>
@@ -505,6 +517,37 @@ onUnmounted(() => { if (pollTimer) clearInterval(pollTimer) })
font-size: 1.3rem;
}
.err-overlay { background: rgba(180,0,0,0.45); }
/* Downloading overlay */
.dl-overlay { background: rgba(0,0,0,0.6); flex-direction: column; position: relative; }
.dl-ring { width: 44px; height: 44px; transform: rotate(-90deg); }
.dl-ring-bg { fill: none; stroke: rgba(255,255,255,0.2); stroke-width: 4; }
.dl-ring-fill {
fill: none; stroke: #1da1f2; stroke-width: 4; stroke-linecap: round;
transition: stroke-dasharray 0.5s ease;
}
@keyframes dl-spin {
from { stroke-dashoffset: 0; }
to { stroke-dashoffset: -125.7; }
}
.dl-ring-spin { animation: dl-spin 1.2s linear infinite; stroke-dasharray: 40 85.7 !important; }
.dl-ring-pct {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 0.68rem; font-weight: 700; color: #fff;
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
pointer-events: none;
}
.dl-cancel {
position: absolute; bottom: 4px; right: 4px;
width: 18px; height: 18px; border-radius: 50%;
background: rgba(231,76,60,0.8); border: none;
color: #fff; font-size: 0.6rem; font-weight: 700;
cursor: pointer; display: flex; align-items: center; justify-content: center;
line-height: 1; padding: 0; transition: background 0.2s;
}
.dl-cancel:hover { background: rgba(231,76,60,1); }
.info { min-width: 0; }
.info h4 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 0.4rem; font-size: 1rem; }
.meta { display: flex; gap: 1rem; font-size: 0.88rem; color: #888; flex-wrap: wrap; }