diff --git a/src/components/cards/PluginCard.vue b/src/components/cards/PluginCard.vue index 9fdb624e..a7cd52c0 100644 --- a/src/components/cards/PluginCard.vue +++ b/src/components/cards/PluginCard.vue @@ -39,6 +39,16 @@ const emit = defineEmits(['remove', 'save', 'actionDone']) // 多语言 const { t } = useI18n() +const hasCardRating = computed(() => (props.plugin?.rating_count || 0) > 0) +const hasCardStatus = computed(() => Boolean(props.plugin?.has_update) || hasCardRating.value) +const cardRatingValue = computed(() => Number(props.plugin?.average_rating || 0).toFixed(1)) +const cardRatingSummary = computed(() => + t('plugin.ratingSummary', { + rating: cardRatingValue.value, + count: props.plugin?.rating_count || 0, + }), +) + // 显示器宽度 const display = useDisplay() @@ -642,6 +652,7 @@ watch( {{ props.plugin?.plugin_name }} @@ -721,8 +732,22 @@ watch( -
- +
+ +
+
+ + {{ cardRatingValue }}
@@ -736,6 +761,28 @@ watch( inline-size: 100%; } +.plugin-card__title--with-status { + padding-inline-end: 4rem !important; +} + +.plugin-card__status { + position: absolute; + z-index: 2; + display: inline-flex; + align-items: center; + color: white; + inset-block-start: 0.625rem; + inset-inline-end: 0.625rem; + line-height: 1; + text-shadow: 0 1px 2px rgba(0, 0, 0, 65%); +} + +.plugin-card__status--rating { + gap: 0.125rem; + font-size: 0.75rem; + font-weight: 600; +} + .card-cover-blurred::before { position: absolute; /* stylelint-disable-next-line property-no-vendor-prefix */ diff --git a/src/components/cards/__tests__/PluginCardAbout.spec.ts b/src/components/cards/__tests__/PluginCardAbout.spec.ts index 61d20ef3..5dcf9929 100644 --- a/src/components/cards/__tests__/PluginCardAbout.spec.ts +++ b/src/components/cards/__tests__/PluginCardAbout.spec.ts @@ -122,4 +122,39 @@ describe('PluginCard about menu', () => { await waitFor(() => expect(replace).toHaveBeenCalledWith('https://github.com/example/plugins')) expect(popup.opener).toBeNull() }) + + it('prioritizes the update status over the rating status', async () => { + await renderWithProviders(PluginCard, { + props: { + plugin: { ...plugin, has_update: true, average_rating: 4.3, rating_count: 12 }, + }, + }) + + expect(screen.getByLabelText('有更新')).toBeInTheDocument() + expect(screen.queryByLabelText('4.3 分,共 12 人评分')).not.toBeInTheDocument() + }) + + it('shows the rating status when no update is available', async () => { + await renderWithProviders(PluginCard, { + props: { + plugin: { ...plugin, has_update: false, average_rating: 4.3, rating_count: 12 }, + }, + }) + + const ratingStatus = screen.getByLabelText('4.3 分,共 12 人评分') + + expect(ratingStatus).toHaveClass('plugin-card__status--rating') + expect(ratingStatus).toHaveTextContent('4.3') + expect(screen.queryByLabelText('有更新')).not.toBeInTheDocument() + }) + + it('leaves the status position empty without an update or rating', async () => { + await renderWithProviders(PluginCard, { + props: { + plugin: { ...plugin, has_update: false, average_rating: 0, rating_count: 0 }, + }, + }) + + expect(document.querySelector('.plugin-card__status')).toBeNull() + }) }) diff --git a/src/components/dialog/PluginMarketDetailDialog.vue b/src/components/dialog/PluginMarketDetailDialog.vue index 3f87f133..e2e65fa8 100644 --- a/src/components/dialog/PluginMarketDetailDialog.vue +++ b/src/components/dialog/PluginMarketDetailDialog.vue @@ -247,7 +247,7 @@ onUnmounted(() => {