@co0ontty/wand 1.24.0 → 1.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,12 +121,55 @@
121
121
  }
122
122
  }
123
123
 
124
- /* ===== PWA 独立窗口模式 ===== */
125
- /* 顶部安全区:用 max() 保底,避免 iPad 横屏/Stage Manager 等 inset 为 0 的场景下贴顶,
126
- 同时为 iPadOS Stage Manager 浮动控件预留视觉缓冲 */
124
+ /* ===== 设备安全区 (notch / 状态栏 / 圆角) =====
125
+ 全局 --wand-safe-top/bottom/left/right 在所有上下文(PWA、Android APK 内嵌
126
+ WebView、普通移动浏览器、桌面) 中都可用。在没有 inset 的设备上回退到
127
+ 0px,所以不会影响桌面浏览体验。固定定位 (position: fixed) 的顶部元素
128
+ (如文件面板抽屉、各类预览/对话框) 必须自己消费这些 inset,因为它们脱离
129
+ 了 .app-container 的 padding 流。
130
+
131
+ 注: Android WebView (targetSdk >= 35 强制边到边渲染) 不会主动把
132
+ WindowInsets 暴露给 env(safe-area-inset-*), 所以纯 env() 在很多 Android
133
+ 机器上会回落到 0 -> 顶部抽屉/模态直接撞到状态栏。我们用 var(--app-inset-top)
134
+ (由 Android 端通过 JS 注入实测像素值) 作为优先来源, 再 fallback 到 env(),
135
+ 最后在窄视口下保证至少 28px 视觉缓冲。*/
136
+ :root {
137
+ --app-inset-top: 0px; /* Android side injects actual status-bar height here */
138
+ --app-inset-bottom: 0px;
139
+ --app-inset-left: 0px;
140
+ --app-inset-right: 0px;
141
+ --wand-safe-top: max(var(--app-inset-top), env(safe-area-inset-top, 0px));
142
+ --wand-safe-bottom: max(var(--app-inset-bottom), env(safe-area-inset-bottom, 0px));
143
+ --wand-safe-left: max(var(--app-inset-left), env(safe-area-inset-left, 0px));
144
+ --wand-safe-right: max(var(--app-inset-right), env(safe-area-inset-right, 0px));
145
+ --safe-bottom: var(--wand-safe-bottom);
146
+ /* 默认与 wand-safe-top 等价; PWA / .is-pwa 下被覆盖为 max(inset, 14px) */
147
+ --pwa-safe-top: var(--wand-safe-top);
148
+ }
149
+
150
+ /* Wand Android APK (UA 后缀 WandApp/*) 的兜底:
151
+ Android 自 targetSdk=35 起强制边到边, WebView 内容会绘制到状态栏底下,
152
+ 但 Android WebView 不会主动把 WindowInsets 暴露给 env(safe-area-inset-*),
153
+ 所以纯 env() 在绝大多数 Android 机器上回落到 0 -> 顶部直接撞到状态栏。
154
+ 这里给 Wand APK 兜一个 32px 最小值, 确保即使旧版 APK 还没装 inset 注入
155
+ 桥的时候, 顶部抽屉/模态也不会撞到状态栏。新版 APK 注入实际 inset 后,
156
+ max() 会自动取更精准的值。*/
157
+ .is-wand-app {
158
+ --wand-safe-top: max(var(--app-inset-top), env(safe-area-inset-top, 0px), 32px);
159
+ --wand-safe-bottom: max(var(--app-inset-bottom), env(safe-area-inset-bottom, 0px), 0px);
160
+ }
161
+
162
+ /* 在普通移动浏览器 / Android WebView 边到边渲染 / 旋转后地址栏隐藏等场景下,
163
+ .app-container 同样需要消费 safe-area-inset-top, 否则 .main-header-row
164
+ 会被状态栏挡住。inset 为 0 的设备上为 0px, 不影响桌面。*/
165
+ .app-container {
166
+ padding-top: var(--wand-safe-top);
167
+ }
168
+
169
+ /* PWA 独立窗口模式: 加一个最小 14px 的视觉缓冲, 避开 iPadOS Stage Manager
170
+ 浮动控件 / iOS 状态栏底色和 UI 太贴的视觉粘连。 */
127
171
  @media (display-mode: standalone) {
128
172
  :root {
129
- --safe-bottom: env(safe-area-inset-bottom, 0px);
130
173
  --pwa-safe-top: max(env(safe-area-inset-top, 0px), 14px);
131
174
  }
132
175
  .app-container {
@@ -143,7 +186,6 @@
143
186
 
144
187
  /* iOS Safari PWA fallback (navigator.standalone adds .is-pwa via JS) */
145
188
  .is-pwa {
146
- --safe-bottom: env(safe-area-inset-bottom, 0px);
147
189
  --pwa-safe-top: max(env(safe-area-inset-top, 0px), 14px);
148
190
  }
149
191
  .is-pwa .app-container {
@@ -175,6 +217,9 @@
175
217
  text-rendering: optimizeLegibility;
176
218
  min-height: 100%;
177
219
  height: 100%;
220
+ /* 兜底背景:iOS Safari 在键盘弹起 / 地址栏收起 / 安全区时
221
+ body 可能短于 html,露出的部分必须也是奶油色,否则会看到默认白底。 */
222
+ background-color: #f6f1e8;
178
223
  }
179
224
 
180
225
  body {
@@ -666,10 +711,10 @@
666
711
  .tree-children.open { display: block; }
667
712
 
668
713
  .file-explorer-header {
669
- padding: 10px 14px 8px;
714
+ padding: 10px 14px 6px;
670
715
  display: flex;
671
716
  align-items: center;
672
- gap: 8px;
717
+ gap: 6px;
673
718
  flex-shrink: 0;
674
719
  }
675
720
 
@@ -688,11 +733,11 @@
688
733
  /* When rendered as <input> (editable path) keep the same look but reveal
689
734
  an editable affordance on hover/focus. */
690
735
  input.file-explorer-path {
691
- background: transparent;
692
- border: 1px solid transparent;
693
- border-radius: var(--radius-sm);
694
- padding: 4px 8px;
695
- height: 28px;
736
+ background: var(--bg-secondary);
737
+ border: 1px solid var(--border-subtle);
738
+ border-radius: 8px;
739
+ padding: 6px 10px;
740
+ height: 30px;
696
741
  line-height: 1.2;
697
742
  cursor: text;
698
743
  transition: background-color var(--transition-fast),
@@ -708,7 +753,7 @@
708
753
  opacity: 0.6;
709
754
  }
710
755
  input.file-explorer-path:hover {
711
- background: rgba(255, 255, 255, 0.5);
756
+ background: var(--bg-primary);
712
757
  border-color: var(--border);
713
758
  color: var(--text-secondary);
714
759
  }
@@ -717,6 +762,7 @@
717
762
  border-color: var(--accent);
718
763
  color: var(--text-primary);
719
764
  text-overflow: clip;
765
+ box-shadow: 0 0 0 3px rgba(212, 152, 99, 0.12);
720
766
  }
721
767
 
722
768
  .file-explorer-actions { display: flex; gap: 4px; margin-left: auto; flex-shrink: 0; }
@@ -751,6 +797,10 @@
751
797
  display: flex;
752
798
  flex-direction: column;
753
799
  box-shadow: -4px 0 24px rgba(0, 0, 0, 0.1);
800
+ /* 抽屉是 position:fixed, 脱离了 app-container 的 padding, 必须自己消费
801
+ 状态栏 / notch 安全区, 否则 .file-side-panel-header 会被刘海/状态栏挡住。*/
802
+ padding-top: var(--wand-safe-top);
803
+ padding-bottom: var(--wand-safe-bottom);
754
804
  }
755
805
 
756
806
  .file-side-panel.open {
@@ -788,15 +838,95 @@
788
838
  display: flex;
789
839
  align-items: center;
790
840
  justify-content: space-between;
791
- padding: 12px 16px;
792
- border-bottom: 1px solid var(--border);
841
+ padding: 12px 14px 10px;
842
+ border-bottom: 1px solid var(--border-subtle);
793
843
  flex-shrink: 0;
844
+ gap: 8px;
845
+ background: linear-gradient(
846
+ to bottom,
847
+ rgba(255, 255, 255, 0.4),
848
+ rgba(255, 255, 255, 0)
849
+ );
850
+ }
851
+
852
+ .file-side-panel-title-group {
853
+ display: flex;
854
+ align-items: center;
855
+ gap: 8px;
856
+ min-width: 0;
857
+ flex: 1;
858
+ }
859
+
860
+ .file-side-panel-icon {
861
+ display: inline-flex;
862
+ align-items: center;
863
+ justify-content: center;
864
+ color: var(--accent);
865
+ opacity: 0.85;
794
866
  }
795
867
 
796
868
  .file-side-panel-title {
797
869
  font-size: 0.875rem;
798
870
  font-weight: 600;
799
871
  color: var(--text-primary);
872
+ letter-spacing: 0.01em;
873
+ }
874
+
875
+ .file-side-panel-header-actions {
876
+ display: flex;
877
+ align-items: center;
878
+ gap: 2px;
879
+ flex-shrink: 0;
880
+ }
881
+
882
+ .file-side-panel-iconbtn {
883
+ width: 30px;
884
+ height: 30px;
885
+ display: inline-flex;
886
+ align-items: center;
887
+ justify-content: center;
888
+ padding: 0;
889
+ background: transparent;
890
+ border: 1px solid transparent;
891
+ border-radius: 8px;
892
+ color: var(--text-muted);
893
+ cursor: pointer;
894
+ transition: background var(--transition-fast),
895
+ color var(--transition-fast),
896
+ border-color var(--transition-fast),
897
+ transform var(--transition-fast);
898
+ }
899
+
900
+ .file-side-panel-iconbtn:hover {
901
+ background: var(--bg-tertiary);
902
+ color: var(--text-primary);
903
+ border-color: var(--border-subtle);
904
+ }
905
+
906
+ .file-side-panel-iconbtn:active {
907
+ transform: scale(0.94);
908
+ }
909
+
910
+ .file-side-panel-iconbtn.active {
911
+ color: var(--accent);
912
+ background: var(--accent-muted);
913
+ border-color: rgba(212, 152, 99, 0.35);
914
+ }
915
+
916
+ .file-side-panel-iconbtn.close:hover {
917
+ color: var(--text-primary);
918
+ background: rgba(220, 70, 70, 0.08);
919
+ border-color: rgba(220, 70, 70, 0.25);
920
+ }
921
+
922
+ .file-side-panel-iconbtn .wand-icon {
923
+ display: block;
924
+ }
925
+
926
+ /* The refresh icon nudges with a subtle spin on hover to reinforce its purpose. */
927
+ .file-side-panel-iconbtn:hover .wand-icon-refresh {
928
+ transform: rotate(60deg);
929
+ transition: transform 0.25s var(--ease-out-expo);
800
930
  }
801
931
 
802
932
  .file-side-panel-body {
@@ -861,30 +991,44 @@
861
991
  }
862
992
 
863
993
  .file-search-box {
864
- padding: 8px 12px;
994
+ padding: 8px 12px 10px;
865
995
  display: flex;
866
996
  align-items: center;
867
- gap: 8px;
997
+ gap: 0;
868
998
  border-bottom: 1px solid var(--border-subtle);
869
999
  flex-shrink: 0;
1000
+ position: relative;
1001
+ }
1002
+
1003
+ .file-search-icon {
1004
+ position: absolute;
1005
+ left: 22px;
1006
+ top: 50%;
1007
+ transform: translateY(-50%);
1008
+ color: var(--text-muted);
1009
+ pointer-events: none;
1010
+ display: inline-flex;
1011
+ align-items: center;
1012
+ opacity: 0.7;
870
1013
  }
871
1014
 
872
1015
  .file-search-input {
873
1016
  flex: 1;
874
- padding: 6px 10px;
1017
+ padding: 7px 32px 7px 30px;
875
1018
  border: 1px solid var(--border);
876
- border-radius: 6px;
1019
+ border-radius: 8px;
877
1020
  font-size: 0.8125rem;
878
1021
  font-family: var(--font-sans);
879
1022
  background: var(--bg-secondary);
880
1023
  color: var(--text-primary);
881
1024
  outline: none;
882
- transition: border-color 0.15s ease;
1025
+ transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
883
1026
  }
884
1027
 
885
1028
  .file-search-input:focus {
886
1029
  border-color: var(--accent);
887
1030
  background: var(--bg-primary);
1031
+ box-shadow: 0 0 0 3px rgba(212, 152, 99, 0.12);
888
1032
  }
889
1033
 
890
1034
  .file-search-input::placeholder {
@@ -892,20 +1036,31 @@
892
1036
  }
893
1037
 
894
1038
  .file-search-clear {
1039
+ position: absolute;
1040
+ right: 18px;
1041
+ top: 50%;
1042
+ transform: translateY(-50%);
895
1043
  background: none;
896
1044
  border: none;
897
1045
  cursor: pointer;
898
- font-size: 1rem;
899
1046
  padding: 4px;
900
- border-radius: 4px;
1047
+ width: 22px;
1048
+ height: 22px;
1049
+ border-radius: 50%;
901
1050
  color: var(--text-muted);
902
1051
  display: none;
903
1052
  align-items: center;
904
1053
  justify-content: center;
1054
+ transition: background 0.15s ease, color 0.15s ease;
1055
+ }
1056
+
1057
+ .file-search-clear:hover {
1058
+ background: var(--bg-tertiary);
1059
+ color: var(--text-primary);
905
1060
  }
906
1061
 
907
1062
  .file-search-clear.visible {
908
- display: flex;
1063
+ display: inline-flex;
909
1064
  }
910
1065
 
911
1066
  .file-search-clear:hover {
@@ -6712,7 +6867,11 @@
6712
6867
  display: flex;
6713
6868
  align-items: center;
6714
6869
  justify-content: center;
6715
- padding: 32px;
6870
+ /* 给安全区让位, 避免 iPhone notch / Dynamic Island / 横屏圆角切到模态内容 */
6871
+ padding-top: max(32px, var(--wand-safe-top));
6872
+ padding-bottom: max(32px, var(--wand-safe-bottom));
6873
+ padding-left: max(32px, var(--wand-safe-left));
6874
+ padding-right: max(32px, var(--wand-safe-right));
6716
6875
  animation: liquidBackdropIn 0.28s var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1)) both;
