mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 07:28:37 +08:00
fix(dashboard): show media empty and retry states (#589)
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps<{
|
||||
/** 空结果使用的图标。 */
|
||||
emptyIcon: string
|
||||
/** 成功空结果对应的业务文案。 */
|
||||
emptyText: string
|
||||
/** 当前是否正在等待首次可用结果。 */
|
||||
loading: boolean
|
||||
/** 当前是否因请求失败而没有可展示的快照。 */
|
||||
failed: boolean
|
||||
/** 卡片标题。 */
|
||||
title: string
|
||||
}>()
|
||||
|
||||
defineSlots<{
|
||||
/** 在标题栏右侧显示与当前状态相关的轻量操作。 */
|
||||
append?: () => unknown
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard class="dashboard-media-state dashboard-grid-fill">
|
||||
<VCardItem class="dashboard-media-state-header">
|
||||
<VCardTitle>{{ props.title }}</VCardTitle>
|
||||
<template #append>
|
||||
<slot name="append" />
|
||||
</template>
|
||||
</VCardItem>
|
||||
|
||||
<VCardText
|
||||
class="dashboard-media-state-content text-medium-emphasis"
|
||||
:role="props.failed ? 'alert' : 'status'"
|
||||
aria-live="polite"
|
||||
>
|
||||
<template v-if="props.loading">
|
||||
<VProgressCircular indeterminate color="primary" size="28" width="2" />
|
||||
<span>{{ t('common.loading') }}</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="props.failed">
|
||||
<VIcon icon="mdi-server-network-off" color="warning" size="30" />
|
||||
<span>{{ t('dashboard.mediaServerLoadFailed') }}</span>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<VIcon :icon="props.emptyIcon" size="30" />
|
||||
<span>{{ props.emptyText }}</span>
|
||||
</template>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-media-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-block-size: 10rem;
|
||||
}
|
||||
|
||||
.dashboard-media-state-header {
|
||||
padding-block-end: 0.25rem;
|
||||
}
|
||||
|
||||
.dashboard-media-state-content {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 0.65rem;
|
||||
min-block-size: 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
/** 有可展示快照时,在支持悬停的桌面设备上延后到卡片交互时显示。 */
|
||||
deferred?: boolean
|
||||
/** 描述当前卡片重试目标的可访问文案。 */
|
||||
label: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
/** 请求用户主动重新加载当前卡片。 */
|
||||
retry: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VBtn
|
||||
icon
|
||||
variant="text"
|
||||
color="warning"
|
||||
size="small"
|
||||
:class="{ 'dashboard-retry-button--deferred': props.deferred }"
|
||||
:aria-label="props.label"
|
||||
@click="emit('retry')"
|
||||
>
|
||||
<VIcon icon="mdi-cloud-alert-outline" size="20" />
|
||||
<VTooltip activator="parent" location="top">
|
||||
{{ props.label }}
|
||||
</VTooltip>
|
||||
</VBtn>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (hover: none), (pointer: coarse) {
|
||||
.dashboard-retry-button--deferred {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.dashboard-retry-button--deferred {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 180ms ease;
|
||||
}
|
||||
|
||||
:global(.v-card:hover .dashboard-retry-button--deferred),
|
||||
:global(.v-card:focus-within .dashboard-retry-button--deferred) {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.dashboard-retry-button--deferred {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user