mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-29 03:56:51 +08:00
Improve plugin market detail layout and rating sorting
This commit is contained in:
@@ -247,190 +247,285 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VDialog v-if="visible" v-model="visible" max-width="30rem">
|
||||
<VCard>
|
||||
<VDialog v-if="visible" v-model="visible" width="100%" max-width="32rem" max-height="90dvh" scrollable>
|
||||
<VCard class="plugin-market-detail">
|
||||
<VDialogCloseBtn v-model="visible" />
|
||||
<VCardText>
|
||||
<VCol>
|
||||
<div class="d-flex justify-space-between flex-wrap flex-md-nowrap flex-column flex-md-row">
|
||||
<div class="mx-auto mt-5">
|
||||
<VAvatar size="64">
|
||||
<VImg :src="pluginIconPath()" aspect-ratio="4/3" cover @error="imageLoadError = true" />
|
||||
</VAvatar>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<VCardItem>
|
||||
<VCardTitle class="text-center text-md-left">
|
||||
{{ props.plugin?.plugin_name }}
|
||||
</VCardTitle>
|
||||
<VCardSubtitle
|
||||
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-4 overflow-hidden text-ellipsis ..."
|
||||
>
|
||||
{{ props.plugin?.plugin_desc }}
|
||||
</VCardSubtitle>
|
||||
<VList lines="one" class="border-0">
|
||||
<VListItem class="ps-0">
|
||||
<VListItemTitle class="text-center text-md-left">
|
||||
<span class="font-weight-medium">{{ t('common.version') }}:</span>
|
||||
<span class="text-body-1"> v{{ props.plugin?.plugin_version }}</span>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem class="ps-0">
|
||||
<VListItemTitle class="text-center text-md-left">
|
||||
<span class="font-weight-medium">{{ t('common.author') }}:</span>
|
||||
<span class="text-body-1 cursor-pointer" @click="visitPluginPage">
|
||||
{{ props.plugin?.plugin_author }}
|
||||
</span>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem v-if="props.plugin?.system_version" class="ps-0">
|
||||
<VListItemTitle class="text-center text-md-left">
|
||||
<span class="font-weight-medium">{{ t('plugin.systemVersion') }}:</span>
|
||||
<span class="text-body-1">{{ props.plugin?.system_version }}</span>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem v-if="rating.rating_count > 0" class="ps-0">
|
||||
<VListItemTitle class="plugin-market-detail-rating-row text-center text-md-left">
|
||||
<span class="font-weight-medium">{{ t('plugin.rating') }}:</span>
|
||||
<PluginRatingDisplay
|
||||
:rating="rating.average_rating"
|
||||
:count="rating.rating_count"
|
||||
:icon-size="18"
|
||||
/>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<VAlert
|
||||
v-if="props.plugin?.system_version_compatible === false"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
density="compact"
|
||||
class="mb-3"
|
||||
:text="props.plugin?.system_version_message || t('plugin.incompatibleSystemVersion')"
|
||||
/>
|
||||
<div class="plugin-market-detail-actions">
|
||||
<div class="plugin-market-detail-actions__buttons">
|
||||
<VBtn
|
||||
v-if="!isInstalled"
|
||||
color="primary"
|
||||
@click="installPlugin()"
|
||||
prepend-icon="mdi-download"
|
||||
:disabled="props.plugin?.system_version_compatible === false"
|
||||
>
|
||||
{{ t('plugin.installToLocal') }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-else-if="props.plugin?.has_update"
|
||||
color="primary"
|
||||
prepend-icon="mdi-arrow-up-circle-outline"
|
||||
:disabled="props.plugin?.system_version_compatible === false"
|
||||
@click="installPlugin()"
|
||||
>
|
||||
{{ t('plugin.update') }}
|
||||
</VBtn>
|
||||
<VBtn variant="tonal" @click="showUpdateHistory" prepend-icon="mdi-update">
|
||||
{{ t('plugin.versionHistory') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
<div class="plugin-market-detail-actions__downloads" v-if="props.count">
|
||||
<VIcon icon="mdi-fire" />
|
||||
{{ t('plugin.totalDownloads', { count: formatDownloadCount(props.count) }) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isInstalled" class="plugin-market-detail-user-rating mt-5">
|
||||
<div class="text-body-2 font-weight-medium mb-2">
|
||||
{{ t('plugin.yourRating') }}
|
||||
</div>
|
||||
<div class="plugin-market-detail-user-rating__controls">
|
||||
<VRating
|
||||
v-model="selectedRating"
|
||||
:disabled="ratingLoading || ratingSubmitting"
|
||||
half-increments
|
||||
hover
|
||||
density="compact"
|
||||
active-color="warning"
|
||||
/>
|
||||
<VBtn
|
||||
size="small"
|
||||
variant="tonal"
|
||||
prepend-icon="mdi-star-check-outline"
|
||||
:loading="ratingSubmitting"
|
||||
:disabled="ratingLoading || selectedRating <= 0"
|
||||
@click="submitPluginRating"
|
||||
>
|
||||
{{ t('plugin.submitRating') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
</VCardItem>
|
||||
</div>
|
||||
<VCardText class="plugin-market-detail__content">
|
||||
<header class="plugin-market-detail__header">
|
||||
<VAvatar size="64" class="plugin-market-detail__avatar">
|
||||
<VImg :src="pluginIconPath()" aspect-ratio="4/3" cover @error="imageLoadError = true" />
|
||||
</VAvatar>
|
||||
<h2 class="plugin-market-detail__title">
|
||||
{{ props.plugin?.plugin_name }}
|
||||
</h2>
|
||||
<p v-if="props.plugin?.plugin_desc" class="plugin-market-detail__description">
|
||||
{{ props.plugin?.plugin_desc }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<dl class="plugin-market-detail__metadata">
|
||||
<div class="plugin-market-detail__metadata-row">
|
||||
<dt>{{ t('common.version') }}:</dt>
|
||||
<dd>v{{ props.plugin?.plugin_version }}</dd>
|
||||
</div>
|
||||
</VCol>
|
||||
<div class="plugin-market-detail__metadata-row">
|
||||
<dt>{{ t('common.author') }}:</dt>
|
||||
<dd>
|
||||
<button type="button" class="plugin-market-detail__author" @click="visitPluginPage">
|
||||
{{ props.plugin?.plugin_author }}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
<div v-if="props.plugin?.system_version" class="plugin-market-detail__metadata-row">
|
||||
<dt>{{ t('plugin.systemVersion') }}:</dt>
|
||||
<dd>{{ props.plugin?.system_version }}</dd>
|
||||
</div>
|
||||
<div v-if="rating.rating_count > 0" class="plugin-market-detail__metadata-row">
|
||||
<dt>{{ t('plugin.rating') }}:</dt>
|
||||
<dd class="plugin-market-detail__rating-summary">
|
||||
<PluginRatingDisplay :rating="rating.average_rating" :count="rating.rating_count" :icon-size="18" />
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<VAlert
|
||||
v-if="props.plugin?.system_version_compatible === false"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
density="compact"
|
||||
class="plugin-market-detail__warning"
|
||||
:text="props.plugin?.system_version_message || t('plugin.incompatibleSystemVersion')"
|
||||
/>
|
||||
|
||||
<div class="plugin-market-detail-actions">
|
||||
<div class="plugin-market-detail-actions__buttons">
|
||||
<VBtn
|
||||
v-if="!isInstalled"
|
||||
color="primary"
|
||||
prepend-icon="mdi-download"
|
||||
:disabled="props.plugin?.system_version_compatible === false"
|
||||
@click="installPlugin()"
|
||||
>
|
||||
{{ t('plugin.installToLocal') }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-else-if="props.plugin?.has_update"
|
||||
color="primary"
|
||||
prepend-icon="mdi-arrow-up-circle-outline"
|
||||
:disabled="props.plugin?.system_version_compatible === false"
|
||||
@click="installPlugin()"
|
||||
>
|
||||
{{ t('plugin.update') }}
|
||||
</VBtn>
|
||||
<VBtn variant="tonal" prepend-icon="mdi-update" @click="showUpdateHistory">
|
||||
{{ t('plugin.versionHistory') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
<div v-if="props.count" class="plugin-market-detail-actions__downloads">
|
||||
<VIcon icon="mdi-fire" size="18" />
|
||||
<span>{{ t('plugin.totalDownloads', { count: formatDownloadCount(props.count) }) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section v-if="isInstalled" class="plugin-market-detail-user-rating">
|
||||
<h3 class="plugin-market-detail-user-rating__title">
|
||||
{{ t('plugin.yourRating') }}
|
||||
</h3>
|
||||
<div class="plugin-market-detail-user-rating__controls">
|
||||
<VRating
|
||||
v-model="selectedRating"
|
||||
:disabled="ratingLoading || ratingSubmitting"
|
||||
half-increments
|
||||
hover
|
||||
density="compact"
|
||||
active-color="warning"
|
||||
/>
|
||||
<VBtn
|
||||
size="small"
|
||||
variant="tonal"
|
||||
prepend-icon="mdi-star-check-outline"
|
||||
:loading="ratingSubmitting"
|
||||
:disabled="ratingLoading || selectedRating <= 0"
|
||||
@click="submitPluginRating"
|
||||
>
|
||||
{{ t('plugin.submitRating') }}
|
||||
</VBtn>
|
||||
</div>
|
||||
</section>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.plugin-market-detail__content {
|
||||
padding: 2.25rem 1.5rem 1.5rem;
|
||||
}
|
||||
|
||||
.plugin-market-detail__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plugin-market-detail__avatar {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.plugin-market-detail__title {
|
||||
max-inline-size: 100%;
|
||||
margin: 1rem 0 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.plugin-market-detail__description {
|
||||
max-inline-size: 28rem;
|
||||
margin: 0.35rem 0 0;
|
||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
overflow-wrap: anywhere;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.plugin-market-detail__metadata {
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
max-inline-size: 26rem;
|
||||
margin: 1.5rem auto 0;
|
||||
}
|
||||
|
||||
.plugin-market-detail__metadata-row {
|
||||
display: grid;
|
||||
grid-template-columns: 7rem minmax(0, 1fr);
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
min-inline-size: 0;
|
||||
}
|
||||
|
||||
.plugin-market-detail__metadata dt {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
text-align: end;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.plugin-market-detail__metadata dd {
|
||||
min-inline-size: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.4;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.plugin-market-detail__author {
|
||||
max-inline-size: 100%;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
overflow-wrap: anywhere;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.plugin-market-detail__author:hover,
|
||||
.plugin-market-detail__author:focus-visible {
|
||||
color: rgb(var(--v-theme-primary));
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.plugin-market-detail__rating-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.plugin-market-detail__warning {
|
||||
margin-block-start: 1.25rem;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
margin-block-start: 1.25rem;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions__buttons {
|
||||
/* 窄屏换行时用统一 gap 控制按钮间距,避免第二个按钮带左边距导致视觉偏移。 */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions__downloads {
|
||||
flex-basis: 100%;
|
||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||
font-size: 0.75rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plugin-market-detail-rating-row {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
white-space: normal;
|
||||
gap: 0.3rem;
|
||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.plugin-market-detail-user-rating {
|
||||
padding-block-start: 1rem;
|
||||
margin-block-start: 1.5rem;
|
||||
padding-block-start: 1.25rem;
|
||||
border-block-start: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
}
|
||||
|
||||
.plugin-market-detail-user-rating__title {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plugin-market-detail-user-rating__controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
min-inline-size: 0;
|
||||
}
|
||||
|
||||
@media (width >= 960px) {
|
||||
.plugin-market-detail-actions {
|
||||
justify-content: flex-start;
|
||||
@media (width < 360px) {
|
||||
.plugin-market-detail__content {
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions__buttons {
|
||||
justify-content: flex-start;
|
||||
.plugin-market-detail__metadata-row {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions__downloads {
|
||||
.plugin-market-detail__metadata dt {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.plugin-market-detail-rating-row {
|
||||
justify-content: flex-start;
|
||||
.plugin-market-detail-actions__buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.plugin-market-detail-actions__buttons :deep(.v-btn) {
|
||||
inline-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (width >= 480px) {
|
||||
.plugin-market-detail-user-rating__controls {
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user