@donotdev/ui 0.0.11 → 0.0.13

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.
Files changed (35) hide show
  1. package/dist/components/common/FeatureCard.js +1 -1
  2. package/dist/components/common/RedirectOverlay.js +1 -1
  3. package/dist/components/cookie-consent/CookieConsent.js +3 -3
  4. package/dist/components/layout/GameContainer.d.ts +26 -8
  5. package/dist/components/layout/GameContainer.d.ts.map +1 -1
  6. package/dist/components/layout/GameContainer.js +21 -2
  7. package/dist/components/layout/GameFlow.d.ts.map +1 -1
  8. package/dist/components/layout/GameFlow.js +27 -11
  9. package/dist/components/layout/PageContainer.d.ts +1 -1
  10. package/dist/components/layout/PageContainer.d.ts.map +1 -1
  11. package/dist/components/layout/components/header/CacheSettings.js +1 -1
  12. package/dist/crud/components/EntityCardList.d.ts.map +1 -1
  13. package/dist/crud/components/EntityCardList.js +16 -10
  14. package/dist/crud/components/EntityDisplayRenderer.js +2 -2
  15. package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
  16. package/dist/crud/components/EntityFormRenderer.js +31 -20
  17. package/dist/crud/components/EntityList.d.ts +1 -1
  18. package/dist/crud/components/EntityList.d.ts.map +1 -1
  19. package/dist/crud/components/EntityList.js +11 -11
  20. package/dist/crud/components/Form.js +1 -1
  21. package/dist/dndev.css +128 -83
  22. package/dist/index.js +4 -4
  23. package/dist/internal/common/RouteErrorFallback.js +3 -3
  24. package/dist/internal/devtools/components/ConfigTab.js +1 -1
  25. package/dist/internal/devtools/components/CookieTab.js +1 -1
  26. package/dist/internal/devtools/components/DesignTab.js +2 -2
  27. package/dist/internal/devtools/components/StoresTab.js +2 -2
  28. package/dist/internal/layout/config/presets/game.d.ts.map +1 -1
  29. package/dist/internal/layout/config/presets/game.js +10 -5
  30. package/dist/internal/layout/zones/DnDevFooter.js +1 -1
  31. package/dist/internal/layout/zones/DnDevMergedBar.js +1 -1
  32. package/dist/routing/404.js +3 -3
  33. package/dist/routing/AuthGuardFallback.js +2 -2
  34. package/dist/styles/index.css +128 -83
  35. package/package.json +5 -5
