diff --git a/Dockerfile b/Dockerfile
index ae96cd1..ff47455 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -165,7 +165,7 @@ RUN php -r "file_exists('.env') || copy('.env.example', '.env');" \
RUN printf '%s\n' \
'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./public/js/context-js/context-js.js' \
'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./resources/js/context-js.js' \
- '1292ea8123868897023def9dc9bcf5ac ./resources/views/user/images.blade.php' \
+ '23835058801c2b609c2134f0f10d0a5d ./resources/views/user/images.blade.php' \
| md5sum -c - \
&& grep -q "assetVersion('js/context-js/context-js.js')" ./resources/views/user/images.blade.php \
&& grep -q 'isIOSWebKit' ./public/js/context-js/context-js.js \
@@ -208,7 +208,7 @@ RUN APP_SRC_MD5=$(find app config routes -type f -print0 2>/dev/null | sort -z |
"fork_sha=${FORK_SHA}" \
"lsky_commit=${LSKY_COMMIT}" \
"context_js_md5=c0e513ec8e93fd81b34b3c6de5cf5eb8" \
- "images_blade_md5=1292ea8123868897023def9dc9bcf5ac" \
+ "images_blade_md5=23835058801c2b609c2134f0f10d0a5d" \
"app_src_md5=${APP_SRC_MD5}" \
"app_js_md5=${APP_JS_MD5}" \
"app_css_md5=${APP_CSS_MD5}" \
diff --git a/patches/ios-longpress.patch b/patches/ios-longpress.patch
index aee2ea0..e06da16 100644
--- a/patches/ios-longpress.patch
+++ b/patches/ios-longpress.patch
@@ -52,7 +52,7 @@
# 三个文件各自的 md5(与 Dockerfile「自证 2」里的期望值一致):
# c0e513ec8e93fd81b34b3c6de5cf5eb8 src/resources/js/context-js.js
# c0e513ec8e93fd81b34b3c6de5cf5eb8 src/public/js/context-js/context-js.js
-# 1292ea8123868897023def9dc9bcf5ac src/resources/views/user/images.blade.php
+# 23835058801c2b609c2134f0f10d0a5d src/resources/views/user/images.blade.php
#
# 上游原文件 md5(改动前,供比对):
# c8e57f6232848ca8277341ddf1a3a7a6 resources/js/context-js.js
@@ -62,8 +62,9 @@
# 2026-10-01 第二轮(老师试完测试版提的意见):两个标签窗口合并成一个(旧 tag-manage-modal 删除)、
# 三态勾选改成两态、加「显示图片标签」开关、修好卡片拖动框选(图片穿透 + 拖动起点放宽 +
# 由卡片自己开预览)。
---- a/resources/js/context-js.js
-+++ b/resources/js/context-js.js
+---- src/resources/js/context-js.js
+--- /root/.hermes/cache/scratch/tmp.BQ92ALlEpf/up/resources/js/context-js.js 2026-10-02 14:31:26.703747972 +0800
++++ src/resources/js/context-js.js 2026-10-01 15:40:13.406864745 +0800
@@ -2,9 +2,49 @@
* Context.js
* Copyright Jacob Kelley, Modified by WispX
@@ -1147,8 +1148,9 @@
+
+ return api;
})();
---- a/public/js/context-js/context-js.js
-+++ b/public/js/context-js/context-js.js
+---- src/public/js/context-js/context-js.js
+--- /root/.hermes/cache/scratch/tmp.BQ92ALlEpf/up/public/js/context-js/context-js.js 2026-10-02 14:31:26.695747977 +0800
++++ src/public/js/context-js/context-js.js 2026-10-02 12:22:32.584186106 +0800
@@ -1 +1,1148 @@
-window.context=window.context||function(){let e={fadeSpeed:100,filter:function(e){},above:"auto",preventDoubleContext:!0,compress:!1};function t(o,n,d,i){let a=i?" dropdown-context-sub":"",s=e.compress?" compressed-context":"",f=$('
'),l=0,r="";for(;l');else if(void 0!==n[l].header)f.append('");else{let e;void 0===n[l].href&&(n[l].href="javascript:void(0)"),void 0!==n[l].target&&(r=' target="'+n[l].target+'"'),e=void 0!==n[l].subMenu?$('"):$('"+n[l].text+""),"function"==typeof n[l].visible&&(n[l].visible(o)||e.hide());let i=e.find("a");if(void 0!==n[l].classes)for(const e in n[l].classes)i.addClass(n[l].classes[e]);if(void 0!==n[l].attributes)for(const e in n[l].attributes)i.attr(e,n[l].attributes[e]);if(void 0!==n[l].action){let e="event-"+(new Date).getTime()*Math.floor(1e5*Math.random()),t=n[l].action;i.attr("id",e),$("#"+e).addClass("context-event"),$(document).on("click","#"+e,(function(){t.call(this,o)}))}if(f.append(e),void 0!==n[l].subMenu){let e=t(o,n[l].subMenu,d,!0);f.find("li:last").append(e)}}"function"==typeof e.filter&&e.filter(f.find("li:last"))}return f}return{init:function(t){e=$.extend({},e,t),$(document).on("click","html",(function(){$(".dropdown-context").fadeOut(e.fadeSpeed,(function(){$(".dropdown-context").css({display:""}).find(".drop-left").removeClass("drop-left")}))})),e.preventDoubleContext&&$(document).on("contextmenu",".dropdown-context",(function(e){e.preventDefault()})),$(document).on("mouseenter",".dropdown-submenu",(function(){let e=$(this).find(".dropdown-context-sub:first");e.width()+e.offset().left>window.innerWidth&&e.addClass("drop-left")}))},settings:function(t){e=$.extend({},e,t)},attach:function(o,n){let d=(n=n||{}).data||{},i=(new Date).getTime();$(document).on("contextmenu",o,(function(a){a.preventDefault(),a.stopPropagation();let s=a.target.closest(o);"function"==typeof n.beforeOpen&&n.beforeOpen.call(a,s);let f=t(s,d,i);$("body .dropdown-menu.dropdown-context").remove(),$("body").append(f),$(".dropdown-context:not(.dropdown-context-sub)").hide();let l=$("#dropdown-"+i);if("boolean"==typeof e.above&&e.above)l.addClass("dropdown-context-up").css({top:a.pageY-20-$("#dropdown-"+i).height(),left:a.pageX-13}).fadeIn(e.fadeSpeed);else if("string"==typeof e.above&&"auto"===e.above){l.removeClass("dropdown-context-up");let t=l.height()+12;a.pageY+t>$("html").height()?l.addClass("dropdown-context-up").css({top:a.pageY-20-t,left:a.pageX-13}).fadeIn(e.fadeSpeed):l.css({top:a.pageY+10,left:a.pageX-13}).fadeIn(e.fadeSpeed)}"function"==typeof n.afterOpen&&n.afterOpen.call(a,s,l.get(0))}))},destroy:function(e){$(document).off("contextmenu",e).off("click",".context-event")}}}();
+/*
@@ -2299,9 +2301,10 @@
+
+ return api;
+})();
---- a/resources/views/user/images.blade.php
-+++ b/resources/views/user/images.blade.php
-@@ -4,45 +4,88 @@
+---- src/resources/views/user/images.blade.php
+--- /root/.hermes/cache/scratch/tmp.BQ92ALlEpf/up/resources/views/user/images.blade.php 2026-10-02 14:31:26.707747969 +0800
++++ src/resources/views/user/images.blade.php 2026-10-02 14:28:58.367831314 +0800
+@@ -4,45 +4,79 @@
@@ -2330,15 +2333,6 @@
+ }
+ }
+
-+ /* fork:卡片里的图片设成鼠标穿透。原因(实测):这套 DragSelect 只在 mousedown
-+ 落在「已登记的可选元素本人」上时才起框选,而卡片 被里面的
-+
铺满 —— 逐像素扫过整张卡片都没有一个点能按到 自己,所以框选永远起不来。
-+ 穿透后按下落在 上,框选恢复(predragstart → elementselect → dragstart);
-+ 代价是「点图片开预览」收不到点击了,改由下面 $photos.on('click', '.images-item') 接管。 */
-+ .images-item img {
-+ pointer-events: none;
-+ }
-+
+ /* 「显示图片标签」开关关掉时,卡片角标整体不显示(角标是每次翻页重新渲染的,
+ 所以用容器上的一个类来控制,而不是去改每一张卡片的 DOM)。 */
+ .image-tags-off .image-tags {
@@ -2403,7 +2397,7 @@
-@@ -57,142 +100,352 @@
+@@ -57,151 +91,382 @@
@@ -2424,7 +2418,9 @@
+ (否则会顶动 sticky 吸顶工具栏那一行)。--}}
+
+ 标签
-+
++ {{-- 实测:图标墨迹中心比文字高 0.5px(文字 90.0 / 图标 89.5,截图按像素量的),
++ 用 relative+top 精确压下去 0.5px。--}}
++
@@ -2440,11 +2436,16 @@
+ 清除筛选
+ {{-- 卡片角标开关:控制图库里图片上的标签显不显示,状态记在本地(默认显示) --}}
+
-+ {{-- 唯一的「标签管理」入口:新建 / 重命名 / 删除标签 + 给选中的图片打标,都在同一个窗口 --}}
-+
+
@@ -2739,7 +2740,7 @@
+ 可以现场增删,也可以直接输入新名字回车新建(JS 渲染 + 绑定)。 --}}
+
+
-+
++
+
+
+
@@ -2798,25 +2799,26 @@
+
+
标签管理
+
__hint__
-+
++ {{-- 新建标签放在首行(老师要求):进窗口第一眼就能建新标签 --}}
+
-+
++
+
+
++
+
+
+
-+
-+
-+
-+
+
+
+
+
+ {{-- 标签重命名的行内表单(在那一行下方就地展开,再点一次收起)。
+ 名称不写进模板 —— 由 JS 用 .val() 填,避免标签名里的引号/尖括号破坏属性。 --}}
+
-@@ -201,7 +454,8 @@
++
++
++
++
++ @push('styles')
++
++ @endpush
++
+ @push('scripts')
@@ -2850,7 +2865,7 @@
+