6717
6876
  }
6718
6877
 
@@ -8237,6 +8396,10 @@
8237
8396
  .app-container {
8238
8397
  min-height: 100dvh;
8239
8398
  height: 100dvh;
8399
+ /* 与 body 同步:键盘弹起时 JS 注入 --app-viewport-height,
8400
+ app-container 跟随 visualViewport 收缩,input-panel 自动贴键盘上沿;
8401
+ 键盘收起后变量被移除,回到 100dvh,input-panel 自然回到屏幕底部。 */
8402
+ height: var(--app-viewport-height, 100dvh);
8240
8403
  overflow: hidden;
8241
8404
  }
8242
8405
 
@@ -8378,7 +8541,11 @@
8378
8541
  padding-bottom: calc(6px + var(--safe-bottom, 0px) + var(--keyboard-offset, 0px));
8379
8542
  flex: 0 0 auto;
8380
8543
  margin-top: auto;
8381
- background: linear-gradient(180deg, rgba(246, 241, 232, 0.5) 0%, rgba(246, 241, 232, 0.88) 30%, rgba(246, 241, 232, 0.96) 100%);
8544
+ /* 渐变只覆盖上半段做平滑过渡,下半段用纯色铺满 safe-area 区域,
8545
+ 避免 iOS Safari 在 home indicator / 安全区域露出 html 背景。 */
8546
+ background:
8547
+ linear-gradient(180deg, rgba(246, 241, 232, 0.5) 0%, rgba(246, 241, 232, 0.88) 30%, #f6f1e8 100%),
8548
+ #f6f1e8;
8382
8549
  backdrop-filter: blur(12px);
8383
8550
  }
