From 2babd364ba1beaf6f8daec68f53aad0e013f033f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Wed, 23 Sep 2026 14:29:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(viewer):=20hide=20like=20feature=20?= =?UTF-8?q?=E2=80=94=20action=20bar=20like=20slot,=20photo=20like=20badges?= =?UTF-8?q?,=20hot=20sort=20tab,=20others'=20like=20bubbles=20(user=20requ?= =?UTF-8?q?est=202026-09-23)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PhotoFeed: cell like badge not rendered - AlbumHeader: sort tabs row removed (hot depends on likes; latest-only has no toggle value) - PhotoActionBar: like slot v-if=false (share/download remain, auto re-center) - ActivityPage: LikeBubbles hidden - specs updated to hidden assertions; 244 green Co-Authored-By: Claude Code --- apps/viewer/src/__tests__/activity.spec.ts | 16 ++------- .../viewer/src/__tests__/album-header.spec.ts | 17 +++------ apps/viewer/src/__tests__/feed.spec.ts | 35 ++++--------------- apps/viewer/src/__tests__/lightbox.spec.ts | 12 +++---- .../src/__tests__/photo-action-bar.spec.ts | 30 +++++++--------- apps/viewer/src/components/PhotoFeed.vue | 6 ++-- .../src/components/album/AlbumHeader.vue | 25 ++----------- .../src/components/viewer/PhotoActionBar.vue | 4 ++- apps/viewer/src/pages/ActivityPage.vue | 3 +- 9 files changed, 40 insertions(+), 108 deletions(-) diff --git a/apps/viewer/src/__tests__/activity.spec.ts b/apps/viewer/src/__tests__/activity.spec.ts index 3e50f3a..8c9d52d 100644 --- a/apps/viewer/src/__tests__/activity.spec.ts +++ b/apps/viewer/src/__tests__/activity.spec.ts @@ -233,21 +233,11 @@ describe('activity page (Task 6)', () => { // —— UI-02 V02:排序/分类经 AlbumHeader 上抛,沿用本页序列重置机制 —— - it('selecting the Popular tab refetches the sequence with sort=hot (active state moves)', async () => { + it('sort tabs removed per user request (2026-09-23): no popular tab, sequence stays latest', async () => { const wrapper = mountPage(); await flushPromises(); - mockedGetPublicPhotos.mockClear(); - - const tabs = wrapper.findAll('.sort-tab'); - expect(tabs.map((tab) => tab.text())).toEqual(['最新', '热门']); - expect(tabs[0].classes()).toContain('active'); - expect(tabs[0].attributes('aria-pressed')).toBe('true'); - - await tabs[1].trigger('click'); - await flushPromises(); - - expect(mockedGetPublicPhotos).toHaveBeenLastCalledWith('tok-activity', expect.objectContaining({ sort: 'hot' })); - expect(wrapper.findAll('.sort-tab')[1].classes()).toContain('active'); + expect(wrapper.findAll('.sort-tab')).toHaveLength(0); + expect(wrapper.find('.sort-tabs').exists()).toBe(false); }); it('category chips filter the sequence and the selection survives a locale switch', async () => { diff --git a/apps/viewer/src/__tests__/album-header.spec.ts b/apps/viewer/src/__tests__/album-header.spec.ts index 5ac6f63..a5f1fb9 100644 --- a/apps/viewer/src/__tests__/album-header.spec.ts +++ b/apps/viewer/src/__tests__/album-header.spec.ts @@ -81,7 +81,7 @@ describe('album header info area (UI-02 V02)', () => { expect(wrapper.find('.meta').text()).toContain('10月1日'); // 工具栏:排序 tab + 分类胶囊(All + 接口分类)。 - expect(wrapper.findAll('.sort-tab').map((tab) => tab.text())).toEqual(['最新', '热门']); + expect(wrapper.findAll('.sort-tab')).toHaveLength(0); // 排序 tab 已移除(2026-09-23) expect(wrapper.findAll('.categories .chip').map((chip) => chip.text())).toEqual(['全部', '签到墙', '开场']); // jsdom 无布局:未溢出 → 不渲染展开按钮。 expect(wrapper.findAll('.text-expand')).toHaveLength(0); @@ -153,19 +153,10 @@ describe('album header info area (UI-02 V02)', () => { expect(wrapper.find('.title').classes()).not.toContain('clamped'); }); - it('sort tabs: latest active by default, clicking popular emits select-sort hot, locked disables', async () => { + it('sort tabs removed per user request (2026-09-23): whole row hidden, mode stays latest', () => { const wrapper = mountHeader({ album: makeAlbum(), viewCount: null }); - - const tabs = wrapper.findAll('.sort-tab'); - expect(tabs[0].classes()).toContain('active'); - expect(tabs[0].attributes('aria-pressed')).toBe('true'); - expect(tabs[1].classes()).not.toContain('active'); - - await tabs[1].trigger('click'); - expect(wrapper.emitted('selectSort')).toEqual([['hot']]); - - const locked = mountHeader({ album: makeAlbum(), viewCount: null, sortLocked: true }); - expect(locked.findAll('.sort-tab').every((tab) => tab.attributes('disabled') !== undefined)).toBe(true); + expect(wrapper.find('.sort-tabs').exists()).toBe(false); + expect(wrapper.find('.sort-tab').exists()).toBe(false); }); it('category chips: selected state from prop, clicks emit the category id and All emits null', async () => { diff --git a/apps/viewer/src/__tests__/feed.spec.ts b/apps/viewer/src/__tests__/feed.spec.ts index d951c1d..55f8833 100644 --- a/apps/viewer/src/__tests__/feed.spec.ts +++ b/apps/viewer/src/__tests__/feed.spec.ts @@ -343,37 +343,14 @@ describe('photo feed (Task 7 / Task 8 sequence props)', () => { expect(wrapper.findAll('.cell')).toHaveLength(1); }); - it('renders the like badge overlay with the real count and no card chrome', async () => { - const likes = { - displayFor: (photo: PublicPhoto) => photo.likeCount, - popNonce: () => 0, - like: vi.fn(), - } as unknown as LikesController; - mockedGetPublicPhotos.mockResolvedValueOnce( - makeList([{ ...makePhoto('p1'), likeCount: 1286 }, makePhoto('p2')], null), - ); - const { wrapper } = mountFeed({ likes }); - await flushPromises(); - - const badge = wrapper.find('.cell .cell-like'); - expect(badge.exists()).toBe(true); - expect(badge.find('.heart').exists()).toBe(true); - // 真实计数(useLikes displayFor 值)经 Intl 分组。 - expect(badge.find('.count').text()).toBe('1,286'); - // 无白色卡片包裹/无常驻文件名/无额外标题:单元格可见文本只有点赞计数 - //(图片 alt 非可见文本,懒加载绑定不影响该断言)。 - expect(wrapper.findAll('.cell')[0].text()).toBe('1,286'); + it('like badge overlay hidden per user request (2026-09-23)', () => { + const { wrapper } = mountFeed(); + expect(wrapper.find('.cell-like').exists()).toBe(false); }); - it('clicking the like badge likes the photo without opening the lightbox', async () => { - const like = vi.fn(); - const likes = { displayFor: () => 0, popNonce: () => 0, like } as unknown as LikesController; - const { wrapper, opened } = mountFeed({ likes }); - await flushPromises(); - - await wrapper.find('.cell-like').trigger('click'); - expect(like).toHaveBeenCalledWith('p1'); - expect(opened).toEqual([]); + it('like badge interactions removed with the badge (hidden 2026-09-23)', () => { + const { wrapper } = mountFeed(); + expect(wrapper.find('.cell-like').exists()).toBe(false); }); it('shows the new-photo pill on hasNew; clicking refreshes without scrolling to top', async () => { diff --git a/apps/viewer/src/__tests__/lightbox.spec.ts b/apps/viewer/src/__tests__/lightbox.spec.ts index b011efb..15ec1bb 100644 --- a/apps/viewer/src/__tests__/lightbox.spec.ts +++ b/apps/viewer/src/__tests__/lightbox.spec.ts @@ -139,9 +139,9 @@ describe('photo lightbox (Task 8)', () => { expect(img(wrapper).attributes('src')).toBe('http://img.test/p2-browse.jpg?s=1'); // 3 张全部加载完成(无更多页)→ 筛选序列 i / n(§5.2)。 expect(wrapper.find('.position-indicator').text()).toBe('2 / 3'); - // 底部操作栏(V04):Like 计数 + Like/Share 标签(无下载控制器 → 下载位省略)。 - expect(wrapper.find('.like-count').text()).toBe('7'); - expect(wrapper.findAll('.action-label').map((label) => label.text())).toEqual(['点赞', '分享']); + // 底部操作栏:点赞已按用户要求隐藏(2026-09-23)→ 仅分享(无下载控制器)。 + expect(wrapper.find('.like-count').exists()).toBe(false); + expect(wrapper.findAll('.action-label').map((label) => label.text())).toEqual(['分享']); }); it('navigates with buttons and arrow keys, keeping the list order', async () => { @@ -553,14 +553,12 @@ describe('photo lightbox interactions (UI-02 V05)', () => { document.documentElement.className = ''; }); - it('bursts heart particles for a local like click on the current photo', async () => { + it('like entry hidden (2026-09-23): no local like click path, no particles', async () => { const { wrapper } = mountV05('p1'); await flushPromises(); + expect(wrapper.find('.like-slot').exists()).toBe(false); expect(wrapper.findAll('.heart-particles-zone .particle')).toHaveLength(0); - await wrapper.find('.like-slot .action-btn').trigger('click'); - await nextTick(); - expect(wrapper.findAll('.heart-particles-zone .particle')).toHaveLength(2); }); it('routes realtime bursts: particles for the current photo, a notice for others; notice click navigates', async () => { diff --git a/apps/viewer/src/__tests__/photo-action-bar.spec.ts b/apps/viewer/src/__tests__/photo-action-bar.spec.ts index 34bacfe..dd6fef3 100644 --- a/apps/viewer/src/__tests__/photo-action-bar.spec.ts +++ b/apps/viewer/src/__tests__/photo-action-bar.spec.ts @@ -39,36 +39,30 @@ describe('photo action bar (UI-02 V04)', () => { vi.restoreAllMocks(); }); - it('renders like/share/download as evenly distributed slots with formatted count (no tap-more hint)', () => { + it('like slot hidden (2026-09-23): share/download slots remain, no like count', () => { const wrapper = mountBar({ likeCount: 1286, canDownload: true }); - // 三个 action-slot flex 均分(下载隐藏时由剩余 slot 自然重排,见下例)。 - expect(wrapper.findAll('.action-slot')).toHaveLength(3); + expect(wrapper.findAll('.action-slot')).toHaveLength(2); const labels = wrapper.findAll('.action-label').map((label) => label.text()); - expect(labels).toEqual(['点赞', '分享', '下载']); - // 计数 Intl 分组 + tabular-nums 容器;「连续点击」提示已按用户要求移除。 - expect(wrapper.find('.like-count').text()).toBe('1,286'); - expect(wrapper.find('.like-hint').exists()).toBe(false); + expect(labels).toEqual(['分享', '下载']); + expect(wrapper.find('.like-slot').exists()).toBe(false); + expect(wrapper.find('.like-count').exists()).toBe(false); }); - it('removes the download action entirely when downloads are disabled', () => { + it('download disabled leaves share only (like hidden 2026-09-23)', () => { const wrapper = mountBar({ likeCount: 0, canDownload: false }); expect(wrapper.find('.download-group').exists()).toBe(false); - expect(wrapper.findAll('.action-slot')).toHaveLength(2); // 剩余两键均分栏宽 - expect(wrapper.findAll('.action-label').map((label) => label.text())).toEqual(['点赞', '分享']); + expect(wrapper.findAll('.action-slot')).toHaveLength(1); + expect(wrapper.findAll('.action-label').map((label) => label.text())).toEqual(['分享']); }); - it('emits like and share from the large tap targets', async () => { - const wrapper = mountBar({ likeCount: 3 }); - const buttons = wrapper.findAll('.action-btn'); - expect(buttons).toHaveLength(2); + it('emits share from the large tap target (like hidden 2026-09-23)', async () => { + const wrapper = mountBar({ likeCount: 0 }); - await buttons[0].trigger('click'); - await buttons[1].trigger('click'); - expect(wrapper.emitted('like')).toHaveLength(1); + await wrapper.get('.action-btn[aria-label="分享照片"]').trigger('click'); expect(wrapper.emitted('share')).toHaveLength(1); - expect(wrapper.emitted('download')).toBeUndefined(); + expect(wrapper.emitted('like')).toBeUndefined(); }); it('downloads the browse variant directly when original download is disabled', async () => { diff --git a/apps/viewer/src/components/PhotoFeed.vue b/apps/viewer/src/components/PhotoFeed.vue index f79a457..6208d5e 100644 --- a/apps/viewer/src/components/PhotoFeed.vue +++ b/apps/viewer/src/components/PhotoFeed.vue @@ -256,16 +256,16 @@ onBeforeUnmount(() => { decoding="async" @error="onImgError(photos[placement.index])" > - +