From 536707f8126a4d80486dc3a5f2fb2885d27f6f9e Mon Sep 17 00:00:00 2001 From: freefire Date: Sat, 8 Aug 2026 02:24:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=B4=B4=E7=BA=B8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=EF=BC=8C=E9=87=8D=E6=9E=84=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E4=B8=8E=E5=86=85=E5=AE=B9=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增多平台贴纸库:贴吧、微博、知乎、小红书、抖音、B站共500+贴纸,搭配颜文字贴纸 2. 实现贴纸选择器面板,支持分类浏览、键盘导航和懒加载 3. 重构评论内容渲染:替换旧的@提及高亮逻辑,新增HTML净化与双向兼容 4. 重构评论编辑器为Tiptap富文本版本,支持表情插入、格式编辑 5. 优化评论编辑体验,修复滚动位置保留问题,调整评论区UI样式 6. 移除旧版EmojiPicker工具类,新增贴纸数据管理模块 --- .trae/documents/emoji-effect-adjustment.md | 151 ++ .trae/documents/emoji_rich_comment_plan.md | 597 ++++++ .../documents/fix-post-scroll-persist-plan.md | 117 ++ frontend/public/stickers/bilibili/bl_01.avif | Bin 0 -> 1833 bytes frontend/public/stickers/bilibili/bl_02.avif | Bin 0 -> 2244 bytes frontend/public/stickers/bilibili/bl_03.avif | Bin 0 -> 1778 bytes frontend/public/stickers/bilibili/bl_04.avif | Bin 0 -> 1794 bytes frontend/public/stickers/bilibili/bl_05.avif | Bin 0 -> 1983 bytes frontend/public/stickers/bilibili/bl_06.avif | Bin 0 -> 1689 bytes frontend/public/stickers/bilibili/bl_07.avif | Bin 0 -> 1888 bytes frontend/public/stickers/bilibili/bl_08.avif | Bin 0 -> 1929 bytes frontend/public/stickers/bilibili/bl_09.avif | Bin 0 -> 1667 bytes frontend/public/stickers/bilibili/bl_10.avif | Bin 0 -> 1750 bytes frontend/public/stickers/bilibili/bl_11.avif | Bin 0 -> 1987 bytes frontend/public/stickers/bilibili/bl_12.avif | Bin 0 -> 1641 bytes frontend/public/stickers/bilibili/bl_13.avif | Bin 0 -> 1766 bytes frontend/public/stickers/bilibili/bl_14.avif | Bin 0 -> 1602 bytes frontend/public/stickers/bilibili/bl_15.avif | Bin 0 -> 1854 bytes frontend/public/stickers/bilibili/bl_16.avif | Bin 0 -> 1841 bytes frontend/public/stickers/bilibili/bl_17.avif | Bin 0 -> 1731 bytes frontend/public/stickers/bilibili/bl_18.avif | Bin 0 -> 1867 bytes frontend/public/stickers/bilibili/bl_19.avif | Bin 0 -> 1765 bytes frontend/public/stickers/bilibili/bl_20.avif | Bin 0 -> 1835 bytes frontend/public/stickers/bilibili/bl_21.avif | Bin 0 -> 1887 bytes frontend/public/stickers/bilibili/bl_22.avif | Bin 0 -> 1698 bytes frontend/public/stickers/bilibili/bl_23.avif | Bin 0 -> 1532 bytes frontend/public/stickers/bilibili/bl_24.avif | Bin 0 -> 1612 bytes frontend/public/stickers/bilibili/bl_25.avif | Bin 0 -> 1889 bytes frontend/public/stickers/bilibili/bl_26.avif | Bin 0 -> 1733 bytes frontend/public/stickers/bilibili/bl_27.avif | Bin 0 -> 1610 bytes frontend/public/stickers/bilibili/bl_28.avif | Bin 0 -> 1841 bytes frontend/public/stickers/bilibili/bl_29.avif | Bin 0 -> 1658 bytes frontend/public/stickers/bilibili/bl_30.avif | Bin 0 -> 1981 bytes frontend/public/stickers/bilibili/bl_31.avif | Bin 0 -> 1782 bytes frontend/public/stickers/bilibili/bl_32.avif | Bin 0 -> 1692 bytes frontend/public/stickers/bilibili/bl_33.avif | Bin 0 -> 1581 bytes frontend/public/stickers/bilibili/bl_34.avif | Bin 0 -> 1846 bytes frontend/public/stickers/bilibili/bl_35.avif | Bin 0 -> 1866 bytes frontend/public/stickers/douyin/dy_01.avif | Bin 0 -> 1756 bytes frontend/public/stickers/douyin/dy_02.avif | Bin 0 -> 1769 bytes frontend/public/stickers/douyin/dy_03.avif | Bin 0 -> 1710 bytes frontend/public/stickers/douyin/dy_04.avif | Bin 0 -> 1930 bytes frontend/public/stickers/douyin/dy_05.avif | Bin 0 -> 1704 bytes frontend/public/stickers/douyin/dy_06.avif | Bin 0 -> 1902 bytes frontend/public/stickers/douyin/dy_07.avif | Bin 0 -> 1572 bytes frontend/public/stickers/douyin/dy_08.avif | Bin 0 -> 1740 bytes frontend/public/stickers/douyin/dy_09.avif | Bin 0 -> 1925 bytes frontend/public/stickers/douyin/dy_10.avif | Bin 0 -> 1518 bytes frontend/public/stickers/douyin/dy_11.avif | Bin 0 -> 1793 bytes frontend/public/stickers/douyin/dy_12.avif | Bin 0 -> 1654 bytes frontend/public/stickers/douyin/dy_13.avif | Bin 0 -> 1984 bytes frontend/public/stickers/douyin/dy_14.avif | Bin 0 -> 2058 bytes frontend/public/stickers/douyin/dy_15.avif | Bin 0 -> 1988 bytes frontend/public/stickers/douyin/dy_16.avif | Bin 0 -> 1763 bytes frontend/public/stickers/douyin/dy_17.avif | Bin 0 -> 2049 bytes frontend/public/stickers/douyin/dy_18.avif | Bin 0 -> 1720 bytes frontend/public/stickers/douyin/dy_19.avif | Bin 0 -> 1866 bytes frontend/public/stickers/douyin/dy_20.avif | Bin 0 -> 1788 bytes frontend/public/stickers/douyin/dy_21.avif | Bin 0 -> 1739 bytes frontend/public/stickers/douyin/dy_22.avif | Bin 0 -> 1868 bytes frontend/public/stickers/douyin/dy_23.avif | Bin 0 -> 1779 bytes frontend/public/stickers/douyin/dy_24.avif | Bin 0 -> 1800 bytes frontend/public/stickers/douyin/dy_25.avif | Bin 0 -> 1626 bytes frontend/public/stickers/douyin/dy_26.avif | Bin 0 -> 1922 bytes frontend/public/stickers/douyin/dy_27.avif | Bin 0 -> 1883 bytes frontend/public/stickers/douyin/dy_28.avif | Bin 0 -> 2218 bytes frontend/public/stickers/douyin/dy_29.avif | Bin 0 -> 1844 bytes frontend/public/stickers/douyin/dy_30.avif | Bin 0 -> 2018 bytes frontend/public/stickers/douyin/dy_31.avif | Bin 0 -> 1820 bytes frontend/public/stickers/douyin/dy_32.avif | Bin 0 -> 1996 bytes frontend/public/stickers/douyin/dy_33.avif | Bin 0 -> 1871 bytes frontend/public/stickers/douyin/dy_34.avif | Bin 0 -> 2073 bytes frontend/public/stickers/douyin/dy_35.avif | Bin 0 -> 2101 bytes frontend/public/stickers/douyin/dy_36.avif | Bin 0 -> 1986 bytes frontend/public/stickers/tieba/tb_01.avif | Bin 0 -> 1537 bytes frontend/public/stickers/tieba/tb_02.avif | Bin 0 -> 1610 bytes frontend/public/stickers/tieba/tb_03.avif | Bin 0 -> 1523 bytes frontend/public/stickers/tieba/tb_04.avif | Bin 0 -> 1576 bytes frontend/public/stickers/tieba/tb_05.avif | Bin 0 -> 1694 bytes frontend/public/stickers/tieba/tb_06.avif | Bin 0 -> 1676 bytes frontend/public/stickers/tieba/tb_07.avif | Bin 0 -> 1577 bytes frontend/public/stickers/tieba/tb_08.avif | Bin 0 -> 1608 bytes frontend/public/stickers/tieba/tb_09.avif | Bin 0 -> 1852 bytes frontend/public/stickers/tieba/tb_10.avif | Bin 0 -> 1568 bytes frontend/public/stickers/tieba/tb_11.avif | Bin 0 -> 1582 bytes frontend/public/stickers/tieba/tb_12.avif | Bin 0 -> 1768 bytes frontend/public/stickers/tieba/tb_13.avif | Bin 0 -> 1598 bytes frontend/public/stickers/tieba/tb_14.avif | Bin 0 -> 1496 bytes frontend/public/stickers/tieba/tb_15.avif | Bin 0 -> 1515 bytes frontend/public/stickers/tieba/tb_16.avif | Bin 0 -> 1613 bytes frontend/public/stickers/tieba/tb_17.avif | Bin 0 -> 1599 bytes frontend/public/stickers/tieba/tb_18.avif | Bin 0 -> 1747 bytes frontend/public/stickers/tieba/tb_19.avif | Bin 0 -> 1580 bytes frontend/public/stickers/tieba/tb_20.avif | Bin 0 -> 1675 bytes frontend/public/stickers/tieba/tb_21.avif | Bin 0 -> 1800 bytes frontend/public/stickers/tieba/tb_22.avif | Bin 0 -> 1836 bytes frontend/public/stickers/tieba/tb_23.avif | Bin 0 -> 1741 bytes frontend/public/stickers/tieba/tb_24.avif | Bin 0 -> 1848 bytes frontend/public/stickers/tieba/tb_25.avif | Bin 0 -> 1628 bytes frontend/public/stickers/weibo/wb_01.avif | Bin 0 -> 2517 bytes frontend/public/stickers/weibo/wb_02.avif | Bin 0 -> 2384 bytes frontend/public/stickers/weibo/wb_03.avif | Bin 0 -> 2343 bytes frontend/public/stickers/weibo/wb_04.avif | Bin 0 -> 2358 bytes frontend/public/stickers/weibo/wb_05.avif | Bin 0 -> 2427 bytes frontend/public/stickers/weibo/wb_06.avif | Bin 0 -> 2347 bytes frontend/public/stickers/weibo/wb_07.avif | Bin 0 -> 2203 bytes frontend/public/stickers/weibo/wb_08.avif | Bin 0 -> 2406 bytes frontend/public/stickers/weibo/wb_09.avif | Bin 0 -> 2416 bytes frontend/public/stickers/weibo/wb_10.avif | Bin 0 -> 2544 bytes frontend/public/stickers/weibo/wb_11.avif | Bin 0 -> 2311 bytes frontend/public/stickers/weibo/wb_12.avif | Bin 0 -> 2426 bytes frontend/public/stickers/weibo/wb_13.avif | Bin 0 -> 2265 bytes frontend/public/stickers/weibo/wb_14.avif | Bin 0 -> 2294 bytes frontend/public/stickers/weibo/wb_15.avif | Bin 0 -> 1779 bytes frontend/public/stickers/weibo/wb_16.avif | Bin 0 -> 2307 bytes frontend/public/stickers/weibo/wb_17.avif | Bin 0 -> 2488 bytes frontend/public/stickers/weibo/wb_18.avif | Bin 0 -> 2378 bytes frontend/public/stickers/weibo/wb_19.avif | Bin 0 -> 2733 bytes frontend/public/stickers/weibo/wb_20.avif | Bin 0 -> 2375 bytes frontend/public/stickers/weibo/wb_21.avif | Bin 0 -> 2683 bytes frontend/public/stickers/weibo/wb_22.avif | Bin 0 -> 2612 bytes frontend/public/stickers/weibo/wb_23.avif | Bin 0 -> 2136 bytes frontend/public/stickers/weibo/wb_24.avif | Bin 0 -> 1575 bytes frontend/public/stickers/weibo/wb_25.avif | Bin 0 -> 1834 bytes frontend/public/stickers/weibo/wb_26.avif | Bin 0 -> 1839 bytes frontend/public/stickers/weibo/wb_27.avif | Bin 0 -> 1699 bytes frontend/public/stickers/weibo/wb_28.avif | Bin 0 -> 1942 bytes frontend/public/stickers/weibo/wb_29.avif | Bin 0 -> 2165 bytes frontend/public/stickers/weibo/wb_30.avif | Bin 0 -> 1869 bytes .../public/stickers/xiaohongshu/xhs_01.avif | Bin 0 -> 1731 bytes .../public/stickers/xiaohongshu/xhs_02.avif | Bin 0 -> 1890 bytes .../public/stickers/xiaohongshu/xhs_03.avif | Bin 0 -> 1809 bytes .../public/stickers/xiaohongshu/xhs_04.avif | Bin 0 -> 2182 bytes .../public/stickers/xiaohongshu/xhs_05.avif | Bin 0 -> 1926 bytes .../public/stickers/xiaohongshu/xhs_06.avif | Bin 0 -> 1965 bytes .../public/stickers/xiaohongshu/xhs_07.avif | Bin 0 -> 1834 bytes .../public/stickers/xiaohongshu/xhs_08.avif | Bin 0 -> 1824 bytes .../public/stickers/xiaohongshu/xhs_09.avif | Bin 0 -> 1504 bytes .../public/stickers/xiaohongshu/xhs_10.avif | Bin 0 -> 2045 bytes .../public/stickers/xiaohongshu/xhs_11.avif | Bin 0 -> 1961 bytes .../public/stickers/xiaohongshu/xhs_12.avif | Bin 0 -> 1677 bytes .../public/stickers/xiaohongshu/xhs_13.avif | Bin 0 -> 1776 bytes .../public/stickers/xiaohongshu/xhs_14.avif | Bin 0 -> 1887 bytes .../public/stickers/xiaohongshu/xhs_15.avif | Bin 0 -> 2190 bytes .../public/stickers/xiaohongshu/xhs_16.avif | Bin 0 -> 1981 bytes .../public/stickers/xiaohongshu/xhs_17.avif | Bin 0 -> 1821 bytes .../public/stickers/xiaohongshu/xhs_18.avif | Bin 0 -> 1835 bytes .../public/stickers/xiaohongshu/xhs_19.avif | Bin 0 -> 1935 bytes .../public/stickers/xiaohongshu/xhs_20.avif | Bin 0 -> 2071 bytes .../public/stickers/xiaohongshu/xhs_21.avif | Bin 0 -> 2017 bytes .../public/stickers/xiaohongshu/xhs_22.avif | Bin 0 -> 2042 bytes .../public/stickers/xiaohongshu/xhs_23.avif | Bin 0 -> 1960 bytes .../public/stickers/xiaohongshu/xhs_24.avif | Bin 0 -> 1953 bytes .../public/stickers/xiaohongshu/xhs_25.avif | Bin 0 -> 1881 bytes .../public/stickers/xiaohongshu/xhs_26.avif | Bin 0 -> 2143 bytes .../public/stickers/xiaohongshu/xhs_27.avif | Bin 0 -> 1897 bytes .../public/stickers/xiaohongshu/xhs_28.avif | Bin 0 -> 2361 bytes .../public/stickers/xiaohongshu/xhs_29.avif | Bin 0 -> 1964 bytes .../public/stickers/xiaohongshu/xhs_30.avif | Bin 0 -> 1726 bytes frontend/public/stickers/zhihu/zh_01.avif | Bin 0 -> 1875 bytes frontend/public/stickers/zhihu/zh_02.avif | Bin 0 -> 1595 bytes frontend/public/stickers/zhihu/zh_03.avif | Bin 0 -> 1902 bytes frontend/public/stickers/zhihu/zh_04.avif | Bin 0 -> 1757 bytes frontend/public/stickers/zhihu/zh_05.avif | Bin 0 -> 1762 bytes frontend/public/stickers/zhihu/zh_06.avif | Bin 0 -> 1651 bytes frontend/public/stickers/zhihu/zh_07.avif | Bin 0 -> 1999 bytes frontend/public/stickers/zhihu/zh_08.avif | Bin 0 -> 1727 bytes frontend/public/stickers/zhihu/zh_09.avif | Bin 0 -> 2094 bytes frontend/public/stickers/zhihu/zh_10.avif | Bin 0 -> 1882 bytes frontend/public/stickers/zhihu/zh_11.avif | Bin 0 -> 2037 bytes frontend/public/stickers/zhihu/zh_12.avif | Bin 0 -> 2143 bytes frontend/public/stickers/zhihu/zh_13.avif | Bin 0 -> 2078 bytes frontend/public/stickers/zhihu/zh_14.avif | Bin 0 -> 2046 bytes frontend/public/stickers/zhihu/zh_15.avif | Bin 0 -> 1873 bytes frontend/public/stickers/zhihu/zh_16.avif | Bin 0 -> 1906 bytes frontend/public/stickers/zhihu/zh_17.avif | Bin 0 -> 1855 bytes frontend/public/stickers/zhihu/zh_18.avif | Bin 0 -> 1890 bytes frontend/public/stickers/zhihu/zh_19.avif | Bin 0 -> 1908 bytes frontend/public/stickers/zhihu/zh_20.avif | Bin 0 -> 1971 bytes frontend/public/stickers/zhihu/zh_21.avif | Bin 0 -> 2047 bytes frontend/public/stickers/zhihu/zh_22.avif | Bin 0 -> 1737 bytes frontend/public/stickers/zhihu/zh_23.avif | Bin 0 -> 1743 bytes frontend/public/stickers/zhihu/zh_24.avif | Bin 0 -> 1923 bytes frontend/public/stickers/zhihu/zh_25.avif | Bin 0 -> 1740 bytes frontend/public/stickers/zhihu/zh_26.avif | Bin 0 -> 2012 bytes frontend/public/stickers/zhihu/zh_27.avif | Bin 0 -> 1778 bytes frontend/src/App.tsx | 2 +- frontend/src/components/CommentBox.tsx | 254 +-- frontend/src/components/CommentContent.tsx | 4 +- frontend/src/components/CommentEditor.tsx | 293 +++ frontend/src/components/CommentThreadList.tsx | 12 +- frontend/src/components/EmojiPicker.tsx | 68 - .../src/components/emoji/StickerPicker.tsx | 116 ++ frontend/src/data/stickers/emoji.json | 1594 +++++++++++++++++ frontend/src/data/stickers/emojiData.ts | 57 + frontend/src/data/stickers/hot.ts | 24 + frontend/src/data/stickers/index.ts | 35 + frontend/src/data/stickers/kaomoji.ts | 32 + frontend/src/styles/global.css | 207 ++- frontend/src/utils/content.ts | 51 + frontend/src/utils/emojis.ts | 21 - frontend/src/utils/postContent.ts | 8 +- service/comment.go | 6 +- 203 files changed, 3313 insertions(+), 336 deletions(-) create mode 100644 .trae/documents/emoji-effect-adjustment.md create mode 100644 .trae/documents/emoji_rich_comment_plan.md create mode 100644 .trae/documents/fix-post-scroll-persist-plan.md create mode 100644 frontend/public/stickers/bilibili/bl_01.avif create mode 100644 frontend/public/stickers/bilibili/bl_02.avif create mode 100644 frontend/public/stickers/bilibili/bl_03.avif create mode 100644 frontend/public/stickers/bilibili/bl_04.avif create mode 100644 frontend/public/stickers/bilibili/bl_05.avif create mode 100644 frontend/public/stickers/bilibili/bl_06.avif create mode 100644 frontend/public/stickers/bilibili/bl_07.avif create mode 100644 frontend/public/stickers/bilibili/bl_08.avif create mode 100644 frontend/public/stickers/bilibili/bl_09.avif create mode 100644 frontend/public/stickers/bilibili/bl_10.avif create mode 100644 frontend/public/stickers/bilibili/bl_11.avif create mode 100644 frontend/public/stickers/bilibili/bl_12.avif create mode 100644 frontend/public/stickers/bilibili/bl_13.avif create mode 100644 frontend/public/stickers/bilibili/bl_14.avif create mode 100644 frontend/public/stickers/bilibili/bl_15.avif create mode 100644 frontend/public/stickers/bilibili/bl_16.avif create mode 100644 frontend/public/stickers/bilibili/bl_17.avif create mode 100644 frontend/public/stickers/bilibili/bl_18.avif create mode 100644 frontend/public/stickers/bilibili/bl_19.avif create mode 100644 frontend/public/stickers/bilibili/bl_20.avif create mode 100644 frontend/public/stickers/bilibili/bl_21.avif create mode 100644 frontend/public/stickers/bilibili/bl_22.avif create mode 100644 frontend/public/stickers/bilibili/bl_23.avif create mode 100644 frontend/public/stickers/bilibili/bl_24.avif create mode 100644 frontend/public/stickers/bilibili/bl_25.avif create mode 100644 frontend/public/stickers/bilibili/bl_26.avif create mode 100644 frontend/public/stickers/bilibili/bl_27.avif create mode 100644 frontend/public/stickers/bilibili/bl_28.avif create mode 100644 frontend/public/stickers/bilibili/bl_29.avif create mode 100644 frontend/public/stickers/bilibili/bl_30.avif create mode 100644 frontend/public/stickers/bilibili/bl_31.avif create mode 100644 frontend/public/stickers/bilibili/bl_32.avif create mode 100644 frontend/public/stickers/bilibili/bl_33.avif create mode 100644 frontend/public/stickers/bilibili/bl_34.avif create mode 100644 frontend/public/stickers/bilibili/bl_35.avif create mode 100644 frontend/public/stickers/douyin/dy_01.avif create mode 100644 frontend/public/stickers/douyin/dy_02.avif create mode 100644 frontend/public/stickers/douyin/dy_03.avif create mode 100644 frontend/public/stickers/douyin/dy_04.avif create mode 100644 frontend/public/stickers/douyin/dy_05.avif create mode 100644 frontend/public/stickers/douyin/dy_06.avif create mode 100644 frontend/public/stickers/douyin/dy_07.avif create mode 100644 frontend/public/stickers/douyin/dy_08.avif create mode 100644 frontend/public/stickers/douyin/dy_09.avif create mode 100644 frontend/public/stickers/douyin/dy_10.avif create mode 100644 frontend/public/stickers/douyin/dy_11.avif create mode 100644 frontend/public/stickers/douyin/dy_12.avif create mode 100644 frontend/public/stickers/douyin/dy_13.avif create mode 100644 frontend/public/stickers/douyin/dy_14.avif create mode 100644 frontend/public/stickers/douyin/dy_15.avif create mode 100644 frontend/public/stickers/douyin/dy_16.avif create mode 100644 frontend/public/stickers/douyin/dy_17.avif create mode 100644 frontend/public/stickers/douyin/dy_18.avif create mode 100644 frontend/public/stickers/douyin/dy_19.avif create mode 100644 frontend/public/stickers/douyin/dy_20.avif create mode 100644 frontend/public/stickers/douyin/dy_21.avif create mode 100644 frontend/public/stickers/douyin/dy_22.avif create mode 100644 frontend/public/stickers/douyin/dy_23.avif create mode 100644 frontend/public/stickers/douyin/dy_24.avif create mode 100644 frontend/public/stickers/douyin/dy_25.avif create mode 100644 frontend/public/stickers/douyin/dy_26.avif create mode 100644 frontend/public/stickers/douyin/dy_27.avif create mode 100644 frontend/public/stickers/douyin/dy_28.avif create mode 100644 frontend/public/stickers/douyin/dy_29.avif create mode 100644 frontend/public/stickers/douyin/dy_30.avif create mode 100644 frontend/public/stickers/douyin/dy_31.avif create mode 100644 frontend/public/stickers/douyin/dy_32.avif create mode 100644 frontend/public/stickers/douyin/dy_33.avif create mode 100644 frontend/public/stickers/douyin/dy_34.avif create mode 100644 frontend/public/stickers/douyin/dy_35.avif create mode 100644 frontend/public/stickers/douyin/dy_36.avif create mode 100644 frontend/public/stickers/tieba/tb_01.avif create mode 100644 frontend/public/stickers/tieba/tb_02.avif create mode 100644 frontend/public/stickers/tieba/tb_03.avif create mode 100644 frontend/public/stickers/tieba/tb_04.avif create mode 100644 frontend/public/stickers/tieba/tb_05.avif create mode 100644 frontend/public/stickers/tieba/tb_06.avif create mode 100644 frontend/public/stickers/tieba/tb_07.avif create mode 100644 frontend/public/stickers/tieba/tb_08.avif create mode 100644 frontend/public/stickers/tieba/tb_09.avif create mode 100644 frontend/public/stickers/tieba/tb_10.avif create mode 100644 frontend/public/stickers/tieba/tb_11.avif create mode 100644 frontend/public/stickers/tieba/tb_12.avif create mode 100644 frontend/public/stickers/tieba/tb_13.avif create mode 100644 frontend/public/stickers/tieba/tb_14.avif create mode 100644 frontend/public/stickers/tieba/tb_15.avif create mode 100644 frontend/public/stickers/tieba/tb_16.avif create mode 100644 frontend/public/stickers/tieba/tb_17.avif create mode 100644 frontend/public/stickers/tieba/tb_18.avif create mode 100644 frontend/public/stickers/tieba/tb_19.avif create mode 100644 frontend/public/stickers/tieba/tb_20.avif create mode 100644 frontend/public/stickers/tieba/tb_21.avif create mode 100644 frontend/public/stickers/tieba/tb_22.avif create mode 100644 frontend/public/stickers/tieba/tb_23.avif create mode 100644 frontend/public/stickers/tieba/tb_24.avif create mode 100644 frontend/public/stickers/tieba/tb_25.avif create mode 100644 frontend/public/stickers/weibo/wb_01.avif create mode 100644 frontend/public/stickers/weibo/wb_02.avif create mode 100644 frontend/public/stickers/weibo/wb_03.avif create mode 100644 frontend/public/stickers/weibo/wb_04.avif create mode 100644 frontend/public/stickers/weibo/wb_05.avif create mode 100644 frontend/public/stickers/weibo/wb_06.avif create mode 100644 frontend/public/stickers/weibo/wb_07.avif create mode 100644 frontend/public/stickers/weibo/wb_08.avif create mode 100644 frontend/public/stickers/weibo/wb_09.avif create mode 100644 frontend/public/stickers/weibo/wb_10.avif create mode 100644 frontend/public/stickers/weibo/wb_11.avif create mode 100644 frontend/public/stickers/weibo/wb_12.avif create mode 100644 frontend/public/stickers/weibo/wb_13.avif create mode 100644 frontend/public/stickers/weibo/wb_14.avif create mode 100644 frontend/public/stickers/weibo/wb_15.avif create mode 100644 frontend/public/stickers/weibo/wb_16.avif create mode 100644 frontend/public/stickers/weibo/wb_17.avif create mode 100644 frontend/public/stickers/weibo/wb_18.avif create mode 100644 frontend/public/stickers/weibo/wb_19.avif create mode 100644 frontend/public/stickers/weibo/wb_20.avif create mode 100644 frontend/public/stickers/weibo/wb_21.avif create mode 100644 frontend/public/stickers/weibo/wb_22.avif create mode 100644 frontend/public/stickers/weibo/wb_23.avif create mode 100644 frontend/public/stickers/weibo/wb_24.avif create mode 100644 frontend/public/stickers/weibo/wb_25.avif create mode 100644 frontend/public/stickers/weibo/wb_26.avif create mode 100644 frontend/public/stickers/weibo/wb_27.avif create mode 100644 frontend/public/stickers/weibo/wb_28.avif create mode 100644 frontend/public/stickers/weibo/wb_29.avif create mode 100644 frontend/public/stickers/weibo/wb_30.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_01.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_02.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_03.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_04.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_05.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_06.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_07.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_08.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_09.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_10.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_11.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_12.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_13.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_14.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_15.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_16.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_17.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_18.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_19.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_20.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_21.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_22.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_23.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_24.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_25.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_26.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_27.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_28.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_29.avif create mode 100644 frontend/public/stickers/xiaohongshu/xhs_30.avif create mode 100644 frontend/public/stickers/zhihu/zh_01.avif create mode 100644 frontend/public/stickers/zhihu/zh_02.avif create mode 100644 frontend/public/stickers/zhihu/zh_03.avif create mode 100644 frontend/public/stickers/zhihu/zh_04.avif create mode 100644 frontend/public/stickers/zhihu/zh_05.avif create mode 100644 frontend/public/stickers/zhihu/zh_06.avif create mode 100644 frontend/public/stickers/zhihu/zh_07.avif create mode 100644 frontend/public/stickers/zhihu/zh_08.avif create mode 100644 frontend/public/stickers/zhihu/zh_09.avif create mode 100644 frontend/public/stickers/zhihu/zh_10.avif create mode 100644 frontend/public/stickers/zhihu/zh_11.avif create mode 100644 frontend/public/stickers/zhihu/zh_12.avif create mode 100644 frontend/public/stickers/zhihu/zh_13.avif create mode 100644 frontend/public/stickers/zhihu/zh_14.avif create mode 100644 frontend/public/stickers/zhihu/zh_15.avif create mode 100644 frontend/public/stickers/zhihu/zh_16.avif create mode 100644 frontend/public/stickers/zhihu/zh_17.avif create mode 100644 frontend/public/stickers/zhihu/zh_18.avif create mode 100644 frontend/public/stickers/zhihu/zh_19.avif create mode 100644 frontend/public/stickers/zhihu/zh_20.avif create mode 100644 frontend/public/stickers/zhihu/zh_21.avif create mode 100644 frontend/public/stickers/zhihu/zh_22.avif create mode 100644 frontend/public/stickers/zhihu/zh_23.avif create mode 100644 frontend/public/stickers/zhihu/zh_24.avif create mode 100644 frontend/public/stickers/zhihu/zh_25.avif create mode 100644 frontend/public/stickers/zhihu/zh_26.avif create mode 100644 frontend/public/stickers/zhihu/zh_27.avif create mode 100644 frontend/src/components/CommentEditor.tsx delete mode 100644 frontend/src/components/EmojiPicker.tsx create mode 100644 frontend/src/components/emoji/StickerPicker.tsx create mode 100644 frontend/src/data/stickers/emoji.json create mode 100644 frontend/src/data/stickers/emojiData.ts create mode 100644 frontend/src/data/stickers/hot.ts create mode 100644 frontend/src/data/stickers/index.ts create mode 100644 frontend/src/data/stickers/kaomoji.ts delete mode 100644 frontend/src/utils/emojis.ts diff --git a/.trae/documents/emoji-effect-adjustment.md b/.trae/documents/emoji-effect-adjustment.md new file mode 100644 index 0000000..c31764f --- /dev/null +++ b/.trae/documents/emoji-effect-adjustment.md @@ -0,0 +1,151 @@ +# 表情效果调整计划 + +## 问题分析 + +当前实现存在 5 个问题,根因如下: + +### 1. 插入表情后有选择状态(蓝色高亮) +- **根因**: Tiptap `setImage` 插入图片节点后,节点处于 "node-selected" 状态,显示蓝色选中框 +- **位置**: [CommentEditor.tsx](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/components/CommentEditor.tsx) L155-163 + +### 2. 输入框表情太大 +- **根因**: CSS 选择器 `img[src^="data:image/svg"]` 只匹配旧 SVG data URI,不匹配新的 AVIF URL(`/stickers/tieba/tb_01.avif`),导致表情图片无尺寸约束,以原始大尺寸渲染 +- **位置**: [global.css](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/styles/global.css) L5584-5603 + +### 3. 插入表情后光标换行 +- **根因**: `ArticleImage.configure({ inline: false })` 使图片为块级节点,插入后自动换行 +- **位置**: [CommentEditor.tsx](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/components/CommentEditor.tsx) L92 + +### 4. 表情栏目太宽松 +- **根因**: Grid 仅 6 列,gap 4px,padding 10px +- **位置**: [global.css](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/styles/global.css) L5502-5510 + +### 5. 颜文字太小 +- **根因**: `.sticker-picker-text` 的 `font-size: 8px`,极小 +- **位置**: [global.css](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/styles/global.css) L5606-5616 + +## 改动方案 + +### 文件 1: CommentEditor.tsx +**改动 A — 图片改为内联** (L92): +```typescript +// 旧 +ArticleImage.configure({ inline: false, allowBase64: true }), +// 新 +ArticleImage.configure({ inline: true, allowBase64: true }), +``` + +**改动 B — insertSticker 插入后取消选中和换行** (L155-163): +```typescript +const insertSticker = useCallback((sticker: Sticker) => { + if (!editor) return; + if (sticker.type === 'text' && sticker.text) { + editor.chain().focus().insertContent(sticker.text).run(); + } else if (sticker.url) { + // 插入内联图片 + 尾随零宽空格,确保光标在图片后面而非选中图片 + editor.chain().focus().insertContent([ + { type: 'image', attrs: { src: sticker.url, alt: sticker.name } }, + { type: 'text', text: '\u200b' }, + ]).run(); + } + setShowSticker(false); +}, [editor]); +``` +> 用 `insertContent` + 零宽空格替代 `setImage`,避免 node-selected 状态,光标自然落在图片后。 + +### 文件 2: StickerPicker.tsx +**改动 C — 键盘导航列数匹配新网格** (L44): +```typescript +// 旧 +const cols = 6; +// 新 +const cols = 8; +``` + +### 文件 3: global.css +**改动 D — 表情选择器密度提升** (L5502-5510): +```css +.sticker-picker-grid { + display: grid; + grid-template-columns: repeat(8, 1fr); /* 6 → 8 */ + gap: 2px; /* 4px → 2px */ + padding: 6px; /* 10px → 6px */ + overflow-y: auto; + flex: 1; + min-height: 0; +} +``` + +**改动 E — 选择器项缩小** (L5512-5522): +```css +.sticker-picker-item { + padding: 2px; /* 4px → 2px */ + /* 其余不变 */ +} +``` + +**改动 F — 颜文字字体放大** (L5606-5616): +```css +.sticker-picker-text { + font-size: 14px; /* 8px → 14px */ + line-height: 1.4; /* 1.2 → 1.4 */ + /* 其余不变 */ +} +``` + +**改动 G — 替换旧 SVG 选择器为通用贴纸选择器** (L5584-5603): + +删除旧的 `img[src^="data:image/svg"]` 选择器,替换为基于 `/stickers/` 路径的选择器: + +```css +/* 编辑器内贴纸 img 尺寸约束 */ +.comment-editor .article-prosemirror img[src*="/stickers/"], +.comment-editor .article-editor-content img[src*="/stickers/"] { + display: inline-block; + width: 28px; + height: 28px; + vertical-align: middle; + margin: 0 1px; + border-radius: 4px; + object-fit: contain; +} + +/* 评论正文中的贴纸 img */ +.floor-body img[src*="/stickers/"], +.comment-body img[src*="/stickers/"] { + display: inline-block; + vertical-align: middle; + width: 28px; + height: 28px; + margin: 0 1px; + background: transparent; + border-radius: 4px; + object-fit: contain; +} +``` + +**改动 H — 移动端网格也改为 8 列** (L5619-5624): +```css +@media (max-width: 640px) { + .sticker-picker { max-height: 240px; } + .sticker-picker-grid { grid-template-columns: repeat(6, 1fr); } /* 移动端 6 列 */ + .sticker-picker-tab { padding: 6px 10px; font-size: 12px; } + .comment-editor .article-tool-btn { width: 30px; height: 30px; } +} +``` +> 移动端保持 6 列(屏幕窄),桌面端 8 列。 + +## 不改动 +- `ArticleImageExtension.tsx` — 无需修改,`inline: true` 通过 `configure()` 传入即可 +- `kaomoji.ts` / `emojiData.ts` / `hot.ts` — 数据层不变 +- `CommentContent.tsx` — 渲染层不变(CSS 覆盖即可) +- PostEditor(帖子编辑器)— 不受影响,仍使用 `inline: false` + +## 验证 +1. `npm run build` 无报错 +2. 浏览器验证: + - 选择表情后插入无蓝色选中框 + - 表情在输入框中显示 28px,内联在文字中 + - 插入表情后光标紧跟表情后方,不换行 + - 表情选择器 8 列密度更高 + - 颜文字标签内字体清晰可读 diff --git a/.trae/documents/emoji_rich_comment_plan.md b/.trae/documents/emoji_rich_comment_plan.md new file mode 100644 index 0000000..ca7b25e --- /dev/null +++ b/.trae/documents/emoji_rich_comment_plan.md @@ -0,0 +1,597 @@ +# 评论表情包改造 + 富文本评论编辑器计划 + +## 一、摘要 + +将评论系统从「纯文本 textarea + Unicode Emoji」升级为「Tiptap 富文本编辑器 + 姜十三专属 SVG 贴纸」,实现: +1. 去除所有 Unicode Emoji,替换为自定义 SVG 贴纸(懒加载) +2. 姜十三专属表情包:萌系吉祥物表情 + 中文网络流行语文字气泡(混合风格) +3. 评论复用帖子编辑器核心能力(精简变体),支持代码块、链接、图片、格式化等 + +--- + +## 二、当前状态分析 + +### 2.1 评论输入:纯文本 textarea + +[CommentBox.tsx](file:///c:/Users/freefire/Documents/jiang13-forum/frontend/src/components/CommentBox.tsx) 使用 `