8384
8551
 
@@ -8706,6 +8873,9 @@
8706
8873
  /* 模态框移动端优化 */
8707
8874
  .modal-backdrop {
8708
8875
  padding: 8px;
8876
+ padding-top: max(8px, var(--wand-safe-top));
8877
+ padding-left: max(8px, var(--wand-safe-left));
8878
+ padding-right: max(8px, var(--wand-safe-right));
8709
8879
  align-items: flex-end;
8710
8880
  }
8711
8881
 
@@ -8729,10 +8899,14 @@
8729
8899
  /* 文件面板 */
8730
8900
  .main-content.file-panel-open { margin-right: 0; }
8731
8901
  .file-side-panel { width: 100%; }
8732
- .file-side-panel-header { padding: 6px 8px; min-height: 36px; }
8733
- .file-explorer-header { padding: 4px 6px; }
8734
- .file-search-box { padding: 4px; }
8735
- .file-search-input { min-height: 32px; font-size: 14px; }
8902
+ .file-side-panel-header { padding: 10px 12px; min-height: 48px; }
8903
+ .file-side-panel-iconbtn { width: 34px; height: 34px; }
8904
+ .file-explorer-header { padding: 6px 10px 4px; gap: 6px; }
8905
+ .file-explorer-up { width: 32px; height: 32px; }
8906
+ .file-search-box { padding: 6px 10px 8px; }
8907
+ .file-search-icon { left: 20px; }
8908
+ .file-search-clear { right: 16px; }
8909
+ .file-search-input { min-height: 34px; font-size: 14px; padding: 7px 32px 7px 30px; }
8736
8910
  .file-item { padding: 6px 8px; min-height: 32px; }
