Skip to content

feat: refine forum settings, uploads, and transitions - #28

Merged
lezi-fun merged 2 commits into
nextfrom
feat/forum-settings-uploads-motion
Aug 14, 2026
Merged

lezi-fun merged 2 commits into
nextfrom
feat/forum-settings-uploads-motion

Conversation

@lezi-fun

Copy link
Copy Markdown
Collaborator

Summary

  • add administrator favicon upload, live favicon refresh, and current commit display
  • compress 5–20 MB favicon and post images before upload while preserving server-side type and size validation
  • improve Docker Compose port behavior and inject the build commit into Docker images
  • add stable left-drawer transitions for admin sections, including asynchronous report content resizing
  • animate the home new-post button into the compose-page heading and replace it with typed titles using a terminal-style cursor

Validation

  • git diff --check
  • node --test test/image-type.test.js test/i18n-ui.test.js (6 tests passed)
  • npm run build in an isolated copy
  • Playwright checks for light/dark themes, 390px mobile layout, reduced-motion fallback, forward/reverse new-post transitions, and delayed report loading

Notes

  • .playwright-cli/ artifacts remain local and are not included in this PR.

@forumlify forumlify Bot added the enhancement New feature or request label Aug 14, 2026
@forumlify

forumlify Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Automated review has started. I am checking this pull request now.

@codecov

