mosaic-headless 1.25.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.
- package/SKILL.md +2 -2
- 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/mobile-audit.csv +20 -20
- package/data/navigation-verification.csv +14 -19
- package/data/placement-rules.csv +127 -127
- package/data/slider-verification.csv +15 -15
- package/package.json +1 -1
- package/references/design-system.md +32 -0
- package/scripts/check-release.mjs +1 -1
- package/sites/_moksa.py +104 -3
- package/sites/moksa.json +2410 -1033
- package/tools/build_page.py +8 -1
- package/tools/extract_placement.py +12 -1
package/sites/_moksa.py
CHANGED
|
@@ -277,9 +277,40 @@ def mask_line(attr, text, tag="h1", **st):
|
|
|
277
277
|
|
|
278
278
|
|
|
279
279
|
# ── content, all of it Moksa Web's own ───────────────────────────────────────
|
|
280
|
+
# Nine flat links was the wrong answer to "the site grew". The top level is the
|
|
281
|
+
# studio's own site; everything that demonstrates what Mosaic can DO is one
|
|
282
|
+
# labelled group, which is also the only honest shape - those five pages are a
|
|
283
|
+
# set, not five more sections of the homepage.
|
|
280
284
|
NAV = [("服務", "#services"), ("作品", "#works"),
|
|
281
|
-
("產品", "#products"), ("
|
|
282
|
-
|
|
285
|
+
("產品", "#products"), ("聯絡", "#contact")]
|
|
286
|
+
|
|
287
|
+
# Read from the shipped tables rather than typed, so the menu cannot claim a
|
|
288
|
+
# number the evidence no longer supports.
|
|
289
|
+
def _count(table, fn):
|
|
290
|
+
import csv as _c, io as _i, os as _o
|
|
291
|
+
path = _o.path.join(_o.path.dirname(_o.path.abspath(__file__)), "..", "data", table)
|
|
292
|
+
with _i.open(path, encoding="utf-8") as fh:
|
|
293
|
+
return fn(list(_c.DictReader(fh)))
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
TOKENABLE_COUNT = _count("style-properties.csv",
|
|
297
|
+
lambda rs: sum(1 for r in rs if r["tokenable"]))
|
|
298
|
+
CONVERTED_COUNT = _count("conversion-batch.csv",
|
|
299
|
+
lambda rs: sum(int(r["converted"]) for r in rs))
|
|
300
|
+
|
|
301
|
+
# label, href, one line of what it demonstrates
|
|
302
|
+
CAPABILITIES = [
|
|
303
|
+
("彈窗與觸發", "/dialogs/",
|
|
304
|
+
"九種形態、四種觸發、四種執行規則"),
|
|
305
|
+
("輪播", "/sliders/",
|
|
306
|
+
"四種動畫並排、輪轉模式、鍵盤與減少動態"),
|
|
307
|
+
("設計系統", "/tokens/",
|
|
308
|
+
"設計代幣、variant 層、%d 個接得住代幣的屬性" % TOKENABLE_COUNT),
|
|
309
|
+
("動態內容", "/dynamic/",
|
|
310
|
+
"迴圈、@VAR 表達式、自訂欄位"),
|
|
311
|
+
("Elementor 轉換", "/conversion/",
|
|
312
|
+
"19 頁、%s 個元素、每一段字都核過" % "{:,}".format(CONVERTED_COUNT)),
|
|
313
|
+
]
|
|
283
314
|
|
|
284
315
|
# key / figure / caption, read as a datasheet rather than as four big numbers
|
|
285
316
|
SPEC = [
|
|
@@ -1322,6 +1353,76 @@ def motion_css():
|
|
|
1322
1353
|
|
|
1323
1354
|
|
|
1324
1355
|
# ── the shared shell ──────────────────────────────────────────────────────────
|
|
1356
|
+
NAV_LINK = {"color": {"token": "--mk-ink"}, "fontSize": "13px",
|
|
1357
|
+
"fontWeight": "400", "letterSpacing": "0.04em", "fontFamily": MONO,
|
|
1358
|
+
"cursor": "pointer"}
|
|
1359
|
+
|
|
1360
|
+
|
|
1361
|
+
def capability_dropdown():
|
|
1362
|
+
"""The capability pages as one labelled group.
|
|
1363
|
+
|
|
1364
|
+
`dropdown` heals in its own `dropdown-toggle` and `dropdown-wrapper`, so only
|
|
1365
|
+
the two are authored here and the wrapper's children are the links. The
|
|
1366
|
+
wrapper reads as a leaf in `placement-rules.csv` because `canBeParentFor()`
|
|
1367
|
+
is never overridden on it - but its factory is
|
|
1368
|
+
`getDropdownWrapperElementDefaultData($data, $children)`, which is why that
|
|
1369
|
+
table now carries a `takes_children` column and the build guard reads it.
|
|
1370
|
+
"""
|
|
1371
|
+
return {"type": "dropdown",
|
|
1372
|
+
"data": {"attrID": "mk-cap", "horizontalAlign": "left"},
|
|
1373
|
+
"style": {"&": {"_": {"position": "relative"}}},
|
|
1374
|
+
"children": [
|
|
1375
|
+
{"type": "dropdown-toggle",
|
|
1376
|
+
"data": {"attrID": "mk-cap-toggle"},
|
|
1377
|
+
"style": {"&": {"_": dict(NAV_LINK, **{
|
|
1378
|
+
"display": "flex", "alignItems": "center", "columnGap": "6px",
|
|
1379
|
+
"customDeclarations":
|
|
1380
|
+
"white-space:nowrap;"}),
|
|
1381
|
+
"_t": {"fontSize": "12px", "paddingTop": "8px",
|
|
1382
|
+
"paddingBottom": "8px"}},
|
|
1383
|
+
"hover": {"_": {"color": {"token": "--mk-accent"}}},
|
|
1384
|
+
"focus-visible": {"_": dict(FOCUS_RING)}},
|
|
1385
|
+
"children": [
|
|
1386
|
+
T("p", "能力展示", fontFamily=MONO,
|
|
1387
|
+
fontSize="13px", letterSpacing="0.04em",
|
|
1388
|
+
color={"token": "--mk-ink"}, _t={"fontSize": "12px"}),
|
|
1389
|
+
T("p", "+", fontFamily=MONO, fontSize="11px",
|
|
1390
|
+
color={"token": "--mk-faint"}),
|
|
1391
|
+
]},
|
|
1392
|
+
{"type": "dropdown-wrapper",
|
|
1393
|
+
"data": {"attrID": "mk-cap-menu"},
|
|
1394
|
+
"style": bp({"backgroundColor": {"token": "--mk-paper"},
|
|
1395
|
+
"paddingTop": "10px", "paddingBottom": "10px",
|
|
1396
|
+
"minWidth": "272px",
|
|
1397
|
+
"customDeclarations":
|
|
1398
|
+
"border:1px solid rgb(22,24,28);"
|
|
1399
|
+
"box-shadow:0 20px 48px rgba(22,24,28,.14);"},
|
|
1400
|
+
None,
|
|
1401
|
+
{"minWidth": "0px", "width": "100%",
|
|
1402
|
+
"customDeclarations":
|
|
1403
|
+
"border:1px solid " + RULE + ";box-shadow:none;"}),
|
|
1404
|
+
"children": [
|
|
1405
|
+
{"type": "menu-link",
|
|
1406
|
+
"data": {"attrID": "mk-cap-%d" % i, "url": href},
|
|
1407
|
+
"style": {"&": {"_": {
|
|
1408
|
+
"display": "block", "cursor": "pointer",
|
|
1409
|
+
"paddingTop": "9px", "paddingBottom": "9px",
|
|
1410
|
+
"paddingLeft": "16px", "paddingRight": "16px"}},
|
|
1411
|
+
"hover": {"_": {
|
|
1412
|
+
"backgroundColor": {"token": "--mk-panel"}}},
|
|
1413
|
+
"focus-visible": {"_": dict(FOCUS_RING)}},
|
|
1414
|
+
"children": [
|
|
1415
|
+
T("p", label, fontFamily=CJK, fontSize="13px",
|
|
1416
|
+
fontWeight="500", color={"token": "--mk-ink"}),
|
|
1417
|
+
T("p", blurb, fontFamily=CJK, fontSize="11px",
|
|
1418
|
+
lineHeight="1.6", color={"token": "--mk-muted"},
|
|
1419
|
+
marginTop="3px"),
|
|
1420
|
+
]}
|
|
1421
|
+
for i, (label, href, blurb) in enumerate(CAPABILITIES)
|
|
1422
|
+
]},
|
|
1423
|
+
]}
|
|
1424
|
+
|
|
1425
|
+
|
|
1325
1426
|
HEADER = box("mk-shell-top", {}, [
|
|
1326
1427
|
# a `code` node with insertLocation "head" is the only way to get @keyframes into
|
|
1327
1428
|
# the document - customDeclarations is emitted inside a rule and cannot hold one
|
|
@@ -1404,7 +1505,7 @@ HEADER = box("mk-shell-top", {}, [
|
|
|
1404
1505
|
"focus-visible": {"_": FOCUS_RING}},
|
|
1405
1506
|
"text": text}
|
|
1406
1507
|
for i, (text, href) in enumerate(NAV)
|
|
1407
|
-
]},
|
|
1508
|
+
] + [capability_dropdown()]},
|
|
1408
1509
|
# not a pill: a bracketed link, the way a document cross-references
|
|
1409
1510
|
{"type": "button", "data": {"attrID": "mk-header-cta",
|
|
1410
1511
|
"url": "#contact"},
|