8737
8911
 
8738
8912
  /* 欢迎页移动端 */
@@ -10685,12 +10859,16 @@
10685
10859
  flex-shrink: 0;
10686
10860
  }
10687
10861
  .file-preview-toolbar-btn {
10688
- padding: 4px 6px;
10862
+ padding: 0 6px;
10689
10863
  font-size: 0.75rem;
10690
10864
  }
10691
10865
  .file-preview-close {
10692
- font-size: 1.375rem;
10693
- padding: 6px 10px;
10866
+ width: 34px;
10867
+ height: 34px;
10868
+ padding: 0;
10869
+ }
10870
+ .file-preview-icon {
10871
+ font-size: 1.125rem;
10694
10872
  }
10695
10873
  /* 底部安全区(小白条 / 圆角) */
10696
10874
  .file-preview-body {
@@ -10702,8 +10880,8 @@
10702
10880
  display: flex;
10703
10881
  align-items: center;
10704
10882
  gap: 12px;
10705
- padding: 10px 16px;
10706
- border-bottom: 1px solid var(--border);
10883
+ padding: 12px 18px;
10884
+ border-bottom: 1px solid var(--border-subtle);
10707
10885
  background: var(--bg-secondary);
10708
10886
  flex-shrink: 0;
10709
10887
  }
