地点库 / 时间线 / 统计:窄屏筛选卡默认收成一条(与地图页筛选面板同形)
手机上这三页共用的筛选卡一上来就占掉大半屏(时间预设 + 已选条件 + 类型 chips + 六个输入框,
实测 945px),内容反而看不见。按地图页那套 .panel-fold 收成一条:
- 折叠条显示「筛选 + 当前时间范围〔+ N 个条件〕」,展开/收起箭头都能点;
- 状态记在 localStorage('rond-filters-fold'),翻页/换页不会又自己弹开;
- 收起只是 CSS 隐藏,表单控件照旧随提交带上(act/hw/sort 那几个 hidden 也在);
- 整组显示规则都在窄屏媒体查询里 ⇒ 桌面端 .collapsed 不生效、折叠条也 display:none,零影响;
- 折叠脚本紧跟表单(放 body 末尾会先按展开画一帧再收起,手机上就是闪一下整张大卡)。
实测:390 三页站长/访客都默认收起、条高 44、内容隐藏、滚动时粘在导航下方(top=50);
筛选卡 945px → 46px;1440 无变化;320/350 摘要不溢出;全站审计 320/390/1440 溢出全 0、
0 JS 报错、小触控只减不增(A/B 31/181/82 vs 35/185/86);关键词回车提交未受影响
(折叠条是 type="button",默认按钮仍是「查询」)。
新增回归 internal/web/filters_fold_test.go(三页的挂载点 + 筛选控件仍在,做了变异验证)。
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestFiltersFoldHook 盯住「地点库 / 时间线 / 统计三页共用筛选卡在窄屏默认收起」的挂载点。
|
||||||
|
//
|
||||||
|
// 折叠是纯前端的事:CSS 认 `.filters-card.collapsed`,脚本认 `#filters-fold`,两边都靠
|
||||||
|
// 模板里的类名/ID 挂钩子。谁哪天把表单的 class 换了、或者把这个按钮删了,页面照样能渲染、
|
||||||
|
// 桌面端也看不出问题 —— 只有手机会退化成「永远展开」,所以在这里钉住。
|
||||||
|
//
|
||||||
|
// ROND_TEST_CONF=conf/app-test.ini ROND_SRC=data/xxx.rondbackup go test ./internal/web -run FiltersFold -v
|
||||||
|
func TestFiltersFoldHook(t *testing.T) {
|
||||||
|
f := newMovementFixture(t)
|
||||||
|
for _, path := range []string{"/places", "/timeline", "/stats"} {
|
||||||
|
var h http.HandlerFunc
|
||||||
|
switch path {
|
||||||
|
case "/places":
|
||||||
|
h = f.srv.placesPage
|
||||||
|
case "/timeline":
|
||||||
|
h = f.srv.timelinePage
|
||||||
|
case "/stats":
|
||||||
|
h = f.srv.statsPage
|
||||||
|
}
|
||||||
|
// 访客身份:这三页公开,折叠对访客同样生效
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h(w, httptest.NewRequest("GET", path, nil).WithContext(context.Background()))
|
||||||
|
body := w.Body.String()
|
||||||
|
if w.Code != 200 {
|
||||||
|
t.Fatalf("%s 渲染失败: code=%d", path, w.Code)
|
||||||
|
}
|
||||||
|
for _, want := range []string{
|
||||||
|
`class="card filters-card"`, // CSS 的挂载点
|
||||||
|
`id="filters-fold"`, // 折叠条
|
||||||
|
`id="filters-fold-caret"`, // 箭头(脚本要改它的字)
|
||||||
|
`id="filters-form"`, // 脚本靠它找表单;收起时表单控件仍在里面
|
||||||
|
`rond-filters-fold`, // 记收起状态的本地键:翻了页不该又弹开
|
||||||
|
`name="q"`, // 收起只是 CSS 隐藏,筛选控件得照旧提交得出去
|
||||||
|
} {
|
||||||
|
if !strings.Contains(body, want) {
|
||||||
|
t.Fatalf("%s 里找不到 %q:窄屏筛选折叠的挂载点断了", path, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -993,4 +993,17 @@ label.f > span.span-actions { display: flex; align-items: center; justify-conten
|
|||||||
/* 导航左上角那个 logo 是回首页的入口,原来只有 25×29:给它撑到 44 高,
|
/* 导航左上角那个 logo 是回首页的入口,原来只有 25×29:给它撑到 44 高,
|
||||||
横向也补到 44(.brand .t 在窄屏被隐藏,加内边距就够了)。 */
|
横向也补到 44(.brand .t 在窄屏被隐藏,加内边距就够了)。 */
|
||||||
.brand { min-width: 44px; min-height: 44px; justify-content: center; }
|
.brand { min-width: 44px; min-height: 44px; justify-content: center; }
|
||||||
|
|
||||||
|
/* ---------- 地点库 / 时间线 / 统计三页共用的筛选卡:窄屏默认收成一条 ----------
|
||||||
|
与地图页那块 .panel-fold 同形——手机上它一上来就占掉大半屏(预设 + 已选 + 类型 + 六个
|
||||||
|
输入框),内容反而看不见。展开时折叠条用负外边距贴到卡片上沿(圆角照着卡片补,
|
||||||
|
卡片没有 overflow:hidden,否则折叠条就粘不住了);收起时卡片内边距归零、只留那一条。
|
||||||
|
top 取 --nav-h:导航是 sticky 的,写 0 会被压在它下面。
|
||||||
|
这些规则整条在媒体查询里 ⇒ 桌面端 .collapsed 不生效,等于没影响。 */
|
||||||
|
.filters-card > .panel-fold {
|
||||||
|
margin: -18px -18px 14px; border-radius: var(--radius) var(--radius) 0 0; top: var(--nav-h);
|
||||||
|
}
|
||||||
|
.filters-card.collapsed { padding: 0; }
|
||||||
|
.filters-card.collapsed > .panel-fold { margin: 0; border-radius: var(--radius); }
|
||||||
|
.filters-card.collapsed > :not(.panel-fold) { display: none; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,15 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "filters"}}
|
{{define "filters"}}
|
||||||
<form class="card" method="get" action="{{.FilterBase}}" id="filters-form">
|
<form class="card filters-card" method="get" action="{{.FilterBase}}" id="filters-form">
|
||||||
|
{{/* 窄屏折叠开关,与地图页筛选面板同一套(.panel-fold):桌面端它 display:none、表单照旧常开;
|
||||||
|
手机上默认收成这一条,只留「筛选 + 当前范围 + 箭头」。收起只是 CSS 隐藏,
|
||||||
|
表单里的控件都还在,筛选条件照旧随提交带上(act/hw/sort 那几个 hidden 也在)。 */}}
|
||||||
|
<button class="panel-fold" id="filters-fold" type="button" aria-controls="filters-form" aria-expanded="true">
|
||||||
|
<span>筛选</span>
|
||||||
|
<span class="pf-n">{{.RangeLabel}}{{if .ActiveChips}} · {{len .ActiveChips}} 个条件{{end}}</span>
|
||||||
|
<span class="pf-c" id="filters-fold-caret" aria-hidden="true">▾</span>
|
||||||
|
</button>
|
||||||
<div class="chips" style="margin-bottom:12px">
|
<div class="chips" style="margin-bottom:12px">
|
||||||
{{range .Presets}}<a class="chip {{if .Active}}on{{end}}" href="{{$.RangeLink .From .To}}">{{.Label}}</a>{{end}}
|
{{range .Presets}}<a class="chip {{if .Active}}on{{end}}" href="{{$.RangeLink .From .To}}">{{.Label}}</a>{{end}}
|
||||||
<span class="chip" style="background:transparent;color:var(--text-3)">{{.RangeLabel}}</span>
|
<span class="chip" style="background:transparent;color:var(--text-3)">{{.RangeLabel}}</span>
|
||||||
@@ -104,6 +112,37 @@
|
|||||||
{{if .ShowHomeWork}}<input type="hidden" name="hw" value="1">{{end}}
|
{{if .ShowHomeWork}}<input type="hidden" name="hw" value="1">{{end}}
|
||||||
{{if .Sort}}<input type="hidden" name="sort" value="{{.Sort}}">{{end}}
|
{{if .Sort}}<input type="hidden" name="sort" value="{{.Sort}}">{{end}}
|
||||||
</form>
|
</form>
|
||||||
|
{{/* 窄屏折叠:脚本必须紧跟这个表单 —— 放到 body 末尾时,手机上会先按「全部展开」画一帧
|
||||||
|
再收起,看着就是闪一下整张大卡(地图页那块面板也是贴在面板后面)。收起态记在本地,
|
||||||
|
翻页/换页之后不该又自己弹开。 */}}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('filters-form');
|
||||||
|
var btn = document.getElementById('filters-fold');
|
||||||
|
if (!form || !btn) return;
|
||||||
|
var caret = document.getElementById('filters-fold-caret');
|
||||||
|
var KEY = 'rond-filters-fold';
|
||||||
|
var desk = window.matchMedia('(min-width: 621px)');
|
||||||
|
var saved = null;
|
||||||
|
try { saved = localStorage.getItem(KEY); } catch (e) { /* 隐私模式禁用了,忽略 */ }
|
||||||
|
|
||||||
|
function apply(collapsed) {
|
||||||
|
form.classList.toggle('collapsed', collapsed);
|
||||||
|
btn.setAttribute('aria-expanded', String(!collapsed));
|
||||||
|
btn.title = collapsed ? '展开筛选' : '收起筛选';
|
||||||
|
if (caret) caret.textContent = collapsed ? '▸' : '▾';
|
||||||
|
}
|
||||||
|
// 没记过状态时窄屏默认收起。桌面端这条 class 不生效(显示规则整条在窄屏媒体查询里),
|
||||||
|
// 所以同一个浏览器在手机上收起过、回桌面照样看得见筛选。
|
||||||
|
apply(saved === null ? !desk.matches : saved === '1');
|
||||||
|
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
var collapsed = !form.classList.contains('collapsed');
|
||||||
|
apply(collapsed);
|
||||||
|
try { localStorage.setItem(KEY, collapsed ? '1' : '0'); } catch (e) { /* 同上 */ }
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "emptystate"}}
|
{{define "emptystate"}}
|
||||||
|
|||||||
Reference in New Issue
Block a user