@@ -104,7 +104,7 @@ export const RouteErrorFallback = ({ error, resetError, componentStack, eventId,
104
104
  width: '2.5rem',
105
105
  height: '2.5rem',
106
106
  color: 'var(--destructive)',
107
- }, "aria-hidden": "true" }) }), _jsxs(Stack, { gap: "medium", children: [_jsx("h1", { className: "dndev-text-base", "data-level": "h1", style: {
107
+ }, "aria-hidden": "true" }) }), _jsxs(Stack, { children: [_jsx("h1", { className: "dndev-text-base", "data-level": "h1", style: {
108
108
  fontSize: 'var(--font-size-2xl)',
109
109
  fontWeight: 'var(--font-weight-bold)',
110
110
  margin: 0,
@@ -119,7 +119,7 @@ export const RouteErrorFallback = ({ error, resetError, componentStack, eventId,
119
119
  fontSize: 'var(--font-size-xs)',
120
120
  fontFamily: 'var(--font-mono)',
121
121
  color: 'var(--foreground)',
122
- }, children: [t('routeError.errorId', 'Error ID'), ": ", eventId] })), isDevelopment && errorMessage && (_jsxs(Card, { variant: CARD_VARIANT.MUTED, className: "dndev-w-full", children: [_jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "medium", children: [_jsx("span", { className: "dndev-text-base", style: {
122
+ }, children: [t('routeError.errorId', 'Error ID'), ": ", eventId] })), isDevelopment && errorMessage && (_jsxs(Card, { variant: CARD_VARIANT.MUTED, className: "dndev-w-full", children: [_jsxs(Stack, { direction: "row", align: "center", justify: "between", children: [_jsx("span", { className: "dndev-text-base", style: {
123
123
  fontSize: 'var(--font-size-sm)',
124
124
  fontWeight: 'var(--font-weight-semibold)',
125
125
  color: 'var(--destructive)',
@@ -133,7 +133,7 @@ export const RouteErrorFallback = ({ error, resetError, componentStack, eventId,
133
133
  color: 'var(--foreground)',
134
134
  margin: 0,
135
135
  marginTop: 'var(--gap-sm)',
136
- }, children: errorMessage })] })), _jsxs(Stack, { gap: "medium", className: "dndev-w-full", children: [_jsx(Button, { variant: BUTTON_VARIANT.DESTRUCTIVE, icon: RotateCw, onClick: handleRetry, fullWidth: true, children: t('routeError.tryAgain', 'Try Again') }), _jsxs(Stack, { direction: "row", gap: "medium", justify: "center", children: [_jsx(Link, { path: "/", children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, fullWidth: true, children: t('routeError.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleGoBack, fullWidth: true, children: t('routeError.goBack', 'Go Back') })] })] }), _jsx("p", { className: "dndev-text-base", style: {
136
+ }, children: errorMessage })] })), _jsxs(Stack, { className: "dndev-w-full", children: [_jsx(Button, { variant: BUTTON_VARIANT.DESTRUCTIVE, icon: RotateCw, onClick: handleRetry, fullWidth: true, children: t('routeError.tryAgain', 'Try Again') }), _jsxs(Stack, { direction: "row", justify: "center", children: [_jsx(Link, { path: "/", children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, fullWidth: true, children: t('routeError.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleGoBack, fullWidth: true, children: t('routeError.goBack', 'Go Back') })] })] }), _jsx("p", { className: "dndev-text-base", style: {
137
137
  fontSize: 'var(--font-size-sm)',
138
138
  color: 'var(--muted-foreground)',
139
139
  margin: 0,
@@ -57,5 +57,5 @@ export const ConfigTab = () => {
57
57
  label: _jsx(Text, { className: "dndev-font-mono dndev-text-xs", children: key }),
58
58
  value: _jsx(MaskedValue, { keyName: key, value: String(value) }),
59
59
  }));
60
- return (_jsxs(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: [_jsx(Card, { title: "Framework", subtitle: source.source, children: _jsx(DescriptionList, { items: frameworkItems }) }), summaryItems.length > 0 && (_jsx(Card, { title: "Discovery", children: _jsx(DescriptionList, { items: summaryItems }) })), envItems.length > 0 && (_jsx(Card, { title: "Environment", subtitle: `${envItems.length} variables`, children: _jsx(DescriptionList, { items: envItems }) }))] }));
60
+ return (_jsxs(Stack, { style: { padding: 'var(--gap-md)' }, children: [_jsx(Card, { title: "Framework", subtitle: source.source, children: _jsx(DescriptionList, { items: frameworkItems }) }), summaryItems.length > 0 && (_jsx(Card, { title: "Discovery", children: _jsx(DescriptionList, { items: summaryItems }) })), envItems.length > 0 && (_jsx(Card, { title: "Environment", subtitle: `${envItems.length} variables`, children: _jsx(DescriptionList, { items: envItems }) }))] }));
61
61
  };
@@ -144,7 +144,7 @@ export const CookieTab = () => {
144
144
  categories,
145
145
  timestamp,
146
146
  version,
147
- }), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Consent state copied') })] }), children: _jsx(DescriptionList, { items: consentStateItems }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Categories" }), _jsx(CopyToClipboard, { text: formatJSON(categories), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Categories copied') })] }), children: _jsx(DescriptionList, { items: categoryItems }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Cookie Value" }), _jsxs(Stack, { direction: "row", gap: "tight", children: [_jsx(CopyToClipboard, { text: cookieValue || 'null', variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Cookie value copied') }), _jsx(Button, { onClick: handleClearCookie, icon: Trash2, variant: BUTTON_VARIANT.GHOST, title: "Clear Cookie", children: "Clear" })] })] }), children: _jsx("pre", { className: "dndev-overflow-y-auto dndev-font-mono dndev-text-xs dndev-max-h-60", children: cookieValue || 'No cookie found' }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "DOM Elements" }), _jsx(CopyToClipboard, { text: formatJSON(domInfo), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'DOM info copied') })] }), children: _jsxs(Stack, { gap: "medium", children: [_jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Cookie Banner:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Exists: ", domInfo.cookieBanner?.exists ? '✅' : '❌'] }), _jsxs(Text, { children: ["Visible: ", domInfo.cookieBanner?.visible ? '✅' : '❌'] }), _jsxs(Text, { children: ["z-index: ", domInfo.cookieBanner?.zIndex || 'N/A'] }), _jsxs(Text, { children: ["Position: ", domInfo.cookieBanner?.position || 'N/A'] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Dialogs:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Count: ", domInfo.dialogs?.count || 0] }), _jsxs(Text, { children: ["Open: ", domInfo.dialogs?.open || 0] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Overlays:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Count: ", domInfo.overlays?.count || 0] }), _jsxs(Text, { children: ["Visible: ", domInfo.overlays?.visible || 0] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Portals:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md", children: _jsxs(Text, { children: ["Count: ", domInfo.portals?.count || 0] }) })] })] }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Z-Index Stacking" }), _jsx(CopyToClipboard, { text: formatJSON(zIndexInfo), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Z-index info copied') })] }), children: _jsxs(Stack, { gap: "medium", children: [_jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "CSS Variables:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md dndev-font-mono dndev-text-sm", children: Object.entries(zIndexInfo.cssVariables || {}).map(([key, value]) => (_jsxs(Text, { children: [key, ": ", String(value) || 'not set'] }, key))) })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Computed Values:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md dndev-font-mono dndev-text-sm", children: Object.entries(zIndexInfo.computed || {}).map(([key, value]) => (_jsxs(Text, { children: [key, ": ", String(value)] }, key))) })] })] }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Full Store State" }), _jsx(CopyToClipboard, { text: formatJSON({
147
+ }), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Consent state copied') })] }), children: _jsx(DescriptionList, { items: consentStateItems }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Categories" }), _jsx(CopyToClipboard, { text: formatJSON(categories), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Categories copied') })] }), children: _jsx(DescriptionList, { items: categoryItems }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Cookie Value" }), _jsxs(Stack, { direction: "row", gap: "tight", children: [_jsx(CopyToClipboard, { text: cookieValue || 'null', variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Cookie value copied') }), _jsx(Button, { onClick: handleClearCookie, icon: Trash2, variant: BUTTON_VARIANT.GHOST, title: "Clear Cookie", children: "Clear" })] })] }), children: _jsx("pre", { className: "dndev-overflow-y-auto dndev-font-mono dndev-text-xs dndev-max-h-60", children: cookieValue || 'No cookie found' }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "DOM Elements" }), _jsx(CopyToClipboard, { text: formatJSON(domInfo), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'DOM info copied') })] }), children: _jsxs(Stack, { children: [_jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Cookie Banner:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Exists: ", domInfo.cookieBanner?.exists ? '✅' : '❌'] }), _jsxs(Text, { children: ["Visible: ", domInfo.cookieBanner?.visible ? '✅' : '❌'] }), _jsxs(Text, { children: ["z-index: ", domInfo.cookieBanner?.zIndex || 'N/A'] }), _jsxs(Text, { children: ["Position: ", domInfo.cookieBanner?.position || 'N/A'] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Dialogs:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Count: ", domInfo.dialogs?.count || 0] }), _jsxs(Text, { children: ["Open: ", domInfo.dialogs?.open || 0] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Overlays:" }), _jsxs(Stack, { gap: "tight", className: "dndev-ml-md", children: [_jsxs(Text, { children: ["Count: ", domInfo.overlays?.count || 0] }), _jsxs(Text, { children: ["Visible: ", domInfo.overlays?.visible || 0] })] })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Portals:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md", children: _jsxs(Text, { children: ["Count: ", domInfo.portals?.count || 0] }) })] })] }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Z-Index Stacking" }), _jsx(CopyToClipboard, { text: formatJSON(zIndexInfo), variant: BUTTON_VARIANT.GHOST, onCopy: () => toast('success', 'Z-index info copied') })] }), children: _jsxs(Stack, { children: [_jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "CSS Variables:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md dndev-font-mono dndev-text-sm", children: Object.entries(zIndexInfo.cssVariables || {}).map(([key, value]) => (_jsxs(Text, { children: [key, ": ", String(value) || 'not set'] }, key))) })] }), _jsxs("div", { children: [_jsx(Label, { className: "dndev-font-semibold", children: "Computed Values:" }), _jsx(Stack, { gap: "tight", className: "dndev-ml-md dndev-font-mono dndev-text-sm", children: Object.entries(zIndexInfo.computed || {}).map(([key, value]) => (_jsxs(Text, { children: [key, ": ", String(value)] }, key))) })] })] }) }), _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Full Store State" }), _jsx(CopyToClipboard, { text: formatJSON({
148
148
  hasConsented,