@@ -10711,57 +10889,114 @@
10711
10889
  .file-preview-title {
10712
10890
  display: flex;
10713
10891
  align-items: center;
10714
- gap: 8px;
10892
+ gap: 10px;
10715
10893
  font-size: 0.9375rem;
10716
10894
  font-weight: 600;
10717
10895
  color: var(--text-primary);
10896
+ flex: 1;
10897
+ min-width: 0;
10898
+ }
10899
+
10900
+ .file-preview-icon {
10901
+ font-size: 1.25rem;
10902
+ line-height: 1;
10718
10903
  flex-shrink: 0;
10719
10904
  }
10720
10905
 
10906
+ .file-preview-name-block {
10907
+ display: flex;
10908
+ flex-direction: column;
10909
+ gap: 2px;
10910
+ min-width: 0;
10911
+ flex: 1;
10912
+ }
10913
+
10914
+ .file-preview-name-row {
10915
+ display: flex;
10916
+ align-items: baseline;
10917
+ gap: 8px;
10918
+ min-width: 0;
10919
+ }
10920
+
10721
10921
  .file-preview-filename {
10722
10922
  overflow: hidden;
10723
10923
  text-overflow: ellipsis;
10724
10924
  white-space: nowrap;
10925
+ font-size: 0.9375rem;
10926
+ font-weight: 600;
10927
+ color: var(--text-primary);
10928
+ letter-spacing: 0.01em;
10929
+ min-width: 0;
10725
10930
  }
10726
10931
 
10727
10932
  .file-preview-path {
10728
- font-size: 0.75rem;
10933
+ font-size: 0.7rem;
10729
10934
  color: var(--text-muted);
10730
10935
  font-family: var(--font-mono);
10731
10936
  overflow: hidden;
10732
10937
  text-overflow: ellipsis;
10733
10938
  white-space: nowrap;
10734
- flex: 1;
10735
10939
  min-width: 0;
10736
- margin: 0 12px;
10940
+ opacity: 0.8;
10941
+ }
10942
+
10943
+ .file-preview-dirty {
10944
+ font-size: 0.6875rem;
10945
+ color: #c66a1a;
10946
+ font-weight: 600;
10947
+ letter-spacing: 0.02em;
10948
+ flex-shrink: 0;
10949
+ padding: 1px 8px;
10950
+ background: rgba(198, 106, 26, 0.1);
10951
+ border: 1px solid rgba(198, 106, 26, 0.25);
10952
+ border-radius: 999px;
10953
+ animation: dirty-pulse 1.6s ease-in-out infinite;
10954
+ }
10955
+
10956
+ @keyframes dirty-pulse {
10957
+ 0%, 100% { opacity: 0.65; }
10958
+ 50% { opacity: 1; }
10737
10959
  }
