feat(viewer): UI-02 heart particles, interaction notices, share and download

Task 5 (V05 §5.4/§6): decorative heart particles on the lightbox stage
(local like clicks + others' WS bursts for the current photo), compact
cross-photo interaction notices above the action bar (click to locate),
navigator.share-first share orchestration with clipboard fallback for
album and photo deep links (lang param), and download failures attributed
to the photo that triggered them. Self-echo dedup stays in the realtime
router (own batches never produce particles/notices); particles cap at
12 with visibility/unmount cleanup and are suppressed under reduced
motion; notices cap at 3 with ~4s auto-dismiss and throttled SR summary.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-21 22:20:19 +08:00
parent 89f45896b7
commit 160e7e5f1a
18 changed files with 1042 additions and 58 deletions
+19 -3
View File
@@ -184,6 +184,17 @@ const currentPhoto = computed(() => {
return sequence.photos.find((photo) => photo.photoId === lightboxPhotoId.value) ?? null;
});
/** 当前照片分享深链(V05 §5.4):/a/:token/p/:photoId + lang 参数(当前 UI
* 语言),始终分享观众端路由——不分享 OSS 签名 URL。 */
const photoShareUrl = computed(() => {
if (lightboxPhotoId.value === null) return undefined;
const href = router.resolve({
name: 'activity-photo',
params: { token: token.value, photoId: lightboxPhotoId.value },
}).href;
return `${href}?lang=${locale.value}`;
});
/** 下载控制器(P4a Task 4):开关来自相册载荷,当前照片随大图键控。 */
const download = useDownload({
token,
@@ -344,19 +355,24 @@ onBeforeUnmount(() => {
<PhotoFeed :sequence="sequence" :likes="likes" @open="openFromFeed" />
</template>
<!-- 大图查看器(Task 8):当前照片以 photoId 键控(v-model)。 -->
<!-- 大图查看器(Task 8):当前照片以 photoId 键控(v-model)。V05 新增:
相册标题/照片深链(navigator.share)与实时气泡(粒子/互动提示分层)。 -->
<PhotoLightbox
v-if="lightboxPhotoId !== null && currentPhoto !== null"
v-model:photo-id="lightboxPhotoId"
:sequence="sequence"
:likes="likes"
:download="download"
:album-title="album !== null ? album.translation.title : undefined"
:share-url="photoShareUrl"
:like-bubbles="realtime.bubbles"
@removed="onPhotoRemoved"
@close="closeLightbox"
/>
<!-- 他人点赞气泡(Task 10):点击定位打开该照片大图。 -->
<LikeBubbles :bubbles="realtime.bubbles" @open="openFromFeed" />
<!-- 他人点赞气泡(Task 10):点击定位打开该照片大图。大图打开期间改由
查看器内互动提示承载(§6.2:避免页面级气泡被模态框盖住或遮住下载)。 -->
<LikeBubbles :bubbles="lightboxPhotoId === null ? realtime.bubbles : []" @open="openFromFeed" />
<!-- 照片下线轻提示(大图 404 刷新 / WS hidden/deleted 推送移除时)。 -->
<p v-if="photoRemovedNotice" class="removed-notice" role="status">{{ t('viewer.photoRemoved') }}</p>