149
149
  categories,
150
150
  timestamp,
@@ -359,11 +359,11 @@ export const DesignTab = () => {
359
359
  colorRatio.secondary <= 40 &&
360
360
  colorRatio.accent >= 5 &&
361
361
  colorRatio.accent <= 20;
362
- return (_jsxs(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: [_jsx(Accordion, { type: "single", collapsible: true, items: [
362
+ return (_jsxs(Stack, { style: { padding: 'var(--gap-md)' }, children: [_jsx(Accordion, { type: "single", collapsible: true, items: [
363
363
  {
364
364
  value: 'theme',
365
365
  trigger: _jsx("span", { children: "Theme Info" }),
366
- content: (_jsxs(Stack, { gap: "medium", children: [_jsx(Card, { title: "Theme", subtitle: currentTheme, children: _jsx(DescriptionList, { items: themeItems }) }), _jsx(Card, { title: "CSS Variables", subtitle: `${Object.keys(cssVars).length} variables`, children: _jsx(ScrollArea, { className: "dndev-max-h-48", children: _jsx(Stack, { gap: "tight", children: Object.entries(cssVars).map(([name, value]) => (_jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "tight", children: [_jsx(Text, { className: "dndev-font-mono dndev-text-xs", children: name }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx("div", { style: {
366
+ content: (_jsxs(Stack, { children: [_jsx(Card, { title: "Theme", subtitle: currentTheme, children: _jsx(DescriptionList, { items: themeItems }) }), _jsx(Card, { title: "CSS Variables", subtitle: `${Object.keys(cssVars).length} variables`, children: _jsx(ScrollArea, { className: "dndev-max-h-48", children: _jsx(Stack, { gap: "tight", children: Object.entries(cssVars).map(([name, value]) => (_jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "tight", children: [_jsx(Text, { className: "dndev-font-mono dndev-text-xs", children: name }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx("div", { style: {
367
367
  width: '1rem',
368
368
  height: '1rem',
369
369
  backgroundColor: `var(${name})`,
@@ -59,9 +59,9 @@ export const StoresTab = () => {
59
59
  }, [refreshStores]);
60
60
  const getDisplayName = (name) => STORE_NAMES[name] || name.replace(/-store$/, '').replace(/-/g, ' ');
61
61
  if (storeNames.length === 0) {
62
- return (_jsx(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: "Stores", subtitle: "No stores registered", children: _jsx(Text, { className: "dndev-text-muted-foreground", children: "globalThis._DNDEV_STORES_ is empty or not initialized." }) }) }));
62
+ return (_jsx(Stack, { style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: "Stores", subtitle: "No stores registered", children: _jsx(Text, { className: "dndev-text-muted-foreground", children: "globalThis._DNDEV_STORES_ is empty or not initialized." }) }) }));
63
63
  }
64
- return (_jsx(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Stores" }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx(Badge, { variant: BADGE_VARIANT.SECONDARY, children: storeNames.length }), _jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: RefreshCw, onClick: refreshStores, title: "Refresh stores" })] })] }), children: _jsx(Accordion, { type: "single", collapsible: true, items: storeNames.map((name) => {
64
+ return (_jsx(Stack, { style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Stores" }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx(Badge, { variant: BADGE_VARIANT.SECONDARY, children: storeNames.length }), _jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: RefreshCw, onClick: refreshStores, title: "Refresh stores" })] })] }), children: _jsx(Accordion, { type: "single", collapsible: true, items: storeNames.map((name) => {
65
65
  const state = storeStates[name];
66
66
  const hasError = state?._error;
67
67
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/config/presets/game.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AASnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,YAkCxB,CAAC"}
1
+ {"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/config/presets/game.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAYnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,YAwCxB,CAAC"}
@@ -13,6 +13,9 @@ import { DISPLAY } from '@donotdev/components';
13
13
  import { LanguageSelector } from '@donotdev/core';
14
14
  import { AuthHeader } from '../../../../components/auth';
15
15
  import { GameTitle, ThemeToggle, } from '../../../../components/layout/components';
16
+ import { FooterCopyright } from '../../components/footer/FooterCopyright';
17
+ import { FooterLegalLinks } from '../../components/footer/FooterLegalLinks';
18
+ import { DEFAULT_SLOTS } from '../defaults';
16
19
  /**
17
20
  * Game preset - mobile gaming layout
18
21
  *
@@ -37,12 +40,14 @@ export const gamePreset = {
37
40
  mergedBar: {
38
41
  position: 'top',
39
42
  // Desktop → Mobile mapping:
40
- trigger: () => _jsx(GameTitle, {}), // header.center → trigger (GameTitle, since header.start is null)
41
- top: () => _jsx(GameTitle, {}), // header.center → top (GameTitle)
42
- content: () => null, // No sidebar content is null
43
- bottom: () => (
44
- // header.end → bottom (Auth, Language, Theme)
43
+ trigger: () => _jsx(GameTitle, {}), // header.center → trigger
44
+ top: () => (
45
+ // header.endtop (Auth, Language, Theme)
45
46
  _jsxs(_Fragment, { children: [_jsx(AuthHeader, { display: DISPLAY.AUTO }), _jsx(LanguageSelector, { display: DISPLAY.AUTO }), _jsx(ThemeToggle, { display: DISPLAY.AUTO })] })),
47
+ content: DEFAULT_SLOTS.sidebar.content, // Navigation menu
48
+ bottom: () => (
49
+ // Footer content: copyright + legal links (includes branding)
50
+ _jsxs(_Fragment, { children: [_jsx(FooterCopyright, {}), _jsx(FooterLegalLinks, {})] })),
46
51
  },
47
52
  },
48
53
  };
@@ -49,7 +49,7 @@ function DnDevFooterComponent({ app = {} }) {
49
49
  : copyrightConfig;
50
50
  // Desktop/Wide: 2-zone layout [Copyright] | [Links + DoNotDev]
51
51
  if (isLaptopOrDesktop) {
52
- return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "none", children: [showCopyright && (_jsx("div", { className: "dndev-flex dndev-justify-start", children: _jsx("span", { className: "footer-copyright", children: copyrightText }) })), _jsx("div", { className: "dndev-flex dndev-justify-end", children: _jsxs(Stack, { direction: "row", gap: "medium", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] }) })] }) }));
52
+ return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "none", children: [showCopyright && (_jsx("div", { className: "dndev-flex dndev-justify-start", children: _jsx("span", { className: "footer-copyright", children: copyrightText }) })), _jsx("div", { className: "dndev-flex dndev-justify-end", children: _jsxs(Stack, { direction: "row", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] }) })] }) }));
53
53
  }
54
54
  // Mobile/Tablet: stacked layout
55
55
  return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { align: "center", gap: "tight", children: [showCopyright && (_jsx("span", { className: "footer-copyright", children: copyrightText })), _jsxs(Stack, { direction: "row", wrap: "wrap", gap: "tight", justify: "center", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] })] }) }));
@@ -36,7 +36,7 @@ function DnDevMergedBarComponent({ position, height, trigger, top, content, bott
36
36
  setOpen(false);
37
37
  }, [location.pathname]);
38
38
  // Build sheet content
39
- const sheetNode = (_jsxs(Stack, { direction: "column", gap: "medium", className: "merged-bar-sheet-content", children: [top && (_jsxs(_Fragment, { children: [top, _jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED })] })), content && _jsx("div", { className: "merged-bar-sheet-scroll", children: content }), bottom && (_jsxs(_Fragment, { children: [_jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED }), bottom] }))] }));
39
+ const sheetNode = (_jsxs(Stack, { direction: "column", className: "merged-bar-sheet-content", children: [top && (_jsxs(_Fragment, { children: [top, _jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED })] })), content && _jsx("div", { className: "merged-bar-sheet-scroll", children: content }), bottom && (_jsxs(_Fragment, { children: [_jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED }), bottom] }))] }));
40
40
  const triggerButton = (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: Icon, "aria-label": "Open navigation" }));
41
41
  return (_jsx("div", { className: "merged-bar", "data-position": position, children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "merged-bar-trigger", children: [trigger, _jsx(Sheet, { trigger: triggerButton, side: sheetSide, open: open, onOpenChange: setOpen, title: t('sheet.navigation', { defaultValue: 'Navigation' }), children: sheetNode })] }) }));
42
42
  }
@@ -64,7 +64,7 @@ export default function NotFoundPage() {
64
64
  const handleBack = () => {
65
65
  navigate('back');
66
66
  };
67
- return (_jsx(PageContainer, { variant: "docs", centered: true, children: _jsxs(Stack, { gap: "large", align: "center", justify: "center", children: [_jsxs(Stack, { gap: "medium", align: "center", children: [_jsx(Text, { level: "h1", style: {
67
+ return (_jsx(PageContainer, { variant: "docs", centered: true, children: _jsxs(Stack, { gap: "large", align: "center", justify: "center", children: [_jsxs(Stack, { align: "center", children: [_jsx(Text, { level: "h1", style: {
68
68
  fontSize: 'clamp(4rem, 12vw, 8rem)',
69
69
  fontWeight: 'var(--font-weight-bold)',
70
70
  lineHeight: 1,
@@ -95,10 +95,10 @@ export default function NotFoundPage() {
95
95
  overflow: 'hidden',
96
96
  textOverflow: 'ellipsis',
97
97
  border: '1px solid var(--border-hairline)',
98
- }, children: location.pathname }))] }), suggestedRoutes.length > 0 && (_jsxs(Stack, { gap: "medium", align: "center", children: [_jsx("p", { className: "dndev-text-base", style: {
98
+ }, children: location.pathname }))] }), suggestedRoutes.length > 0 && (_jsxs(Stack, { align: "center", children: [_jsx("p", { className: "dndev-text-base", style: {
99
99
  fontSize: 'var(--font-size-md)',
100
100
  fontWeight: 'var(--font-weight-semibold)',
101
101
  margin: 0,
102
102
  color: 'var(--muted-foreground)',
103
- }, children: t('errors.notFound.suggestions', 'You might be looking for:') }), _jsx(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "tight", children: suggestedRoutes.map((route) => (_jsx(Link, { path: route.path, replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: _jsx(Icon, { icon: route.icon, fallback: LinkIcon }), "aria-label": t('errors.notFound.navigateTo', `Navigate to ${route.label}`, { label: route.label }), children: route.label }) }, route.path))) })] })), _jsxs(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "medium", children: [_jsx(Link, { path: "/", replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, "aria-label": t('errors.notFound.goHome', 'Go to home page'), children: t('errors.notFound.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleBack, "aria-label": t('errors.notFound.goBack', 'Go back to previous page'), children: t('errors.notFound.goBack', 'Go Back') })] })] }) }));
103
+ }, children: t('errors.notFound.suggestions', 'You might be looking for:') }), _jsx(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "tight", children: suggestedRoutes.map((route) => (_jsx(Link, { path: route.path, replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: _jsx(Icon, { icon: route.icon, fallback: LinkIcon }), "aria-label": t('errors.notFound.navigateTo', `Navigate to ${route.label}`, { label: route.label }), children: route.label }) }, route.path))) })] })), _jsxs(Stack, { direction: "row", wrap: "wrap", justify: "center", children: [_jsx(Link, { path: "/", replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, "aria-label": t('errors.notFound.goHome', 'Go to home page'), children: t('errors.notFound.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleBack, "aria-label": t('errors.notFound.goBack', 'Go back to previous page'), children: t('errors.notFound.goBack', 'Go Back') })] })] }) }));
104
104
  }
@@ -50,14 +50,14 @@ export function AuthGuardFallback({ title, description, showBackButton = true, o
50
50
  maxWidth: '28rem',
51
51
  border: 'none',
52
52
  boxShadow: 'var(--shadow-xl)',
53
- }, title: _jsxs(Stack, { gap: "medium", children: [_jsx(Stack, { justify: "center", children: _jsx("div", { style: {
53
+ }, title: _jsxs(Stack, { children: [_jsx(Stack, { justify: "center", children: _jsx("div", { style: {
54
54
  borderRadius: '9999px',
55
55
  backgroundColor: 'color-mix(in oklab, var(--primary) 10%, transparent)',
56
56
  padding: 'var(--gap-md)',
57
57
  }, children: _jsx(Lock, { className: "dndev-size-touch", style: { color: 'var(--primary)' } }) }) }), _jsx("div", { style: {
58
58
  fontSize: 'var(--font-size-2xl)',
59
59
  fontWeight: 700,
60
- }, children: t('auth.fallback.title', 'Authentication Required') }), _jsx("p", { style: { color: 'var(--muted-foreground)' }, children: t('auth.fallback.description', 'Please sign in to access this page') })] }), children: _jsxs(Stack, { gap: "medium", children: [_jsxs(Stack, { gap: "large", children: [_jsx("div", { children: _jsx("p", { style: {
60
+ }, children: t('auth.fallback.title', 'Authentication Required') }), _jsx("p", { style: { color: 'var(--muted-foreground)' }, children: t('auth.fallback.description', 'Please sign in to access this page') })] }), children: _jsxs(Stack, { children: [_jsxs(Stack, { gap: "large", children: [_jsx("div", { children: _jsx("p", { style: {
61
61
  fontSize: 'var(--font-size-sm)',
62
62
  color: 'var(--muted-foreground)',
63
63
  }, children: t('auth.fallback.chooseProvider') }) }), _jsx(Suspense, { fallback: _jsx("div", { children: "Loading providers..." }), children: _jsx(MultipleAuthProviders, { layout: "vertical", spacing: "tight", fullWidth: true, ariaLabel: t('auth.fallback.authOptions') }) })] }), showBackButton && (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { children: _jsx(Button, { onClick: handleBack, className: "dndev-gap-sm", icon: ArrowLeft, children: t('common.back') }) })] })), _jsxs(Stack, { gap: "tight", style: {
@@ -3140,7 +3140,7 @@ em {
3140
3140
 
3141
3141
  .dndev-cta-actions {
3142
3142
  display: flex;
3143
- flex-direction: column;
3143
+ flex-direction: row;
3144
3144
  gap: var(--gap-md);
3145
3145
  justify-content: center;
3146
3146
  }
@@ -3175,13 +3175,6 @@ em {
3175
3175
  border-color: var(--foreground);
3176
3176
  }
3177
3177
 
3178
- @media (width >= 768px) {
3179
-
3180
- .dndev-cta-actions {
3181
- flex-direction: row;
3182
- }
3183
- }
3184
-
3185
3178
  /* packages/components/src/atomic/Card/Card.css */
3186
3179
 
3187
3180
  /* Card layout - grid with gap */
@@ -3631,12 +3624,10 @@ em {
3631
3624
  /* Code-specific overrides: background color, text color, and layout */
3632
3625
  display: flex;
3633
3626
  flex-direction: column;
3634
- background: var(
3635
- --muted
3636
- ); /* Override surface gradient with code-specific dark background */
3637
- color: var(
3638
- --muted-foreground
3639
- ); /* Override surface text color for dark background */
3627
+ background: var(--muted);
3628
+ /* Override surface gradient with code-specific dark background */
3629
+ color: var(--muted-foreground);
3630
+ /* Override surface text color for dark background */
3640
3631
  overflow: hidden;
3641
3632
  font-family: var(--font-mono);
3642
3633
  font-size: var(--font-size-sm);
@@ -3710,8 +3701,6 @@ em {
3710
3701
  white-space: pre;
3711
3702
  overflow-x: auto;
3712
3703
  overflow-y: visible;
3713
- min-width: -moz-min-content;
3714
- min-width: min-content;
3715
3704
  }
3716
3705
 
3717
3706
  .dndev-code-pre[data-compact='true'] {
@@ -3728,16 +3717,19 @@ em {
3728
3717
  user-select: none;
3729
3718
  padding-inline-end: var(--gap-md);
3730
3719
  text-align: end;
3731
- font-size: inherit; /* Match parent code font-size */
3720
+ font-size: inherit;
3721
+ /* Match parent code font-size */
3732
3722
  opacity: var(--opacity-muted);
3733
3723
  width: 3rem;
3734
3724
  flex-shrink: 0;
3735
3725
  color: var(--muted-foreground);
3736
- line-height: 1.5; /* Consistent line height */
3726
+ line-height: 1.5;
3727
+ /* Consistent line height */
3737
3728
  }
3738
3729
 
3739
3730
  .dndev-code-line-number {
3740
- line-height: inherit; /* Inherit from parent */
3731
+ line-height: inherit;
3732
+ /* Inherit from parent */
3741
3733
  }
3742
3734
 
3743
3735
  .dndev-code-code {
@@ -3745,8 +3737,10 @@ em {
3745
3737
  min-width: 0;
3746
3738
  text-align: start;
3747
3739
  display: block;
3748
- line-height: 1.5; /* Match line numbers */
3749
- font-size: var(--font-size-sm); /* Explicit match with line numbers */
3740
+ line-height: 1.5;
3741
+ /* Match line numbers */
3742
+ font-size: var(--font-size-sm);
3743
+ /* Explicit match with line numbers */
3750
3744
  }
3751
3745
 
3752
3746
  /* Ensure shiki-generated code respects line-height AND font-size */
@@ -3754,7 +3748,8 @@ em {
3754
3748
  .dndev-code-code pre,
3755
3749
  .dndev-code-code code {
3756
3750
  line-height: inherit;
3757
- font-size: inherit; /* Match parent font-size */
3751
+ font-size: inherit;
3752
+ /* Match parent font-size */
3758
3753
  }
3759
3754
 
3760
3755
  /* packages/components/src/atomic/Command/Command.css */
@@ -7535,6 +7530,10 @@ input[type='number'] {
7535
7530
  font-weight: var(--font-weight-bold);
7536
7531
  }
7537
7532
 
7533
+ .dndev-text-base[data-italic] {
7534
+ font-style: italic;
7535
+ }
7536
+
7538
7537
  /* packages/components/src/atomic/Toaster/Toaster.css */
7539
7538
 
7540
7539
  .dndev-toast-viewport {
@@ -7734,8 +7733,9 @@ input[type='number'] {
7734
7733
 
7735
7734
  .dndev-toggle-group {
7736
7735
  display: inline-flex;
7736
+ flex-wrap: wrap;
7737
7737
  align-items: center;
7738
- gap: 0;
7738
+ gap: var(--gap-sm);
7739
7739
  padding: 0.125rem;
7740
7740
  border-radius: var(--radius-interactive);
7741
7741
  background-color: var(--muted);
@@ -7931,12 +7931,16 @@ input[type='number'] {
7931
7931
 
7932
7932
  .dndev-video-dialog {
7933
7933
  max-width: 90vw;
7934
- max-height: 90vh;
7935
7934
  }
7936
7935
 
7937
7936
  .dndev-video-dialog .dndev-modal-body {
7938
7937
  padding: 0;
7938
+ overflow: hidden;
7939
+ }
7940
+
7941
+ .dndev-video-dialog .dndev-video-frame {
7939
7942
  aspect-ratio: 16/9;
7943
+ max-height: calc(90vh - 5rem);
7940
7944
  }
7941
7945
 
7942
7946
  /* 6. Animation keyframes */
@@ -9073,9 +9077,16 @@ h4[data-variant='code'] {
9073
9077
  --sidebar-resize-handle-width: 6px;
9074
9078
 
9075
9079
  /* Content width - max constraint only, grid handles sidebar space */
9076
- /* PageContainer sets --max-content-width, main's 1fr handles available space */
9080
+ /* PageContainer sets --max-content-width per variant, components use --content-width */
9081
+ --max-content-width: 100%;
9077
9082
  --content-width: var(--max-content-width, 100%);
9078
9083
 
9084
+ /* Narrow content (mobile-first PWA, app-like single column) - single source of truth */
9085
+ --narrow-content-max: 37.5rem;
9086
+ /* 600px */
9087
+ --narrow-form-max: 30rem;
9088
+ /* 480px - inner form/input width within narrow layout */
9089
+
9079
9090
  /* Content Area Calculations */
9080
9091
  /* Header content area (excludes sidebar on some presets) */
9081
9092
  --header-content-width: 100%;
@@ -9308,52 +9319,74 @@ main[role='main'][data-routing-animation='none'] {
9308
9319
  auto
9309
9320
  );
9310
9321
  grid-template-columns: var(--sidebar-width) 1fr;
9311
-
9312
- /* Mobile: Grid scrolls instead of main - footer scrolls with content */
9313
9322
  }
9314
9323
 
9315
- @media (width <=1023px) {
9316
-
9317
- .dndev-layout {
9318
- overflow-y: auto;
9319
- overflow-x: hidden;
9320
- /* Keep footer row - grid scrolls so footer scrolls with content */
9321
- grid-template-areas:
9322
- 'header header'
9323
- 'sidebar main'
9324
- 'footer footer';
9325
- grid-template-rows: var(--header-height) min-content auto;
9326
- }
9327
- }
9324
+ /* Footer scroll mode: grid scrolls, footer scrolls with content */
9328
9325
 
9329
- /* Footer scroll mode - grid scrolls, footer scrolls with content (opt-in for desktop) */
9326
+ /* Desktop: opt-in via data-footer-mode="scroll" */
9330
9327
 
9331
9328
  .dndev-layout[data-footer-mode='scroll'] {
9332
9329
  overflow-y: auto;
9333
9330
  overflow-x: hidden;
9334
- grid-template-rows: var(--header-height) min-content auto;
9331
+ grid-template-rows: var(--header-height) 1fr auto;
9335
9332
  }
9336
9333
 
9337
9334
  .dndev-layout[data-footer-mode='scroll'] header[role='banner'] {
9338
- position: sticky;
9339
- top: 0;
9340
- }
9335
+ position: sticky;
9336
+ top: 0;
9337
+ }
9338
+
9339
+ .dndev-layout[data-footer-mode='scroll'] aside.sidebar[role='navigation'] {
9340
+ position: sticky;
9341
+ top: var(--header-height);
9342
+ height: calc(100dvh - var(--header-height));
9343
+ align-self: start;
9344
+ }
9341
9345
 
9342
9346
  .dndev-layout[data-footer-mode='scroll'] main[role='main'] {
9343
- overflow: visible;
9344
- min-height: -moz-min-content;
9345
- min-height: min-content;
9346
- }
9347
+ overflow-y: visible;
9348
+ overflow-x: hidden;
9349
+ }
9347
9350
 
9348
9351
  .dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo'] {
9349
- height: auto;
9350
- }
9352
+ grid-column: 2 / -1;
9353
+ height: auto;
9354
+ }
9351
9355
 
9352
9356
  :is(.dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo']) > * {
9353
- height: auto;
9354
- min-height: var(--footer-height);
9357
+ height: auto;
9358
+ min-height: var(--footer-height);
9359
+ }
9360
+
9361
+ /* Mobile: footer scroll mode ON by default (same rules) */
9362
+
9363
+ @media (width <=1023px) {
9364
+ .dndev-layout {
9365
+ overflow-y: auto;
9366
+ overflow-x: hidden;
9367
+ grid-template-rows: var(--header-height) 1fr auto;
9355
9368
  }
9356
9369
 
9370
+ .dndev-layout header[role='banner'] {
9371
+ position: sticky;
9372
+ top: 0;
9373
+ }
9374
+
9375
+ .dndev-layout main[role='main'] {
9376
+ overflow-y: visible;
9377
+ overflow-x: hidden;
9378
+ }
9379
+
9380
+ .dndev-layout footer[role='contentinfo'] {
9381
+ height: auto;
9382
+ }
9383
+
9384
+ :is(.dndev-layout footer[role='contentinfo']) > * {
9385
+ height: auto;
9386
+ min-height: var(--footer-height);
9387
+ }
9388
+ }
9389
+
9357
9390
  /* Presets with no footer at all */
9358
9391
 
9359
9392
  [data-layout='moolti'] footer[role='contentinfo'],
@@ -9718,17 +9751,6 @@ main[role='main'] > *:not(.breadcrumbs-container):first-of-type,main[role='main'
9718
9751
  flex: 1 1 auto;
9719
9752
  }
9720
9753
 
9721
- /* Mobile: Grid scrolls, main doesn't */
9722
-
9723
- @media (width <=1023px) {
9724
-
9725
- main[role='main'] {
9726
- overflow: visible;
9727
- min-height: -moz-min-content;
9728
- min-height: min-content;
9729
- }
9730
- }
9731
-
9732
9754
  /* Footer: Full width by default, app presets start after sidebar */
9733
9755
 
9734
9756
  /* box-sizing: border-box ensures borders are included in height */
@@ -10207,32 +10229,26 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
10207
10229
  /* Standard width - responsive */
10208
10230
 
10209
10231
  .dndev-container[data-variant='standard'] {
10210
- --max-content-width: 100%;
10232
+ --max-content-width: min(87.5rem, 100%);
10233
+ max-width: var(--content-width);
10234
+ /* 1480px max, but never exceeds container width */
10211
10235
  }
10212
10236
 
10213
- @media (width >=1024px) {
10214
-
10215
- .dndev-container[data-variant='standard'] {
10216
- --max-content-width: 87.5rem;
10217
- /* 1480px */
10218
- /* Padding stays: part of centering space when max-width applies */
10219
- }
10220
- }
10221
-
10222
10237
  /* Docs width - responsive */
10223
10238
 
10224
10239
  .dndev-container[data-variant='docs'] {
10225
- --max-content-width: 100%;
10240
+ --max-content-width: min(56.25rem, 100%);
10241
+ max-width: var(--content-width);
10242
+ /* 900px max, but never exceeds container width */
10226
10243
  }
10227
10244
 
10228
- @media (width >=1024px) {
10245
+ /* Narrow width - mobile-first single column (PWA, app-like on every device) */
10229
10246
 
10230
- .dndev-container[data-variant='docs'] {
10231
- --max-content-width: 56.25rem;
10232
- /* 900px */
10233
- /* Padding stays: always prevents edge touching */
10247
+ .dndev-container[data-variant='narrow'] {
10248
+ --max-content-width: min(var(--narrow-content-max), 100%);
10249
+ max-width: var(--content-width);
10250
+ /* 600px max, but never exceeds container width */
10234
10251
  }
10235
- }
10236
10252
 
10237
10253
  /* Fixed frame - fills parent exactly, prevents parent scroll */
10238
10254
 
@@ -10322,7 +10338,16 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
10322
10338
  width: 100%;
10323
10339
  }
10324
10340
 
10325
- /* ScrollArea wrapper */
10341
+ /* Scroll wrapper - stretches to full width so scrollbar is at viewport edge */
10342
+
10343
+ .dndev-game-container__scroll-wrapper {
10344
+ flex: 1 1 0;
10345
+ min-height: 0;
10346
+ width: 100%;
10347
+ align-self: stretch;
10348
+ }
10349
+
10350
+ /* ScrollArea - fills wrapper */
10326
10351
 
10327
10352
  .dndev-game-container__scroll {
10328
10353
  width: 100%;
@@ -10361,17 +10386,37 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
10361
10386
  justify-content: space-between;
10362
10387
  }
10363
10388
 
10364
- /* CTA Zone - Fixed at bottom */
10389
+ /* Narrow content wrapper - constrained by --narrow-content-max, centered inside scroll */
10390
+
10391
+ /* height: 100% fills the scroll viewport so children can use percentage heights.
10392
+ Content taller than viewport still scrolls — overflow propagates to the scroll container. */
10393
+
10394
+ .dndev-game-container__content-narrow {
10395
+ width: 100%;
10396
+ max-width: var(--narrow-content-max);
10397
+ margin-inline: auto;
10398
+ height: 100%;
10399
+ }
10400
+
10401
+ /* CTA Zone - Fixed at bottom; safe area for notched devices */
10365
10402
 
10366
10403
  .dndev-game-container__cta {
10367
10404
  display: flex;
10368
10405
  flex-direction: column;
10369
10406
  padding-top: var(--gap-md);
10407
+ padding-bottom: env(safe-area-inset-bottom);
10370
10408
  border-top: 2px solid var(--border);
10371
10409
  }
10372
10410
 
10373
10411
  /* CTA Button */
10374
10412
 
10413
+ .dndev-game-container__cta-buttons {
10414
+ display: grid;
10415
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
10416
+ gap: var(--gap-sm);
10417
+ width: 100%;
10418
+ }
10419
+
10375
10420
  .dndev-game-container__cta-button {
10376
10421
  height: var(--touch-target);
10377
10422
  width: 100%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donotdev/ui",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -53,12 +53,12 @@
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@donotdev/adv-comps": "^0.0.9",
56
- "@donotdev/auth": "^0.0.5",
56
+ "@donotdev/auth": "^0.0.6",
57
57
  "@donotdev/billing": "^0.0.5",
58
58
  "@donotdev/components": "^0.0.15",
59
- "@donotdev/core": "^0.0.19",
60
- "@donotdev/crud": "^0.0.10",
61
- "@donotdev/firebase": "^0.0.8",
59
+ "@donotdev/core": "^0.0.20",
60
+ "@donotdev/crud": "^0.0.11",
61
+ "@donotdev/firebase": "^0.0.9",
62
62
  "@donotdev/oauth": "^0.0.5",
63
63
  "firebase": "^12.8.0",
64
64
  "lucide-react": "^0.563.0",