@conduction/docusaurus-preset 3.45.3 → 3.46.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/docusaurus-preset",
3
- "version": "3.45.3",
3
+ "version": "3.46.0",
4
4
  "scripts": {
5
5
  "prepack": "node scripts/prepack-bundle-css.js",
6
6
  "test": "node --test"
@@ -35,9 +35,9 @@
35
35
  * game={<HiddenGame id="stamp-rush" unlock={...}><StampRush /></HiddenGame>}
36
36
  * />
37
37
  *
38
- * `game` is the app's hidden mini-game. It renders across the full
39
- * width of the hero, under the copy and the illustration, and shows
40
- * nothing until the player finds it.
38
+ * `game` is the app's hidden mini-game. It shows nothing until the
39
+ * player finds it, and then takes the illustration's place: the hero
40
+ * widens that column and the mock steps aside.
41
41
  *
42
42
  * Each cta object also accepts `tone: "orange"` to flip the primary
43
43
  * (or secondary) variant to the KNVB-orange accent. Reserved for
@@ -396,18 +396,25 @@ export default function DetailHero({
396
396
  )}
397
397
  </div>
398
398
 
399
- {hasIllustration && (
400
- <div className={styles.illustration}>{illustration}</div>
401
- )}
399
+ {/* The app's hidden mini-game, when it has one, and the mock
400
+ it takes the place of.
402
401
 
403
- {/* The app's hidden mini-game, when it has one. It lives here
404
- rather than further down the page because the way in is up
405
- here too: you knock on the logo in this hero, and what you
406
- unlocked should not be somewhere you have to scroll to find.
407
- It spans both columns, so the game gets the width of the
408
- hero instead of the width of the mock. While the game is
409
- still hidden this renders nothing at all. */}
410
- {game && <div className={styles.game}>{game}</div>}
402
+ Both live in the same column. The game renders nothing at
403
+ all until somebody finds it, and once it is open the mock
404
+ gives way: the way in is up here (you knock on the logo in
405
+ this hero), so what you unlocked belongs where you were
406
+ already looking, not below the fold and not beside the
407
+ picture of the app. The swap is a sibling selector on
408
+ HiddenGame's own `data-hidden-game="found"`, so the mock
409
+ stays while a `link` opener is still sitting unclicked. */}
410
+ {(hasIllustration || game) && (
411
+ <div className={styles.visual}>
412
+ {game}
413
+ {hasIllustration && (
414
+ <div className={styles.illustration}>{illustration}</div>
415
+ )}
416
+ </div>
417
+ )}
411
418
  </div>
412
419
  </section>
413
420
  );
@@ -235,18 +235,34 @@ a.downloadsBadge:hover {
235
235
  }
236
236
  .illustration > * { width: 100%; max-width: 560px; }
237
237
 
238
- /* The app's mini-game, across the whole hero rather than in the
239
- illustration's column: the games are wide, and a card squeezed into
240
- half a hero reads as an accident. Empty until the game is found, and
241
- `:empty` keeps the margin off until then. */
242
- .game {
243
- grid-column: 1 / -1;
244
- margin-top: 40px; /* The games hold between 460 and 760px of content, so a card
245
- stretched across the whole hero is mostly empty on the right. Wide
246
- enough for the widest board, and no wider. */
247
- max-width: 820px;
248
- }
249
- .game:empty { display: none; }
238
+ /* The mini-game and the mock share the hero's right-hand column. */
239
+ .visual { min-width: 0; }
240
+
241
+ /* Found, so the mock steps aside. A sibling selector rather than
242
+ :has(), because the swap must work everywhere: an opener that is
243
+ still unclicked carries a different value and leaves the mock
244
+ alone. */
245
+ [data-hidden-game='found'] + .illustration { display: none; }
246
+
247
+ /* A game needs more room than a mock does: the boards hold up to
248
+ 760px and the column is about 560. Progressive, so a browser
249
+ without :has() shows a narrower game rather than a broken hero. */
250
+ .withIllustration .headInner:has([data-hidden-game='found']) {
251
+ grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
252
+ }
250
253
  @media (max-width: 900px) {
251
- .illustration { justify-content: flex-start; }
254
+ .withIllustration .headInner:has([data-hidden-game='found']) {
255
+ grid-template-columns: minmax(0, 1fr);
256
+ }
252
257
  }
258
+
259
+ /* The quiet opener for the `link` kind, which is the one way in that
260
+ shows itself. It sits above the mock rather than replacing it. */
261
+ .visual > [data-hidden-game='opener'] { margin: 0 0 12px; }
262
+
263
+ /* Its own colour is picked for a white page and lands at about 3:1 on
264
+ the cobalt hero, under AA. The crumb and the badges up top already
265
+ answered this with cobalt-100, so the opener uses it too. */
266
+ .bgCobalt .visual [data-hidden-game='opener'] button { color: var(--c-cobalt-100); }
267
+ .bgCobalt .visual [data-hidden-game='opener'] button:hover,
268
+ .bgCobalt .visual [data-hidden-game='opener'] button:focus-visible { color: white; }
@@ -17,9 +17,9 @@
17
17
  * <FeaturedCard
18
18
  * href="/posts/install-opencatalogi"
19
19
  *
