fix(V0.2): 智能截断去尾部标点; 看板左列收窄; 项目头像三处统一
Docker Build and Push / build-image (push) Successful in 1m7s

- splitTitle: 截断后用 \p{P} 去掉标题尾部连续分隔符 (原字符类重组有
  转义坑, 换 Unicode 属性类)
- 看板卡片左列 (状态点+⋯) 收窄至 14px 并负外距悬进卡片内边距
- 项目头像统一: 新增 .pavatar 基类与 projectIcon.colorOfProject,
  项目管理预览改用同配色/同圆角/居中首字, 修复灰底与文字歪斜
This commit is contained in:
jif2.zhang
2026-10-25 18:38:16 +08:00
parent cee21a39d9
commit fd66c529c2
6 changed files with 29 additions and 12 deletions
+2 -3
View File
@@ -1,12 +1,11 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { getRecentIds, getRecentOrder, setRecentOrder } from '../../pages/task/prefs.js'
import { colorOfProject } from '../../pages/task/projectIcon.js'
// 首屏最近项目条 (T-VW-08/10)
// - 展示最近使用的 3 个项目 + 「更多项目」入口
// - 顺序: 手动排序(recentOrder)优先, 其次最近访问(recentIds), 兜底列表顺序
// - 长按卡片 300ms 进入拖拽态, 水平拖动实时换位, 松手持久化(设备端)
const COLORS = ['#1677ff', '#00b578', '#ff8f1f', '#a855f7', '#14b8a6', '#f43f9e']
const colorOf = (id) => COLORS[Math.abs(id) % COLORS.length]
const LONG_PRESS = 300
const MOVE_TOLERANCE = 8
@@ -127,7 +126,7 @@ export default function RecentProjects({ projects, currentId, onSelect, onMore }
className="rp-ico"
style={p.icon
? { background: `url(${p.icon}) center/cover no-repeat` }
: { background: colorOf(p.id) }}
: { background: colorOfProject(p) }}
>
{p.icon ? '' : (p.name || '?').slice(0, 1)}
</div>
+7 -4
View File
@@ -7,6 +7,7 @@ import useOverlayBack from '../../hooks/useOverlayBack.js'
import ColumnSettings from './ColumnSettings.jsx'
import ProjectMembers from './ProjectMembers.jsx'
import { DEFAULT_KINDS, kindColor } from './kind.js'
import { colorOfProject } from './projectIcon.js'
// 项目管理 (T-PJ-11/12): 成员 / 看板列 / 项目信息 三个分区的统一入口
// onExited: 项目被删除/退出/归档后, 上层应离开该项目(回落个人默认项目)
@@ -270,11 +271,13 @@ export default function ProjectManage({ project, onClose, onChanged, onExited })
<div className="set-row" style={{ padding: '12px 14px' }}>
<span className="pn" style={{ flex: 1, fontSize: 13.5 }}>项目图标</span>
<div
className="pico"
className="pavatar"
style={{
width: 34, height: 34, borderRadius: 9, flexShrink: 0,
background: project.icon ? `url(${project.icon}) center/cover no-repeat` : '#dfe6f0',
color: '#5a6a80', cursor: 'pointer',
width: 34, height: 34, borderRadius: 9, fontSize: 14,
background: project.icon
? `url(${project.icon}) center/cover no-repeat`
: colorOfProject(project),
cursor: 'pointer',
}}
onClick={pickIcon}
>
+2 -3
View File
@@ -126,8 +126,7 @@ export default function TaskPage() {
)
}
const COLORS = ['#1677ff', '#00b578', '#ff8f1f', '#a855f7', '#14b8a6', '#f43f9e']
const colorOf = (p) => COLORS[Math.abs(p.id) % COLORS.length]
import { colorOfProject } from './projectIcon.js'
const LONG_PRESS = 300
const MOVE_TOLERANCE = 8
@@ -290,7 +289,7 @@ function ProjectList({ projects, err, onRetry, onOpen, onChanged, createSignal,
className="pico"
style={p.icon
? { background: `url(${p.icon}) center/cover no-repeat` }
: { background: colorOf(p) }}
: { background: colorOfProject(p) }}
>
{p.icon ? '' : (p.name || '?').slice(0, 1)}
</div>
+4
View File
@@ -0,0 +1,4 @@
// 项目头像配色: 项目列表 / 最近项目 / 项目管理 三处共用, 保证观感一致
export const PROJECT_COLORS = ['#1677ff', '#00b578', '#ff8f1f', '#a855f7', '#14b8a6', '#f43f9e']
export const colorOfProject = (p) => PROJECT_COLORS[Math.abs(p.id) % PROJECT_COLORS.length]
+4 -1
View File
@@ -16,7 +16,10 @@ export function splitTitle(raw) {
if (SEPARATOR.test(text[i - 1])) { cut = i; break }
}
if (cut < 0) cut = MAX_TITLE
return { title: text.slice(0, cut).trim(), desc: text }
// 截断落在分隔符上: 分隔符留在标题末尾很难看, 去掉尾部连续分隔符/空白
// (\p{P} 覆盖中英文全部标点; 之前用 SEPARATOR.source 重组字符类有转义坑)
const title = text.slice(0, cut).replace(/[\s\p{P}]+$/u, '').trim()
return { title, desc: text }
}
// 时间词 → 日期 (返回 YYYY-MM-DD):
+10 -1
View File
@@ -985,6 +985,12 @@ body.me-safe-top .app-safe-top { height: 0; }
width: 34px; height: 34px; border-radius: 9px; display: flex; align-items: center;
justify-content: center; color: #fff; font-size: 14px; font-weight: 700; flex-shrink: 0;
}
/* 项目头像基类 (不依赖 .proj-item 作用域): 项目管理编辑页预览等裸用场景 */
.pavatar {
display: flex; align-items: center; justify-content: center;
color: #fff; font-weight: 700; flex-shrink: 0;
background-size: cover; background-position: center; background-repeat: no-repeat;
}
.proj-item .pmain { flex: 1; min-width: 0; }
.proj-item .ptitle {
font-size: 14.5px; font-weight: 600; display: flex; align-items: center; gap: 6px;
@@ -1085,11 +1091,14 @@ body.me-safe-top .app-safe-top { height: 0; }
box-shadow: 0 1px 2px rgba(0,0,0,.05); cursor: pointer; flex-shrink: 0;
display: flex; gap: 7px; align-items: flex-start;
}
/* 左侧竖排操作列: 状态点在上, ⋯ 沉到左下角 */
/* 左侧竖排操作列: 状态点在上, ⋯ 沉到左下角; 负外距悬进卡片内边距, 少占横向空间 */
.bcard-left {
display: flex; flex-direction: column; align-items: center; flex-shrink: 0;
align-self: stretch; justify-content: space-between; padding: 1px 0 2px;
margin: 0 -5px; width: 14px;
}
.bcard-left .bstat { padding: 0; }
.bcard-left .bmore-btn { font-size: 12px; padding: 0; line-height: 1.1; }
.bcard-body { flex: 1; min-width: 0; }
.bcard.hl { outline: 2px solid var(--color-primary); outline-offset: 1px; }
.brow1 { display: flex; align-items: flex-start; gap: 6px; }