已部署到线上(frontend-only)。本提交把工作区里已上线但未提交的实现固化为分支基线。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.7 KiB
3.7 KiB
照片墙 Photo Wall(#photo 入口)
模拟软木板/墙面的互动照片展示页:上传本地照片,以宝丽来风格散落摆放,用胶带、
图钉、便签、贴纸、印章、手绘箭头自由装扮,可导出为一张 PNG。纯前端(无后端改动),
状态存浏览器 localStorage。
设计来源:photo-wall-design.docx(产品设计文档 v1.0)。本页是其 React 重写版。
入口与鉴权流
地址栏 #photo 是一个写死的公开入口,与开发者入口门(dev_gate)无关:
浏览器 #photo
└─ 直接显示登录页(复用 LoginPage,但去掉顶部服务器负载栏) ← 不查后端 gate
登录页提交用户名 + 密码
└─ POST /api/web/login → 校验同一套 ccuser 账号 → 成功后进入照片墙
#photo不走POST /api/web/gate(藏门口令),但照片墙本身仍被登录挡住—— 用的是同一套ccuser后端账号(见 auth-login-gate.md)。- 已登录用户访问
#photo会跳过登录页,直接进墙。 - 墙内右上角「退出」= 清登录态 + 抹掉地址栏
#photo,回到导航页(StartPage)。
涉及文件(全部前端)
Client/src/App.tsx— 监听hashchange:#photo短路 gate,置wantsPhoto; 已登录 +wantsPhoto→ 渲染PhotoWallPage,否则博客页。Client/src/components/LoginPage.tsx— 新增hideStats开关,隐藏顶部AnnouncementBar(系统负载栏);把轮询的useSystemStats拆进只在显示时挂载的StatsBar子组件,隐藏时不发请求。Client/src/components/PhotoWallPage.tsx— 照片墙组件本体。Client/src/index.css— 末尾.pw-命名空间的全部照片墙美术样式(软木板/宝丽来/ 便签折角/胶带/图钉等,无法用 Tailwind 表达的部分)。
后端零改动:登录走既有
/api/web/login,照片墙数据只存浏览器,不落服务器。
功能
- 照片:宝丽来白边(底部加大留白)、随机旋转 ±15°、立体投影;三种随机固定方式 (胶带 / 彩色图钉 / 双角胶带)。
- 交互:拖拽移动、双击编辑标注、右键菜单(旋转 ±5°、放大/缩小、移到最前/最后、 删除;便签额外可改色)。触摸端长按 = 右键。
- 装饰:便签(5 色 + 折角)、胶带条、12 预设贴纸 + 自定义文字、SVG 印章、手绘箭头 (选中后在画布拖动绘制)。
- 背景:软木板 / 黑板 / 白墙 / 牛皮纸,工具栏循环切换。
- 上传:按钮选择 / 拖入画布 / 剪贴板粘贴(
FileReader读 Base64)。 - 历史:撤销/重做 Ctrl+Z / Ctrl+Y,最多 30 步。
- 持久化:操作后防抖 1s 自动写
localStorage,keyphoto-wall-state({ bgIndex, els });工具栏显示「保存中…/已保存」。 - 导出:
html2canvas(CDN 懒加载)截图画布为photo-wall-<时间戳>.png。
实现注记
- 拖拽性能:拖拽过程中只直接改 DOM 的
transform(GPU 合成),不触发 React 重渲染;松手后才一次性 commit 进状态并记一步历史。故拖拽中不得setState。 - 元素统一 Pointer Events 处理鼠标 + 触摸;
touch-action: none防止滚动抢手势。 - 「保存中…」由各改动入口(mutate / undo / redo / 拖拽 commit / 换背景)打标,
防抖 effect 仅负责落盘并置「已保存」——避免在 effect 内同步
setState引发级联渲染。
线上访问
部署后:http://8.130.143.54:8548/#photo(纯前端改动,按
部署计划的 frontend-only redeploy 路径上线,
后端无需重启)。