10738
10960
 
10739
10961
  .file-preview-lang {
10740
- font-size: 0.75rem;
10741
- font-weight: 500;
10962
+ font-size: 0.6875rem;
10963
+ font-weight: 600;
10742
10964
  padding: 2px 8px;
10743
- border-radius: 4px;
10744
- background: var(--bg-tertiary);
10745
- color: var(--text-secondary);
10746
- border: 1px solid var(--border);
10965
+ border-radius: 999px;
10966
+ background: var(--accent-muted);
10967
+ color: var(--accent);
10968
+ border: 1px solid rgba(212, 152, 99, 0.3);
10969
+ letter-spacing: 0.04em;
10970
+ text-transform: uppercase;
10971
+ flex-shrink: 0;
10972
+ align-self: center;
10747
10973
  }
10748
10974
 
10749
10975
  .file-preview-close {
10750
10976
  background: none;
10751
- border: none;
10752
- font-size: 1.25rem;
10977
+ border: 1px solid transparent;
10753
10978
  cursor: pointer;
10754
10979
  color: var(--text-muted);
10755
- padding: 4px 8px;
10756
- border-radius: var(--radius-sm);
10757
- transition: background 0.15s, color 0.15s;
10980
+ width: 32px;
10981
+ height: 32px;
10982
+ padding: 0;
10983
+ border-radius: 8px;
10984
+ display: inline-flex;
10985
+ align-items: center;
10986
+ justify-content: center;
10987
+ transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.15s;
10758
10988
  line-height: 1;
10759
10989
  flex-shrink: 0;
10760
10990
  }
10761
10991
 
10762
10992
  .file-preview-close:hover {
10763
- background: var(--bg-tertiary);
10993
+ background: rgba(220, 70, 70, 0.08);
10764
10994
  color: var(--text-primary);
10995
+ border-color: rgba(220, 70, 70, 0.25);
10996
+ }
10997
+
10998
+ .file-preview-close:active {
10999
+ transform: scale(0.94);
10765
11000
  }
10766
11001
 
10767
11002
  .file-preview-body {
@@ -11078,31 +11313,31 @@
11078
11313
  }
11079
11314
 
11080
11315
  /* ── File explorer header extras ── */
