mosaic-headless 1.20.0 → 1.20.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/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +42 -3
- package/README.zh-TW.md +35 -3
- package/SKILL.md +5 -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/browser-verification.csv +144 -0
- package/data/intro-verification.csv +7 -7
- package/data/rwd-verification.csv +2 -0
- package/package.json +6 -6
- package/references/dialog-and-triggers.md +33 -0
- package/{bin → scripts}/check-release.mjs +22 -8
- package/{bin → scripts}/sync-version.mjs +14 -2
- package/sites/_moksa.py +164 -1
- package/sites/moksa.json +358 -1
- package/tools/verify_dialog.py +61 -34
- /package/{bin → scripts}/install.mjs +0 -0
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Write package.json's version into every other place that carries one.
|
|
4
4
|
*
|
|
5
|
-
* node
|
|
5
|
+
* node scripts/sync-version.mjs
|
|
6
6
|
*
|
|
7
7
|
* Runs from the `version` npm lifecycle script, after npm has bumped package.json
|
|
8
8
|
* and before it makes the commit and the tag - so the tagged commit already has all
|
|
9
|
-
*
|
|
9
|
+
* four versions agreeing, and `npm version patch` is the only command anyone has to
|
|
10
10
|
* remember.
|
|
11
11
|
*
|
|
12
12
|
* Targets:
|
|
13
13
|
* SKILL.md frontmatter `version:`
|
|
14
14
|
* assets/templates/platforms/*.json frontmatter.version, where present
|
|
15
|
+
* .claude-plugin/plugin.json version (the Claude plugin directory reads it)
|
|
15
16
|
*
|
|
16
17
|
* check-release.mjs asserts afterwards that this worked, so a silent miss here
|
|
17
18
|
* cannot reach npm.
|
|
@@ -60,4 +61,15 @@ for (const f of fs.readdirSync(platDir).filter((x) => x.endsWith(".json"))) {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
// Claude plugin manifest - the directory listing and Claude Code's version pinning read it
|
|
65
|
+
const manPath = path.join(ROOT, ".claude-plugin", "plugin.json");
|
|
66
|
+
if (fs.existsSync(manPath)) {
|
|
67
|
+
const man = JSON.parse(fs.readFileSync(manPath, "utf8"));
|
|
68
|
+
if (man.version !== v) {
|
|
69
|
+
man.version = v;
|
|
70
|
+
fs.writeFileSync(manPath, JSON.stringify(man, null, 2) + "\n");
|
|
71
|
+
touched.push(".claude-plugin/plugin.json");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
63
75
|
console.log(`synced v${v} into ${touched.length} file(s): ${touched.join(", ") || "none"}`);
|
package/sites/_moksa.py
CHANGED
|
@@ -26,6 +26,7 @@ Run from this directory: python _moksa.py
|
|
|
26
26
|
"""
|
|
27
27
|
import json
|
|
28
28
|
import os
|
|
29
|
+
import uuid
|
|
29
30
|
|
|
30
31
|
# Monospace leads. The grotesque is the display face and appears at three sizes only;
|
|
31
32
|
# Noto Sans TC carries running Chinese text.
|
|
@@ -748,6 +749,24 @@ def motion_css():
|
|
|
748
749
|
"#mk-mark-3{bottom:20px;right:40px;border-right:1px solid " + RULE_INK
|
|
749
750
|
+ ";border-bottom:1px solid " + RULE_INK + "}",
|
|
750
751
|
"@media (max-width:1279px){" + marks + "{display:none}}",
|
|
752
|
+
# the colophon card's own trim marks, inside it rather than fixed to the
|
|
753
|
+
# viewport - the card is a leaf of the same document
|
|
754
|
+
"#mk-colophon-mark-tl,#mk-colophon-mark-br{position:absolute;"
|
|
755
|
+
"width:11px;height:11px;pointer-events:none}",
|
|
756
|
+
"#mk-colophon-mark-tl{top:9px;left:9px;border-left:1px solid " + RULE_INK
|
|
757
|
+
+ ";border-top:1px solid " + RULE_INK + "}",
|
|
758
|
+
"#mk-colophon-mark-br{bottom:9px;right:9px;border-right:1px solid " + RULE_INK
|
|
759
|
+
+ ";border-bottom:1px solid " + RULE_INK + "}",
|
|
760
|
+
# the dialog itself: Mosaic lays the host out as a centred grid, so the
|
|
761
|
+
# card only has to say how wide it is. The entrance is the card's, not the
|
|
762
|
+
# veil's - a 1px rule sliding up reads as a page being laid down.
|
|
763
|
+
"#mk-colophon[open] #mk-colophon-card{animation:mk-colophon-in .42s "
|
|
764
|
+
"cubic-bezier(.2,.7,.3,1) both}",
|
|
765
|
+
"@keyframes mk-colophon-in{from{opacity:0;transform:translateY(14px)}"
|
|
766
|
+
"to{opacity:1;transform:none}}",
|
|
767
|
+
"@media (prefers-reduced-motion:reduce){"
|
|
768
|
+
"#mk-colophon[open] #mk-colophon-card{animation:none}}",
|
|
769
|
+
|
|
751
770
|
|
|
752
771
|
# the clause index. It needs room outside the document margin, so it only
|
|
753
772
|
# appears once the viewport is wide enough to have that room.
|
|
@@ -2526,11 +2545,155 @@ INDEX = box("mk-index", {}, [
|
|
|
2526
2545
|
for i, (num, name, href, _tl) in enumerate(CLAUSES)
|
|
2527
2546
|
])
|
|
2528
2547
|
|
|
2548
|
+
# The colophon modal's own node id. A modalClose action targets a NODE id, so the
|
|
2549
|
+
# button inside the modal has to know it before either row is written - which is
|
|
2550
|
+
# why it is a constant here rather than something build_page mints.
|
|
2551
|
+
#
|
|
2552
|
+
# Minted fresh on every generation, never hard-coded: wp_mosaic_nodes' primary key
|
|
2553
|
+
# is (ID, themeID), so a fixed id collides with the row the PREVIOUS build of this
|
|
2554
|
+
# same page left in the same theme, and the commit dies on a duplicate key.
|
|
2555
|
+
COLOPHON_NODE_ID = str(uuid.uuid4())
|
|
2556
|
+
|
|
2529
2557
|
CUE = box("mk-cue", {}, [
|
|
2530
2558
|
mono("SCROLL", size="10px", color="--mk-faint", track="0.22em"),
|
|
2531
2559
|
box("mk-cue-rail", {}, []),
|
|
2532
2560
|
])
|
|
2533
2561
|
|
|
2562
|
+
|
|
2563
|
+
# ── §9 the colophon modal ─────────────────────────────────────────────────────
|
|
2564
|
+
# Mosaic 1.0.9's dialog, in this document's voice rather than a popup's: paper
|
|
2565
|
+
# ground, hairline border, trim marks at two corners, mono label, no radius, the
|
|
2566
|
+
# accent on one action only. It is the last page of a printed document - the
|
|
2567
|
+
# colophon - shown to a reader who is about to leave.
|
|
2568
|
+
#
|
|
2569
|
+
# Nothing on the page points at it. The modal names its own trigger in
|
|
2570
|
+
# `interactionShorthand`, which Mosaic expands at render into a real interaction
|
|
2571
|
+
# carrying the element's own `modalOpen` - the one element type that offers the
|
|
2572
|
+
# shorthand is the modal, because "open this when ..." is the only thing it would
|
|
2573
|
+
# ever mean. The cap rule beside it is what keeps the thing civil: once a session,
|
|
2574
|
+
# remembered under a name of its own, and `exitIntent` never fires on a touch
|
|
2575
|
+
# device at all, so a phone reader is never shown it.
|
|
2576
|
+
#
|
|
2577
|
+
# `closedby: "everything"` means Esc and a click on the overlay both close it; the
|
|
2578
|
+
# overlay child is also what makes Mosaic emit `aria-modal="true"`, because the
|
|
2579
|
+
# overlay is what actually blocks the page. The close control is a real button so
|
|
2580
|
+
# it is in the tab order, and the whole thing is reachable and dismissable from
|
|
2581
|
+
# the keyboard alone - measured, not assumed (tools/verify_dialog.py).
|
|
2582
|
+
COLOPHON = {
|
|
2583
|
+
"type": "modal",
|
|
2584
|
+
"data": {
|
|
2585
|
+
"attrID": "mk-colophon",
|
|
2586
|
+
"accessibleLabel": "開始一個專案",
|
|
2587
|
+
"closedby": "everything",
|
|
2588
|
+
"interactionShorthand": {
|
|
2589
|
+
"type": "exitIntent",
|
|
2590
|
+
"exitIntentOptions": {
|
|
2591
|
+
"settings": {"awayFor": "500ms"},
|
|
2592
|
+
"runs": {"rules": [{
|
|
2593
|
+
"uuid": "6f1d3a92-5c84-4e71-9b20-7d8a1f4c2e55",
|
|
2594
|
+
"type": "cap",
|
|
2595
|
+
"capOptions": {"max": "1", "remember": "session",
|
|
2596
|
+
"name": "mk-colophon"}}]}}},
|
|
2597
|
+
},
|
|
2598
|
+
"style": bp({"paddingLeft": "40px", "paddingRight": "40px"},
|
|
2599
|
+
None, {"paddingLeft": "18px", "paddingRight": "18px"}),
|
|
2600
|
+
"children": [
|
|
2601
|
+
{"type": "modal-overlay", "data": {"attrID": "mk-colophon-veil"},
|
|
2602
|
+
"style": {"&": {"_": {"backgroundColor": "rgba(22,24,28,.62)"}}}},
|
|
2603
|
+
# a modal-window, not a plain div: the window is what Mosaic scrolls and
|
|
2604
|
+
# focus-traps, and a modal without one is a dialog with loose children
|
|
2605
|
+
dict(box("mk-colophon-card",
|
|
2606
|
+
{"backgroundColor": {"token": "--mk-paper"},
|
|
2607
|
+
"maxWidth": "520px", "width": "100%",
|
|
2608
|
+
"flexDirection": "column", "rowGap": "0px",
|
|
2609
|
+
"position": "relative",
|
|
2610
|
+
"paddingTop": "34px", "paddingBottom": "30px",
|
|
2611
|
+
"paddingLeft": "34px", "paddingRight": "34px",
|
|
2612
|
+
"customDeclarations": "border:1px solid rgb(22,24,28);"},
|
|
2613
|
+
[
|
|
2614
|
+
# the same trim marks the document uses, so the card reads as a
|
|
2615
|
+
# leaf of it rather than something the site threw at the reader
|
|
2616
|
+
box("mk-colophon-mark-tl", {}, []),
|
|
2617
|
+
box("mk-colophon-mark-br", {}, []),
|
|
2618
|
+
box("mk-colophon-head",
|
|
2619
|
+
{"display": "flex", "justifyContent": "space-between",
|
|
2620
|
+
"alignItems": "baseline", "columnGap": "16px",
|
|
2621
|
+
"paddingBottom": "14px",
|
|
2622
|
+
"customDeclarations": "border-bottom:1px solid " + RULE + ";"},
|
|
2623
|
+
[mono("COLOPHON", size="10px", color="--mk-faint", track="0.26em"),
|
|
2624
|
+
mono("09 / 離開前", size="10px", color="--mk-faint", track="0.18em")]),
|
|
2625
|
+
ml("h2", "還沒找到\n要的東西?",
|
|
2626
|
+
fontFamily=DISPLAY, fontWeight="600", fontSize="34px",
|
|
2627
|
+
# positive, not tight: a Han glyph sits on a full em body and is
|
|
2628
|
+
# already as close as it is meant to be. The design audit fails a
|
|
2629
|
+
# CJK run below -0.15px, and caught this line at -0.68px.
|
|
2630
|
+
lineHeight="1.12", letterSpacing="0.005em",
|
|
2631
|
+
color={"token": "--mk-ink"}, marginTop="20px",
|
|
2632
|
+
_m={"fontSize": "28px"}),
|
|
2633
|
+
T("p", "把想做的事寫三行給我,兩個工作天內會收到一份能直接討論的提案——"
|
|
2634
|
+
"範圍、做法、時間,不是報價單。",
|
|
2635
|
+
fontFamily=CJK, fontSize="14px", lineHeight="1.85",
|
|
2636
|
+
color={"token": "--mk-muted"}, marginTop="14px"),
|
|
2637
|
+
box("mk-colophon-cta",
|
|
2638
|
+
{"display": "flex", "columnGap": "14px", "rowGap": "10px",
|
|
2639
|
+
"marginTop": "26px", "flexWrap": "wrap",
|
|
2640
|
+
"alignItems": "center"},
|
|
2641
|
+
[
|
|
2642
|
+
{"type": "button",
|
|
2643
|
+
"data": {"attrID": "mk-colophon-go", "url": "#contact"},
|
|
2644
|
+
"style": {"&": {"_": {
|
|
2645
|
+
"backgroundColor": {"token": "--mk-accent"},
|
|
2646
|
+
"color": {"token": "--mk-ink"},
|
|
2647
|
+
"fontFamily": MONO, "fontSize": "11px",
|
|
2648
|
+
"letterSpacing": "0.18em", "fontWeight": "500",
|
|
2649
|
+
"paddingLeft": "22px", "paddingRight": "22px",
|
|
2650
|
+
"paddingTop": "13px", "paddingBottom": "13px",
|
|
2651
|
+
"customDeclarations": "border:1px solid rgb(255,90,54);"}},
|
|
2652
|
+
"hover": {"_": {"backgroundColor": {"token": "--mk-ink"},
|
|
2653
|
+
"color": {"token": "--mk-paper"},
|
|
2654
|
+
"customDeclarations":
|
|
2655
|
+
"border:1px solid rgb(22,24,28);"}},
|
|
2656
|
+
"focus-visible": {"_": dict(FOCUS_RING)}},
|
|
2657
|
+
"children": [{"type": "wysiwyg-text",
|
|
2658
|
+
"data": {"text": "START A PROJECT"}}]},
|
|
2659
|
+
# closes the dialog and nothing else: a modalClose action
|
|
2660
|
+
# aimed at the modal's own node id
|
|
2661
|
+
{"type": "button",
|
|
2662
|
+
"data": {"attrID": "mk-colophon-stay",
|
|
2663
|
+
"interactions": [{
|
|
2664
|
+
"type": "click",
|
|
2665
|
+
"uuid": "8b2e5d14-9af3-4c60-8e71-3c5d9b07a4f2",
|
|
2666
|
+
"clickOptions": {
|
|
2667
|
+
"name": "close", "ID":
|
|
2668
|
+
"c41a7e69-0b52-4d38-9f84-61e0ad3b5c77",
|
|
2669
|
+
"actionSlots": {"click": {"actions": [{
|
|
2670
|
+
"type": "modalClose",
|
|
2671
|
+
"uuid": "2d8f4b31-7c06-4e95-a3b2-58d1f9e60c84",
|
|
2672
|
+
"settings": {"target": {
|
|
2673
|
+
"type": "element",
|
|
2674
|
+
"uuid": COLOPHON_NODE_ID}}}]}}}}]},
|
|
2675
|
+
"style": {"&": {"_": {
|
|
2676
|
+
"backgroundColor": "rgba(0,0,0,0)",
|
|
2677
|
+
"color": {"token": "--mk-muted"},
|
|
2678
|
+
"fontFamily": MONO, "fontSize": "11px",
|
|
2679
|
+
"letterSpacing": "0.18em", "fontWeight": "400",
|
|
2680
|
+
"paddingLeft": "4px", "paddingRight": "4px",
|
|
2681
|
+
"paddingTop": "13px", "paddingBottom": "13px",
|
|
2682
|
+
"cursor": "pointer"}},
|
|
2683
|
+
"hover": {"_": {"color": {"token": "--mk-ink"}}},
|
|
2684
|
+
"focus-visible": {"_": dict(FOCUS_RING)}},
|
|
2685
|
+
"children": [{"type": "wysiwyg-text",
|
|
2686
|
+
"data": {"text": "繼續閱讀"}}]},
|
|
2687
|
+
]),
|
|
2688
|
+
]), type="modal-window"),
|
|
2689
|
+
],
|
|
2690
|
+
# The node id is pinned because the close button has to name it, and both are
|
|
2691
|
+
# written in the same commit - there is no second pass in which to learn it.
|
|
2692
|
+
# Unique per THEME, not per document: wp_mosaic_nodes' key is (ID, themeID).
|
|
2693
|
+
"nodeID": COLOPHON_NODE_ID,
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
|
|
2534
2697
|
HOME_TREE = {"type": "div", "data": {"attrID": "mk-home"},
|
|
2535
2698
|
"children": [BOOT, box("mk-doc", {}, [
|
|
2536
2699
|
MARKS, INDEX, CUE, LOOP_WINDOW, box("mk-sweep", {}, []),
|
|
@@ -2538,7 +2701,7 @@ HOME_TREE = {"type": "div", "data": {"attrID": "mk-home"},
|
|
|
2538
2701
|
# changes ground five times so it reads as chapters
|
|
2539
2702
|
MASTHEAD, TICKER_BAND, PLATE, SERVICE_SEC, MATRIX_SEC,
|
|
2540
2703
|
PROCESS_SEC, FIGURE_SEC, WORK_SEC, PAN, SPECIMEN, STACK_SEC,
|
|
2541
|
-
BOARD, PRODUCT_SEC, VOICE_SEC, CONTACT,
|
|
2704
|
+
BOARD, PRODUCT_SEC, VOICE_SEC, CONTACT, COLOPHON,
|
|
2542
2705
|
])]}
|
|
2543
2706
|
|
|
2544
2707
|
|