Commit Graph

232 Commits

Author SHA1 Message Date
TerryM
5ce52943e9 feat: add image save hint 2026-05-30 18:44:15 +08:00
TerryM
0e877d4959 i18n: add longPressImageSave string used by the image lightbox
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:14:58 +08:00
TerryM
942db88f58 fix(ui): disable text selection on header, filter chips, and bottom nav
Add `select-none` to the sticky header, the type filter chips row, and the
mobile bottom nav so their labels and icons can't be highlighted/selected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:14:58 +08:00
TerryM
5f7c4eea62 fix: show recommended card thumbnails 2026-05-30 18:08:41 +08:00
TerryM
b2e4a4e710 fix: bound post deeplink scrolling 2026-05-30 18:08:39 +08:00
TerryM
41299b5b65 feat(deeplink): jump from banner/rank list to the exact post in All Materials
- FigmaBanner: route same-app linkUrl through SPA navigation so the stream's
  scroll-to-post runs without a full reload; defer pointer capture until a real
  drag starts, fixing plain clicks being swallowed by setPointerCapture
- PopularRankList: rank rows navigate straight to /browse?sort=popular&post=<id>
- MessageStream: ?post= deep links jump directly to the target instead of
  resetting to the top and animating through the stream
- ScrollToTop: skip the top-reset for ?post= navigations so the target page
  handles its own alignment

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 17:54:16 +08:00
TerryM
0733ea8b18 feat(category-icon): 分类图标支持 PNG 资源,学院类目改用 PNG
categorySvgUrlForSlug → categoryAssetUrlForSlug,映射值改为带子目录
的相对路径(svg/ 或 png/),新增 academy-materials / academy-video
的 PNG 图标并兼容拼写别名 acedemy-video。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 17:34:18 +08:00
TerryM
07f040a549 fix(video): 全屏关闭后内嵌进度条跳变而非从0扫动
程序化 seek 同步全屏播放进度时,新增 snapProgress 抑制进度条
的宽度过渡动画,使其直接落到观看位置,恢复播放时再启用过渡。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 16:54:03 +08:00
TerryM
eb0eabe21f Merge remote-tracking branch 'origin/main' into terry-staging 2026-05-30 16:04:04 +08:00
TerryM
40d64f1293 fix: 链接预览强调色按域名兜底,腾讯会议不再用黑色
部分站点(如 meeting.tencent.com)返回 themeColor=#000000,在深色气泡上看不见。
按域名覆盖为品牌金色,其余仍优先用 themeColor。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 15:43:30 +08:00
TerryM
9bef178bc8 feat: 大图查看器支持 iOS 长按"存储到照片"
去掉全尺寸图上的 select-none 并显式设 -webkit-touch-callout:default,使 iOS
Safari 长按图片能弹出原生「存储到照片」菜单(保存的是 current.url 全图)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 15:43:30 +08:00
TerryM
cc9f0a5730 fix(stream): preserve filename extension in narrow bubbles
Previously the file bubble wrapped JS middle-ellipsis in CSS truncate,
so narrow containers silently clipped the tail+extension, leaving
e.g. "25cb264a-e06…." instead of "25cb264a-e06…811a.jpg".