11081
- .file-explorer-up,
11082
- .file-explorer-toggle-hidden {
11083
- background: none;
11084
- border: none;
11316
+ .file-explorer-up {
11317
+ background: transparent;
11318
+ border: 1px solid transparent;
11085
11319
  cursor: pointer;
11086
- font-size: 1rem;
11087
- padding: 4px;
11088
- width: 28px;
11089
- height: 28px;
11090
- border-radius: 6px;
11320
+ padding: 0;
11321
+ width: 30px;
11322
+ height: 30px;
11323
+ border-radius: 8px;
11091
11324
  color: var(--text-muted);
11092
- display: flex;
11325
+ display: inline-flex;
11093
11326
  align-items: center;
11094
11327
  justify-content: center;
11095
- transition: background var(--transition-fast), color var(--transition-fast);
11328
+ transition: background var(--transition-fast),
11329
+ color var(--transition-fast),
11330
+ border-color var(--transition-fast),
11331
+ transform var(--transition-fast);
11096
11332
  flex-shrink: 0;
11097
11333
  }
11098
- .file-explorer-up:hover,
11099
- .file-explorer-toggle-hidden:hover {
11334
+ .file-explorer-up:hover {
11100
11335
  background: var(--bg-tertiary);
11101
- color: var(--text-secondary);
11336
+ color: var(--text-primary);
11337
+ border-color: var(--border-subtle);
11102
11338
  }
11103
- .file-explorer-toggle-hidden.active {
11104
- color: var(--accent);
11105
- background: var(--accent-muted);
11339
+ .file-explorer-up:active {
11340
+ transform: translateY(-1px);
11106
11341
  }
11107
11342
 
11108
11343
  /* ── File tree size/meta column ── */
@@ -11194,29 +11429,127 @@
11194
11429
  margin-left: 8px;
11195
11430
  }
11196
11431
  .file-preview-toolbar-btn {
11197
- background: none;
11198
- border: 1px solid transparent;
11432
+ background: var(--bg-primary);
11433
+ border: 1px solid var(--border-subtle);
11199
11434
  cursor: pointer;
11200
- padding: 4px 8px;
11201
- min-width: 32px;
11202
- height: 28px;
11203
- border-radius: 6px;
11204
- color: var(--text-muted);
11435
+ padding: 0 8px;
11436
+ min-width: 30px;
11437
+ height: 30px;
11438
+ gap: 6px;
11439
+ border-radius: 8px;
11440
+ color: var(--text-secondary);
11205
11441
  font-size: 0.75rem;
11206
11442
  display: inline-flex;
11207
11443
  align-items: center;
11208
11444
  justify-content: center;
11209
- transition: background 0.15s, color 0.15s, border-color 0.15s;
11445
+ transition: background 0.15s, color 0.15s, border-color 0.15s,
11446
+ box-shadow 0.15s, transform 0.1s;
11210
11447
  }
11211
11448
  .file-preview-toolbar-btn:hover {
11212
11449
  background: var(--bg-tertiary);
11213
11450
  color: var(--text-primary);
11214
11451
  border-color: var(--border);
11452
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
11453
+ }
11454
+ .file-preview-toolbar-btn:active {
11455
+ transform: scale(0.95);
11456
+ }
11457
+ .file-preview-toolbar-btn:disabled {
11458
+ opacity: 0.5;
11459
+ cursor: not-allowed;
11460
+ transform: none;
11461
+ }
11462
+ .file-preview-toolbar-btn .toolbar-icon {
11463
+ display: inline-flex;
11464
+ align-items: center;
11465
+ justify-content: center;
11466
+ }
11467
+ .file-preview-toolbar-btn .toolbar-text {
11468
+ font-weight: 600;
11469
+ letter-spacing: 0.01em;
11215
11470
  }
11216
11471
  .file-preview-toolbar-btn.toolbar-active {
11217
11472
  background: var(--accent-muted);
11218
11473
  color: var(--accent);
11474
+ border-color: rgba(212, 152, 99, 0.4);
11475
+ }
11476
+ .file-preview-toolbar-btn.primary {
11477
+ background: var(--accent);
11478
+ color: #fff;
11219
11479
  border-color: var(--accent);
11480
+ box-shadow: 0 1px 2px rgba(89, 58, 32, 0.15);
11481
+ }
11482
+ .file-preview-toolbar-btn.primary:hover {
11483
+ background: #b87a47;
11484
+ border-color: #b87a47;
11485
+ color: #fff;
11486
+ box-shadow: 0 2px 6px rgba(89, 58, 32, 0.2);
11487
+ }
11488
+ .file-preview-toolbar-btn.danger {
11489
+ color: #c0392b;
11490
+ }
11491
+ .file-preview-toolbar-btn.danger:hover {
11492
+ background: rgba(220, 70, 70, 0.08);
11493
+ border-color: rgba(220, 70, 70, 0.3);
11494
+ color: #a02818;
11495
+ }
11496
+
11497
+ /* Grouped chip (e.g. font-size −/+ combo) */
11498
+ .file-preview-toolbar-group {
11499
+ display: inline-flex;
11500
+ align-items: stretch;
11501
+ border: 1px solid var(--border-subtle);
11502
+ border-radius: 8px;
11503
+ overflow: hidden;
11504
+ background: var(--bg-primary);
11505
+ }
11506
+ .file-preview-toolbar-group .file-preview-toolbar-btn {
11507
+ border: none;
11508
+ border-radius: 0;
11509
+ background: transparent;
11510
+ min-width: 28px;
11511
+ height: 28px;
11512
+ box-shadow: none;
11513
+ }
11514
+ .file-preview-toolbar-group .file-preview-toolbar-btn:hover {
11515
+ background: var(--bg-tertiary);
11516
+ }
11517
+ .file-preview-toolbar-grouplabel {
11518
+ display: inline-flex;
11519
+ align-items: center;
11520
+ justify-content: center;
11521
+ padding: 0 6px;
11522
+ color: var(--text-muted);
11523
+ border-left: 1px solid var(--border-subtle);
11524
+ border-right: 1px solid var(--border-subtle);
11525
+ background: var(--bg-secondary);
11526
+ }
11527
+
11528
+ /* In edit mode the toolbar shows only save / revert / cancel; emphasize the
11529
+ primary save action visually. */
11530
+ .file-preview-toolbar.editing {
11531
+ gap: 6px;
11532
+ }
11533
+
11534
+ /* Mobile: shrink toolbar buttons a hair so they fit. */
11535
+ @media (max-width: 768px) {
11536
+ .file-preview-toolbar-btn {
11537
+ height: 28px;
11538
+ min-width: 28px;
11539
+ padding: 0 6px;
11540
+ }
11541
+ .file-preview-toolbar-btn .toolbar-text {
11542
+ display: none;
11543
+ }
11544
+ .file-preview-toolbar-btn.primary .toolbar-text {
11545
+ display: inline-flex;
11546
+ }
11547
+ }
11548
+
11549
+ /* ── Inline file-icon glyph (header) ── */
11550
+ .wand-icon {
11551
+ flex-shrink: 0;
11552
+ vertical-align: middle;
11220
11553
  }
11221
11554
 
11222
11555
  /* ── Code preview wrap mode ── */
@@ -11225,6 +11558,50 @@
11225
11558
  word-break: break-word;
11226
11559
  }
11227
11560
 
11561
+ /* ── Code editor (inline file edit mode) ── */
11562
+ .file-preview-body.editing {
11563
+ padding: 0;
11564
+ background: var(--bg-primary);
11565
+ }
11566
+ .code-editor-wrapper {
11567
+ display: flex;
11568
+ width: 100%;
11569
+ height: 100%;
11570
+ min-height: 0;
11571
+ background: var(--bg-primary);
11572
+ }
11573
+ .code-editor-textarea {
11574
+ flex: 1;
11575
+ width: 100%;
11576
+ height: 100%;
11577
+ min-height: 0;
11578
+ box-sizing: border-box;
11579
+ padding: 16px 20px;
11580
+ margin: 0;
11581
+ border: none;
11582
+ outline: none;
11583
+ resize: none;
11584
+ font-family: var(--font-mono);
11585
+ font-size: var(--font-size-sm);
11586
+ line-height: var(--line-height);
11587
+ color: var(--text-primary);
11588
+ background: var(--bg-primary);
11589
+ tab-size: 2;
11590
+ -moz-tab-size: 2;
11591
+ white-space: pre;
11592
+ overflow: auto;
11593
+ caret-color: var(--accent);
11594
+ scrollbar-width: thin;
11595
+ scrollbar-color: var(--border-default) transparent;
11596
+ }
11597
+ .code-editor-textarea::-webkit-scrollbar { width: 8px; height: 8px; }
11598
+ .code-editor-textarea::-webkit-scrollbar-track { background: transparent; }
11599
+ .code-editor-textarea::-webkit-scrollbar-thumb { background: var(--border-default); border-radius: 4px; }
11600
+ .code-editor-textarea::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
11601
+ .code-editor-textarea:focus {
11602
+ box-shadow: inset 0 0 0 2px rgba(212, 152, 99, 0.15);
11603
+ }
11604
+
11228
11605
  /* ── Image preview ── */
11229
11606
  .file-preview-body.kind-image {
11230
11607
  display: flex;
@@ -13168,7 +13545,11 @@
13168
13545
  display: flex;
13169
13546
  align-items: center;
13170
13547
  justify-content: center;
13171
- padding: 24px;
13548
+ /* 给安全区让位, 避免对话框在 iPhone 横屏 / 小屏被刘海或 Home Indicator 切到 */
13549
+ padding-top: max(24px, var(--wand-safe-top));
13550
+ padding-bottom: max(24px, var(--wand-safe-bottom));
13551
+ padding-left: max(24px, var(--wand-safe-left));
13552
+ padding-right: max(24px, var(--wand-safe-right));
13172
13553
  background: rgba(20, 14, 8, 0.34);
13173
13554
  backdrop-filter: blur(18px) saturate(140%);
13174
13555
  -webkit-backdrop-filter: blur(18px) saturate(140%);