@hagicode/hagilight-starlight 0.15.1 → 0.15.2-dev.159.1.216d0b5

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.
@@ -20,7 +20,7 @@ import ArticlePromotionPicker from './ArticlePromotionPicker.astro';
20
20
 
21
21
  interface Props {
22
22
  lang?: string;
23
- /** Swap the illustration for one random pool entry per page view. Defaults to `true`. */
23
+ /** Deal the illustration as a fan of random cat heads, like the footer avatar. Defaults to `true`. */
24
24
  randomAvatar?: boolean;
25
25
  }
26
26
 
@@ -46,7 +46,7 @@ const galleryImages: Record<string, ImageMetadata> = {
46
46
  heroes,
47
47
  'cat-head': catHead,
48
48
  };
49
- // The illustration slot is the only gallery image that may change; its pool lives in the showcase manifest.
49
+ // The illustration slot is the only gallery image that may change; its pool lives in the showcase manifest. It is dealt as the footer's fan of cat heads.
50
50
  const ILLUSTRATION_ID = 'cat-head';
51
51
  const avatarEntry = showcaseManifest.assets.find(({ id }) => id === ILLUSTRATION_ID);
52
52
  const avatarPool = randomAvatar && avatarEntry && 'pool' in avatarEntry ? randomPoolFromManifest(avatarEntry.pool) : undefined;
@@ -106,7 +106,7 @@ const gallery = copy.gallery.flatMap((item) => {
106
106
  <ul class="hagilight-article-promotion__gallery" aria-labelledby="hagilight-article-promotion-gallery-title">
107
107
  {gallery.map((item) => (
108
108
  <li>
109
- <figure data-random-pool={item.id === ILLUSTRATION_ID && avatarPool ? randomPoolAttribute(avatarPool) : undefined}>
109
+ <figure>
110
110
  <Picture
111
111
  src={item.image}
112
112
  alt={item.alt}
@@ -119,6 +119,7 @@ const gallery = copy.gallery.flatMap((item) => {
119
119
  loading="lazy"
120
120
  decoding="async"
121
121
  fetchpriority="low"
122
+ pictureAttributes={item.id === ILLUSTRATION_ID && avatarPool ? { 'data-random-fan': randomPoolAttribute(avatarPool) } : undefined}
122
123
  />
123
124
  <figcaption>{item.caption}</figcaption>
124
125
  </figure>
@@ -442,6 +443,90 @@ const gallery = copy.gallery.flatMap((item) => {
442
443
  max-width: 12rem;
443
444
  }
444
445
 
446
+ /*
447
+ * The illustration's fan, the footer avatar's fan at the illustration's size: three cards pivot on a point
448
+ * below the stack, the vendored default is the first centre card and fades out as the random cards are dealt
449
+ * over it. Offsets are percentages of a card, so the fan scales with the 12 rem box.
450
+ */
451
+ .hagilight-article-promotion picture[data-random-fan] {
452
+ position: relative;
453
+ aspect-ratio: 112 / 76;
454
+ }
455
+
456
+ .hagilight-article-promotion picture[data-random-fan] img,
457
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card) {
458
+ position: absolute;
459
+ top: 13.16%;
460
+ left: 25%;
461
+ width: 50%;
462
+ height: auto;
463
+ aspect-ratio: 1;
464
+ border: 0;
465
+ box-shadow: 0 0 0 2px var(--sl-color-bg), 0 3px 8px -2px color-mix(in srgb, var(--sl-color-black) 45%, transparent);
466
+ transform-origin: 50% 140%;
467
+ transition: opacity 320ms ease-out, transform 760ms cubic-bezier(0.16, 1, 0.3, 1);
468
+ }
469
+
470
+ .hagilight-article-promotion figure:hover picture[data-random-fan] img,
471
+ .hagilight-article-promotion figure:hover picture[data-random-fan] :global(.hagilight-fan__card) {
472
+ border: 0;
473
+ }
474
+
475
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan) {
476
+ position: absolute;
477
+ inset: 0;
478
+ display: block;
479
+ }
480
+
481
+ .hagilight-article-promotion figure:hover picture[data-random-fan] img[data-fan-out],
482
+ .hagilight-article-promotion picture[data-random-fan] img[data-fan-out] {
483
+ opacity: 0;
484
+ transform: scale(0.9);
485
+ }
486
+
487
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card) {
488
+ z-index: 0;
489
+ opacity: 0;
490
+ transform: scale(0.6);
491
+ }
492
+
493
+ .hagilight-article-promotion figure:hover picture[data-random-fan] :global(.hagilight-fan__card[data-slot="0"]),
494
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="0"]) {
495
+ z-index: 1;
496
+ opacity: 1;
497
+ transform: translate(-11%, 2%) rotate(-17deg);
498
+ }
499
+
500
+ .hagilight-article-promotion figure:hover picture[data-random-fan] :global(.hagilight-fan__card[data-slot="1"]),
501
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="1"]) {
502
+ z-index: 3;
503
+ opacity: 1;
504
+ transform: none;
505
+ }
506
+
507
+ .hagilight-article-promotion figure:hover picture[data-random-fan] :global(.hagilight-fan__card[data-slot="2"]),
508
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="2"]) {
509
+ z-index: 2;
510
+ opacity: 1;
511
+ transform: translate(11%, 2%) rotate(17deg);
512
+ }
513
+
514
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="3"]),
515
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="4"]) {
516
+ transform: translate(18%, 0) rotate(34deg) scale(0.7);
517
+ }
518
+
519
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card[data-slot="5"]) {
520
+ transform: translate(-18%, 0) rotate(-36deg) scale(0.7);
521
+ }
522
+
523
+ @media (prefers-reduced-motion: reduce) {
524
+ .hagilight-article-promotion picture[data-random-fan] img,
525
+ .hagilight-article-promotion picture[data-random-fan] :global(.hagilight-fan__card) {
526
+ transition: none;
527
+ }
528
+ }
529
+
445
530
  /* Closing: a full-bleed band, the heaviest surface, so "get it" is where the eye lands last. */
