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/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
- """Sections carry no vertical padding here - the document's rhythm is set by the
115
- rules between clauses, not by a stack of padded bands."""
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({"backgroundColor": {"token": bg},
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"}, {"columnGap": "12px"}),
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"}, {"columnGap": "15px"}),
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
- "_m": {"fontSize": "12px"}},
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")})