create-ailk 0.13.0 → 0.14.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/README.md +12 -4
- package/component-catalog.json +247 -33
- package/component-catalog.md +10 -6
- package/dist/apply-design.d.ts +21 -2
- package/dist/apply-design.js +120 -19
- package/dist/cli.js +1 -0
- package/dist/design-compile.d.ts +70 -2
- package/dist/design-compile.js +97 -1
- package/dist/design-home.d.ts +74 -0
- package/dist/design-home.js +256 -0
- package/dist/design-package.d.ts +39 -2
- package/dist/design-package.js +223 -9
- package/dist/design-presets.d.ts +17 -1
- package/dist/design-presets.js +17 -5
- package/dist/design-scaffold.d.ts +6 -25
- package/dist/design-scaffold.js +26 -74
- package/dist/index.d.ts +1 -0
- package/dist/lib/design-checks.d.ts +12 -1
- package/dist/lib/design-checks.js +38 -2
- package/dist/lib/module-license-gate.d.ts +9 -0
- package/dist/lib/module-license-gate.js +18 -0
- package/dist/programmatic.js +70 -26
- package/dist/site-chrome.d.ts +38 -0
- package/dist/site-chrome.js +109 -2
- package/dist/site-fonts.d.ts +21 -0
- package/dist/site-fonts.js +54 -0
- package/dist/site-roster.d.ts +16 -0
- package/dist/site-roster.js +81 -0
- package/dist/starter-grid.js +15 -0
- package/dist/surfaces.js +12 -0
- package/dist/team-profiles.d.ts +29 -0
- package/dist/team-profiles.js +43 -0
- package/package.json +3 -3
- package/release-scope.json +1 -1
- package/site-templates/_base/content/en/TeamList/team.mdx +68 -0
- package/site-templates/_base/content/en/TeamMember/first-member.mdx +22 -0
- package/site-templates/_base/content/en/TeamMember/second-member.mdx +22 -0
- package/site-templates/_base/content/en/TeamMember/third-member.mdx +22 -0
- package/site-templates/designs/minimalism/DESIGN.md +164 -34
- package/site-templates/designs/minimalism/home/local-business-service.mdx +119 -0
- package/site-templates/designs/minimalism/home/organization-product.mdx +132 -0
- package/site-templates/designs/minimalism/home/organization-service.mdx +131 -0
- package/site-templates/designs/minimalism/home/person-service.mdx +101 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +34 -1
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +20 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +34 -1
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +22 -1
- package/site-templates/marketing-site-free/ailk-template.json +1 -1
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +34 -1
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -7
- package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +34 -1
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -7
- package/site-templates/shapes/organization-service/ailk-template.json +1 -1
- package/templates/README.md +2 -0
- package/templates/apps/api/CLAUDE.md +4 -1
- package/templates/apps/mcp/package.json +1 -1
- package/templates/apps/web/CLAUDE.md +11 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/settings.test.tsx +10 -0
- package/templates/apps/web/app/[locale]/(authed)/account/settings/__tests__/theme-modes.test.ts +42 -0
- package/templates/apps/web/app/[locale]/(authed)/account/settings/theme-modes.ts +8 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +14 -1
- package/templates/apps/web/app/[locale]/contact/__tests__/site-contact-lines.test.ts +69 -0
- package/templates/apps/web/app/[locale]/contact/site-contact-lines.ts +64 -0
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +4 -4
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +15 -3
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +17 -6
- package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +14 -1
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +4 -6
- package/templates/apps/web/app/[locale]/layout.tsx +156 -53
- package/templates/apps/web/app/[locale]/page.tsx +37 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +4 -6
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +15 -2
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +43 -6
- package/templates/apps/web/app/[locale]/services/page.tsx +14 -2
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/team/[slug]/page.tsx +45 -0
- package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +155 -0
- package/templates/apps/web/app/[locale]/team/page.tsx +49 -0
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +14 -1
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +2 -2
- package/templates/apps/web/app/not-found.tsx +47 -0
- package/templates/apps/web/lib/__tests__/profile-back-link.test.ts +95 -0
- package/templates/apps/web/lib/__tests__/site-theme-head.test.ts +70 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +64 -1
- package/templates/apps/web/lib/profile-back-link.ts +51 -0
- package/templates/apps/web/lib/site-chrome.ts +12 -0
- package/templates/apps/web/lib/site-fonts.ts +15 -0
- package/templates/apps/web/lib/site-logo.tsx +39 -1
- package/templates/apps/web/lib/site-theme-head.ts +33 -0
- package/templates/apps/web/lib/site-theme.ts +13 -1
- package/templates/apps/web/messages/en.json +7 -1
- package/templates/database/CHANGELOG.md +7 -0
- package/templates/database/package.json +1 -1
- package/versions.json +34 -34
- package/site-templates/designs/minimalism/sample/README.md +0 -48
- package/site-templates/designs/minimalism/sample/content/en/HomePage/home.mdx +0 -244
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-1.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-2.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-3.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-4.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-5.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/avatar-placeholder-6.svg +0 -7
- package/site-templates/designs/minimalism/sample/public/hero-backdrop.svg +0 -17
- package/site-templates/designs/minimalism/sample/public/logo-placeholder-1.svg +0 -6
- package/site-templates/designs/minimalism/sample/public/logo-placeholder-2.svg +0 -6
- package/site-templates/designs/minimalism/sample/public/logo-placeholder-3.svg +0 -6
- package/site-templates/designs/minimalism/sample/public/wordmark-placeholder.svg +0 -28
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// Auth route group — the marketing chrome is dropped on the five (auth) paths (#5963)
|
|
8
8
|
// Account area — the marketing chrome AND the consent Banner are dropped on /account paths (#7430)
|
|
9
9
|
// Site-declared theme — `_site.mdx` `theme:` block → token overlay → CSS vars
|
|
10
|
+
// Design web faces — generated `lib/site-fonts.ts` → beneath `brand.fonts` (#7720)
|
|
10
11
|
//
|
|
11
12
|
// Sits under app/[locale]/ and sets the <html lang> attribute to the
|
|
12
13
|
// active locale. next-intl's NextIntlClientProvider is wired here so
|
|
@@ -26,7 +27,6 @@ import "../globals.css";
|
|
|
26
27
|
|
|
27
28
|
import { Telemetry, VerificationMeta } from "@working-theory/analytics";
|
|
28
29
|
import { MarketingShell } from "@working-theory/templates/shells";
|
|
29
|
-
import { themeToCssVarsBothModes } from "@working-theory/theme";
|
|
30
30
|
import { Link, isRtl, localeHref } from "@working-theory/ui";
|
|
31
31
|
import { BRAND_PATHS, LocaleSwitcherNav } from "@working-theory/ui/blocks";
|
|
32
32
|
import {
|
|
@@ -57,8 +57,9 @@ import { isAccountPath, isAuthPath } from "../../lib/auth-routes";
|
|
|
57
57
|
import { assertEnabledLocale } from "../../lib/locale-guard";
|
|
58
58
|
import { footerColumns, navItems } from "../../lib/nav-config";
|
|
59
59
|
import { getOgImageUrl } from "../../lib/og";
|
|
60
|
+
import { backLinkHref } from "../../lib/profile-back-link";
|
|
60
61
|
import { SITE_NAME } from "../../lib/site-brand";
|
|
61
|
-
import { siteChrome } from "../../lib/site-chrome";
|
|
62
|
+
import { siteChrome, type SiteChrome } from "../../lib/site-chrome";
|
|
62
63
|
import { siteLogo } from "../../lib/site-logo";
|
|
63
64
|
// Registers the `_site.mdx` identity with page-renderer at module load, so
|
|
64
65
|
// every page rendered under this layout carries the sitewide JSON-LD (#6597).
|
|
@@ -67,9 +68,23 @@ import "../../lib/site-identity";
|
|
|
67
68
|
// live listicle's landing page gets its shelves and each entry its page
|
|
68
69
|
// (#7521). Inert without AILK_LISTING_PUBLIC_KEY or the paid package.
|
|
69
70
|
import "../../lib/listings";
|
|
70
|
-
import {
|
|
71
|
+
import { siteThemeHead } from "../../lib/site-theme-head";
|
|
71
72
|
import { resolveBaseUrl } from "../../src/lib/routes";
|
|
72
73
|
|
|
74
|
+
import { readSiteContactLines } from "./contact/site-contact-lines";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The generated `siteChrome`, read through a widened type (#7740 D8): a
|
|
78
|
+
* scaffold generated before `deckPresentation` existed has no such member,
|
|
79
|
+
* so this compiles against both shapes of the generated file, as the home
|
|
80
|
+
* page reads `deckGrounds`. `colorMode` and `chromeStyle` (#7742 D1) likewise.
|
|
81
|
+
*/
|
|
82
|
+
const chrome: SiteChrome & {
|
|
83
|
+
deckPresentation?: true;
|
|
84
|
+
colorMode?: "light";
|
|
85
|
+
chromeStyle?: "minimal";
|
|
86
|
+
} = siteChrome;
|
|
87
|
+
|
|
73
88
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
74
89
|
|
|
75
90
|
const DEFAULT_LOCALE = "en";
|
|
@@ -226,7 +241,13 @@ export default async function LocaleLayout({
|
|
|
226
241
|
// message load or session read.
|
|
227
242
|
assertEnabledLocale(locale);
|
|
228
243
|
const messages = await getMessages();
|
|
229
|
-
|
|
244
|
+
// #7742 D2 — `colorMode: "light"` pins the mode: a saved dark cookie is
|
|
245
|
+
// ignored, no flash script runs and no theme switch renders.
|
|
246
|
+
const pinLight = chrome.colorMode === "light";
|
|
247
|
+
const themeMode: ThemeMode = pinLight ? "light" : await resolveThemeMode();
|
|
248
|
+
// #7742 D3/D5 — the minimal chrome: the closing slide, the hairline consent
|
|
249
|
+
// bar and the cue offset.
|
|
250
|
+
const isMinimalChrome = chrome.chromeStyle === "minimal";
|
|
230
251
|
const consentDecided = await hasConsentChoice();
|
|
231
252
|
// Server-side session read (#4984) — the same `auth.api.getSession` idiom
|
|
232
253
|
// the `(authed)` segment guard uses. Null when signed out or auth is unset.
|
|
@@ -325,6 +346,13 @@ export default async function LocaleLayout({
|
|
|
325
346
|
// `kind: "flow"` so Nav hands their triggers back through
|
|
326
347
|
// `renderFlowTrigger`, which `SignedInNav` owns (see NAV_CLIENT_ACTION_FLOW
|
|
327
348
|
// above).
|
|
349
|
+
// The signed-out auth pair, shared by the header (every page but the deck
|
|
350
|
+
// home) and the deck home's closing footer slide (#7718 D4).
|
|
351
|
+
const authActions = [
|
|
352
|
+
// NO_HAND_IMPLEMENT_OK: operator-directed live Free-template pass.
|
|
353
|
+
{ labelKey: "signIn", path: "/sign-in", variant: "outline-strong" },
|
|
354
|
+
{ labelKey: "signUp", path: "/sign-up", variant: "primary" },
|
|
355
|
+
] as const satisfies readonly NavAction[];
|
|
328
356
|
const navActions: NavAction[] = session
|
|
329
357
|
? [
|
|
330
358
|
{ labelKey: "account", kind: "flow", flow: NAV_CLIENT_ACTION_FLOW },
|
|
@@ -335,11 +363,45 @@ export default async function LocaleLayout({
|
|
|
335
363
|
variant: "outline-strong",
|
|
336
364
|
},
|
|
337
365
|
]
|
|
338
|
-
: [
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
366
|
+
: [...authActions];
|
|
367
|
+
|
|
368
|
+
// The announcement bar is HOME-ONLY (#5469 D5): its route gate matches the
|
|
369
|
+
// pathname literally, and under next-intl's `as-needed` prefixing the home
|
|
370
|
+
// path is `/` for the default locale and `/<locale>` for every other one.
|
|
371
|
+
const homePath = locale === DEFAULT_LOCALE ? "/" : `/${locale}`;
|
|
372
|
+
|
|
373
|
+
// Deck home (#5612 D3): `siteChrome.home === "deck"` only ever applies
|
|
374
|
+
// `snap="mandatory"` + `deckHero` on the locale-root route — every other
|
|
375
|
+
// path renders byte-identically regardless of the knob. `x-pathname` is the
|
|
376
|
+
// same header `generateMetadata` above reads (forwarded by middleware.ts);
|
|
377
|
+
// Next.js's `headers()` is request-scoped and cheap to call again here.
|
|
378
|
+
const pathname = (await headers()).get("x-pathname") ?? homePath;
|
|
379
|
+
const isDeckHome = siteChrome.home === "deck" && pathname === homePath;
|
|
380
|
+
// Inner pages (#7721 D4): under `innerPages: "bare"` every page but the
|
|
381
|
+
// home wears the bare header (back arrow + the mark) and the one-bar
|
|
382
|
+
// footer. Fail-safe like the deck gate: a missing `x-pathname` resolves to
|
|
383
|
+
// the home path, so the full bar and its auth buttons render.
|
|
384
|
+
const isBareInner = siteChrome.innerPages === "bare" && pathname !== homePath;
|
|
385
|
+
|
|
386
|
+
// The deck home's header is bare (#7718 D1): no actions, signed in or out.
|
|
387
|
+
// Its auth links move to the footer, the deck's closing slide (D4) — the
|
|
388
|
+
// auth pair signed out, an Account link signed in (the route where Sign
|
|
389
|
+
// out lives; its label is the user's name, `navLabels.items.account`).
|
|
390
|
+
const headerActions: NavAction[] = isDeckHome || isBareInner ? [] : navActions;
|
|
391
|
+
const deckFooterActions = session
|
|
392
|
+
? [{ labelKey: "account", path: "/account", variant: "outline-strong" as const }]
|
|
393
|
+
: [...authActions];
|
|
394
|
+
// A bare inner page's auth (#7721 D3/D4) rides the one-bar footer's link
|
|
395
|
+
// group: Sign in / Sign up signed out, Account signed in (where Sign out
|
|
396
|
+
// lives). Labels from the existing `nav` namespace.
|
|
397
|
+
const accountLinks = !isBareInner
|
|
398
|
+
? []
|
|
399
|
+
: session
|
|
400
|
+
? [{ label: tNav("account"), href: localeHref(locale, "/account") }]
|
|
401
|
+
: [
|
|
402
|
+
{ label: tNav("signIn"), href: localeHref(locale, "/sign-in") },
|
|
403
|
+
{ label: tNav("signUp"), href: localeHref(locale, "/sign-up") },
|
|
404
|
+
];
|
|
343
405
|
|
|
344
406
|
// A flow action needs `renderFlowTrigger`, a function — and this layout is a
|
|
345
407
|
// Server Component. Nav forwards that function into NavMobileMenu ("use
|
|
@@ -352,7 +414,7 @@ export default async function LocaleLayout({
|
|
|
352
414
|
// `renderFlowTrigger` and imports `navItems` (icon components are functions
|
|
353
415
|
// too) on the client side. Without one, Nav stays a Server Component and
|
|
354
416
|
// nothing callable crosses.
|
|
355
|
-
const hasFlowAction =
|
|
417
|
+
const hasFlowAction = headerActions.some((action) => action.kind === "flow");
|
|
356
418
|
|
|
357
419
|
// Shared brand mark injected into both Nav and Footer chrome slots. The
|
|
358
420
|
// mark comes from site-logo.tsx (the mark the /sign-in card also renders);
|
|
@@ -372,19 +434,6 @@ export default async function LocaleLayout({
|
|
|
372
434
|
// middleware and hreflang alternates read (NEXT_PUBLIC_ENABLED_LOCALES).
|
|
373
435
|
const enabledLocales = readLocales();
|
|
374
436
|
|
|
375
|
-
// The announcement bar is HOME-ONLY (#5469 D5): its route gate matches the
|
|
376
|
-
// pathname literally, and under next-intl's `as-needed` prefixing the home
|
|
377
|
-
// path is `/` for the default locale and `/<locale>` for every other one.
|
|
378
|
-
const homePath = locale === DEFAULT_LOCALE ? "/" : `/${locale}`;
|
|
379
|
-
|
|
380
|
-
// Deck home (#5612 D3): `siteChrome.home === "deck"` only ever applies
|
|
381
|
-
// `snap="mandatory"` + `deckHero` on the locale-root route — every other
|
|
382
|
-
// path renders byte-identically regardless of the knob. `x-pathname` is the
|
|
383
|
-
// same header `generateMetadata` above reads (forwarded by middleware.ts);
|
|
384
|
-
// Next.js's `headers()` is request-scoped and cheap to call again here.
|
|
385
|
-
const pathname = (await headers()).get("x-pathname") ?? homePath;
|
|
386
|
-
const isDeckHome = siteChrome.home === "deck" && pathname === homePath;
|
|
387
|
-
|
|
388
437
|
// The (auth) route group's chrome branch (#5963).
|
|
389
438
|
//
|
|
390
439
|
// A route group's layout nests INSIDE its parent segment's layout, so
|
|
@@ -424,7 +473,13 @@ export default async function LocaleLayout({
|
|
|
424
473
|
// `wordmark` (Nav.tsx:344), which are passed below. Scoped to the SAME
|
|
425
474
|
// `isDeckHome` gate MarketingShell's snap/deckHero use, so a non-deck
|
|
426
475
|
// route's render is byte-identical to before this branch existed.
|
|
427
|
-
|
|
476
|
+
// #7718 D1 — and `bar: "bare"`: no rule, fill or actions, the logomark
|
|
477
|
+
// alone, centred.
|
|
478
|
+
// #7721 D4 (gap F) — `mark-only` means the mark alone: no wordmark beside
|
|
479
|
+
// it on any page. On the deck home `deckMorph` still governs the brand:
|
|
480
|
+
// Nav spreads its `full-logo` composition after `logoDisplay`'s.
|
|
481
|
+
...(siteChrome.nav === "mark-only" ? { logoDisplay: "mark" as const } : {}),
|
|
482
|
+
...(isDeckHome ? { sticky: true, deckMorph: true, bar: "bare" as const } : {}),
|
|
428
483
|
siteName: SITE_NAME,
|
|
429
484
|
frame: "contained",
|
|
430
485
|
navAlignment: "right",
|
|
@@ -432,7 +487,7 @@ export default async function LocaleLayout({
|
|
|
432
487
|
logo: brandLogo,
|
|
433
488
|
wordmark: brandWordmark,
|
|
434
489
|
overflowLabel: navOverflowLabel,
|
|
435
|
-
actions:
|
|
490
|
+
...(headerActions.length > 0 ? { actions: headerActions } : {}),
|
|
436
491
|
};
|
|
437
492
|
|
|
438
493
|
// Placeholder social handles (#5469 D5): `{{COMPANY_HANDLE}}` is a
|
|
@@ -483,40 +538,38 @@ export default async function LocaleLayout({
|
|
|
483
538
|
: []),
|
|
484
539
|
];
|
|
485
540
|
|
|
486
|
-
// The site's own declared colours
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
// Both theme modes, gated by [data-theme="dark"] (#1532 — sibling fix; the
|
|
495
|
-
// single-mode call inlined an unconditional :root block that never
|
|
496
|
-
// responded to a client-side data-theme toggle). themeMode still drives
|
|
497
|
-
// the initial data-theme attribute below for a no-flash first paint.
|
|
498
|
-
// Site shape settings (`theme.corners`, `theme.eyebrowCase`) appended after
|
|
499
|
-
// the token block so they win; "" for a site that sets neither.
|
|
500
|
-
const inlineThemeStyle =
|
|
501
|
-
themeToCssVarsBothModes(siteBrandTokens ? { brand: siteBrandTokens } : {}) +
|
|
502
|
-
loadSiteShapeCss();
|
|
541
|
+
// The site's own declared colours (`content/_site.mdx` `theme:` + `brand:`)
|
|
542
|
+
// as a token overlay, the design's web faces (#7720) beneath `brand.fonts`,
|
|
543
|
+
// both theme modes gated by [data-theme="dark"] (#1532) and the site's shape
|
|
544
|
+
// settings after them — one helper, shared with the minimal 404 (#7742 D6).
|
|
545
|
+
// A site that declares no theme gets byte-for-byte the CSS it got before
|
|
546
|
+
// this wiring existed; with no design faces <html> gets no class.
|
|
547
|
+
// themeMode still drives the initial data-theme attribute below.
|
|
548
|
+
const themeHead = siteThemeHead();
|
|
503
549
|
|
|
504
550
|
return (
|
|
505
551
|
<html
|
|
506
552
|
lang={locale}
|
|
507
553
|
dir={isRtl(locale) ? "rtl" : "ltr"}
|
|
508
554
|
data-theme={themeMode}
|
|
555
|
+
className={themeHead.fontClassName}
|
|
556
|
+
// #7742 D5 — scopes the cue's consent-bar offset; absent otherwise.
|
|
557
|
+
{...(isMinimalChrome ? { "data-chrome-style": "minimal" } : {})}
|
|
509
558
|
>
|
|
510
559
|
<head>
|
|
511
|
-
{/* Flash-prevention: runs synchronously before any styled element
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
560
|
+
{/* Flash-prevention: runs synchronously before any styled element.
|
|
561
|
+
Not under `colorMode: light` (#7742 D2) — the mode is pinned, and
|
|
562
|
+
the script would apply the OS dark preference. */}
|
|
563
|
+
{pinLight ? null : (
|
|
564
|
+
<script
|
|
565
|
+
data-testid="theme-flash-prevention"
|
|
566
|
+
dangerouslySetInnerHTML={{ __html: FLASH_PREVENTION_SCRIPT }}
|
|
567
|
+
/>
|
|
568
|
+
)}
|
|
516
569
|
{/* Inline CSS-variable declarations for the active theme mode */}
|
|
517
570
|
<style
|
|
518
571
|
data-ailk="theme-vars"
|
|
519
|
-
dangerouslySetInnerHTML={{ __html:
|
|
572
|
+
dangerouslySetInnerHTML={{ __html: themeHead.css }}
|
|
520
573
|
/>
|
|
521
574
|
{/* Favicons — single brand mark (theme-independent), PNG fallbacks, ICO legacy */}
|
|
522
575
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
@@ -628,10 +681,41 @@ export default async function LocaleLayout({
|
|
|
628
681
|
}
|
|
629
682
|
: {})}
|
|
630
683
|
{...(isDeckHome
|
|
631
|
-
? {
|
|
684
|
+
? {
|
|
685
|
+
snap: "mandatory" as const,
|
|
686
|
+
deckHero: true,
|
|
687
|
+
// #7740 D8 — the design's deck presentation dial.
|
|
688
|
+
...(chrome.deckPresentation === true ? { presentation: true } : {}),
|
|
689
|
+
// The deck's slide-advance controls (#7732) — named from
|
|
690
|
+
// the `nav` catalog, never the shell's English default.
|
|
691
|
+
slideAdvanceLabels: {
|
|
692
|
+
next: tNav("nextSlide"),
|
|
693
|
+
top: tNav("backToTop"),
|
|
694
|
+
},
|
|
695
|
+
}
|
|
632
696
|
: {})}
|
|
633
697
|
nav={
|
|
634
|
-
|
|
698
|
+
// #7721 D4 — a bare inner page's header: the back arrow home
|
|
699
|
+
// and the mark. It carries no actions, so it is always the
|
|
700
|
+
// server Nav (nothing callable crosses the RSC boundary).
|
|
701
|
+
// #7744 D7 — on a deck home a team profile's arrow returns
|
|
702
|
+
// to the people slide (`/#slide-people`) instead.
|
|
703
|
+
isBareInner ? (
|
|
704
|
+
<Nav
|
|
705
|
+
{...navProps}
|
|
706
|
+
navItems={[]}
|
|
707
|
+
bar="bare"
|
|
708
|
+
backLink={{
|
|
709
|
+
href: backLinkHref({
|
|
710
|
+
pathname,
|
|
711
|
+
homePath,
|
|
712
|
+
home: siteChrome.home,
|
|
713
|
+
locales: enabledLocales,
|
|
714
|
+
}),
|
|
715
|
+
label: tNav("home"),
|
|
716
|
+
}}
|
|
717
|
+
/>
|
|
718
|
+
) : hasFlowAction ? (
|
|
635
719
|
<SignedInNav {...navProps} />
|
|
636
720
|
) : (
|
|
637
721
|
<Nav
|
|
@@ -650,10 +734,26 @@ export default async function LocaleLayout({
|
|
|
650
734
|
logo={brandLogo}
|
|
651
735
|
wordmark={brandWordmark}
|
|
652
736
|
social={[...socialLinks]}
|
|
653
|
-
|
|
654
|
-
|
|
737
|
+
// #7742 D3 — under `chromeStyle: minimal` the deck home's
|
|
738
|
+
// closing slide is the wordmark, the contact lines and the
|
|
739
|
+
// legal line: no actions and no centred lockup, so Sign in /
|
|
740
|
+
// Sign up are on no part of the home.
|
|
741
|
+
// #7721 D4 — a bare inner page's footer is the one bar, its
|
|
742
|
+
// link group carrying the account links the header drops.
|
|
743
|
+
{...(isDeckHome && isMinimalChrome
|
|
744
|
+
? { layout: "closing" as const, contactLines: readSiteContactLines() }
|
|
745
|
+
: isBareInner
|
|
746
|
+
? { layout: "line" as const, accountLinks }
|
|
747
|
+
: siteChrome.footer === "centered"
|
|
748
|
+
? { layout: "centered" as const }
|
|
749
|
+
: {})}
|
|
750
|
+
// #7718 D4 — the deck home's closing slide carries the
|
|
751
|
+
// centred brand and the auth links its bare header drops.
|
|
752
|
+
{...(isDeckHome && !isMinimalChrome
|
|
753
|
+
? { centeredBrand: true, actions: deckFooterActions }
|
|
655
754
|
: {})}
|
|
656
|
-
|
|
755
|
+
// #7742 D2 — no theme switch under `colorMode: light`.
|
|
756
|
+
showThemeToggle={!pinLight}
|
|
657
757
|
bottomBarAlign="content"
|
|
658
758
|
copyrightText={copyrightText}
|
|
659
759
|
legalLinks={legalLinks}
|
|
@@ -713,6 +813,9 @@ export default async function LocaleLayout({
|
|
|
713
813
|
secondaryAction={{ label: tConsent("rejectLabel") }}
|
|
714
814
|
rejectLabel={tConsent("rejectLabel")}
|
|
715
815
|
locale={locale}
|
|
816
|
+
// #7742 D5 — the minimal chrome's consent bar: the page ground,
|
|
817
|
+
// a hairline, no shadow.
|
|
818
|
+
{...(isMinimalChrome ? { consentAppearance: "hairline" as const } : {})}
|
|
716
819
|
/>
|
|
717
820
|
)}
|
|
718
821
|
<Telemetry />
|
|
@@ -14,6 +14,19 @@ import {
|
|
|
14
14
|
import type { Metadata } from "next";
|
|
15
15
|
import type { ReactElement } from "react";
|
|
16
16
|
|
|
17
|
+
import { siteChrome, type SiteChrome } from "../../lib/site-chrome";
|
|
18
|
+
import { siteLogomarkAsset, siteWordmarkAsset } from "../../lib/site-logo";
|
|
19
|
+
|
|
20
|
+
/** The ground sequence `renderPage` cycles over a deck home's slides (#7719). */
|
|
21
|
+
type DeckGrounds = NonNullable<Parameters<typeof renderPage>[0]["deckGrounds"]>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The generated `siteChrome`, read through a widened type: its interface
|
|
25
|
+
* carries `deckGrounds` only when the site's design sets one (#7719 D3), so
|
|
26
|
+
* this compiles against both shapes of the generated file.
|
|
27
|
+
*/
|
|
28
|
+
const chrome: SiteChrome & { deckGrounds?: DeckGrounds; deckPresentation?: true } = siteChrome;
|
|
29
|
+
|
|
17
30
|
interface Props {
|
|
18
31
|
params: Promise<{ locale: string }>;
|
|
19
32
|
/**
|
|
@@ -22,6 +35,12 @@ interface Props {
|
|
|
22
35
|
*/
|
|
23
36
|
getMdxSource?: typeof defaultGetMdxSource;
|
|
24
37
|
getPageSections?: typeof defaultGetPageSections;
|
|
38
|
+
/** The site's `layout.home` knob; defaults to the generated `siteChrome`. */
|
|
39
|
+
home?: SiteChrome["home"];
|
|
40
|
+
/** The design's `layout.deckGrounds`; defaults to the generated `siteChrome`'s. */
|
|
41
|
+
deckGrounds?: DeckGrounds;
|
|
42
|
+
/** The design's `layout.deckPresentation` (#7740); defaults to the generated `siteChrome`'s. */
|
|
43
|
+
deckPresentation?: boolean;
|
|
25
44
|
}
|
|
26
45
|
|
|
27
46
|
export async function generateMetadata({
|
|
@@ -35,6 +54,9 @@ export default async function Page({
|
|
|
35
54
|
params,
|
|
36
55
|
getMdxSource,
|
|
37
56
|
getPageSections,
|
|
57
|
+
home = chrome.home,
|
|
58
|
+
deckGrounds = chrome.deckGrounds,
|
|
59
|
+
deckPresentation = chrome.deckPresentation,
|
|
38
60
|
}: Props): Promise<ReactElement> {
|
|
39
61
|
const { locale } = await params;
|
|
40
62
|
return renderPage({
|
|
@@ -46,5 +68,20 @@ export default async function Page({
|
|
|
46
68
|
emptyStateTestId: "home-description",
|
|
47
69
|
...(getMdxSource !== undefined && { getMdxSource }),
|
|
48
70
|
...(getPageSections !== undefined && { getPageSections }),
|
|
71
|
+
// #7733 — the deck home's header is bare on slide 1 (#5697), so its
|
|
72
|
+
// landing carries the brand: a centred leading hero renders as bondcap's
|
|
73
|
+
// landing with the site's wordmark in the headline's place; any other
|
|
74
|
+
// leading hero keeps its composition and takes the logomark (#7711).
|
|
75
|
+
// Content that authors its own lockup keeps it.
|
|
76
|
+
...(home === "deck" && {
|
|
77
|
+
deckLanding: { wordmark: siteWordmarkAsset(), logomark: siteLogomarkAsset() },
|
|
78
|
+
}),
|
|
79
|
+
// #7719 — a deck home cycles its design's ground sequence, slide by
|
|
80
|
+
// slide, onto every slide that authors no surface of its own.
|
|
81
|
+
...(home === "deck" && deckGrounds !== undefined && { deckGrounds }),
|
|
82
|
+
// #7740 — a deck home under the presentation dial: every slide with an
|
|
83
|
+
// alignment field centred, card grids one column on phones, and slide
|
|
84
|
+
// anchors clear of the page's JSON-LD @id fragments.
|
|
85
|
+
...(home === "deck" && deckPresentation === true && { deckPresentation: true }),
|
|
49
86
|
});
|
|
50
87
|
}
|
|
@@ -68,7 +68,7 @@ describe("partners/page — snapshot regression", () => {
|
|
|
68
68
|
});
|
|
69
69
|
const { container } = render(element);
|
|
70
70
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
71
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Partners","description":"Organisations partnering with AI Launch Kit.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"Organization"}]}}</script><main id="main"><h1>Partners</h1><p data-testid="partners-description">Organisations partnering with AI Launch Kit.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-rendered">mdx-body-content</div></article></div></div></main>"`,
|
|
71
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Partners","description":"Organisations partnering with AI Launch Kit.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"Organization"}]}}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Partners</h1><p data-testid="partners-description" class="mt-block-tight text-lead">Organisations partnering with AI Launch Kit.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-fg) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-rendered">mdx-body-content</div></div></article></div></div></div></main>"`,
|
|
72
72
|
);
|
|
73
73
|
});
|
|
74
74
|
});
|
|
@@ -93,7 +93,7 @@ describe("partners/[slug]/page — snapshot regression", () => {
|
|
|
93
93
|
});
|
|
94
94
|
const { container } = render(element);
|
|
95
95
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
96
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Acme Corp","description":"Acme Corp is a strategic partner.","mainEntity":{"@context":"https://schema.org","@type":"Organization","name":"Acme Corp","description":"Acme Corp is a strategic partner."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Partners","item":"http://localhost:3000/en/partners"},{"@type":"ListItem","position":3,"name":"Acme Corp","item":"http://localhost:3000/en/partners/acme-corp"}]}]}</script><main id="main"><h1>Acme Corp</h1><p data-testid="acme-corp-description">Acme Corp is a strategic partner.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-rendered">mdx-body-content</div></article></div></div></main>"`,
|
|
96
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Acme Corp","description":"Acme Corp is a strategic partner.","mainEntity":{"@context":"https://schema.org","@type":"Organization","name":"Acme Corp","description":"Acme Corp is a strategic partner."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Partners","item":"http://localhost:3000/en/partners"},{"@type":"ListItem","position":3,"name":"Acme Corp","item":"http://localhost:3000/en/partners/acme-corp"}]}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Acme Corp</h1><p data-testid="acme-corp-description" class="mt-block-tight text-lead">Acme Corp is a strategic partner.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-fg) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-rendered">mdx-body-content</div></div></article></div></div></div></main>"`,
|
|
97
97
|
);
|
|
98
98
|
});
|
|
99
99
|
|
|
@@ -87,9 +87,8 @@ describe("ProductsPage — snapshot regression", () => {
|
|
|
87
87
|
});
|
|
88
88
|
const { container } = render(element);
|
|
89
89
|
expect(container.innerHTML).toMatchInlineSnapshot(`
|
|
90
|
-
"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Products","description":"All products.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"SoftwareApplication"}]}}</script><main id="main"><h1>Products</h1><p data-testid="products-description">All products.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source="
|
|
91
|
-
|
|
92
|
-
Body."></div></article></div></div></main>"
|
|
90
|
+
"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Products","description":"All products.","mainEntity":{"@type":"ItemList","itemListElement":[{"@type":"SoftwareApplication"}]}}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">Products</h1><p data-testid="products-description" class="mt-block-tight text-lead">All products.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-fg) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-remote" data-source="
|
|
91
|
+
Body."></div></div></article></div></div></div></main>"
|
|
93
92
|
`);
|
|
94
93
|
});
|
|
95
94
|
});
|
|
@@ -111,9 +110,8 @@ describe("ProductSlugPage — snapshot regression", () => {
|
|
|
111
110
|
});
|
|
112
111
|
const { container } = render(element);
|
|
113
112
|
expect(container.innerHTML).toMatchInlineSnapshot(`
|
|
114
|
-
"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"AI Launch Kit","description":"The AX-first OSS template.","mainEntity":{"@context":"https://schema.org","@type":"SoftwareApplication","name":"AI Launch Kit","description":"The AX-first OSS template."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Products","item":"http://localhost:3000/en/products"},{"@type":"ListItem","position":3,"name":"AI Launch Kit","item":"http://localhost:3000/en/products/launch-kit"}]}]}</script><main id="main"><h1>AI Launch Kit</h1><p data-testid="product-description">The AX-first OSS template.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source="
|
|
115
|
-
|
|
116
|
-
Body."></div></article></div></div></main>"
|
|
113
|
+
"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"AI Launch Kit","description":"The AX-first OSS template.","mainEntity":{"@context":"https://schema.org","@type":"SoftwareApplication","name":"AI Launch Kit","description":"The AX-first OSS template."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Products","item":"http://localhost:3000/en/products"},{"@type":"ListItem","position":3,"name":"AI Launch Kit","item":"http://localhost:3000/en/products/launch-kit"}]}]}</script><main id="main"><div class="mx-auto w-full max-w-container-xl px-4 md:px-6 lg:px-8 py-section"><h1 class="text-heading-1 lg:text-display-sm font-display text-fg hero-type-display">AI Launch Kit</h1><p data-testid="product-description" class="mt-block-tight text-lead">The AX-first OSS template.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div class="ailk-prose max-w-none text-(--color-fg) text-body-sm leading-relaxed [&>*:first-child]:mt-0 [&_h2]:mt-block-loose [&_h2]:scroll-mt-24 [&_h2]:text-heading-3 [&_h2]:font-display [&_h2]:text-(--color-fg) [&_h3]:mt-block-loose [&_h3]:scroll-mt-24 [&_h3]:text-heading-4 [&_h3]:font-display [&_h3]:text-(--color-fg) [&_h4]:mt-block-tight [&_h4]:scroll-mt-24 [&_h4]:text-heading-4 [&_h4]:font-display [&_h4]:text-(--color-fg) [&_h5]:mt-block-tight [&_h5]:scroll-mt-24 [&_h5]:text-heading-4 [&_h5]:font-display [&_h5]:text-(--color-fg) [&_h6]:mt-block-tight [&_h6]:scroll-mt-24 [&_h6]:text-heading-4 [&_h6]:font-display [&_h6]:text-(--color-fg) [&_p]:mt-paragraph [&_strong]:font-semibold [&_strong]:text-(--color-fg) [&_em]:italic [&_ul]:mt-paragraph [&_ul]:list-disc [&_ul]:ps-6 [&_ol]:mt-paragraph [&_ol]:list-decimal [&_ol]:ps-6 [&_li]:mt-1 [&_li]:ps-1 [&_li]:marker:text-(--color-text-muted) [&_li>ul]:mt-1 [&_li>ol]:mt-1 [&_blockquote]:mt-paragraph [&_blockquote]:border-s-4 [&_blockquote]:border-(--color-border-strong) [&_blockquote]:ps-4 [&_blockquote]:italic [&_blockquote]:text-(--color-text-muted) [&_hr]:my-block-loose [&_hr]:border-(--color-border) [&_a]:text-(--color-accent) [&_a]:underline [&_a]:underline-offset-4 [&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-(--color-surface-secondary) [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:text-code [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-(--color-fg) [&_pre]:mt-paragraph [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:border-hairline [&_pre]:border-(--color-border) [&_pre]:bg-(--color-bg) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-body-sm [&_img]:mt-paragraph [&_img]:h-auto [&_img]:max-w-full [&_img]:rounded-lg [&_table]:mt-paragraph [&_table]:w-full [&_table]:border-collapse [&_table]:text-body-sm [&_th]:border-b [&_th]:border-(--color-border) [&_th]:bg-(--color-surface-secondary) [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-semibold [&_th]:text-(--color-fg) [&_td]:border-b [&_td]:border-(--color-border) [&_td]:px-3 [&_td]:py-2 [&_kbd]:rounded [&_kbd]:border-hairline [&_kbd]:border-(--color-border) [&_kbd]:bg-(--color-surface-secondary) [&_kbd]:px-1.5 [&_kbd]:py-0.5 [&_kbd]:text-caption [&_kbd]:font-mono" data-testid="mdx-content"><div data-testid="mdx-remote" data-source="
|
|
114
|
+
Body."></div></div></article></div></div></div></main>"
|
|
117
115
|
`);
|
|
118
116
|
});
|
|
119
117
|
|
package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx
CHANGED
|
@@ -19,6 +19,19 @@ import { render } from "@testing-library/react";
|
|
|
19
19
|
|
|
20
20
|
// ── @working-theory/ui mock ─────────────────────────────────────────────────────────────
|
|
21
21
|
jest.mock("@working-theory/ui", () => ({
|
|
22
|
+
// #7745: renderPage's mdx-body branch frames its head and body in the
|
|
23
|
+
// section Container and renders the body through MDXContent + the shared map.
|
|
24
|
+
Container: ({
|
|
25
|
+
children,
|
|
26
|
+
}: {
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
}): React.ReactElement => React.createElement("div", null, children),
|
|
29
|
+
MDXContent: ({
|
|
30
|
+
children,
|
|
31
|
+
}: {
|
|
32
|
+
children?: React.ReactNode;
|
|
33
|
+
}): React.ReactElement => React.createElement(React.Fragment, null, children),
|
|
34
|
+
getMDXComponents: (overrides?: Record<string, unknown>) => ({ ...overrides }),
|
|
22
35
|
// #4446/#4447: renderPage's own fallback/empty-state title now composes
|
|
23
36
|
// Heading (mobile type-budget classes, #4417) instead of a bare <h1>.
|
|
24
37
|
Heading: ({
|
|
@@ -81,7 +94,7 @@ describe("ResourcesPage — snapshot regression", () => {
|
|
|
81
94
|
});
|
|
82
95
|
const { container } = render(element);
|
|
83
96
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
84
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Resources","description":"Guides, templates, and tools.","mainEntity":{"@type":"ItemList"}}</script><main id="main"><h1>Resources</h1><p data-testid="resources-description">Guides, templates, and tools.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source=""></div></article></div></div></main>"`,
|
|
97
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@type":"CollectionPage","inLanguage":"en","name":"Resources","description":"Guides, templates, and tools.","mainEntity":{"@type":"ItemList"}}</script><main id="main"><div><h1>Resources</h1><p data-testid="resources-description" class="mt-block-tight text-lead">Guides, templates, and tools.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source=""></div></article></div></div></div></main>"`,
|
|
85
98
|
);
|
|
86
99
|
});
|
|
87
100
|
});
|
|
@@ -111,7 +124,7 @@ describe("ResourceDetailPage — snapshot regression", () => {
|
|
|
111
124
|
});
|
|
112
125
|
const { container } = render(element);
|
|
113
126
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
|
114
|
-
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Getting Started","description":"A guide for new users.","mainEntity":{"@context":"https://schema.org","@type":"Article","headline":"Getting Started","description":"A guide for new users."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Resources","item":"http://localhost:3000/en/resources"},{"@type":"ListItem","position":3,"name":"Getting Started","item":"http://localhost:3000/en/resources/getting-started"}]}]}</script><main id="main"><h1>Getting Started</h1><p data-testid="resource-description">A guide for new users.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source=""></div></article></div></div></main>"`,
|
|
127
|
+
`"<script type="application/ld+json" data-testid="json-ld">{"@context":"https://schema.org","@graph":[{"@context":"https://schema.org","@type":"WebPage","inLanguage":"en","name":"Getting Started","description":"A guide for new users.","mainEntity":{"@context":"https://schema.org","@type":"Article","headline":"Getting Started","description":"A guide for new users."}},{"@context":"https://schema.org","@type":"BreadcrumbList","inLanguage":"en","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http://localhost:3000/en/"},{"@type":"ListItem","position":2,"name":"Resources","item":"http://localhost:3000/en/resources"},{"@type":"ListItem","position":3,"name":"Getting Started","item":"http://localhost:3000/en/resources/getting-started"}]}]}</script><main id="main"><div><h1>Getting Started</h1><p data-testid="resource-description" class="mt-block-tight text-lead">A guide for new users.</p><div data-testid="markdown-view-toggle" class="ailk-markdown-view-toggle mt-block-loose"><div class="flex justify-end mb-3"><div role="radiogroup" aria-label="Page view" data-testid="markdown-view-toggle" class="inline-flex items-center gap-0.5 rounded-lg p-1 bg-(--color-surface-secondary)"><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) bg-(--color-bg) text-(--color-fg) shadow-sm" type="button" role="radio" aria-checked="true" aria-label="Rendered" tabindex="0" data-testid="markdown-view-toggle-rendered">Rendered</button><button class="inline-flex items-center justify-center gap-2 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:shrink-0 text-(--color-fg) hover:bg-(--color-surface-secondary) active:bg-gray-200 rounded-control px-control-x h-(--control-height-thin) text-caption leading-none rounded-md px-3 text-body-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--color-accent) focus-visible:ring-offset-1 min-w-(--control-height-thin) min-h-(--control-height-big) text-(--color-text-muted) hover:text-(--color-fg)" type="button" role="radio" aria-checked="false" aria-label="Markdown" tabindex="-1" data-testid="markdown-view-toggle-markdown">Markdown</button></div></div><div role="status" aria-live="polite" aria-atomic="true" class="sr-only" data-testid="markdown-view-toggle-status">Showing Rendered view</div><div data-testid="markdown-view-rendered"><article data-testid="mdx-body"><div data-testid="mdx-remote" data-source=""></div></article></div></div></div></main>"`,
|
|
115
128
|
);
|
|
116
129
|
});
|
|
117
130
|
|