Split the displayed name into a shrinking head (with CSS truncate)
and a non-shrinking tail (last 4 base chars + extension). The browser
now decides how much head to clip while the suffix is always visible.
2026-05-30 15:42:13 +08:00
TerryM
1d74f29c2a copy(search): shorten mobile search placeholder 2026-05-30 13:55:52 +08:00
21e078fd89 Merge pull request 'terry-staging' (#11) from terry-staging into main
All checks were successful
Deploy to Frontend Servers / deploy (push) Successful in 35s
Reviewed-on: #11
2026-05-29 19:29:58 +00:00
TerryM
1557d29af7 docs(posts): clarify backend title field requirements
Clarify that compact browsing surfaces should receive short post title fields
from the backend even if some frontend pages do not display them yet. Separate
the product requirement from current frontend implementation status so backend
can implement the API contract first and frontend can opt in per surface later.
2026-05-30 03:28:33 +08:00
TerryM
a8fd540ef5 fix(stream): smooth scroll to linked post cards
Route resource card clicks to /browse?post=<id> instead of relying on hash
anchors, then manually calculate the sticky filter offset when scrolling to
the target bubble. Start from the top and smooth-scroll to the card for a
clear transition, with delayed auto realignments after media above the target
settles.
2026-05-30 03:11:03 +08:00
TerryM
6798e90708 feat(posts): support short titles for resource cards
Add optional post-level and localized title fields, and use a new
postTitleText helper for Resource.title so card/list surfaces prefer short
backend-provided titles instead of full body text. When title is missing,
fallback to the first non-empty body line, then filename, then post id.

Document the backend handoff in docs/posts-title-api.md alongside the other
backend task docs.
2026-05-30 03:11:03 +08:00
TerryM
2b9ab9eb2c fix: 搜索弹窗开启时点 burger 能正常打开菜单
关闭搜索弹窗会触发滚动恢复(window.scrollTo)发出 scroll 事件,被菜单的
closeOnScroll 立即捕获、把刚打开的菜单关掉。菜单打开后 250ms 内忽略滚动关闭,
跳过这次恢复滚动;之后用户真实滚动仍正常收起菜单。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 03:04:09 +08:00
TerryM
4c441244c8 style: 搜索提示行与输入框内容像素级对齐
输入框 border 改为 ring-inset(不占布局),使输入框内容与下方提示行(ⓘ+文字)
都位于「容器左缘+12px」同一基准,图标列严丝合缝对齐,不再依赖魔法数值。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 03:00:44 +08:00
TerryM
f1e5e17fce docs: 新增搜索与标签接口说明(给后端)
说明 /api/posts/search 期望的模糊匹配规则(跨标题/分类/标签/简介/类型/正文、
大小写不敏感、相关度排序)与参数,以及新增 /api/tags 返回全量标签+计数以替代
前端从最新80条现算的不完整标签来源。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:51:20 +08:00
TerryM
ea38503f37 ui(thumbnails): force preview images to fixed ratio
Use object-fill for compact preview thumbnails so rank-list covers and
file previews fill their fixed boxes without cropping or black bars. This
keeps the list layout stable while matching the desired compressed-ratio
thumbnail treatment.
2026-05-30 02:51:09 +08:00
TerryM
609c119277 fix: 搜索面板标签可再次点击取消(toggle)
再次点击已选中的标签时清空选中/查询/结果,而不是永久停留在该标签。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:50:19 +08:00
TerryM
78d055bb99 style: 热门榜封面与文件档预览缩略图改 object-contain 完整显示
热门榜单封面、文件档预览缩略图由 object-cover 改为 object-contain(文件预览
加底色),完整显示不裁剪。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:47:41 +08:00
TerryM
ce5505ea23 perf: 预热扩展至最新页,串行错峰避免卡顿
预热列表新增「最新」(/browse?sort=latest)。三个预取改为串行执行:每个在空闲
(requestIdleCallback)时触发、间隔 400ms,避免并发请求拖卡低端手机。仅 JSON。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:46:26 +08:00
TerryM
2e50b301a3 perf: 空闲预热全部资料/热门资料,点击前已缓存
usePostStream 导出 prefetchPostStream(已缓存/mock 则跳过)。PublicLayout 在
requestIdleCallback 空闲时后台预取「全部资料」「热门资料」首页数据并写入缓存,
用户点击进入时直接读缓存秒显,不再进页面才开始加载。预取仅 JSON,不拉图片。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:44:53 +08:00
TerryM
4a20d80f68 feat: 顶栏显示当前页名,去掉独立标题行;Logo回首页/页名回顶部
- 新增 PageTitleContext:页面上报标题,顶栏 brand 位显示当前页名(全部资料/
  热门资料/最新/官方/分类名/搜索/我的收藏),未上报则回退品牌名
- AssetStreamPage、Favorites 上报标题;移除资料流内单独的标题行,省出空间
- 顶栏拆分点击:Logo→首页(首页则回顶部);页名文字→回到当前页顶部

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:37:30 +08:00
TerryM
ed6e0023b8 ui(lightbox): hide nav arrow at the gallery ends
Clamp goPrev / goNext instead of wrapping the index, and hide the
left chevron on the first image and the right chevron on the last
one. Arrow keys, swipe gestures, and the on-screen buttons all
behave like a linear gallery now, so users get a clear cue that
they have reached the end instead of unexpectedly looping back.
2026-05-30 02:27:20 +08:00
TerryM
b848ce5db3 fix: 2图相册按真实比例+缩放贴合,竖图不再被裁
- albumLayout: 2 图不再 clamp 比例,格子按图片真实比例,避免下限 0.55 把竖图
  当矮图导致裁顶;3+ 张马赛克仍 clamp 保持整齐
- AlbumBubble: 2 图改用 object-contain,整图缩放贴合框内,永不裁剪;高度上限
  不变,不占用过多空间

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:26:43 +08:00
TerryM
27f9dbbc45 fix(album): keep true aspect ratios for two-image layouts
Split clampRatio into a sanity-check helper (safeRatio: reject
zero / NaN / negatives) and the actual aspect clamp. Two-image
albums now keep each image's real ratio so the cells match the
images exactly with no object-cover cropping. Three-plus image
layouts still clamp ratios to a 0.55-2 band so a single extreme
image cannot warp the mosaic.
2026-05-30 02:25:01 +08:00
TerryM
8646b51b6c feat(video): cross-platform inline player + polished overlay controls
- MessageInlineVideo (new): custom-controlled inline video that disables
  the iOS Safari / Chromium native overlays entirely and reimplements
  the essentials: tap-to-play, centered play affordance while paused,
  bottom bar with play/pause + current time + drag-to-scrub progress
  bar + remaining time + fullscreen. Pointer events with pointer
  capture cover both mouse and touch scrubbing, including dragging
  past the bar's bounds. The element listens to 'seeked' as well as
  'timeupdate' so external currentTime writes paint the bar even when
  the video is paused, and the goFullscreen callback synchronously
  syncs React state on close so the inline progress reflects the user's
  fullscreen playhead with no perceptible delay.
- VideoBubble: replace the inline <video controls> with
  MessageInlineVideo and thread postId through openVideo so the
  fullscreen overlay can attach the download pill to the right post.
- VideoPlayer overlay: replace its <video controls> with
  MessageInlineVideo size='lg', removing the iOS native arrows / PiP /
  mute / overflow controls. The overlay supplies its own large
  download pill and a beefier close button.
- AttachmentDownloadPill: new 'size' prop ('sm' default 30 px, 'lg'
  44 px with 22 px icon and text-[14px]) for overlay surfaces where
  the affordance can breathe and should feel touch-friendly.
- ImageLightbox: drop the inline LightboxDownloadButton and use the
  shared AttachmentDownloadPill size='lg' instead, with a matching
  larger close button. Unused imports cleaned up.
2026-05-30 02:25:01 +08:00
TerryM
3d5681e7de fix: 消除页面切换残影,旧页瞬间移除仅新页淡入
页面过渡改为纯 opacity 且 exit 时长 0:配合 AnimatePresence mode="wait",
旧页立即卸载、不再残留一帧,只有新页淡入。既无交叉淡入淡出的残影,又保留
进场动画。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:15:34 +08:00
TerryM
ae14b33f83 perf: 资料流会话级缓存,切换页面不再重载
usePostStream 增加按筛选参数为 key 的内存缓存,保存已加载的全部内容与分页
游标。再次进入同一视图(如首页⇄全部资料来回切)时直接还原,不重置、不重新
请求、不显示骨架屏。整页刷新清空缓存以获取最新数据。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 02:04:26 +08:00
TerryM
6d62aad8c4 style: 缩小视觉气泡标题与底部时间的间距
视觉气泡(图片/视频/图文)底部时间上间距 pt-3(12px) → pt-0.5(2px),
标题与日期时间更贴近。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:58:30 +08:00
TerryM
a4884a689d perf: 图片渐进加载,缩短首屏等待
- 流内单图改用缩略图(原图仅在灯箱按需加载),体积大幅减小
- BubbleImage 加 decoding=async + 加载完淡入(ark-img-fade),图片逐张出现
- 视频海报/文件预览/推荐卡/热门榜补 decoding=async、lazy
原图无缩略图时自动回退,无回归。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:54:28 +08:00
TerryM
29dc71d2dd feat(link-preview): frontend interface for Telegram-style URL preview
Adds the front-end side of the link-preview feature so the back-end
team has a fixed contract to implement against.

- docs/link-preview.md: full spec for the `/api/link-preview` proxy
  and the preferred inline-on-Post integration. Covers caching, SSRF
  guards, metadata-extraction precedence, provider quirks, and the
  front-end rendering rules. Scope is the first URL only.
- types/post.ts: new `LinkPreview` type and optional `linkPreview`
  field on `Post`.
- LinkPreviewCard: clickable card with a themeColor accent bar,
  siteName / title / description (line-clamped), and an optional
  1.91:1 thumbnail. Whole card is an `<a target="_blank">` to the
  canonical URL.
- MessageBubble: render the card between the bubble body and the
  timestamp, with padding that matches visual vs. text-only bubbles.
- mockPosts: example `linkPreview` payloads on p-005 and p-010 so
  the visual works when running with VITE_USE_MOCK_POSTS=true,
  and so the back-end has concrete reference values.
2026-05-30 01:40:00 +08:00
TerryM
09d887dd52 feat: 筛选条支持鼠标滚轮横向滚动
桌面鼠标无横向滚轮且滚动条隐藏,溢出时末尾筛选项不可达。加非被动 wheel
监听,溢出时将 deltaY 转为横向 scrollLeft;未溢出则不接管,不影响页面滚动。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:39:06 +08:00
TerryM
8425809f98 fix: 全部资料页底部导航固定在屏幕底部
/browse 的 main 分支缺少 flex-1,内容少时主区不撑开,底部导航跟着内容
跳到屏幕中间。补上 flex-1,主区填满剩余高度,sticky 底部导航始终贴底。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:34:16 +08:00
TerryM
8610ac521e fix: 筛选标签选中态手机端改为金色
之前手机端选中标签是白色(text-white),仅桌面金色;统一为 text-ark-gold,
与品牌色一致。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:32:06 +08:00
TerryM
61f3c41567 feat: 资料流标题+筛选吸顶,滚动时保持可见
把「全部资料」标题与筛选标签合并为一个吸顶块,钉在全局顶栏下方
(top-[64px]/md:top-[70px]),向下滚动时标题和筛选都不再消失,仅内容流滚动。
移除 FilterChips 原先吸到 top-0(藏到顶栏背后)的行为。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:31:10 +08:00
TerryM
e9245875a3 feat(stream): floating page title pill when heading scrolls out
Add a Telegram-style sticky title to AssetStreamPage: an
IntersectionObserver watches a sentinel placed just under the main
heading and, once the heading scrolls past the sticky global header,
a floating pill slides in showing the current page title so users
always have a context anchor.
2026-05-30 01:27:02 +08:00
TerryM
fd46359fd9 ui: re-introduce adaptive download pill sizing for album tiles
- AttachmentDownloadPill: bring back the optional adaptive sizing
  branch (default off). When the host sets containerType: inline-size,
  the pill scales 22-30px with the tile width using a steeper
  18cqw curve, so two-image tiles already reach 30px while tiny
  thumbs in mixed layouts stay at 22px.
- AlbumBubble: opt every tile into adaptive sizing and add the query
  container so the cqw units resolve against each tile's width.
- Single-image and video bubbles continue to render the pill at a
  fixed 30px (no host opt-in needed).
2026-05-30 01:27:02 +08:00
TerryM
4e5093cae0 ui: drop the 'download complete' success toast
Successful downloads no longer pop a 'downloadOk' toast across all
the download sites (PopularRankList, RecommendedCard, FileDocBubble,
ImageLightbox). The browser's native download UI already confirms
the action, and the toast was redundant noise. Failure toasts and
the spinner state remain so users still see errors.
2026-05-30 01:21:35 +08:00
TerryM
92e6ce9dd8 feat(video): explicit fullscreen button, simplify download pill sizing
- VideoBubble: add a Maximize2 fullscreen button at the top-right of
  the inline player (mirrors the download pill on the left), so the
  user explicitly opts into fullscreen instead of any tile click being
  promoted to one. Removed the outer onClick that opened fullscreen
  on any tap.
- AttachmentDownloadPill: drop the adaptive (cqw-based) sizing branch
  and the corresponding 'adaptive' prop. The pill is now a uniform
  30px tall in every host (album tile, single image, video tile),
  matching the design without needing query containers on parents.
- AlbumBubble: remove the now-unused 'adaptive' prop and the
  containerType: inline-size hook that supported it.
2026-05-30 01:21:35 +08:00
TerryM
6b42981419 fix(video): keep scroll position and stop pause from going fullscreen
- VideoBubble: stopPropagation on the inline <video> element so
  clicks on the native controls (play/pause/seek) don't bubble up
  to the outer tile, which previously promoted any control click
  into a fullscreen overlay.
- VideoPlayer: replace overflow:hidden body lock with the iOS-safe
  position-fixed + scroll-restore pattern. Closing the fullscreen
  player now returns the page to the exact scroll offset it had,
  instead of snapping back to the top on iOS Safari.
2026-05-30 01:09:19 +08:00
TerryM
f7230de12b ui(mobile): block pinch-zoom and iOS input auto-zoom
- index.html: tighten the viewport meta with maximum-scale=1,
  user-scalable=no, viewport-fit=cover so pinch-zoom is disabled
  on browsers that honor the hint (Android Chrome).
- SearchPanel: bump the mobile search input from text-sm (14px) to
  text-base (16px). iOS Safari auto-zooms inputs whose font-size is
  below 16px on focus, which widened the viewport and let the user
  pan horizontally; 16px stops that behavior at the source.
2026-05-30 01:05:25 +08:00
TerryM
ac208dfe25 style: stronger contrast on image lightbox nav buttons
Bump the previous/next chevron buttons from translucent white tint
to a solid-ish black with a subtle ring + shadow, so the controls
stay legible on light or busy image backgrounds.
2026-05-30 01:02:18 +08:00
TerryM
cb14cb166a ui: prevent layout shift when mobile search overlay opens
- SearchPanel: focus input with { preventScroll: true } so the browser
  doesn't auto-scroll the underlying page when the overlay mounts.
- SearchPanel: add overscroll-contain on the scroll container so
  reaching the panel's edges does not chain into the body on Android.
- PublicLayout: lock background scroll while the mobile search overlay
  is open using the iOS-compatible position-fixed + restore pattern,
  so the page underneath cannot move at all.
2026-05-30 01:02:18 +08:00
TerryM
d19f2f9efa feat: 移除「关于本站」按钮与功能
- PublicLayout: 删除桌面导航/下拉菜单/页脚三处入口及空页脚,移除 about 导航类型与判断
- App: 移除 /about 路由及 AboutPage 引入
- 删除 pages/About 页面
- DocumentMeta: 移除 /about 的 meta 处理与 about 描述文案(中/英)
- i18n: 移除 aboutTitle / aboutIntro / footerAbout(中/英)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 00:59:06 +08:00
TerryM
15bcb6bdf0 feat: 相册下载胶囊自适应尺寸(随图块大小缩放)
- AttachmentDownloadPill 新增 adaptive 模式:用容器查询单位 cqw + clamp,
  尺寸随所在容器宽度缩放(图标框 22~30px、图标 13~18px、文字 10~12px)
- 相册图块设 container-type: inline-size 作为查询容器,小缩略图上的下载按钮
  自动缩小;单图/视频默认固定尺寸不受影响

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 00:52:23 +08:00
TerryM
d7e2e56cde ui: home carousel height lock + bubble polish
- Home: lock category carousel height to the tallest page so the
  Official Recommendations section below does not jump up when
  swiping to a page with fewer categories.
- CollapsibleText: raise default threshold to 25 lines and tighten
  the spacing between the expand-all button and the timestamp
  (drop the fixed h-8 and use mt-1 instead of mt-1.5).
- formatTime: always render dates as yyyy/m/d HH:mm regardless of
  locale, matching the requested timestamp format.
2026-05-30 00:43:54 +08:00