20
- * `game` puts a hidden mini-game across the bottom of the card. Only
21
- * on a card without `href`: inside a link the card would swallow every
22
- * click before the game saw it.
20
+ * `game` puts a hidden mini-game where the visual is, once the reader
21
+ * finds it. Only on a card without `href`: inside a link the card
22
+ * would swallow every click before the game saw it.
23
23
  * eyebrow="Featured guide"
24
24
  * title="Install OpenCatalogi in two minutes."
25
25
  * lede="From app store to first register, no terminal required."
@@ -166,6 +166,19 @@ export default function FeaturedCard({
166
166
  )}
167
167
  </div>
168
168
 
169
+ {/* The post's hidden mini-game, when it has one. It belongs in
170
+ the hero for the same reason the app games do: the way in is
171
+ up here, so what you unlocked should be too. It shows
172
+ nothing until the game is found, and then takes the visual's
173
+ place.
174
+
175
+ Not rendered when the whole card is a link: a game inside an
176
+ anchor cannot be played, because the card swallows the click
177
+ before the game sees it. `game` and `href` do not go
178
+ together, and a card that links somewhere is a teaser, not a
179
+ place to play. */}
180
+ {!href && game}
181
+
169
182
  <div className={[styles.visual, hasVisual && styles.visualNode].filter(Boolean).join(' ')} aria-hidden="true">
170
183
  {hasVisual ? visual : (<>
171
184
  {thumbProps.src
@@ -180,18 +193,6 @@ export default function FeaturedCard({
180
193
  ].join(' ')} />
181
194
  </>)}
182
195
  </div>
183
-
184
- {/* The post's hidden mini-game, when it has one. It belongs in
185
- the hero for the same reason the app games do: the way in is
186
- up here, so what you unlocked should be too. It spans both
187
- columns and shows nothing until the game is found.
188
-
189
- Not rendered when the whole card is a link: a game inside an
190
- anchor cannot be played, because the card swallows the click
191
- before the game sees it. `game` and `href` do not go
192
- together, and a card that links somewhere is a teaser, not a
193
- place to play. */}
194
- {game && !href && <div className={styles.game}>{game}</div>}
195
196
  </Tag>
196
197
  );
197
198
  }
@@ -25,17 +25,20 @@
25
25
 
26
26
  .body { min-width: 0; }
27
27
 
28
- /* The post's mini-game, across the whole card rather than in the
29
- visual's column: the games are wide, and a card squeezed into half a
30
- hero reads as an accident. Empty until the game is found. */
31
- .game {
32
- grid-column: 1 / -1;
33
- margin-top: var(--space-8); /* The games hold between 460 and 760px of content, so a card
34
- stretched across the whole hero is mostly empty on the right. Wide
35
- enough for the widest board, and no wider. */
36
- max-width: 820px;
28
+ /* Found, so the visual steps aside and the game takes its column. A
29
+ sibling selector rather than :has(), so the swap works everywhere;
30
+ an opener that is still unclicked carries a different value and
31
+ leaves the visual alone. */
32
+ [data-hidden-game='found'] + .visual { display: none; }
33
+
34
+ /* A game needs more of the card than a thumbnail does. Progressive: a
35
+ browser without :has() shows a narrower game, not a broken card. */
36
+ .card:has([data-hidden-game='found']) {
37
+ grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
38
+ }
39
+ @media (max-width: 900px) {
40
+ .card:has([data-hidden-game='found']) { grid-template-columns: minmax(0, 1fr); }
37
41
  }
38
- .game:empty { display: none; }
39
42
 
40
43
  .eyebrow {
41
44
  display: inline-flex;
@@ -35,6 +35,14 @@
35
35
  * Once found, a game stays found for that browser: reopening the page
36
36
  * shows it straight away, because hiding it again would punish the
37
37
  * person who solved it.
38
+ *
39
+ * The wrapper carries `data-hidden-game="found"` once it is open, and
40
+ * the `link` opener carries `data-hidden-game="opener"`. That is how a
41
+ * host can give the game the space something else is using: a product
42
+ * hero hides its mock when the game beside it is found, with a plain
43
+ * sibling selector rather than a class from this module. The two
44
+ * values are distinct because an opener is not a game: the hero keeps
45
+ * its mock while the way in is still sitting there unclicked.
38
46
  */
39
47
 
40
48
  import React, {useCallback, useEffect, useRef, useState} from 'react';
@@ -170,7 +178,7 @@ export default function HiddenGame({id, unlock = {}, children, className}) {
170
178
  nothing at all: an empty wrapper is the point. */
171
179
  if (unlock.kind !== 'link') return null;
172
180
  return (
173
- <p className={[styles.opener, className].filter(Boolean).join(' ')}>
181
+ <p className={[styles.opener, className].filter(Boolean).join(' ')} data-hidden-game="opener">
174
182
  <button type="button" className={styles.openerButton} onClick={reveal}>
175
183
  {unlock.label || translate({
176
184
  id: 'preset.hiddenGame.opener',
@@ -183,7 +191,7 @@ export default function HiddenGame({id, unlock = {}, children, className}) {
183
191
  }
184
192
 
185
193
  return (
186
- <div className={[styles.found, className].filter(Boolean).join(' ')} ref={holder}>
194
+ <div className={[styles.found, className].filter(Boolean).join(' ')} ref={holder} data-hidden-game="found">
187
195
  {children}
188
196
  </div>
189
197
  );