codecov Bot commented Aug 14, 2026 •

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 47.25kB (1.4%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
forumlify-next-server-cjs 1.93MB 29.31kB (1.54%) ⬆️
forumlify-next-client-array-push 1.48MB 17.95kB (1.22%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: forumlify-next-client-array-push

Assets Changed:

Asset Name Size Change Total Size Change (%)
static/chunks/3464-*.js 9.16kB 123.64kB 8.01% ⚠️
static/css/*.css 5.41kB 78.17kB 7.43% ⚠️
static/chunks/2215-*.js 2.4kB 30.4kB 8.59% ⚠️
static/A1yUOh6WAZtcu6PJ2n2lT/_buildManifest.js (New) 1.97kB 1.97kB 100.0% 🚀
server/middleware-*.js 414 bytes 450 bytes 1150.0% ⚠️
server/middleware-*.js -414 bytes 36 bytes -92.0%
server/app/api/auth/recovery-*.js -6 bytes 373 bytes -1.58%
server/app/api/auth/recovery-*.js 6 bytes 379 bytes 1.61%
server/app/api/admin/custom-*.js -4 bytes 355 bytes -1.11%
server/app/api/admin/custom-*.js 4 bytes 359 bytes 1.13%
static/chunks/app/api/admin/custom-pages/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/admin/custom-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/admin/custom-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/admin/favicon/route-*.js (New) 355 bytes 355 bytes 100.0% 🚀
static/chunks/app/api/auth/login/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/auth/recovery-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/auth/recovery-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/auth/me/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/auth/register/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/auth/reset-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/captcha/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/conversations/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/conversations/[id]/messages/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/_global-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/custom-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/custom-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/custom-pages/[name]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/links/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/links/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/messages/[id]/read/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/notifications/[id]/read/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/notifications/read-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/notifications/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/event-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/posts/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/posts/[id]/pin/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/posts/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/reports/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/replies/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/settings/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/reports/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/stats/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/upload/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/uploads/[name]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/[id]/avatar/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/[id]/password/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/[id]/role/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/[id]/email/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/[id]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/users/profile/[username]/route-*.js 5 bytes 355 bytes 1.43%
static/chunks/next/dist/client/components/builtin/app-*.js 5 bytes 355 bytes 1.43%
static/chunks/next/dist/client/components/builtin/forbidden-*.js 5 bytes 355 bytes 1.43%
static/chunks/next/dist/client/components/builtin/not-*.js 5 bytes 355 bytes 1.43%
static/chunks/next/dist/client/components/builtin/unauthorized-*.js 5 bytes 355 bytes 1.43%
static/chunks/app/api/posts/[id]/replies/route-*.js 5 bytes 355 bytes 1.43%
server/app/api/admin/favicon/route_client-*.js (New) 349 bytes 349 bytes 100.0% 🚀
static/A1yUOh6WAZtcu6PJ2n2lT/_ssgManifest.js (New) 77 bytes 77 bytes 100.0% 🚀
static/uBrl4YbtrWNH-*.js (Deleted) -77 bytes 0 bytes -100.0% 🗑️
static/uBrl4YbtrWNH-*.js (Deleted) -1.93kB 0 bytes -100.0% 🗑️
view changes for bundle: forumlify-next-server-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
3494.js 7.52kB 115.36kB 6.97% ⚠️
5222.js 2.4kB 34.62kB 7.46% ⚠️
../app/api/uploads/[name]/route.js 338 bytes 18.35kB 1.88%
../app/api/posts/[id]/pin/route.js -2 bytes 12.65kB -0.02%
9113.js (New) 11.5kB 11.5kB 100.0% 🚀
../app/api/settings/route.js 66 bytes 10.94kB 0.61%
../app/api/admin/custom-pages/route.js 2 bytes 10.55kB 0.02%
../app/api/auth/login/route.js -2 bytes 10.49kB -0.02%
../app/api/admin/custom-pages/[id]/route.js 2 bytes 10.48kB 0.02%
../app/api/users/[id]/email/route.js 2 bytes 10.24kB 0.02%
../app/api/auth/reset-password/route.js 2 bytes 9.9kB 0.02%
../app/api/event-logs/route.js 2 bytes 9.68kB 0.02%
../app/api/auth/recovery-codes/count/route.js 2 bytes 9.65kB 0.02%
../app/api/admin/favicon/route.js (New) 9.28kB 9.28kB 100.0% 🚀
../../types/app/api/admin/favicon/route.ts (New) 9.06kB 9.06kB 100.0% 🚀
../app/api/upload/route.js -11.14kB 8.36kB -57.11%
../app/post/[id]/page.js -2 bytes 2.76kB -0.07%
../app/api/admin/favicon/route.js.nft.json (New) 242 bytes 242 bytes 100.0% 🚀
../app/api/upload/route.js.nft.json 26 bytes 224 bytes 13.13% ⚠️

Files in 5222.js:

  • ./app/globals.css → Total Size: 1 bytes

Files in ../app/api/uploads/[name]/route.js:

  • ./app/api/uploads/[name]/route.js → Total Size: 1.47kB

Files in 9113.js:

  • ./lib/image-type.js → Total Size: 1.23kB

Files in ../app/api/settings/route.js:

  • ./app/api/settings/route.js → Total Size: 2.09kB

Files in ../app/api/admin/favicon/route.js:

  • ./app/api/admin/favicon/route.js → Total Size: 3.01kB

Files in ../app/api/upload/route.js:

  • ./app/api/upload/route.js → Total Size: 1.76kB

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

forumlify[bot]
forumlify Bot previously requested changes Aug 14, 2026

@forumlify forumlify Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded automated review

The review for commit f5d173350bb6 has been replaced by the automated review for commit 5f81b819af40.

Its previous inline review and change comments were removed. Refer to the latest commit review for the current result.

@forumlify

forumlify Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Automated review completed for commit 5f81b819af40. The latest review result and ghbot review check now reflect this commit.

@forumlify forumlify Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review

Mode: normal

Comment

All three issues from the earlier review are resolved in the current head: the post.* translation keys (post.imageUpload, post.imageUploading, post.imageCompressing, post.imageTooLarge, post.imageCompressFailed, post.imageUploadFailed) now exist in both locales/en.json and locales/zh.json; the admin favicon swap is now transactional with SELECT ... FOR UPDATE and a concurrency regression test; and admin nav clicks during the opening animation are re-queued via pendingTab instead of being silently dropped. The compression helpers, image-type refactor, settings/favicon storage flow, and view transitions look consistent and are well guarded with fallbacks. The two remaining observations are non-blocking: the edit form's shared upload state is not per-file when multiple images are selected, and the new favicon route returns hardcoded Chinese errors that appear inside English toast templates.

Result for maintainers

All previously blocking findings are fixed in the current payload: post.* i18n keys are present in both locale files, the favicon settings swap is wrapped in a transaction with FOR UPDATE plus a concurrency test, and admin tab clicks during the opening animation are re-queued. No blocking issues remain. Non-blocking review items only: per-file edit-upload state race with multi-image selections, and hardcoded Chinese server errors surfaced through the new English toast template. No malicious code detected.

Model decision: safe to merge
Applied review policy: allow
Final status: safe to merge

Required changes: 0
Review notes: 2

Comment thread components/PostDetail.js
const url = await uploadImage(file);
let uploadFile = file;
if (file.size > DIRECT_IMAGE_LIMIT) {
setEditUploadStage('compressing');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review note: Shared edit-upload state is not per-file: button can finish while sibling uploads are still running

The edit form's file input calls handleEditUpload once per file ([...files].forEach(...)) without awaiting, so multiple large files run concurrently while each call mutates the shared editUploading/editUploadStage state. The first call to reach its finally block sets editUploading=false and editUploadStage='uploading' while a second file is still being compressed or uploaded, so the button reverts to 'Upload image' and re-enables mid-batch. Track an in-flight count or process the files sequentially so the button label and disabled state stay correct until the whole batch finishes.

return Response.json({ error: '请选择图标文件' }, { status: 400 });
}
if (file.size > MAX_SIZE) {
return Response.json({ error: '图标大小不能超过 5MB' }, { status: 400 });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review note: Server-side favicon errors are hardcoded Chinese and surface inside English toasts

The new AdminForumSettings UI renders upload failures through the localized template t('admin.forum.faviconSaveFailed', { msg: error.message }), but every error returned by this route ('请选择图标文件', '图标大小不能超过 5MB', '仅支持 PNG、JPEG、GIF、WebP 或 ICO 图标', '上传失败,请稍后重试') is hardcoded Chinese. In an English UI this yields toasts like 'Icon upload failed: 图标大小不能超过 5MB'. Consider returning error codes and mapping them to locale keys, as done for the other new messages in this PR.

@forumlify
forumlify Bot dismissed their stale review August 14, 2026 02:44

Superseded by the automated review for commit 5f81b81.

@lezi-fun

Copy link
Copy Markdown
Collaborator Author

@bot 这个改动主要改动了什么

@forumlify

forumlify Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

这个 PR 主要围绕「管理后台设置、上传体验、页面过渡动画」三块做了优化,具体如下:

1. 管理员网站图标上传(新增)

  • 新增 app/api/admin/favicon/route.js:管理员上传图标接口,支持 PNG/JPEG/GIF/WebP/ICO,服务端保留 5MB 大小校验和文件头嗅探(不信任扩展名)。
  • 新增 lib/favicon.js:上传后通过 applyFavicon() 立即刷新页面 favicon,并用 favicon_version 做缓存失效。
  • AdminForumSettings.js 增加图标上传 UI:预览、拖拽上传、上传/压缩状态提示。
  • 设置接口 /api/settings 现在返回 favicon_url、favicon_version、version_commit,同时隐藏内部字段 favicon_object。
  • 并发上传有事务保护,旧图标会在新图标提交后清理,测试覆盖了「并发上传不遗留未引用对象」。

2. 图片上传前自动压缩

  • 新增 lib/compress-image.js:5–20MB 的图片在浏览器端先压缩(缩放 + WebP 质量档位递减),再上传,服务端校验不变。
  • 应用到发帖(NewPost.js)和帖子编辑(PostDetail.js),并区分「压缩中 / 上传中」两种状态提示。
  • 新增 lib/image-type.js(从 upload 路由抽出的文件头嗅探),并支持 ICO 签名识别;uploads/[name] 路由补上了 .ico 的 MIME 类型。

3. Docker 与构建信息

  • docker-compose.yml:去掉废弃的 version 字段、不再默认暴露数据库端口、应用端口支持 ${FORUMLIFY_PORT:-3000} 环境变量。
  • dockerfile + GitHub Actions:把 github.sha 作为 FORUMLIFY_COMMIT 构建参数注入镜像。
  • next.config.js 在构建时解析当前 commit,管理后台「当前版本 Commit」直接显示。

4. 管理后台左侧抽屉过渡动画

  • AdminPage.js 改为 clip-path 抽屉切换(closing → hidden → opening → idle),用 ResizeObserver 测量内容高度,解决报告等异步加载内容导致的高度跳动问题。

5. 首页「发布新帖」按钮动画

  • 首页悬浮按钮通过 View Transitions API 平滑过渡到发帖页标题(加号 + 标题)。
  • 发帖页标题用打字机 + 终端光标效果,边输入标题边切换。
  • 支持 prefers-reduced-motion 降级,移动端布局也做了适配。

6. 其他

  • 中英文语言包补充了新文案;新增测试:图片类型嗅探(image-type.test.js)、静态 i18n key 一致性检查、favicon 上传与并发测试。

简单说:给管理员加了图标上传和版本展示,大图上传前自动压缩,Docker 部署更干净,并且给管理后台和新帖页加了一套更顺滑的过渡动画。

@lezi-fun
lezi-fun merged commit e198a5c into next Aug 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant