v11: 家谱按户排布(夫妻并排/长幼排序/父母括号/姻亲);观影设置下拉收拢影院·搜索·统计·年度报告;观影人头像
家谱(用户第 2 点,重写模板与 Kinship::tree): - 同代聚成「夫妻单元」(户):血亲当主位、配偶并排在其右,兄弟_姐妹按长幼(长子左) - 血亲可达性判「姻亲」:只走 parent/child 边从「我」可达者为本家血亲,妻子的父母 走不到 → 标「姻亲」并排到本代末尾(旧判据「上无父母且下无子女」对岳父母恒为假,是真 bug) - 父母括号连线:横杆盖住父母列到其子女各列,竖线落父母列中心、每子女列一道下线 - 称呼按长幼定死:姐夫/妹夫、嫂子/弟媳、大/小舅子、大/小姨子、大伯子/小叔子、 大姑子/小姑子、侄子/侄女、外甥/外甥女、堂/表 - 列宽地板 minmax(min-content,1fr):原 minmax(0,1fr) 在窄屏+户数多时把列压到卡片 (96px)以下 → 同代卡片互相重叠;.tnode 加 flex:0 0 auto 防被 flex 压扁 观影(用户第 3~5 点): - 顶栏删「影院」入口(影院是观影模块的子功能);观影列表右侧加「⚙ 设置」下拉, 内含 影院管理 / 高级搜索 / 统计 / 年度报告(后三者从 MovieLog 迁入, app/MovieStats.php + 三个只读路由,MySQL 方言;图表全用纯 CSS,不引 CDN) - 评价区删除「我」的长条徽标(被 flex column stretch 拉成整行宽的丑色带) - 观影人弹窗列表与已选 chips 带头像;syncChips 点名取 .att-name/.att-av (旧写法取「第一个 span」,v11 起那是隐藏占位,chip 上会没名字) 验证:e2e 432/0、桌面几何 268/0、移动几何 464/0、交互几何 97/0、 静态空跑 199/0、反向验证 v11 十条 10抓/0漏。本轮无 DB 变更(Schema 仍 v10)。 移动几何抓出两个真溢出并已修:高级搜索页 select 长选项撑破 .field、 原生 date 输入撑破 .date-range(360/375px)。
This commit is contained in:
+202
-20
@@ -100,6 +100,16 @@ a:hover { text-decoration: underline; }
|
||||
border-radius: 0 0 8px 8px; color: var(--muted);
|
||||
}
|
||||
.menu-list .menu-exit:hover { color: var(--brand); }
|
||||
/* ---- 观影页的「设置」下拉(v11):一个齿轮图标 + <details> 菜单 ---- */
|
||||
.movie-set { position: relative; }
|
||||
.movie-set > summary {
|
||||
list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
|
||||
}
|
||||
.movie-set > summary::-webkit-details-marker { display: none; }
|
||||
.movie-set[open] > summary { border-color: var(--brand); color: var(--brand); }
|
||||
/* 观影设置菜单是顶栏菜单的复用:位置从右上角改成按钮下方左对齐 */
|
||||
.movie-set .menu-list { left: 0; right: auto; top: calc(100% + 8px); }
|
||||
.movie-set .menu-list a.on { color: var(--brand); background: var(--line-2); }
|
||||
.link-quiet { color: var(--muted); font-size: 14px; }
|
||||
.link-quiet:hover { color: var(--brand); }
|
||||
|
||||
@@ -224,7 +234,11 @@ a:hover { text-decoration: underline; }
|
||||
|
||||
/* ---------------- 表单 ---------------- */
|
||||
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
.field { display: flex; flex-direction: column; gap: 6px; }
|
||||
/* ⚠️ min-width:0 是必需的(v11 实测踩到):.field 是 grid 项,默认 min-width:auto
|
||||
会被内部 <select> 的**最长选项文字**撑开 —— 高级搜索页在 360/375px 下整页横向溢出
|
||||
(scrollW 390 > clientW 360),而「影院」下拉正是长选项。给了 0 之后列才能收进版心,
|
||||
下拉自身由 width:100% 跟着收。与 .hero-main / .person-move .select 同一套做法。 */
|
||||
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
||||
.field.full { grid-column: 1 / -1; }
|
||||
.field label { font-size: 13px; color: var(--muted); font-weight: 500; }
|
||||
.field .tip { font-size: 12px; color: var(--muted); }
|
||||
@@ -366,9 +380,20 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
/* ---------------- 家谱(以我为中心) ---------------- */
|
||||
/* ---------------- 家谱(以我为中心) ----------------
|
||||
v11 改版:每代是「夫妻单元」网格 + 父母括号连线。
|
||||
所有代的列网格共用同一份 template(宽度取最宽那一代),连线才能跟人对齐。 */
|
||||
.tree { display: flex; flex-direction: column; align-items: center; gap: 0; }
|
||||
.tree-gen { width: 100%; }
|
||||
.tree-inner {
|
||||
width: 100%;
|
||||
overflow-x: auto; /* 家里人再多也不挤:横向滚,不改版心 */
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
/* ⚠️ 必须是 min-content 而不是 100%:min-content 让「代」按内容自然展开,
|
||||
.tree-inner 才有东西可滚;列的地板由 .tree-row 的 minmax(min-content,1fr) 兜。
|
||||
两处一起才成立 —— 单改一处会在窄屏下把卡片压重叠(v11 实测踩到)。 */
|
||||
.tree-gen { min-width: min-content; }
|
||||
.tree-gen-label {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
margin: 0 0 8px; padding-left: 2px;
|
||||
@@ -378,13 +403,28 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
font-size: 11px; color: var(--muted); background: var(--line-2);
|
||||
padding: 1px 8px; border-radius: 999px;
|
||||
}
|
||||
/* 一代 = 若干「户」,每户占网格的一列(列数由 inline grid-template-columns 给) */
|
||||
.tree-row {
|
||||
display: flex; flex-wrap: wrap; gap: 10px;
|
||||
justify-content: center; align-items: stretch;
|
||||
display: grid; gap: 14px;
|
||||
align-items: start;
|
||||
}
|
||||
.tree-unit {
|
||||
display: flex; align-items: center; justify-content: center; gap: 0;
|
||||
position: relative; padding: 0 2px;
|
||||
}
|
||||
/* 夫妻之间的短横(儿女亲家那种「连着的两个人」) */
|
||||
.tree-bond { width: 14px; flex: 0 0 auto; display: flex; align-items: center; }
|
||||
.tree-bond i {
|
||||
display: block; width: 100%; height: 2px; border-radius: 2px;
|
||||
background: var(--line); transform: translateY(2px);
|
||||
}
|
||||
.tnode {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 5px;
|
||||
width: 104px; padding: 12px 8px 10px; text-align: center;
|
||||
/* ⚠️ flex:0 0 auto 是必需的(v11 实测踩到):.tnode 是 .tree-unit(flex)的子项,
|
||||
默认 flex-shrink:1 会让卡片**先被压**,列地板的 min-content 也跟着变小 ——
|
||||
等于把「列不许压到卡片以下」这条设计从内部掏空了。卡宽由下面的 width 定,
|
||||
窄屏另有 78px 的媒体查询(那是刻意的窄版式,不是压缩)。 */
|
||||
flex: 0 0 auto; width: 96px; padding: 12px 6px 10px; text-align: center;
|
||||
background: var(--surface); border: 1px solid var(--line);
|
||||
border-radius: 14px; box-shadow: var(--shadow);
|
||||
color: var(--ink); transition: transform .15s ease, box-shadow .15s ease;
|
||||
@@ -401,11 +441,33 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
}
|
||||
.tnode.is-me .tlabel { color: var(--brand-ink); font-weight: 600; }
|
||||
.tnode.is-placeholder { border-style: dashed; }
|
||||
/* 世代之间的连接线(纯装饰,说明"往下走一代") */
|
||||
.tree-link {
|
||||
width: 2px; height: 22px; background: linear-gradient(var(--line), var(--line-2));
|
||||
margin: 6px auto;
|
||||
/* 因婚姻进图、上下都不接血的旁支(如妻子的父母):虚线边框 + 角标,免得像断线 */
|
||||
.tnode.is-inlaw { border-style: dashed; background: #FCFAF6; }
|
||||
.tree-inlaw-tag {
|
||||
position: absolute; top: -8px; right: 0;
|
||||
font-size: 10px; color: var(--faint); background: var(--paper);
|
||||
border: 1px solid var(--line); border-radius: 999px; padding: 0 6px;
|
||||
}
|
||||
/* ---- 父母括号连线 ----
|
||||
.tc-bar = 横杆(占父母列 + 子女各列,居中画一根竖线上去接父母)
|
||||
.tc-down = 每个子女列的一道竖线(接进同一个横杆)*/
|
||||
.tree-conn {
|
||||
display: grid; gap: 14px; height: 30px; position: relative;
|
||||
}
|
||||
.tc-bar { position: relative; align-self: end; border-top: 0; }
|
||||
.tc-bar::before {
|
||||
content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
|
||||
background: var(--line); border-radius: 2px;
|
||||
}
|
||||
.tc-up {
|
||||
position: absolute; bottom: 0; width: 2px; height: 14px;
|
||||
background: var(--line); transform: translateX(-1px);
|
||||
}
|
||||
.tc-down {
|
||||
align-self: end; justify-self: center;
|
||||
width: 2px; height: 30px; background: var(--line);
|
||||
}
|
||||
.tree-legend { font-size: 12px; color: var(--muted); margin: 14px 2px 0; }
|
||||
|
||||
/* 详情页里的迷你家谱 */
|
||||
.mini-tree { display: flex; flex-direction: column; gap: 8px; }
|
||||
@@ -473,9 +535,12 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.rel-form { grid-template-columns: 1fr; }
|
||||
.tnode { width: 88px; padding: 9px 6px 8px; }
|
||||
.tnode .tph { width: 44px; height: 44px; }
|
||||
.tnode { width: 78px; padding: 8px 4px 7px; }
|
||||
.tnode .tph { width: 40px; height: 40px; }
|
||||
.tree-row { gap: 8px; }
|
||||
.tree-unit { padding: 0; }
|
||||
.tree-bond { width: 8px; }
|
||||
.tree-conn { gap: 8px; }
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
@@ -977,14 +1042,18 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
.stars-disp { display: inline-flex; gap: 1px; font-size: 17px; line-height: 1; vertical-align: -2px; }
|
||||
.stars-disp .d-on { color: #f5b301; }
|
||||
.stars-disp .d-off { color: #d3d7de; }
|
||||
/* ---- 同行观影人选择(v10):chips + 弹窗 + 拼音首字母联想 ---- */
|
||||
/* ---- 同行观影人选择(v10):chips + 弹窗 + 拼音首字母联想(v11 起带头像) ---- */
|
||||
.att-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
|
||||
.att-chips:empty { display: none; }
|
||||
.att-chip {
|
||||
display: inline-flex; align-items: center; gap: 6px; padding: 3px 6px 3px 10px;
|
||||
display: inline-flex; align-items: center; gap: 6px; padding: 3px 6px 3px 4px;
|
||||
border: 1px solid var(--line); border-radius: 999px; background: var(--surface);
|
||||
font-size: 13px;
|
||||
}
|
||||
.att-chip img {
|
||||
width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
|
||||
background: #F1E7D6;
|
||||
}
|
||||
.att-chip .att-x {
|
||||
border: 0; background: none; color: var(--muted); font-size: 15px;
|
||||
line-height: 1; padding: 0 2px; cursor: pointer;
|
||||
@@ -1013,7 +1082,12 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
}
|
||||
.att-item:last-child { border-bottom: 0; }
|
||||
.att-item:hover { background: var(--line-2); }
|
||||
.att-item input { accent-color: var(--brand); }
|
||||
.att-item input { accent-color: var(--brand); flex: 0 0 auto; }
|
||||
.att-item .att-av {
|
||||
width: 30px; height: 30px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
|
||||
background: #F1E7D6;
|
||||
}
|
||||
.att-item .att-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.att-item .att-initials { margin-left: auto; color: var(--muted); font-size: 12px; }
|
||||
.att-empty { padding: 10px 12px; color: var(--muted); font-size: 13px; }
|
||||
/* ---- 豆瓣自动补充(v10):片名行 + 下拉候选 + 海报预览 ---- */
|
||||
@@ -1081,11 +1155,10 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
}
|
||||
.rv-who { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
||||
.rv-name { font-size: 14px; font-weight: 600; color: var(--ink); }
|
||||
.rv-mine {
|
||||
display: inline-block; vertical-align: middle; margin-left: 6px;
|
||||
font-size: 11px; line-height: 16px; background: var(--brand);
|
||||
color: #fff; border-radius: 6px; padding: 0 6px;
|
||||
}
|
||||
/* ⚠️ 写着「我」的那个徽标(类名是「评价」区块 + 「我的」后缀)v11 删掉了:
|
||||
它在 .rv-who(flex column)里被 align-items:stretch 拉成整行宽的色带,
|
||||
星星旁边显出一条丑长的品牌色条。删除按钮已经表达了「这是我写的」,
|
||||
不需要徽标。别再把它加回来。 */
|
||||
.rv-time { display: block; font-size: 12px; color: var(--muted); }
|
||||
.rv-score { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px; }
|
||||
.rv-score .stars-disp { font-size: 16px; }
|
||||
@@ -1177,3 +1250,112 @@ textarea.input { min-height: 76px; resize: vertical; }
|
||||
.lb-next { right: 6px; }
|
||||
.lb-img { max-width: 88vw; max-height: 70vh; }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
v11:观影统计 / 高级搜索 / 年度报告(从 MovieLog 迁入)
|
||||
版式沿用家书的暖纸配色;图表全用 CSS(不引 CDN 图表库)。
|
||||
============================================================ */
|
||||
|
||||
/* ---- 统计仪表板 ---- */
|
||||
.stats-grid {
|
||||
display: grid; gap: 14px; margin-bottom: 16px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
}
|
||||
.stat-card {
|
||||
background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
|
||||
padding: 16px 18px; text-align: center; box-shadow: var(--shadow);
|
||||
}
|
||||
.stat-card .number { font-size: 30px; font-weight: 700; color: var(--brand); line-height: 1.2; font-variant-numeric: tabular-nums; }
|
||||
.stat-card .label { font-size: 13px; color: var(--muted); margin-top: 2px; }
|
||||
.stats-span {
|
||||
display: flex; align-items: baseline; gap: 12px; margin-bottom: 16px;
|
||||
}
|
||||
.stats-span .label { font-size: 13px; color: var(--muted); }
|
||||
.stats-span .value { font-size: 16px; font-weight: 600; }
|
||||
|
||||
.chart-card {
|
||||
background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
|
||||
padding: 18px 22px; box-shadow: var(--shadow); margin-bottom: 16px;
|
||||
}
|
||||
.chart-card h3 { font-size: 16px; font-weight: 600; margin: 0 0 14px; display: flex; align-items: baseline; gap: 8px; }
|
||||
.chart-card h3 .hint { font-size: 12px; color: var(--faint); font-weight: 400; }
|
||||
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
@media (max-width: 720px) { .two-col { grid-template-columns: 1fr; } }
|
||||
|
||||
.bar-chart { display: flex; flex-direction: column; gap: 8px; }
|
||||
.bar-item { display: flex; align-items: center; gap: 12px; }
|
||||
.bar-item .bar-label {
|
||||
width: 150px; flex: 0 0 auto; font-size: 13px; color: var(--ink);
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.bar-item .bar-label .bar-sub { color: var(--faint); font-size: 11px; }
|
||||
.bar-item .bar-avatar { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
|
||||
.bar-item .color-dot { display: inline-block; width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }
|
||||
.bar-item .bar-track {
|
||||
flex: 1; height: 20px; background: var(--line-2); border-radius: 6px; overflow: hidden;
|
||||
}
|
||||
.bar-item .bar-fill {
|
||||
display: block; height: 100%; border-radius: 6px; background: var(--brand);
|
||||
}
|
||||
.bar-item .bar-fill-alt { background: var(--brand-2); }
|
||||
.bar-item .bar-fill-green { background: var(--green); }
|
||||
.bar-item .bar-count {
|
||||
width: 40px; flex: 0 0 auto; text-align: right; font-size: 13px; font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.bar-item .bar-label { width: 92px; font-size: 12px; }
|
||||
.bar-item .bar-count { width: 30px; }
|
||||
.chart-card { padding: 14px 16px; }
|
||||
}
|
||||
|
||||
/* ---- 高级搜索 ---- */
|
||||
.adv-form { margin-bottom: 18px; }
|
||||
.date-range { display: flex; align-items: center; gap: 8px; }
|
||||
.date-range .to { color: var(--muted); font-size: 13px; flex: 0 0 auto; }
|
||||
/* ⚠️ 原生 <input type="date"> 的 min-width:auto 约 150px(带日历图标 + 占位数字)——
|
||||
两个日期框 + 「至」在 360px 下会横向溢出(实测 scrollW 390 > clientW 360)。
|
||||
给 0 并让它们等比收缩;这是继 .field(select)之后同一页的第二个溢出源。 */
|
||||
.date-range .input { flex: 1 1 0; min-width: 0; }
|
||||
.results-head {
|
||||
display: flex; align-items: baseline; justify-content: space-between;
|
||||
gap: 10px; margin: 0 2px 12px;
|
||||
}
|
||||
.results-head h3 { margin: 0; font-size: 17px; }
|
||||
.results-head .sub { color: var(--muted); font-size: 13px; }
|
||||
|
||||
/* ---- 年度报告 ---- */
|
||||
.year-pick { display: inline-block; }
|
||||
.report-grid {
|
||||
display: grid; gap: 14px; margin-bottom: 16px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
}
|
||||
.report-grid.two { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
|
||||
.report-card {
|
||||
background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
|
||||
padding: 18px 20px; box-shadow: var(--shadow);
|
||||
}
|
||||
.report-card .n { font-size: 32px; font-weight: 700; color: var(--brand); line-height: 1.15; font-variant-numeric: tabular-nums; }
|
||||
.report-card .l { font-size: 13px; color: var(--muted); }
|
||||
.report-card .v { font-size: 19px; font-weight: 600; margin-top: 2px; }
|
||||
.report-card .s { font-size: 12px; color: var(--faint); margin-top: 4px; }
|
||||
|
||||
/* 月份竖柱图(纯 CSS) */
|
||||
.vgrid {
|
||||
display: grid; grid-template-columns: repeat(12, 1fr); gap: 6px;
|
||||
align-items: end; height: 160px; margin-top: 4px;
|
||||
}
|
||||
.vcol { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 3px; }
|
||||
.vcol .vbar {
|
||||
width: 68%; min-height: 2px; background: linear-gradient(var(--brand-2), var(--brand));
|
||||
border-radius: 5px 5px 2px 2px; transition: height .4s ease;
|
||||
}
|
||||
.vcol .vlab { font-size: 11px; color: var(--muted); }
|
||||
.vcol .vnum { font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }
|
||||
|
||||
.kw-cloud { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.kw-cloud .kw {
|
||||
font-size: 14px; padding: 4px 12px; border-radius: 999px;
|
||||
background: var(--line-2); color: var(--brand-ink); border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user