446
531
  .hagilight-article-promotion__closing {
447
532
  display: grid;
@@ -1,9 +1,9 @@
1
1
  ---
2
- // Rendered only when the showcase's random option is on, so a site that turns it off ships no picker script.
2
+ // Rendered only when the showcase's random option is on, so a site that turns it off ships no picker script. The illustration deals its cats as the footer's fan.
3
3
  ---
4
4
 
5
5
  <script>
6
- import { mountRandomImages } from '@hagicode/hagilight-core/random-image';
6
+ import { mountRandomFans } from '@hagicode/hagilight-core/random-image';
7
7
 
8
- void mountRandomImages(document);
8
+ void mountRandomFans(document);
9
9
  </script>
package/README.md CHANGED
@@ -167,7 +167,7 @@ The copy and assets mirror `repos/web` and `repos/docs` in the HagiCode monorepo
167
167
 
168
168
  - **Copy:** edit `src/article-promotion-copy/<locale>.ts` (every locale must keep the same fields, feature ids, and gallery ids). Terminology is pinned in `GLOSSARY` in `src/article-promotion-copy/index.ts`, seeded from the product locale files in `repos/web/src/locales/<locale>/`. `HagiCode`, `OpenSpec`, `Hero Scenario`, `Microsoft Store`, and `Windows` are never translated.
169
169
  - **Images:** audit the candidate, crop and convert it to WebP (the AVIF and JPEG tiers are derived at build time, so an opaque image needs no extra file), add or update its `manifest.json` entry, register it in the `galleryImages` map in `ArticlePromotion.astro`, and add a caption and text alternative in every locale. The gallery mosaic places the first, second, and third catalog entries as the left top, left bottom, and right tall slot, so keep the three screenshots first. The illustration is the fourth entry: from 36rem it takes a full-width row with a 12 rem square and its caption, and it is the only gallery image that may change. To add a screenshot, revisit the placement in the component's `@container (min-width: 36rem)` block. `npm test` checks that the manifest, the files, the component registry, and the copy agree.
170
- - **Random illustration (R2 pool):** the `cat-head` entry in `assets/showcase/manifest.json` carries `source` (`repo: img-gen`, `album`, `objectKey`), its audit, and `pool` (`album`, `maxBytes` 200 KiB, `entries` with `key` and `bytes`). `ArticlePromotion.astro` builds the pool attribute at build time and renders `ArticlePromotionPicker.astro` only when the option is on. Refresh: take keys from the `cat-head-gallery` album `index.json`, keep 12 to 200 unique keys each within `maxBytes`, audit them text-free and current, update `pool.entries`, and keep the footer pool in `repos/hagilight/packages/core/assets/footer/manifest.json` in step. To rebuild the WebP, resize the source to 1200 px (lanczos3) and encode at quality 88. `npm test` (`test/showcase-assets.test.mjs`) checks the entry, the pool, the byte caps and the budgets.
170
+ - **Random illustration (R2 pool):** the `cat-head` entry in `assets/showcase/manifest.json` carries `source` (`repo: img-gen`, `album`, `objectKey`), its audit, and `pool` (`album`, `maxBytes` 200 KiB, `entries` with `key` and `bytes`). `ArticlePromotion.astro` builds the pool attribute (`data-random-fan` on the illustration's `<picture>`) at build time and renders `ArticlePromotionPicker.astro` only when the option is on. The picker runs `mountRandomFans`, so the illustration is dealt as the same turning fan of three cat heads as the footer avatar, at the illustration's 12 rem width. Refresh: take keys from the `cat-head-gallery` album `index.json`, keep 12 to 200 unique keys each within `maxBytes`, audit them text-free and current, update `pool.entries`, and keep the footer pool in `repos/hagilight/packages/core/assets/footer/manifest.json` in step. To rebuild the WebP, resize the source to 1200 px (lanczos3) and encode at quality 88. `npm test` (`test/showcase-assets.test.mjs`) checks the entry, the pool, the byte caps and the budgets.
171
171
  - **Options:** `hagicodePromotion: { randomAvatar: false }` keeps the default illustration and loads no picker; `footer: { avatar: false }` removes the footer avatar, and `footer: { randomAvatar: false }` keeps its default. A site whose `img-src` policy blocks `https://img-gen.hagicode.com` keeps the defaults.
172
172
  - **Badge:** the product id is parsed from the Store URL and the badge language map lives in `src/windows-download.ts`. Re-check both against `repos/docs/src/components/MicrosoftStoreBadge.tsx` and the official site when the Store listing or the supported languages change.
173
173
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hagicode/hagilight-starlight",
3
- "version": "0.15.1",
3
+ "version": "0.15.2-dev.159.1.216d0b5",
4
4
  "type": "module",
5
5
  "description": "Starlight plugin and components for HagiCode documentation",
6
6
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "assets/showcase/*"
54
54
  ],
55
55
  "dependencies": {
56
- "@hagicode/hagilight-core": "0.15.1"
56
+ "@hagicode/hagilight-core": "0.15.2-dev.159.1.216d0b5"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@astrojs/starlight": "^0.42.4",