4b0504ad by 柴进

fix(ui): caption 重叠问题 + 加截图工具

- caption (生成模式/宽高比/图片尺寸 等) 改用 make_field_group helper:
  组内 caption + control 间距锁死 6px,组高度 fixed = 22+6+34 = 62px
  解决 Qt QSS setStyleSheet 改字号不更新 sizeHint 导致的 caption 文字溢出到下方 widget 的坑
- caption 字号 11pt → 12pt,font-weight DemiBold,颜色 text_primary,视觉权重和 combo 拉开
- settings_layout 间距 18px(组与组之间)
- 主窗口最小尺寸 1180x820,避免压缩破坏 layout
- ImageGeneratorWindow 和 StyleDesignerTab 同步迁移
- capture_window.py:按窗口标题 PrintWindow 截图工具,迭代 UI 时不再依赖手动截图

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8938af9d
1 """按窗口标题截图。
2
3 用法:
4 python capture_window.py <title-substring> [output.png]
5
6 例:
7 python capture_window.py 珠宝壹佰 shot.png
8 python capture_window.py 登录 login.png
9
10 依赖:Pillow(项目已装),ctypes(标准库)。
11 仅 Windows。
12 """
13 import ctypes
14 import sys
15 from ctypes import wintypes
16 from pathlib import Path
17 from PIL import ImageGrab
18
19 user32 = ctypes.windll.user32
20 EnumWindowsProc = ctypes.WINFUNCTYPE(
21 ctypes.c_bool, wintypes.HWND, wintypes.LPARAM
22 )
23
24
25 def _get_window_text(hwnd):
26 length = user32.GetWindowTextLengthW(hwnd)
27 if length == 0:
28 return ""
29 buf = ctypes.create_unicode_buffer(length + 1)
30 user32.GetWindowTextW(hwnd, buf, length + 1)
31 return buf.value
32
33
34 _PROCESS_NAME_CACHE = {}
35
36
37 def _get_process_name(pid: int) -> str:
38 """通过 pid 拿到进程可执行文件名(小写,不含路径)。"""
39 if pid in _PROCESS_NAME_CACHE:
40 return _PROCESS_NAME_CACHE[pid]
41 PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
42 kernel32 = ctypes.windll.kernel32
43 psapi = ctypes.windll.psapi
44 h = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
45 if not h:
46 _PROCESS_NAME_CACHE[pid] = ""
47 return ""
48 try:
49 buf = ctypes.create_unicode_buffer(260)
50 size = wintypes.DWORD(260)
51 if kernel32.QueryFullProcessImageNameW(h, 0, buf, ctypes.byref(size)):
52 name = buf.value.split("\\")[-1].lower()
53 else:
54 name = ""
55 finally:
56 kernel32.CloseHandle(h)
57 _PROCESS_NAME_CACHE[pid] = name
58 return name
59
60
61 def find_window(title_substring: str, exe_filter: tuple = ("pythonw.exe", "python.exe", "zb100imagegenerator.exe")):
62 """返回首个标题包含 title_substring 且属于 exe_filter 进程的可见窗口 hwnd。"""
63 found = []
64
65 def callback(hwnd, lparam):
66 if not user32.IsWindowVisible(hwnd):
67 return True
68 text = _get_window_text(hwnd)
69 if title_substring not in text:
70 return True
71 # 检查进程
72 pid = wintypes.DWORD()
73 user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
74 name = _get_process_name(pid.value)
75 if name in exe_filter:
76 found.append((hwnd, text))
77 return False # 停止枚举
78 return True
79
80 user32.EnumWindows(EnumWindowsProc(callback), 0)
81 return found[0] if found else None
82
83
84 def get_window_bbox(hwnd):
85 """获取窗口外接矩形(含标题栏 / 边框)。"""
86 rect = wintypes.RECT()
87 # DWMWA_EXTENDED_FRAME_BOUNDS = 9,能避开 Win10/11 的不可见 shadow border
88 DWMWA_EXTENDED_FRAME_BOUNDS = 9
89 dwmapi = ctypes.windll.dwmapi
90 res = dwmapi.DwmGetWindowAttribute(
91 wintypes.HWND(hwnd),
92 ctypes.c_uint(DWMWA_EXTENDED_FRAME_BOUNDS),
93 ctypes.byref(rect),
94 ctypes.sizeof(rect),
95 )
96 if res != 0:
97 # 回退到 GetWindowRect
98 user32.GetWindowRect(hwnd, ctypes.byref(rect))
99 return (rect.left, rect.top, rect.right, rect.bottom)
100
101
102 def main():
103 if len(sys.argv) < 2:
104 print(__doc__)
105 sys.exit(1)
106
107 title = sys.argv[1]
108 output = Path(sys.argv[2] if len(sys.argv) > 2 else "shot.png").resolve()
109
110 hit = find_window(title)
111 if not hit:
112 print(f"找不到标题包含 '{title}' 的窗口", file=sys.stderr)
113 sys.exit(2)
114 hwnd, full_title = hit
115
116 # 用 PrintWindow 直接从窗口拿位图,不需要把窗口提前(避免打断用户)
117 bbox = get_window_bbox(hwnd)
118 width = bbox[2] - bbox[0]
119 height = bbox[3] - bbox[1]
120
121 img = _print_window_to_pil(hwnd, width, height)
122 if img is None:
123 # 回退:把窗口提前再截屏
124 import time
125 user32.ShowWindow(hwnd, 9) # SW_RESTORE
126 user32.SetForegroundWindow(hwnd)
127 # 顶置-取消顶置技巧绕开 Windows 前台限制
128 HWND_TOPMOST = -1
129 HWND_NOTOPMOST = -2
130 SWP_NOMOVE = 0x0002
131 SWP_NOSIZE = 0x0001
132 user32.SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
133 user32.SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
134 time.sleep(0.5)
135 img = ImageGrab.grab(bbox=bbox, all_screens=True)
136
137 img.save(output)
138 print(f"OK hwnd={hwnd} title={full_title!r} size={width}x{height} -> {output}")
139
140
141 def _print_window_to_pil(hwnd, width, height):
142 """用 PrintWindow API 从窗口直接拿位图(不依赖窗口在前台)。"""
143 from PIL import Image
144 gdi32 = ctypes.windll.gdi32
145
146 hdcWindow = user32.GetDC(hwnd)
147 hdcMem = gdi32.CreateCompatibleDC(hdcWindow)
148 hbm = gdi32.CreateCompatibleBitmap(hdcWindow, width, height)
149 gdi32.SelectObject(hdcMem, hbm)
150
151 PW_RENDERFULLCONTENT = 0x00000002
152 ok = user32.PrintWindow(hwnd, hdcMem, PW_RENDERFULLCONTENT)
153
154 if ok:
155 # 提取位图数据
156 class BITMAPINFOHEADER(ctypes.Structure):
157 _fields_ = [
158 ("biSize", wintypes.DWORD),
159 ("biWidth", wintypes.LONG),
160 ("biHeight", wintypes.LONG),
161 ("biPlanes", wintypes.WORD),
162 ("biBitCount", wintypes.WORD),
163 ("biCompression", wintypes.DWORD),
164 ("biSizeImage", wintypes.DWORD),
165 ("biXPelsPerMeter", wintypes.LONG),
166 ("biYPelsPerMeter", wintypes.LONG),
167 ("biClrUsed", wintypes.DWORD),
168 ("biClrImportant", wintypes.DWORD),
169 ]
170
171 class BITMAPINFO(ctypes.Structure):
172 _fields_ = [("bmiHeader", BITMAPINFOHEADER), ("bmiColors", wintypes.DWORD * 3)]
173
174 bmi = BITMAPINFO()
175 bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
176 bmi.bmiHeader.biWidth = width
177 bmi.bmiHeader.biHeight = -height # top-down
178 bmi.bmiHeader.biPlanes = 1
179 bmi.bmiHeader.biBitCount = 32
180 bmi.bmiHeader.biCompression = 0 # BI_RGB
181
182 buf_len = width * height * 4
183 buf = (ctypes.c_ubyte * buf_len)()
184 gdi32.GetDIBits(hdcMem, hbm, 0, height, buf, ctypes.byref(bmi), 0)
185 img = Image.frombuffer("RGBA", (width, height), bytes(buf), "raw", "BGRA", 0, 1).convert("RGB")
186 else:
187 img = None
188
189 gdi32.DeleteObject(hbm)
190 gdi32.DeleteDC(hdcMem)
191 user32.ReleaseDC(hwnd, hdcWindow)
192
193 return img
194
195
196 if __name__ == "__main__":
197 main()
...@@ -1527,6 +1527,34 @@ class LoginDialog(QDialog): ...@@ -1527,6 +1527,34 @@ class LoginDialog(QDialog):
1527 THUMB_REORDER_MIME = "application/x-zb100-thumb-index" 1527 THUMB_REORDER_MIME = "application/x-zb100-thumb-index"
1528 1528
1529 1529
1530 def make_caption_label(text: str) -> QLabel:
1531 """构造 caption 风格 label(设置区上方的小标签)。"""
1532 lbl = QLabel(text)
1533 lbl.setProperty("role", "caption")
1534 f = QFont()
1535 f.setPointSize(12)
1536 f.setWeight(QFont.Weight.DemiBold)
1537 lbl.setFont(f)
1538 lbl.setFixedHeight(22)
1539 return lbl
1540
1541
1542 def make_field_group(caption_text: str, control: QWidget) -> QWidget:
1543 """把一个 caption + 控件打包成独立 widget,组内间距锁死 6px。
1544 每组高度 = 22 (caption) + 6 (spacing) + 34 (control) = 62px,硬锁。
1545 """
1546 # 锁住 control 高度(FixedHeight 让 sizeHint = 34,layout 不能压缩)
1547 control.setFixedHeight(34)
1548 w = QWidget()
1549 w.setFixedHeight(22 + 6 + 34) # 锁死整个组高度
1550 layout = QVBoxLayout(w)
1551 layout.setContentsMargins(0, 0, 0, 0)
1552 layout.setSpacing(6)
1553 layout.addWidget(make_caption_label(caption_text))
1554 layout.addWidget(control)
1555 return w
1556
1557
1530 class DraggableThumbnail(QWidget): 1558 class DraggableThumbnail(QWidget):
1531 """可拖拽重排序的缩略图容器""" 1559 """可拖拽重排序的缩略图容器"""
1532 1560
...@@ -1944,8 +1972,8 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -1944,8 +1972,8 @@ class ImageGeneratorWindow(QMainWindow):
1944 def setup_ui(self): 1972 def setup_ui(self):
1945 """Setup the user interface""" 1973 """Setup the user interface"""
1946 self.setWindowTitle("珠宝壹佰图像生成器") 1974 self.setWindowTitle("珠宝壹佰图像生成器")
1947 self.setGeometry(100, 100, 1200, 850) 1975 self.setGeometry(100, 100, 1280, 880)
1948 self.setMinimumSize(1000, 700) 1976 self.setMinimumSize(1180, 820)
1949 1977
1950 # Central widget 1978 # Central widget
1951 central_widget = QWidget() 1979 central_widget = QWidget()
...@@ -2096,19 +2124,16 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2096,19 +2124,16 @@ class ImageGeneratorWindow(QMainWindow):
2096 # Settings section 2124 # Settings section
2097 settings_group = QGroupBox("生成设置") 2125 settings_group = QGroupBox("生成设置")
2098 settings_layout = QVBoxLayout() 2126 settings_layout = QVBoxLayout()
2127 settings_layout.setSpacing(18)
2099 2128
2100 # 生成模式(放在最前面) 2129 # 生成模式(放在最前面)
2101 settings_layout.addWidget(QLabel("生成模式"))
2102 self.generation_mode = QComboBox() 2130 self.generation_mode = QComboBox()
2103 self.generation_mode.addItems(["极速模式", "慢速模式"]) 2131 self.generation_mode.addItems(["极速模式", "慢速模式"])
2104 self.generation_mode.setCurrentIndex(0) # Default to 极速模式 2132 self.generation_mode.setCurrentIndex(0) # Default to 极速模式
2105 self.generation_mode.currentIndexChanged.connect(self.on_generation_mode_changed) 2133 self.generation_mode.currentIndexChanged.connect(self.on_generation_mode_changed)
2106 settings_layout.addWidget(self.generation_mode) 2134 settings_layout.addWidget(make_field_group("生成模式", self.generation_mode))
2107
2108 settings_layout.addSpacing(10)
2109 2135
2110 # 宽高比 2136 # 宽高比
2111 settings_layout.addWidget(QLabel("宽高比"))
2112 self.aspect_ratio = QComboBox() 2137 self.aspect_ratio = QComboBox()
2113 self.aspect_ratio.addItems([ 2138 self.aspect_ratio.addItems([
2114 "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", 2139 "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9",
...@@ -2118,19 +2143,14 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2118,19 +2143,14 @@ class ImageGeneratorWindow(QMainWindow):
2118 # 记录上一次值用于用户拒绝切换模式时回滚,避免留在一个无法提交的状态 2143 # 记录上一次值用于用户拒绝切换模式时回滚,避免留在一个无法提交的状态
2119 self._prev_aspect_ratio = self.aspect_ratio.currentText() 2144 self._prev_aspect_ratio = self.aspect_ratio.currentText()
2120 self.aspect_ratio.currentTextChanged.connect(self._on_aspect_ratio_changed) 2145 self.aspect_ratio.currentTextChanged.connect(self._on_aspect_ratio_changed)
2121 settings_layout.addWidget(self.aspect_ratio) 2146 settings_layout.addWidget(make_field_group("宽高比", self.aspect_ratio))
2122
2123 settings_layout.addSpacing(10)
2124 2147
2125 # 图片尺寸 2148 # 图片尺寸
2126 settings_layout.addWidget(QLabel("图片尺寸"))
2127 self.image_size = QComboBox() 2149 self.image_size = QComboBox()
2128 self.image_size.addItems(["1K", "2K", "4K"]) 2150 self.image_size.addItems(["1K", "2K", "4K"])
2129 self.image_size.setCurrentIndex(0) # Default to 1K for 极速模式 2151 self.image_size.setCurrentIndex(0) # Default to 1K for 极速模式
2130 self.image_size.currentIndexChanged.connect(self.on_image_size_changed) 2152 self.image_size.currentIndexChanged.connect(self.on_image_size_changed)
2131 settings_layout.addWidget(self.image_size) 2153 settings_layout.addWidget(make_field_group("图片尺寸", self.image_size))
2132
2133 settings_layout.addSpacing(10)
2134 2154
2135 settings_layout.addStretch() 2155 settings_layout.addStretch()
2136 settings_group.setLayout(settings_layout) 2156 settings_group.setLayout(settings_layout)
...@@ -4085,23 +4105,16 @@ class StyleDesignerTab(QWidget): ...@@ -4085,23 +4105,16 @@ class StyleDesignerTab(QWidget):
4085 # Settings section 4105 # Settings section
4086 settings_group = QGroupBox("生成设置") 4106 settings_group = QGroupBox("生成设置")
4087 settings_layout = QVBoxLayout() 4107 settings_layout = QVBoxLayout()
4108 settings_layout.setSpacing(18)
4088 4109
4089 # 生成模式(放在最前面) 4110 # 生成模式(放在最前面)
4090 mode_label = QLabel("生成模式")
4091 mode_label.setProperty("role", "caption")
4092 settings_layout.addWidget(mode_label)
4093 self.generation_mode = QComboBox() 4111 self.generation_mode = QComboBox()
4094 self.generation_mode.addItems(["极速模式", "慢速模式"]) 4112 self.generation_mode.addItems(["极速模式", "慢速模式"])
4095 self.generation_mode.setCurrentIndex(0) # Default to 极速模式 4113 self.generation_mode.setCurrentIndex(0) # Default to 极速模式
4096 self.generation_mode.currentIndexChanged.connect(self.on_generation_mode_changed) 4114 self.generation_mode.currentIndexChanged.connect(self.on_generation_mode_changed)
4097 settings_layout.addWidget(self.generation_mode) 4115 settings_layout.addWidget(make_field_group("生成模式", self.generation_mode))
4098
4099 settings_layout.addSpacing(10)
4100 4116
4101 # 宽高比 4117 # 宽高比
4102 aspect_label = QLabel("宽高比")
4103 aspect_label.setProperty("role", "caption")
4104 settings_layout.addWidget(aspect_label)
4105 self.aspect_ratio = QComboBox() 4118 self.aspect_ratio = QComboBox()
4106 self.aspect_ratio.addItems([ 4119 self.aspect_ratio.addItems([
4107 "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", 4120 "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9",
...@@ -4111,21 +4124,14 @@ class StyleDesignerTab(QWidget): ...@@ -4111,21 +4124,14 @@ class StyleDesignerTab(QWidget):
4111 # 记录上一次值用于用户拒绝切换模式时回滚 4124 # 记录上一次值用于用户拒绝切换模式时回滚
4112 self._prev_aspect_ratio = self.aspect_ratio.currentText() 4125 self._prev_aspect_ratio = self.aspect_ratio.currentText()
4113 self.aspect_ratio.currentTextChanged.connect(self._on_aspect_ratio_changed) 4126 self.aspect_ratio.currentTextChanged.connect(self._on_aspect_ratio_changed)
4114 settings_layout.addWidget(self.aspect_ratio) 4127 settings_layout.addWidget(make_field_group("宽高比", self.aspect_ratio))
4115
4116 settings_layout.addSpacing(10)
4117 4128
4118 # 图片尺寸 4129 # 图片尺寸
4119 size_label = QLabel("图片尺寸")
4120 size_label.setProperty("role", "caption")
4121 settings_layout.addWidget(size_label)
4122 self.image_size = QComboBox() 4130 self.image_size = QComboBox()
4123 self.image_size.addItems(["1K", "2K", "4K"]) 4131 self.image_size.addItems(["1K", "2K", "4K"])
4124 self.image_size.setCurrentIndex(0) # Default to 1K for 极速模式 4132 self.image_size.setCurrentIndex(0) # Default to 1K for 极速模式
4125 self.image_size.currentIndexChanged.connect(self.on_image_size_changed) 4133 self.image_size.currentIndexChanged.connect(self.on_image_size_changed)
4126 settings_layout.addWidget(self.image_size) 4134 settings_layout.addWidget(make_field_group("图片尺寸", self.image_size))
4127
4128 settings_layout.addSpacing(10)
4129 4135
4130 settings_layout.addStretch() 4136 settings_layout.addStretch()
4131 settings_group.setLayout(settings_layout) 4137 settings_group.setLayout(settings_layout)
...@@ -4218,22 +4224,25 @@ class StyleDesignerTab(QWidget): ...@@ -4218,22 +4224,25 @@ class StyleDesignerTab(QWidget):
4218 4224
4219 # 添加按钮(使用表情符号) 4225 # 添加按钮(使用表情符号)
4220 add_btn = QPushButton("➕") 4226 add_btn = QPushButton("➕")
4227 add_btn.setProperty("size", "icon")
4221 add_btn.clicked.connect(lambda: self.add_library_item(category)) 4228 add_btn.clicked.connect(lambda: self.add_library_item(category))
4222 add_btn.setFixedWidth(40) 4229 add_btn.setFixedWidth(36)
4223 add_btn.setToolTip("添加词库项") 4230 add_btn.setToolTip("添加词库项")
4224 layout.addWidget(add_btn) 4231 layout.addWidget(add_btn)
4225 4232
4226 # 删除按钮(使用表情符号) 4233 # 删除按钮(使用表情符号)
4227 del_btn = QPushButton("🗑️") 4234 del_btn = QPushButton("🗑️")
4235 del_btn.setProperty("size", "icon")
4228 del_btn.clicked.connect(lambda: self.remove_library_item(category)) 4236 del_btn.clicked.connect(lambda: self.remove_library_item(category))
4229 del_btn.setFixedWidth(40) 4237 del_btn.setFixedWidth(36)
4230 del_btn.setToolTip("删除词库项") 4238 del_btn.setToolTip("删除词库项")
4231 layout.addWidget(del_btn) 4239 layout.addWidget(del_btn)
4232 4240
4233 # 锁定/解锁按钮(使用表情符号) 4241 # 锁定/解锁按钮(使用表情符号)
4234 lock_btn = QPushButton("🔓") 4242 lock_btn = QPushButton("🔓")
4243 lock_btn.setProperty("size", "icon")
4235 lock_btn.clicked.connect(lambda: self.toggle_field_lock(category)) 4244 lock_btn.clicked.connect(lambda: self.toggle_field_lock(category))
4236 lock_btn.setFixedWidth(40) 4245 lock_btn.setFixedWidth(36)
4237 lock_btn.setToolTip("锁定/解锁字段") 4246 lock_btn.setToolTip("锁定/解锁字段")
4238 self.lock_buttons[category] = lock_btn 4247 self.lock_buttons[category] = lock_btn
4239 layout.addWidget(lock_btn) 4248 layout.addWidget(lock_btn)
......
...@@ -167,10 +167,9 @@ QLabel[role="muted"] {{ ...@@ -167,10 +167,9 @@ QLabel[role="muted"] {{
167 font-size: {s['font_sm']}; 167 font-size: {s['font_sm']};
168 }} 168 }}
169 QLabel[role="caption"] {{ 169 QLabel[role="caption"] {{
170 color: {c['text_secondary']}; 170 color: {c['text_primary']};
171 font-size: {s['font_xs']}; 171 font-size: {s['font_base']};
172 text-transform: uppercase; 172 font-weight: 600;
173 letter-spacing: 1px;
174 }} 173 }}
175 QLabel[role="title"] {{ 174 QLabel[role="title"] {{
176 color: {c['text_primary']}; 175 color: {c['text_primary']};
...@@ -190,8 +189,8 @@ QGroupBox {{ ...@@ -190,8 +189,8 @@ QGroupBox {{
190 background-color: {c['bg_surface']}; 189 background-color: {c['bg_surface']};
191 border: 1px solid {c['border_default']}; 190 border: 1px solid {c['border_default']};
192 border-radius: {s['radius_md']}; 191 border-radius: {s['radius_md']};
193 margin-top: 14px; 192 margin-top: 18px;
194 padding: {s['space_4']} {s['space_3']} {s['space_3']} {s['space_3']}; 193 padding: 20px 14px 14px 14px;
195 font-weight: 600; 194 font-weight: 600;
196 font-size: {s['font_sm']}; 195 font-size: {s['font_sm']};
197 color: {c['text_secondary']}; 196 color: {c['text_secondary']};
...@@ -203,9 +202,8 @@ QGroupBox::title {{ ...@@ -203,9 +202,8 @@ QGroupBox::title {{
203 padding: 0 {s['space_2']}; 202 padding: 0 {s['space_2']};
204 color: {c['text_secondary']}; 203 color: {c['text_secondary']};
205 background: transparent; 204 background: transparent;
206 text-transform: uppercase; 205 font-size: {s['font_sm']};
207 letter-spacing: 1px; 206 font-weight: 600;
208 font-size: {s['font_xs']};
209 }} 207 }}
210 208
211 /* ========== 按钮 ========== */ 209 /* ========== 按钮 ========== */
...@@ -672,6 +670,14 @@ QPushButton#thumbDeleteBtn {{ ...@@ -672,6 +670,14 @@ QPushButton#thumbDeleteBtn {{
672 QPushButton#thumbDeleteBtn:hover {{ 670 QPushButton#thumbDeleteBtn:hover {{
673 background-color: {c['danger_hover']}; 671 background-color: {c['danger_hover']};
674 }} 672 }}
673
674 /* ========== 紧凑图标按钮(款式设计 tab 的 ➕🗑🔓 等)========== */
675 QPushButton[size="icon"] {{
676 padding: 0;
677 min-width: 30px;
678 min-height: 30px;
679 font-size: {s['font_base']};
680 }}
675 """ 681 """
676 682
677 683
......