mosaic-headless 1.23.1 → 1.25.0
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.
- package/SKILL.md +9 -5
- package/assets/templates/platforms/claude-ai.json +1 -1
- package/assets/templates/platforms/claude-code.json +1 -1
- package/assets/templates/platforms/codex-cli.json +1 -1
- package/assets/templates/platforms/copilot.json +1 -1
- package/assets/templates/platforms/gemini-cli.json +1 -1
- package/data/default-children.csv +26 -11
- package/data/dialog-form-verification.csv +2 -2
- package/data/mobile-audit.csv +55 -0
- package/data/navigation-verification.csv +27 -46
- package/data/slider-verification.csv +30 -19
- package/data/token-verification.csv +16 -0
- package/package.json +1 -1
- package/references/responsive.md +53 -0
- package/references/slider.md +39 -3
- package/references/styling.md +17 -3
- package/scripts/check-release.mjs +4 -2
- package/sites/_moksa.py +86 -12
- package/sites/moksa.json +17413 -1085
- package/tools/audit_mobile.py +147 -0
- package/tools/build_page.py +20 -2
- package/tools/extract_default_children.py +66 -4
- package/tools/verify_slider.py +63 -9
- package/tools/verify_tokens.py +170 -0
package/sites/_moksa.py
CHANGED
|
@@ -110,13 +110,24 @@ def grid(attr, cols, gap, children, tcols=None, mcols=1, **extra):
|
|
|
110
110
|
"children": children}
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
def section(attr, children, bg="--mk-paper"):
|
|
114
|
-
"""
|
|
115
|
-
|
|
113
|
+
def section(attr, children, bg="--mk-paper", pad_y=None):
|
|
114
|
+
"""A band of the document.
|
|
115
|
+
|
|
116
|
+
The comment here used to say sections carry no vertical padding. They do:
|
|
117
|
+
`section` arrives with 80px top and bottom of its own, which is Mosaic's
|
|
118
|
+
default and is what sets this page's rhythm. It is invisible until a page adds
|
|
119
|
+
its own spacing on top, and then every band on a phone carries 80 + 80 + your
|
|
120
|
+
own - the showcase pages opened with about 200px of nothing above the first
|
|
121
|
+
line. Pass `pad_y` to take the vertical rhythm into your own hands.
|
|
122
|
+
"""
|
|
123
|
+
base = {"backgroundColor": {"token": bg},
|
|
124
|
+
"paddingLeft": "40px", "paddingRight": "40px",
|
|
125
|
+
"fontFamily": CJK}
|
|
126
|
+
if pad_y is not None:
|
|
127
|
+
base["paddingTop"] = pad_y
|
|
128
|
+
base["paddingBottom"] = pad_y
|
|
116
129
|
return {"type": "section", "data": {"attrID": attr},
|
|
117
|
-
"style": bp(
|
|
118
|
-
"paddingLeft": "40px", "paddingRight": "40px",
|
|
119
|
-
"fontFamily": CJK},
|
|
130
|
+
"style": bp(base,
|
|
120
131
|
{"paddingLeft": "28px", "paddingRight": "28px"},
|
|
121
132
|
{"paddingLeft": "18px", "paddingRight": "18px"}),
|
|
122
133
|
"children": children}
|
|
@@ -139,11 +150,30 @@ def ml(tag, text, **st):
|
|
|
139
150
|
return T(tag, text, **st)
|
|
140
151
|
|
|
141
152
|
|
|
153
|
+
# Below this, mono text stops being quiet and starts being unreadable - on a phone
|
|
154
|
+
# in particular, where there is no leaning in. The audit at 390px found 80 runs at
|
|
155
|
+
# 10px on one page alone, which is a decision taken 80 times by accident.
|
|
156
|
+
MONO_FLOOR_M = 12
|
|
157
|
+
|
|
158
|
+
|
|
142
159
|
def mono(text, size="11px", color="--mk-muted", track="0.14em", **st):
|
|
143
160
|
"""The page's primary voice. Everything that is a label, a key, a figure or an
|
|
144
|
-
address is set in it.
|
|
161
|
+
address is set in it.
|
|
162
|
+
|
|
163
|
+
A size authored below `MONO_FLOOR_M` is raised to it on phones. The desktop
|
|
164
|
+
value is left alone: 10px works at arm's length on a large screen and is part
|
|
165
|
+
of the typographic hierarchy there, so this is a floor rather than a rewrite.
|
|
166
|
+
"""
|
|
145
167
|
st.setdefault("fontFamily", MONO)
|
|
146
168
|
st.setdefault("fontWeight", "400")
|
|
169
|
+
try:
|
|
170
|
+
authored = float(str(size).replace("px", ""))
|
|
171
|
+
except ValueError:
|
|
172
|
+
authored = None
|
|
173
|
+
if authored is not None and authored < MONO_FLOOR_M:
|
|
174
|
+
t = dict(st.get("_t") or {})
|
|
175
|
+
t.setdefault("fontSize", "%dpx" % MONO_FLOOR_M)
|
|
176
|
+
st["_t"] = t
|
|
147
177
|
return T("p", text,
|
|
148
178
|
color={"token": color} if color.startswith("--") else color,
|
|
149
179
|
fontSize=size, letterSpacing=track, **st)
|
|
@@ -248,7 +278,7 @@ def mask_line(attr, text, tag="h1", **st):
|
|
|
248
278
|
|
|
249
279
|
# ── content, all of it Moksa Web's own ───────────────────────────────────────
|
|
250
280
|
NAV = [("服務", "#services"), ("作品", "#works"),
|
|
251
|
-
("產品", "#products"), ("彈窗", "/dialogs/"),
|
|
281
|
+
("產品", "#products"), ("彈窗", "/dialogs/"), ("輪播", "/sliders/"), ("系統", "/tokens/"), ("資料", "/dynamic/"), ("轉換", "/conversion/"),
|
|
252
282
|
("聯絡", "#contact")]
|
|
253
283
|
|
|
254
284
|
# key / figure / caption, read as a datasheet rather than as four big numbers
|
|
@@ -611,6 +641,17 @@ def motion_css():
|
|
|
611
641
|
"-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}",
|
|
612
642
|
'#mk-header::after{content:"";position:absolute;left:0;right:0;bottom:0;'
|
|
613
643
|
"height:1px;background:" + RULE + ";opacity:0}",
|
|
644
|
+
# On a phone the bar is no longer one line. The nav grew to nine items
|
|
645
|
+
# and wraps to two rows, which took the FIXED header to 177px - a quarter
|
|
646
|
+
# of the viewport permanently, with the first 97px of every page hidden
|
|
647
|
+
# underneath it, because the pages clear a header height that was decided
|
|
648
|
+
# when it was one line. A fixed element whose height depends on its
|
|
649
|
+
# content cannot be cleared by a constant, so below 768px it simply joins
|
|
650
|
+
# the flow and the problem cannot come back.
|
|
651
|
+
"@media (max-width:767px){#mk-header{position:static;"
|
|
652
|
+
"background:rgb(250,250,247);"
|
|
653
|
+
"-webkit-backdrop-filter:none;backdrop-filter:none;"
|
|
654
|
+
"border-bottom:1px solid " + RULE + "}}",
|
|
614
655
|
"#mk-nav>*{position:relative}",
|
|
615
656
|
'#mk-nav>*::after{content:"";position:absolute;left:0;right:100%;bottom:-5px;'
|
|
616
657
|
"height:1px;background:rgb(255,90,54);"
|
|
@@ -1298,9 +1339,17 @@ HEADER = box("mk-shell-top", {}, [
|
|
|
1298
1339
|
children=
|
|
1299
1340
|
[wrap("mk-header-in", [
|
|
1300
1341
|
{"type": "div", "data": {"attrID": "mk-header-row"},
|
|
1342
|
+
# The nav grew from four items to seven as the showcase pages were
|
|
1343
|
+
# added, and on a phone the row simply ran off the right edge - the
|
|
1344
|
+
# last two links sat at left=393 and left=436 in a 390px viewport,
|
|
1345
|
+
# which is to say they were unreachable. One line is not a layout
|
|
1346
|
+
# that survives new content, so on `_m` the row wraps and the nav
|
|
1347
|
+
# takes the second line to itself.
|
|
1301
1348
|
"style": bp({"display": "flex", "alignItems": "center",
|
|
1302
1349
|
"justifyContent": "space-between", "columnGap": "40px"},
|
|
1303
|
-
{"columnGap": "24px"},
|
|
1350
|
+
{"columnGap": "24px"},
|
|
1351
|
+
{"columnGap": "12px", "flexWrap": "wrap",
|
|
1352
|
+
"rowGap": "10px"}),
|
|
1304
1353
|
"children": [
|
|
1305
1354
|
# the wordmark is the only route back to the top on a one-pager, so
|
|
1306
1355
|
# it has to be a link. `menu-link` with a url renders a real <a>.
|
|
@@ -1319,7 +1368,7 @@ HEADER = box("mk-shell-top", {}, [
|
|
|
1319
1368
|
# time of day - a page cannot know that without JavaScript, and
|
|
1320
1369
|
# labelling a page-load counter "14:32" would be a small lie told
|
|
1321
1370
|
# in the most trustworthy typeface on the site.
|
|
1322
|
-
box("mk-clock", {}, [
|
|
1371
|
+
box("mk-clock", {}, _m={"display": "none"}, children=[
|
|
1323
1372
|
box("mk-clock-dot", {}, []),
|
|
1324
1373
|
T("p", "T+", color={"token": "--mk-faint"}, fontSize="10px",
|
|
1325
1374
|
fontFamily=MONO, letterSpacing="0.18em"),
|
|
@@ -1331,7 +1380,14 @@ HEADER = box("mk-shell-top", {}, [
|
|
|
1331
1380
|
{"type": "menu", "data": {"attrID": "mk-nav"},
|
|
1332
1381
|
"style": bp({"display": "flex", "columnGap": "30px",
|
|
1333
1382
|
"alignItems": "center"},
|
|
1334
|
-
{"columnGap": "20px"
|
|
1383
|
+
{"columnGap": "20px", "flexWrap": "wrap",
|
|
1384
|
+
"rowGap": "6px"},
|
|
1385
|
+
{"columnGap": "16px", "rowGap": "6px",
|
|
1386
|
+
"flexWrap": "wrap", "width": "100%",
|
|
1387
|
+
"justifyContent": "flex-start",
|
|
1388
|
+
"customDeclarations":
|
|
1389
|
+
"order:3;border-top:1px solid " + RULE
|
|
1390
|
+
+ ";padding-top:10px;"}),
|
|
1335
1391
|
"children": [
|
|
1336
1392
|
{"type": "menu-link",
|
|
1337
1393
|
"data": {"attrID": "mk-nav-%d" % i, "url": href},
|
|
@@ -1341,7 +1397,9 @@ HEADER = box("mk-shell-top", {}, [
|
|
|
1341
1397
|
"fontFamily": MONO,
|
|
1342
1398
|
"transitionAll": "160ms ease",
|
|
1343
1399
|
"cursor": "pointer"},
|
|
1344
|
-
"
|
|
1400
|
+
"_t": {"fontSize": "12px",
|
|
1401
|
+
"paddingTop": "8px",
|
|
1402
|
+
"paddingBottom": "8px"}},
|
|
1345
1403
|
"hover": {"_": {"color": {"token": "--mk-accent"}}},
|
|
1346
1404
|
"focus-visible": {"_": FOCUS_RING}},
|
|
1347
1405
|
"text": text}
|
|
@@ -3058,6 +3116,22 @@ if __name__ == "__main__":
|
|
|
3058
3116
|
# `_moksa` (this copy is `__main__`), its own main block does not run, and the
|
|
3059
3117
|
# helpers it reads are pure functions - two copies produce identical dicts.
|
|
3060
3118
|
import _dialogs
|
|
3119
|
+
import _sliders
|
|
3120
|
+
import _tokens
|
|
3121
|
+
import _dynamic
|
|
3122
|
+
import _conversion
|
|
3123
|
+
SITE["pages"].append({"slug": "conversion", "post_id": 273,
|
|
3124
|
+
"title": "Elementor 轉換",
|
|
3125
|
+
"tree": apply_type(_conversion.TREE, DISPLAY, CJK, "600")})
|
|
3126
|
+
SITE["pages"].append({"slug": "dynamic", "post_id": 272,
|
|
3127
|
+
"title": "動態內容",
|
|
3128
|
+
"tree": apply_type(_dynamic.TREE, DISPLAY, CJK, "600")})
|
|
3129
|
+
SITE["pages"].append({"slug": "tokens", "post_id": 271,
|
|
3130
|
+
"title": "設計系統",
|
|
3131
|
+
"tree": apply_type(_tokens.TREE, DISPLAY, CJK, "600")})
|
|
3132
|
+
SITE["pages"].append({"slug": "sliders", "post_id": 270,
|
|
3133
|
+
"title": "輪播實驗室",
|
|
3134
|
+
"tree": apply_type(_sliders.TREE, DISPLAY, CJK, "600")})
|
|
3061
3135
|
SITE["pages"].append({"slug": "dialogs", "post_id": 268,
|
|
3062
3136
|
"title": "彈窗實驗室",
|
|
3063
3137
|
"tree": apply_type(_dialogs.TREE, DISPLAY, CJK, "600")})
|