diff --git a/packages/boxel-ui/test-app/app/components/icons-grid.gts b/packages/boxel-ui/test-app/app/components/icons-grid.gts index 1371244c644..5f1956f6afd 100644 --- a/packages/boxel-ui/test-app/app/components/icons-grid.gts +++ b/packages/boxel-ui/test-app/app/components/icons-grid.gts @@ -3,6 +3,14 @@ import { ALL_ICON_COMPONENTS } from '@cardstack/boxel-icons/boxel-icons-meta'; import { Tooltip } from '@cardstack/boxel-ui/components'; import { tracked } from '@glimmer/tracking'; import { on } from '@ember/modifier'; +import { modifier } from 'ember-modifier'; +import { cn } from '@cardstack/boxel-ui/helpers'; + +import { + BoxelInput, + FieldContainer, + Switch, +} from '@cardstack/boxel-ui/components'; function importStatement(name: string): string { return `import ${toPascalCase(name)} from '@cardstack/boxel-icons/${name}';`; @@ -43,25 +51,67 @@ export default class IconsGridComponent extends Component { }); } @tracked iconFilterString = ''; + @tracked showAll = false; + @tracked isHeaderStuck = false; + sentinelElement: Element | undefined; + // The sentinel sits at the container top, exactly where the sticky header + // rests before it pins. Once it leaves the viewport the header is stuck. + detectHeaderStuck = modifier((element: Element) => { + this.sentinelElement = element; + let observer = new IntersectionObserver(([entry]) => { + this.isHeaderStuck = !entry.isIntersecting; + }); + observer.observe(element); + return () => { + observer.disconnect(); + this.sentinelElement = undefined; + }; + }); + toggleShowAll = () => { + this.showAll = !this.showAll; + // Collapsing the expanded grid can leave the page scrolled deep into + // content that no longer exists; return to the top of the icons section. + if (!this.showAll && this.isHeaderStuck) { + this.sentinelElement?.scrollIntoView({ block: 'start' }); + } + }; get boxelIconsComponents() { return this.allBoxelIconsComponents.filter((c) => { return c.name.toLowerCase().includes(this.iconFilterString.toLowerCase()); }); } - updateIconFilterString = (ev: Event) => { - this.iconFilterString = (ev.target as HTMLInputElement).value; + updateIconFilterString = (value: string) => { + this.iconFilterString = value; }; diff --git a/packages/boxel-ui/test-app/app/templates/index.gts b/packages/boxel-ui/test-app/app/templates/index.gts index ea7975a066f..15b96dd118c 100644 --- a/packages/boxel-ui/test-app/app/templates/index.gts +++ b/packages/boxel-ui/test-app/app/templates/index.gts @@ -1,14 +1,17 @@ import { action } from '@ember/object'; +import { on } from '@ember/modifier'; import type Owner from '@ember/owner'; import Component from '@glimmer/component'; import type { ComponentLike } from '@glint/template'; import { tracked } from '@glimmer/tracking'; import type RouterService from '@ember/routing/router-service'; import { service } from '@ember/service'; +import type EmberFreestyle from 'ember-freestyle/services/ember-freestyle'; import BasicDropdownWormhole from 'ember-basic-dropdown/components/basic-dropdown'; import FreestyleGuide from 'ember-freestyle/components/freestyle-guide'; +import FreestyleMenu from 'ember-freestyle/components/freestyle-menu'; import FreestyleSection from 'ember-freestyle/components/freestyle-section'; import { pageTitle } from 'ember-page-title'; import RouteTemplate from 'ember-route-template'; @@ -19,6 +22,8 @@ import IconsGrid from '../components/icons-grid'; import { CardContainer, + BoxelButton, + BoxelInput, BoxelSelect, CopyButton, FieldContainer, @@ -27,6 +32,7 @@ import { } from '@cardstack/boxel-ui/components'; import formatComponentName from '../helpers/format-component-name'; +import { loadThemeFonts } from '../utils/theme-fonts'; interface UsageComponent { title: string; @@ -34,6 +40,49 @@ interface UsageComponent { importStatement: string; } +// The scroll spy schedules FreestyleMenu#scrollActiveItemIntoView while the +// user scrolls the page. Upstream it uses Element#scrollIntoView, which also +// scrolls the document — hijacking the in-progress page scroll whenever the +// active menu item sits outside the nav's visible area. Constrain the +// auto-scroll to the nav's own scroll container. +FreestyleMenu.prototype.scrollActiveItemIntoView = function () { + let el = document.querySelector('.FreestyleMenu-submenuItem.is-active'); + let nav = el?.closest('.FreestyleGuide-nav'); + if (!el || !nav) { + return; + } + let elRect = el.getBoundingClientRect(); + let navRect = nav.getBoundingClientRect(); + if (elRect.top < navRect.top) { + nav.scrollTop += elRect.top - navRect.top; + } else if (elRect.bottom > navRect.bottom) { + nav.scrollTop += elRect.bottom - navRect.bottom; + } +}; + +// Section links in FreestyleMenu carry an extra click handler that mutates +// the menu's tracked expansion state. Real (trusted) clicks run a microtask +// checkpoint between listeners, so Ember re-renders the menu — rebuilding the +// clicked
  • — before LinkTo's own click handler runs. That handler is the +// one that calls preventDefault, so the browser follows the href instead: +// a full page reload on every section switch. Defer the mutation past the +// click dispatch so the LinkTo survives long enough to handle its own click. +// (Synthetic clicks, e.g. in tests, don't checkpoint mid-dispatch, which is +// why this only bites real users.) +{ + let expandSection = function (this: FreestyleMenu, sectionName: string) { + setTimeout(() => { + this.expandedSections.add(sectionName); + this.userCollapsedSections.delete(sectionName); + }, 0); + }; + Object.defineProperty(FreestyleMenu.prototype, 'expandSection', { + get() { + return expandSection.bind(this); + }, + }); +} + // A handful of usage titles differ from the name the component is exported as. const EXPORT_NAME_OVERRIDES: Record = { Container: 'BoxelContainer', @@ -48,6 +97,17 @@ const EXPORT_NAME_OVERRIDES: Record = { Kanban: 'DndKanbanBoard', }; +// Must match the mobile breakpoint used by the media queries below. +const SMALL_SCREEN = '(max-width: 599px)'; + +// Theme exports (e.g. from tweakcn) also carry @theme blocks, resets, etc.; +// only the :root and .dark variable blocks belong in a theme's cssVariables. +function extractThemeBlocks(css: string): string { + return [...css.matchAll(/(?::root|\.dark)\s*\{[^{}]*\}/g)] + .map((m) => m[0]) + .join('\n\n'); +} + function importStatementFor(title: string): string { let exportName = EXPORT_NAME_OVERRIDES[title] ?? title; return `import { ${exportName} } from '@cardstack/boxel-ui/components';`; @@ -78,39 +138,91 @@ class IndexComponent extends Component { class='boxel-freestyle-theme-settings' @display='flex' > -
    - + - - {{theme.name}} - - - - - -
    - + {{theme.name}} + + + + + + + + Import Theme + + {{#if this.isImportingTheme}} +
    + + + + + + +
    + + Cancel + + + Apply + +
    +
    + {{/if}} @@ -150,6 +262,7 @@ class IndexComponent extends Component { private intervalId?: NodeJS.Timeout; - private themes: Theme[] = [{ name: '' }, ...Themes]; + // Tracked so imported themes show up in the selector. + @tracked private themes: Theme[] = [{ name: '' }, ...Themes]; private usageComponents = ALL_USAGE_COMPONENTS.map(([name, c]) => { return { title: name, @@ -424,10 +592,22 @@ class IndexComponent extends Component { }) as UsageComponent[]; @service declare private router: RouterService; + @service('ember-freestyle') declare private emberFreestyle: EmberFreestyle; @tracked private theme?: Theme; @tracked private mode: 'light' | 'dark' = 'light'; @tracked private isCycleThemesEnabled = false; + @tracked private isImportingTheme = false; + @tracked private importThemeName = ''; + @tracked private importThemeCss = ''; + + private get importedThemeBlocks() { + return extractThemeBlocks(this.importThemeCss); + } + + private get isImportedThemeCssEmpty() { + return this.importedThemeBlocks.length === 0; + } private get isDarkMode() { return this.mode === 'dark'; @@ -435,6 +615,16 @@ class IndexComponent extends Component { constructor(owner: Owner, args: {}) { super(owner, args); + + // On small screens the nav is a modal drawer: closed by default so the + // page lands on scrollable content, opened via the hamburger, dismissed + // by tapping the backdrop or choosing a menu entry. + if (window.matchMedia(SMALL_SCREEN).matches) { + this.emberFreestyle.set('showMenu', false); + } + document.addEventListener('click', this.handleNavClick); + this.syncNavToggleAria(); + let queryParams = this.router?.currentRoute?.queryParams; if (!queryParams) { return; @@ -454,6 +644,81 @@ class IndexComponent extends Component { } } + override willDestroy() { + super.willDestroy(); + document.removeEventListener('click', this.handleNavClick); + clearInterval(this.intervalId); + } + + // The hamburger, nav links, and backdrop all live in ember-freestyle's or + // the browser's markup, so drawer dismissal is handled with one delegated + // listener rather than per-element modifiers. + private handleNavClick = (ev: Event) => { + let target = ev.target as Element | null; + if (target?.closest?.('.FreestyleGuide-cta--nav')) { + // the hamburger already toggles showMenu; just reflect the new state + this.syncNavToggleAria(); + return; + } + if (!window.matchMedia(SMALL_SCREEN).matches) { + return; + } + if (!this.emberFreestyle.showMenu) { + return; + } + let insideNav = target?.closest?.('.FreestyleGuide-nav'); + let onMenuLink = target?.closest?.( + '.FreestyleMenu-itemLink, .FreestyleMenu-submenuItemLink', + ); + // Close on any tap outside the drawer (the backdrop covers the rest of + // the viewport) or on a menu selection, so the chosen section is + // revealed immediately. + if (!insideNav || onMenuLink) { + this.emberFreestyle.set('showMenu', false); + this.syncNavToggleAria(); + } + }; + + private syncNavToggleAria = () => { + requestAnimationFrame(() => { + document + .querySelector('.FreestyleGuide-cta--nav') + ?.setAttribute('aria-expanded', String(this.emberFreestyle.showMenu)); + }); + }; + + @action private toggleImportTheme() { + this.isImportingTheme = !this.isImportingTheme; + } + + @action private updateImportThemeName(value: string) { + this.importThemeName = value; + } + + @action private updateImportThemeCss(value: string) { + this.importThemeCss = value; + } + + @action private importTheme() { + let cssVariables = this.importedThemeBlocks; + if (!cssVariables) { + return; + } + let base = this.importThemeName.trim() || 'Imported Theme'; + let name = base; + for (let i = 2; this.themes.some((t) => t.name === name); i++) { + name = `${base} (${i})`; + } + let theme: Theme = { name, cssVariables }; + // The static font link in index.html only covers the built-in themes. + loadThemeFonts(cssVariables); + this.themes = [...this.themes, theme]; + this.isImportingTheme = false; + this.importThemeName = ''; + this.importThemeCss = ''; + this.selectTheme(theme); + } + @action private selectTheme(theme?: Theme) { this.theme = theme; this.router.replaceWith('index', { diff --git a/packages/boxel-ui/test-app/app/themes/boxel.ts b/packages/boxel-ui/test-app/app/themes/boxel.ts deleted file mode 100644 index 6668821ac8a..00000000000 --- a/packages/boxel-ui/test-app/app/themes/boxel.ts +++ /dev/null @@ -1,120 +0,0 @@ -export const Boxel = `:root { - --background: var(--boxel-100); - --foreground: var(--boxel-700); - --card: var(--boxel-light); - --card-foreground: var(--boxel-dark); - --popover: var(--boxel-light); - --popover-foreground: var(--boxel-dark); - --primary: var(--boxel-highlight); - --primary-foreground: var(--boxel-dark); - --secondary: var(--boxel-100); - --secondary-foreground: var(--boxel-dark); - --muted: var(--boxel-100); - --muted-foreground: var(--boxel-450); - --accent: oklch(0.931 0 0); - --accent-foreground: oklch(0 0 0); - --destructive: var(--boxel-danger); - --destructive-foreground: var(--boxel-light-100); - --border: var(--boxel-border-color); - --input: oklch(1 0 0); - --ring: var(--boxel-highlight); - --chart-1: oklch(0.5838 0.299 307.6101); - --chart-2: oklch(0.5354 0.2684 283.1486); - --chart-3: oklch(0.9194 0.2182 125.1586); - --chart-4: oklch(0.5641 0.2301 259.998); - --chart-5: oklch(0.8277 0.2119 149.9571); - --sidebar: var(--boxel-200); - --sidebar-foreground: var(--boxel-dark); - --sidebar-primary: var(--boxel-highlight); - --sidebar-primary-foreground: var(--boxel-dark); - --sidebar-accent: oklch(0.931 0 0); - --sidebar-accent-foreground: oklch(0 0 0); - --sidebar-border: oklch(0.8669 0 0); - --sidebar-ring: oklch(0.8859 0.1865 164.8865); - --font-sans: 'IBM Plex Sans', 'Helvetica Neue', Arial, ui-sans-serif, sans-serif, system-ui; - --font-serif: 'IBM Plex Serif', 'Georgia', Times, serif; - --font-mono: 'IBM Plex Mono', 'Menlo', 'Courier New', Courier, ui-monospace, monospace; - --radius: 0.625rem; - --shadow-x: 0; - --shadow-y: 1px; - --shadow-blur: 3px; - --shadow-spread: 0px; - --shadow-opacity: 0.1; - --shadow-color: oklch(0 0 0); - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); - --tracking-normal: 0.01em; - --spacing: 0.25rem; - --boxel-switch-background: var(--boxel-400); - --success: var(--boxel-success); - --success-foreground: var(--boxel-success-foreground); - --warning: var(--boxel-warning); - --warning-foreground: var(--boxel-warning-foreground); -} - -.dark { - --background: oklch(0.2663 0.0245 298.8206); - --foreground: oklch(1 0 0); - --card: oklch(0.3541 0.031 289.8048); - --card-foreground: oklch(1 0 0); - --popover: oklch(0.4211 0.0203 300.7169); - --popover-foreground: oklch(1 0 0); - --primary: oklch(0.8859 0.1865 164.8865); - --primary-foreground: oklch(0 0 0); - --secondary: oklch(0 0 0); - --secondary-foreground: oklch(1 0 0); - --muted: oklch(0.4211 0.0203 300.7169); - --muted-foreground: oklch(0.7565 0.0113 286.1261); - --accent: oklch(0.5769 0.0259 290.9642); - --accent-foreground: oklch(1 0 0); - --destructive: oklch(0.6763 0.2115 24.8106); - --destructive-foreground: oklch(0.9672 0 0); - --border: oklch(0.4386 0 0); - --input: oklch(0 0 0); - --ring: oklch(0.8859 0.1865 164.8865); - --chart-1: oklch(0.5838 0.299 307.6101); - --chart-2: oklch(0.5354 0.2684 283.1486); - --chart-3: oklch(0.9194 0.2182 125.1586); - --chart-4: oklch(0.5641 0.2301 259.998); - --chart-5: oklch(0.8277 0.2119 149.9571); - --sidebar: oklch(0.3541 0.031 289.8048); - --sidebar-foreground: oklch(1 0 0); - --sidebar-primary: oklch(0.8859 0.1865 164.8865); - --sidebar-primary-foreground: oklch(0 0 0); - --sidebar-accent: oklch(0.5769 0.0259 290.9642); - --sidebar-accent-foreground: oklch(1 0 0); - --sidebar-border: oklch(0.4386 0 0); - --sidebar-ring: oklch(0.8859 0.1865 164.8865); - --font-sans: 'IBM Plex Sans', 'Helvetica Neue', Arial, ui-sans-serif, sans-serif, system-ui; - --font-serif: 'IBM Plex Serif', 'Georgia', Times, serif; - --font-mono: 'IBM Plex Mono', 'Menlo', 'Courier New', Courier, ui-monospace, monospace; - --radius: 0.625rem; - --shadow-x: 0; - --shadow-y: 1px; - --shadow-blur: 3px; - --shadow-spread: 0px; - --shadow-opacity: 0.1; - --shadow-color: oklch(0 0 0); - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), - 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/bubblegum.ts b/packages/boxel-ui/test-app/app/themes/bubblegum.ts deleted file mode 100644 index 5eac3604435..00000000000 --- a/packages/boxel-ui/test-app/app/themes/bubblegum.ts +++ /dev/null @@ -1,95 +0,0 @@ -export const Bubblegum = `:root { - --background: #f6e6ee; - --foreground: #5b5b5b; - --card: #fdedc9; - --card-foreground: #5b5b5b; - --popover: #ffffff; - --popover-foreground: #5b5b5b; - --primary: #d04f99; - --primary-foreground: #ffffff; - --secondary: #8acfd1; - --secondary-foreground: #333333; - --muted: #b2e1eb; - --muted-foreground: #7a7a7a; - --accent: #fbe2a7; - --accent-foreground: #333333; - --destructive: #f96f70; - --destructive-foreground: #ffffff; - --border: #d04f99; - --input: #e4e4e4; - --ring: #e670ab; - --chart-1: #e670ab; - --chart-2: #84d2e2; - --chart-3: #fbe2a7; - --chart-4: #f3a0ca; - --chart-5: #d7488e; - --sidebar: #f8d8ea; - --sidebar-foreground: #333333; - --sidebar-primary: #ec4899; - --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #f9a8d4; - --sidebar-accent-foreground: #333333; - --sidebar-border: #f3e8ff; - --sidebar-ring: #ec4899; - --font-sans: Poppins, sans-serif; - --font-serif: Lora, serif; - --font-mono: Fira Code, monospace; - --radius: 0.4rem; - --shadow-2xs: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 0.50); - --shadow-xs: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 0.50); - --shadow-sm: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 1px 2px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); - --shadow: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 1px 2px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); - --shadow-md: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 2px 4px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); - --shadow-lg: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 4px 6px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); - --shadow-xl: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 8px 10px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); - --shadow-2xl: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 2.50); - --tracking-normal: 0em; - --spacing: 0.25rem; -} - -.dark { - --background: #12242e; - --foreground: #f3e3ea; - --card: #1c2e38; - --card-foreground: #f3e3ea; - --popover: #1c2e38; - --popover-foreground: #f3e3ea; - --primary: #fbe2a7; - --primary-foreground: #12242e; - --secondary: #e4a2b1; - --secondary-foreground: #12242e; - --muted: #24272b; - --muted-foreground: #e4a2b1; - --accent: #c67b96; - --accent-foreground: #f3e3ea; - --destructive: #e35ea4; - --destructive-foreground: #12242e; - --border: #324859; - --input: #20333d; - --ring: #50afb6; - --chart-1: #50afb6; - --chart-2: #e4a2b1; - --chart-3: #c67b96; - --chart-4: #175c6c; - --chart-5: #24272b; - --sidebar: #101f28; - --sidebar-foreground: #f3f4f6; - --sidebar-primary: #ec4899; - --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #f9a8d4; - --sidebar-accent-foreground: #1f2937; - --sidebar-border: #374151; - --sidebar-ring: #ec4899; - --font-sans: Poppins, sans-serif; - --font-serif: Lora, serif; - --font-mono: Fira Code, monospace; - --radius: 0.4rem; - --shadow-2xs: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 0.50); - --shadow-xs: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 0.50); - --shadow-sm: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 1px 2px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); - --shadow: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 1px 2px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); - --shadow-md: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 2px 4px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); - --shadow-lg: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 4px 6px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); - --shadow-xl: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 8px 10px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); - --shadow-2xl: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 2.50); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/candyland.ts b/packages/boxel-ui/test-app/app/themes/candyland.ts deleted file mode 100644 index e843b0f691a..00000000000 --- a/packages/boxel-ui/test-app/app/themes/candyland.ts +++ /dev/null @@ -1,95 +0,0 @@ -export const Candyland = `:root { - --background: #f7f9fa; - --foreground: #333333; - --card: #ffffff; - --card-foreground: #333333; - --popover: #ffffff; - --popover-foreground: #333333; - --primary: #ffc0cb; - --primary-foreground: #000000; - --secondary: #87ceeb; - --secondary-foreground: #000000; - --muted: #ddd9c4; - --muted-foreground: #6e6e6e; - --accent: #ffff00; - --accent-foreground: #000000; - --destructive: #ef4444; - --destructive-foreground: #ffffff; - --border: #d4d4d4; - --input: #d4d4d4; - --ring: #ffc0cb; - --chart-1: #ffc0cb; - --chart-2: #87ceeb; - --chart-3: #ffff00; - --chart-4: #ff99cc; - --chart-5: #33cc33; - --sidebar: #f7f9fa; - --sidebar-foreground: #333333; - --sidebar-primary: #ffc0cb; - --sidebar-primary-foreground: #000000; - --sidebar-accent: #ffff00; - --sidebar-accent-foreground: #000000; - --sidebar-border: #d4d4d4; - --sidebar-ring: #ffc0cb; - --font-sans: Poppins, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: Roboto Mono, monospace; - --radius: 0.5rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); - --tracking-normal: 0em; - --spacing: 0.25rem; -} - -.dark { - --background: #1a1d23; - --foreground: #e5e5e5; - --card: #2f3436; - --card-foreground: #e5e5e5; - --popover: #2f3436; - --popover-foreground: #e5e5e5; - --primary: #ff99cc; - --primary-foreground: #000000; - --secondary: #33cc33; - --secondary-foreground: #000000; - --muted: #444444; - --muted-foreground: #a3a3a3; - --accent: #87ceeb; - --accent-foreground: #000000; - --destructive: #ef4444; - --destructive-foreground: #ffffff; - --border: #444444; - --input: #444444; - --ring: #ff99cc; - --chart-1: #ff99cc; - --chart-2: #33cc33; - --chart-3: #87ceeb; - --chart-4: #ffff00; - --chart-5: #ffcc00; - --sidebar: #1a1d23; - --sidebar-foreground: #e5e5e5; - --sidebar-primary: #ff99cc; - --sidebar-primary-foreground: #000000; - --sidebar-accent: #87ceeb; - --sidebar-accent-foreground: #000000; - --sidebar-border: #444444; - --sidebar-ring: #ff99cc; - --font-sans: Poppins, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: Roboto Mono, monospace; - --radius: 0.5rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/cs-themes.ts b/packages/boxel-ui/test-app/app/themes/cs-themes.ts new file mode 100644 index 00000000000..7575cdd8a3d --- /dev/null +++ b/packages/boxel-ui/test-app/app/themes/cs-themes.ts @@ -0,0 +1,187 @@ +export const BoxelBrandGuide = `:root { + --accent: var(--cardstack-lime, #C3FC33); + --accent-foreground: var(--boxel-slate, #272330); + --background: var(--boxel-dove, #F7F8FA); + --border: #E2E8F0; + --card: var(--boxel-light, #FFFFFF); + --card-foreground: #111111; + --chart-1: var(--cardstack-magenta, #AC00FF); + --chart-2: var(--cardstack-purple, #6638FF); + --chart-3: var(--cardstack-lime, #C3FC33); + --chart-4: var(--boxel-teal, #00FFBA); + --chart-5: var(--boxel-green, #37EB77); + --destructive: var(--cardstack-red, #FF5050); + --destructive-foreground: #F8FAFC; + --font-mono: 'IBM Plex Mono', 'Menlo', 'Courier New', Courier, ui-monospace, monospace; + --font-sans: 'IBM Plex Sans', 'Helvetica Neue', Arial, ui-sans-serif, sans-serif, system-ui; + --font-serif: 'IBM Plex Serif', 'Georgia', Times, serif; + --foreground: var(--boxel-slate, #272330); + --input: var(--boxel-light, #FFFFFF); + --muted: #F5F5F5; + --muted-foreground: #64748B; + --popover: var(--boxel-light, #FFFFFF); + --popover-foreground: #111111; + --primary: var(--boxel-teal, #00FFBA); + --primary-foreground: var(--boxel-slate, #272330); + --radius: 0.625rem; + --ring: var(--boxel-teal, #00FFBA); + --secondary: var(--cardstack-purple, #6638FF); + --secondary-foreground: var(--boxel-light, #FFFFFF); + --shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); + --shadow-2xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --sidebar: #F0F2F5; + --sidebar-accent: var(--cardstack-lime, #C3FC33); + --sidebar-accent-foreground: #0F172A; + --sidebar-border: #E2E8F0; + --sidebar-foreground: #0F172A; + --sidebar-primary: var(--boxel-teal, #00FFBA); + --sidebar-primary-foreground: #0F172A; + --sidebar-ring: var(--boxel-teal, #00FFBA); + --spacing: 0.25rem; + --tracking-normal: 0.01em; + --brand-primary: var(--boxel-teal); + --brand-secondary: var(--cardstack-purple); + --brand-accent: var(--cardstack-lime); + --brand-light: var(--boxel-dove, #F7F8FA); + --brand-dark: var(--boxel-slate, #272330); + --boxel-teal: #00FFBA; + --boxel-cyan: #00EBE5; + --boxel-slate: #272330; + --boxel-light: #FFFFFF; + --boxel-black: #000000; + --boxel-dove: #F8F7FA; + --cardstack-red: #FF5050; + --cardstack-lime: #C3FC33; + --cardstack-magenta: #AC00FF; + --cardstack-purple: #6638FF; + --cardstack-dark-blue: #281E78; + --theme-heading-font-family: IBM Plex Sans; + --theme-heading-font-size: clamp(2.5rem, 6vw, 4rem); + --theme-heading-font-weight: 700; + --theme-heading-line-height: 1.05; + --theme-section-heading-font-family: IBM Plex Mono; + --theme-section-heading-font-size: 0.75rem; + --theme-section-heading-font-weight: 600; + --theme-section-heading-line-height: 1; + --theme-subheading-font-family: IBM Plex Sans; + --theme-subheading-font-size: 1.5rem; + --theme-subheading-font-weight: 700; + --theme-subheading-line-height: 1.4; + --theme-body-font-family: IBM Plex Sans; + --theme-body-font-size: 0.9375rem; + --theme-body-font-weight: 400; + --theme-body-line-height: 1.6; + --theme-caption-font-family: IBM Plex Mono; + --theme-caption-font-size: 0.75rem; + --theme-caption-font-weight: 600; + --theme-caption-line-height: 1.2; + --brand-primary-mark-clearance-ratio: 1.5; + --brand-primary-mark-min-height: 20px; + --brand-secondary-mark-clearance-ratio: 1.25; + --brand-secondary-mark-min-height: 32px; + --brand-social-media-profile-icon: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/96e9cc96-484c-4dd4-ea9f-5a6d1fad6a00/public); + --brand-primary-mark: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/5de76ce4-d7f6-4203-1b22-009031a0bc00/public); + --brand-secondary-mark: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/47b743a2-3a61-4c85-5277-39d764fea100/public); + --brand-primary-mark-greyscale: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/20fe9504-5b42-4cbe-6402-0872ba33b000/public); + --brand-secondary-mark-greyscale: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/83edd48e-7d26-4038-3452-777ee713e000/public); +} + +.dark { + --accent: var(--cardstack-lime, #C3FC33); + --accent-foreground: #0F172A; + --background: var(--brand-dark, #272330); + --border: #333333; + --card: #1E1E1E; + --card-foreground: var(--boxel-light, #FFFFFF); + --chart-1: var(--cardstack-magenta, #AC00FF); + --chart-2: var(--cardstack-purple, #6638FF); + --chart-3: var(--cardstack-lime, #C3FC33); + --chart-4: var(--boxel-teal, #00FFBA); + --chart-5: var(--boxel-green, #37EB77); + --destructive: var(--cardstack-red, #FF5050); + --destructive-foreground: var(--boxel-light, #FFFFFF); + --font-mono: 'IBM Plex Mono', 'Menlo', 'Courier New', Courier, ui-monospace, monospace; + --font-sans: 'IBM Plex Sans', 'Helvetica Neue', Arial, ui-sans-serif, sans-serif, system-ui; + --font-serif: 'IBM Plex Serif', 'Georgia', Times, serif; + --foreground: var(--brand-light, #F7F8FA); + --input: #27272A; + --muted: #27272A; + --muted-foreground: #A1A1AA; + --popover: #1E1E1E; + --popover-foreground: var(--boxel-light, #FFFFFF); + --primary: var(--boxel-teal, #00FFBA); + --primary-foreground: #0F172A; + --radius: 0.625rem; + --ring: var(--boxel-teal, #00FFBA); + --secondary: var(--boxel-light, #FFFFFF); + --secondary-foreground: var(--cardstack-purple, #6638FF); + --shadow: 0 1px 2px 0 rgb(0 0 0 / 0.5); + --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.5); + --shadow-2xs: 0 1px 2px 0 rgb(0 0 0 / 0.5); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.5); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.5); + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.5); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.5); + --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.5); + --sidebar: #18181B; + --sidebar-accent: oklch(0.9338 0.1913 122.52); + --sidebar-accent-foreground: #0F172A; + --sidebar-border: #333333; + --sidebar-foreground: var(--boxel-light, #FFFFFF); + --sidebar-primary: var(--boxel-teal, #00FFBA); + --sidebar-primary-foreground: #0F172A; + --sidebar-ring: var(--boxel-teal, #00FFBA); + --spacing: 0.25rem; + --tracking-normal: 0.01em; + --brand-primary: var(--boxel-teal); + --brand-secondary: var(--cardstack-purple); + --brand-accent: var(--cardstack-lime); + --brand-light: var(--boxel-dove, #F7F8FA); + --brand-dark: var(--boxel-slate, #272330); + --boxel-teal: #00FFBA; + --boxel-cyan: #00EBE5; + --boxel-slate: #272330; + --boxel-light: #FFFFFF; + --boxel-black: #000000; + --boxel-dove: #F8F7FA; + --cardstack-red: #FF5050; + --cardstack-lime: #C3FC33; + --cardstack-magenta: #AC00FF; + --cardstack-purple: #6638FF; + --cardstack-dark-blue: #281E78; + --theme-heading-font-family: IBM Plex Sans; + --theme-heading-font-size: clamp(2.5rem, 6vw, 4rem); + --theme-heading-font-weight: 700; + --theme-heading-line-height: 1.05; + --theme-section-heading-font-family: IBM Plex Mono; + --theme-section-heading-font-size: 0.75rem; + --theme-section-heading-font-weight: 600; + --theme-section-heading-line-height: 1; + --theme-subheading-font-family: IBM Plex Sans; + --theme-subheading-font-size: 1.5rem; + --theme-subheading-font-weight: 700; + --theme-subheading-line-height: 1.4; + --theme-body-font-family: IBM Plex Sans; + --theme-body-font-size: 0.9375rem; + --theme-body-font-weight: 400; + --theme-body-line-height: 1.6; + --theme-caption-font-family: IBM Plex Mono; + --theme-caption-font-size: 0.75rem; + --theme-caption-font-weight: 600; + --theme-caption-line-height: 1.2; + --brand-primary-mark-clearance-ratio: 1.5; + --brand-primary-mark-min-height: 20px; + --brand-secondary-mark-clearance-ratio: 1.25; + --brand-secondary-mark-min-height: 32px; + --brand-social-media-profile-icon: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/96e9cc96-484c-4dd4-ea9f-5a6d1fad6a00/public); + --brand-primary-mark: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/2c5dc51c-7269-4e7b-538e-9d9f5202b400/public); + --brand-secondary-mark: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/2842930b-f3df-44f9-e78d-40aaa0d2f200/public); + --brand-primary-mark-greyscale: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/cb8e09b0-d55f-421c-8a46-a9d7da935a00/public); + --brand-secondary-mark-greyscale: url(https://imagedelivery.net/TB1OM65i5Go9UkT2wcBzeA/eae47388-af68-4ba7-1f88-7a05f08ed100/public); +}`; diff --git a/packages/boxel-ui/test-app/app/themes/dark-studio.ts b/packages/boxel-ui/test-app/app/themes/dark-studio.ts deleted file mode 100644 index b02025f2ac2..00000000000 --- a/packages/boxel-ui/test-app/app/themes/dark-studio.ts +++ /dev/null @@ -1,88 +0,0 @@ -export const DarkStudio = `:root { - --accent: #8b5cf6; - --accent-foreground: #ffffff; - --background: #0f0f1a; - --border: rgba(255, 255, 255, 0.08); - --card: #1a1a2e; - --card-foreground: #e2e8f0; - --chart-1: #7c3aed; - --chart-2: #00d4ff; - --chart-3: #22c55e; - --chart-4: #a5b4fc; - --chart-5: #4ade80; - --destructive: #ef4444; - --destructive-foreground: #f87171; - --font-sans: system-ui, -apple-system, sans-serif; - --foreground: #e2e8f0; - --input: rgba(255, 255, 255, 0.05); - --muted: rgba(255, 255, 255, 0.05); - --muted-foreground: #64748b; - --popover: #16213e; - --popover-foreground: #e2e8f0; - --primary: #7c3aed; - --primary-foreground: #ffffff; - --radius: 0.75rem; - --ring: #00d4ff; - --secondary: #00d4ff; - --secondary-foreground: #0f0f1a; - --shadow: 0 4px 16px rgba(0,0,0,0.5); - --shadow-2xl: 0 32px 64px rgba(124,58,237,0.35); - --shadow-2xs: 0 1px 2px rgba(0,0,0,0.4); - --shadow-lg: 0 12px 32px rgba(124,58,237,0.25); - --shadow-md: 0 8px 24px rgba(0,0,0,0.6); - --shadow-sm: 0 2px 8px rgba(0,0,0,0.5); - --shadow-xl: 0 20px 48px rgba(124,58,237,0.3); - --shadow-xs: 0 1px 4px rgba(0,0,0,0.5); - --sidebar: #16213e; - --sidebar-accent: #00d4ff; - --sidebar-accent-foreground: #0f0f1a; - --sidebar-border: rgba(255, 255, 255, 0.08); - --sidebar-foreground: #e2e8f0; - --sidebar-primary: #7c3aed; - --sidebar-primary-foreground: #ffffff; - --sidebar-ring: #00d4ff; - --spacing: 0.25rem; - --theme-heading-font-family: system-ui, -apple-system, sans-serif; - --theme-heading-font-size: 2.5rem; - --theme-heading-font-weight: 800; - --theme-heading-line-height: 1.1; - --theme-section-heading-font-family: system-ui, -apple-system, sans-serif; - --theme-section-heading-font-size: 0.6875rem; - --theme-section-heading-font-weight: 600; - --theme-section-heading-line-height: 1.4; - --theme-subheading-font-family: system-ui, -apple-system, sans-serif; - --theme-subheading-font-size: 1.125rem; - --theme-subheading-font-weight: 700; - --theme-subheading-line-height: 1.3; - --theme-body-font-family: system-ui, -apple-system, sans-serif; - --theme-body-font-size: 0.8125rem; - --theme-body-font-weight: 700; - --theme-body-line-height: 1.4; - --theme-caption-font-family: system-ui, -apple-system, sans-serif; - --theme-caption-font-size: 0.5625rem; - --theme-caption-font-weight: 600; - --theme-caption-line-height: 1.4; -} - -.dark { - --theme-heading-font-family: system-ui, -apple-system, sans-serif; - --theme-heading-font-size: 2.5rem; - --theme-heading-font-weight: 800; - --theme-heading-line-height: 1.1; - --theme-section-heading-font-family: system-ui, -apple-system, sans-serif; - --theme-section-heading-font-size: 0.6875rem; - --theme-section-heading-font-weight: 600; - --theme-section-heading-line-height: 1.4; - --theme-subheading-font-family: system-ui, -apple-system, sans-serif; - --theme-subheading-font-size: 1.125rem; - --theme-subheading-font-weight: 700; - --theme-subheading-line-height: 1.3; - --theme-body-font-family: system-ui, -apple-system, sans-serif; - --theme-body-font-size: 0.8125rem; - --theme-body-font-weight: 700; - --theme-body-line-height: 1.4; - --theme-caption-font-family: system-ui, -apple-system, sans-serif; - --theme-caption-font-size: 0.5625rem; - --theme-caption-font-weight: 600; - --theme-caption-line-height: 1.4; -}`; diff --git a/packages/boxel-ui/test-app/app/themes/doom64.ts b/packages/boxel-ui/test-app/app/themes/doom64.ts deleted file mode 100644 index bf81368f4e7..00000000000 --- a/packages/boxel-ui/test-app/app/themes/doom64.ts +++ /dev/null @@ -1,96 +0,0 @@ -export const Doom64 = `:root { - --background: #cccccc; - --foreground: #1f1f1f; - --card: #b0b0b0; - --card-foreground: #1f1f1f; - --popover: #b0b0b0; - --popover-foreground: #1f1f1f; - --primary: #b71c1c; - --primary-foreground: #ffffff; - --secondary: #556b2f; - --secondary-foreground: #ffffff; - --muted: #b8b8b8; - --muted-foreground: #4a4a4a; - --accent: #4682b4; - --accent-foreground: #ffffff; - --destructive: #ff6f00; - --destructive-foreground: #000000; - --border: #505050; - --input: #505050; - --ring: #b71c1c; - --chart-1: #b71c1c; - --chart-2: #556b2f; - --chart-3: #4682b4; - --chart-4: #ff6f00; - --chart-5: #8d6e63; - --sidebar: #b0b0b0; - --sidebar-foreground: #1f1f1f; - --sidebar-primary: #b71c1c; - --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #4682b4; - --sidebar-accent-foreground: #ffffff; - --sidebar-border: #505050; - --sidebar-ring: #b71c1c; - --font-sans: "Oxanium", sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: "Source Code Pro", monospace; - --radius: 0px; - --shadow-2xs: 0px 2px 4px 0px hsl(0 0% 0% / 0.20); - --shadow-xs: 0px 2px 4px 0px hsl(0 0% 0% / 0.20); - --shadow-sm: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); - --shadow: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); - --shadow-md: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 2px 4px -1px hsl(0 0% 0% / 0.40); - --shadow-lg: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 4px 6px -1px hsl(0 0% 0% / 0.40); - --shadow-xl: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 8px 10px -1px hsl(0 0% 0% / 0.40); - --shadow-2xl: 0px 2px 4px 0px hsl(0 0% 0% / 1.00); - --tracking-normal: 0em; - --spacing: 0.25rem; -} - -.dark { - --background: #1a1a1a; - --foreground: #e0e0e0; - --card: #2a2a2a; - --card-foreground: #e0e0e0; - --popover: #2a2a2a; - --popover-foreground: #e0e0e0; - --primary: #e53935; - --primary-foreground: #ffffff; - --secondary: #689f38; - --secondary-foreground: #000000; - --muted: #252525; - --muted-foreground: #a0a0a0; - --accent: #64b5f6; - --accent-foreground: #000000; - --destructive: #ffa000; - --destructive-foreground: #000000; - --border: #4a4a4a; - --input: #4a4a4a; - --ring: #e53935; - --chart-1: #e53935; - --chart-2: #689f38; - --chart-3: #64b5f6; - --chart-4: #ffa000; - --chart-5: #a1887f; - --sidebar: #141414; - --sidebar-foreground: #e0e0e0; - --sidebar-primary: #e53935; - --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #64b5f6; - --sidebar-accent-foreground: #000000; - --sidebar-border: #4a4a4a; - --sidebar-ring: #e53935; - --font-sans: "Oxanium", sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: "Source Code Pro", monospace; - --radius: 0px; - --shadow-2xs: 0px 2px 5px 0px hsl(0 0% 0% / 0.30); - --shadow-xs: 0px 2px 5px 0px hsl(0 0% 0% / 0.30); - --shadow-sm: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 1px 2px -1px hsl(0 0% 0% / 0.60); - --shadow: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 1px 2px -1px hsl(0 0% 0% / 0.60); - --shadow-md: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 2px 4px -1px hsl(0 0% 0% / 0.60); - --shadow-lg: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 4px 6px -1px hsl(0 0% 0% / 0.60); - --shadow-xl: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 8px 10px -1px hsl(0 0% 0% / 0.60); - --shadow-2xl: 0px 2px 5px 0px hsl(0 0% 0% / 1.50); -} -`; diff --git a/packages/boxel-ui/test-app/app/themes/index.ts b/packages/boxel-ui/test-app/app/themes/index.ts index e749b0b6d16..dba08c72680 100644 --- a/packages/boxel-ui/test-app/app/themes/index.ts +++ b/packages/boxel-ui/test-app/app/themes/index.ts @@ -1,33 +1,26 @@ -import { Bubblegum } from './bubblegum.ts'; -import { NeoBrutalism } from './neo-brutalism.ts'; -import { SoftPop } from './soft-pop.ts'; -import { Candyland } from './candyland.ts'; -import { Doom64 } from './doom64.ts'; -import { StarryNight } from './starry-night.ts'; -import { Boxel } from './boxel.ts'; -import { DarkStudio } from './dark-studio.ts'; +import * as CS_THEMES from './cs-themes.ts'; +import * as TCN_THEMES from './tcn-themes.ts'; + +const THEMES = { ...TCN_THEMES, ...CS_THEMES }; export interface Theme { cssVariables?: string; name: string; } -export const THEMES = { - Bubblegum, - Doom64, - SoftPop, - NeoBrutalism, - StarryNight, - Candyland, - DarkStudio, - Boxel, -}; - // adjust for freestyle doc styles overriding theme variables const FREESTYLE_ADJUSTMENTS = `\n\n:root {\n --theme-radius: var(--radius);\n}`; +// PascalCase export name -> display name, e.g. +// "AmethystHaze" -> "Amethyst Haze", "Doom64" -> "Doom 64" +function formatThemeName(name: string): string { + return name + .replace(/([a-z])([A-Z0-9])/g, '$1 $2') + .replace(/(\d)([A-Za-z])/g, '$1 $2'); +} + const Themes: Theme[] = Object.entries(THEMES).map(([name, vars]) => ({ - name, + name: formatThemeName(name), cssVariables: vars + FREESTYLE_ADJUSTMENTS, })); diff --git a/packages/boxel-ui/test-app/app/themes/neo-brutalism.ts b/packages/boxel-ui/test-app/app/themes/neo-brutalism.ts deleted file mode 100644 index 782bc80f9b9..00000000000 --- a/packages/boxel-ui/test-app/app/themes/neo-brutalism.ts +++ /dev/null @@ -1,95 +0,0 @@ -export const NeoBrutalism = `:root { - --background: oklch(1.0000 0 0); - --foreground: oklch(0 0 0); - --card: oklch(1.0000 0 0); - --card-foreground: oklch(0 0 0); - --popover: oklch(1.0000 0 0); - --popover-foreground: oklch(0 0 0); - --primary: oklch(0.6489 0.2370 26.9728); - --primary-foreground: oklch(1.0000 0 0); - --secondary: oklch(0.9680 0.2110 109.7692); - --secondary-foreground: oklch(0 0 0); - --muted: oklch(0.9551 0 0); - --muted-foreground: oklch(0.3211 0 0); - --accent: oklch(0.5635 0.2408 260.8178); - --accent-foreground: oklch(1.0000 0 0); - --destructive: oklch(0 0 0); - --destructive-foreground: oklch(1.0000 0 0); - --border: oklch(0 0 0); - --input: oklch(0 0 0); - --ring: oklch(0.6489 0.2370 26.9728); - --chart-1: oklch(0.6489 0.2370 26.9728); - --chart-2: oklch(0.9680 0.2110 109.7692); - --chart-3: oklch(0.5635 0.2408 260.8178); - --chart-4: oklch(0.7323 0.2492 142.4953); - --chart-5: oklch(0.5931 0.2726 328.3634); - --sidebar: oklch(0.9551 0 0); - --sidebar-foreground: oklch(0 0 0); - --sidebar-primary: oklch(0.6489 0.2370 26.9728); - --sidebar-primary-foreground: oklch(1.0000 0 0); - --sidebar-accent: oklch(0.5635 0.2408 260.8178); - --sidebar-accent-foreground: oklch(1.0000 0 0); - --sidebar-border: oklch(0 0 0); - --sidebar-ring: oklch(0.6489 0.2370 26.9728); - --font-sans: DM Sans, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: Space Mono, monospace; - --radius: 0px; - --shadow-2xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); - --shadow-xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); - --shadow-sm: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); - --shadow: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); - --shadow-md: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 2px 4px -1px hsl(0 0% 0% / 1.00); - --shadow-lg: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 4px 6px -1px hsl(0 0% 0% / 1.00); - --shadow-xl: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 8px 10px -1px hsl(0 0% 0% / 1.00); - --shadow-2xl: 4px 4px 0px 0px hsl(0 0% 0% / 2.50); - --tracking-normal: 0em; - --spacing: 0.25rem; -} - -.dark { - --background: oklch(0 0 0); - --foreground: oklch(1.0000 0 0); - --card: oklch(0.3211 0 0); - --card-foreground: oklch(1.0000 0 0); - --popover: oklch(0.3211 0 0); - --popover-foreground: oklch(1.0000 0 0); - --primary: oklch(0.7044 0.1872 23.1858); - --primary-foreground: oklch(0 0 0); - --secondary: oklch(0.9691 0.2005 109.6228); - --secondary-foreground: oklch(0 0 0); - --muted: oklch(0.3211 0 0); - --muted-foreground: oklch(0.8452 0 0); - --accent: oklch(0.6755 0.1765 252.2592); - --accent-foreground: oklch(0 0 0); - --destructive: oklch(1.0000 0 0); - --destructive-foreground: oklch(0 0 0); - --border: oklch(1.0000 0 0); - --input: oklch(1.0000 0 0); - --ring: oklch(0.7044 0.1872 23.1858); - --chart-1: oklch(0.7044 0.1872 23.1858); - --chart-2: oklch(0.9691 0.2005 109.6228); - --chart-3: oklch(0.6755 0.1765 252.2592); - --chart-4: oklch(0.7395 0.2268 142.8504); - --chart-5: oklch(0.6131 0.2458 328.0714); - --sidebar: oklch(0 0 0); - --sidebar-foreground: oklch(1.0000 0 0); - --sidebar-primary: oklch(0.7044 0.1872 23.1858); - --sidebar-primary-foreground: oklch(0 0 0); - --sidebar-accent: oklch(0.6755 0.1765 252.2592); - --sidebar-accent-foreground: oklch(0 0 0); - --sidebar-border: oklch(1.0000 0 0); - --sidebar-ring: oklch(0.7044 0.1872 23.1858); - --font-sans: DM Sans, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: Space Mono, monospace; - --radius: 0px; - --shadow-2xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); - --shadow-xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); - --shadow-sm: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); - --shadow: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); - --shadow-md: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 2px 4px -1px hsl(0 0% 0% / 1.00); - --shadow-lg: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 4px 6px -1px hsl(0 0% 0% / 1.00); - --shadow-xl: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 8px 10px -1px hsl(0 0% 0% / 1.00); - --shadow-2xl: 4px 4px 0px 0px hsl(0 0% 0% / 2.50); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/soft-pop.ts b/packages/boxel-ui/test-app/app/themes/soft-pop.ts deleted file mode 100644 index 48b4f9e4a13..00000000000 --- a/packages/boxel-ui/test-app/app/themes/soft-pop.ts +++ /dev/null @@ -1,95 +0,0 @@ -export const SoftPop = `:root { - --background: #f7f9f3; - --foreground: #000000; - --card: #ffffff; - --card-foreground: #000000; - --popover: #ffffff; - --popover-foreground: #000000; - --primary: #4f46e5; - --primary-foreground: #ffffff; - --secondary: #14b8a6; - --secondary-foreground: #ffffff; - --muted: #f0f0f0; - --muted-foreground: #333333; - --accent: #f59e0b; - --accent-foreground: #000000; - --destructive: #ef4444; - --destructive-foreground: #ffffff; - --border: #000000; - --input: #737373; - --ring: #a5b4fc; - --chart-1: #4f46e5; - --chart-2: #14b8a6; - --chart-3: #f59e0b; - --chart-4: #ec4899; - --chart-5: #22c55e; - --sidebar: #f7f9f3; - --sidebar-foreground: #000000; - --sidebar-primary: #4f46e5; - --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #f59e0b; - --sidebar-accent-foreground: #000000; - --sidebar-border: #000000; - --sidebar-ring: #a5b4fc; - --font-sans: DM Sans, sans-serif; - --font-serif: DM Sans, sans-serif; - --font-mono: Space Mono, monospace; - --radius: 1rem; - --shadow-2xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); - --shadow-xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); - --shadow-sm: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); - --shadow: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-md: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 2px 4px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-lg: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 4px 6px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 8px 10px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-2xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.13); - --tracking-normal: normal; - --spacing: 0.25rem; -} - -.dark { - --background: #000000; - --foreground: #ffffff; - --card: #1a212b; - --card-foreground: #ffffff; - --popover: #1a212b; - --popover-foreground: #ffffff; - --primary: #818cf8; - --primary-foreground: #000000; - --secondary: #2dd4bf; - --secondary-foreground: #000000; - --muted: #333333; - --muted-foreground: #cccccc; - --accent: #fcd34d; - --accent-foreground: #000000; - --destructive: #f87171; - --destructive-foreground: #000000; - --border: #545454; - --input: #ffffff; - --ring: #818cf8; - --chart-1: #818cf8; - --chart-2: #2dd4bf; - --chart-3: #fcd34d; - --chart-4: #f472b6; - --chart-5: #4ade80; - --sidebar: #000000; - --sidebar-foreground: #ffffff; - --sidebar-primary: #818cf8; - --sidebar-primary-foreground: #000000; - --sidebar-accent: #fcd34d; - --sidebar-accent-foreground: #000000; - --sidebar-border: #ffffff; - --sidebar-ring: #818cf8; - --font-sans: DM Sans, sans-serif; - --font-serif: DM Sans, sans-serif; - --font-mono: Space Mono, monospace; - --radius: 1rem; - --shadow-2xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); - --shadow-xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); - --shadow-sm: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); - --shadow: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-md: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 2px 4px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-lg: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 4px 6px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 8px 10px -1px hsl(0 0% 10.1961% / 0.05); - --shadow-2xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.13); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/starry-night.ts b/packages/boxel-ui/test-app/app/themes/starry-night.ts deleted file mode 100644 index 3ccda3aee27..00000000000 --- a/packages/boxel-ui/test-app/app/themes/starry-night.ts +++ /dev/null @@ -1,95 +0,0 @@ -export const StarryNight = `:root { - --background: oklch(0.9755 0.0045 258.3245); - --foreground: oklch(0.2558 0.0433 268.0662); - --card: oklch(0.9341 0.0132 251.5628); - --card-foreground: oklch(0.2558 0.0433 268.0662); - --popover: oklch(0.9856 0.0278 98.0540); - --popover-foreground: oklch(0.2558 0.0433 268.0662); - --primary: oklch(0.4815 0.1178 263.3758); - --primary-foreground: oklch(0.9856 0.0278 98.0540); - --secondary: oklch(0.8567 0.1164 81.0092); - --secondary-foreground: oklch(0.2558 0.0433 268.0662); - --muted: oklch(0.9202 0.0080 106.5563); - --muted-foreground: oklch(0.4815 0.1178 263.3758); - --accent: oklch(0.6896 0.0714 234.0387); - --accent-foreground: oklch(0.9856 0.0278 98.0540); - --destructive: oklch(0.2611 0.0376 322.5267); - --destructive-foreground: oklch(0.9856 0.0278 98.0540); - --border: oklch(0.7791 0.0156 251.1926); - --input: oklch(0.6896 0.0714 234.0387); - --ring: oklch(0.8567 0.1164 81.0092); - --chart-1: oklch(0.4815 0.1178 263.3758); - --chart-2: oklch(0.8567 0.1164 81.0092); - --chart-3: oklch(0.6896 0.0714 234.0387); - --chart-4: oklch(0.7791 0.0156 251.1926); - --chart-5: oklch(0.2611 0.0376 322.5267); - --sidebar: oklch(0.9341 0.0132 251.5628); - --sidebar-foreground: oklch(0.2558 0.0433 268.0662); - --sidebar-primary: oklch(0.4815 0.1178 263.3758); - --sidebar-primary-foreground: oklch(0.9856 0.0278 98.0540); - --sidebar-accent: oklch(0.8567 0.1164 81.0092); - --sidebar-accent-foreground: oklch(0.2558 0.0433 268.0662); - --sidebar-border: oklch(0.7791 0.0156 251.1926); - --sidebar-ring: oklch(0.8567 0.1164 81.0092); - --font-sans: Libre Baskerville, serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - --radius: 0.5rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); - --tracking-normal: 0em; - --spacing: 0.25rem; -} - -.dark { - --background: oklch(0.2204 0.0198 275.8439); - --foreground: oklch(0.9366 0.0129 266.6974); - --card: oklch(0.2703 0.0407 281.3036); - --card-foreground: oklch(0.9366 0.0129 266.6974); - --popover: oklch(0.2703 0.0407 281.3036); - --popover-foreground: oklch(0.9097 0.1440 95.1120); - --primary: oklch(0.4815 0.1178 263.3758); - --primary-foreground: oklch(0.9097 0.1440 95.1120); - --secondary: oklch(0.9097 0.1440 95.1120); - --secondary-foreground: oklch(0.2703 0.0407 281.3036); - --muted: oklch(0.2703 0.0407 281.3036); - --muted-foreground: oklch(0.6243 0.0412 262.0375); - --accent: oklch(0.8469 0.0524 264.7751); - --accent-foreground: oklch(0.2204 0.0198 275.8439); - --destructive: oklch(0.5280 0.1200 357.1130); - --destructive-foreground: oklch(0.9097 0.1440 95.1120); - --border: oklch(0.3072 0.0287 281.7681); - --input: oklch(0.6896 0.0714 234.0387); - --ring: oklch(0.9097 0.1440 95.1120); - --chart-1: oklch(0.4815 0.1178 263.3758); - --chart-2: oklch(0.9097 0.1440 95.1120); - --chart-3: oklch(0.6896 0.0714 234.0387); - --chart-4: oklch(0.6243 0.0412 262.0375); - --chart-5: oklch(0.5280 0.1200 357.1130); - --sidebar: oklch(0.2703 0.0407 281.3036); - --sidebar-foreground: oklch(0.9366 0.0129 266.6974); - --sidebar-primary: oklch(0.4815 0.1178 263.3758); - --sidebar-primary-foreground: oklch(0.9097 0.1440 95.1120); - --sidebar-accent: oklch(0.9097 0.1440 95.1120); - --sidebar-accent-foreground: oklch(0.2703 0.0407 281.3036); - --sidebar-border: oklch(0.3072 0.0287 281.7681); - --sidebar-ring: oklch(0.9097 0.1440 95.1120); - --font-sans: Libre Baskerville, serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - --radius: 0.5rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); -}`; diff --git a/packages/boxel-ui/test-app/app/themes/tcn-themes.ts b/packages/boxel-ui/test-app/app/themes/tcn-themes.ts new file mode 100644 index 00000000000..538878a66bd --- /dev/null +++ b/packages/boxel-ui/test-app/app/themes/tcn-themes.ts @@ -0,0 +1,869 @@ +export const AmethystHaze = `:root { + --background: #f8f7fa; + --foreground: #3d3c4f; + --card: #ffffff; + --card-foreground: #3d3c4f; + --popover: #ffffff; + --popover-foreground: #3d3c4f; + --primary: #8a79ab; + --primary-foreground: #f8f7fa; + --secondary: #dfd9ec; + --secondary-foreground: #3d3c4f; + --muted: #dcd9e3; + --muted-foreground: #6b6880; + --accent: #e6a5b8; + --accent-foreground: #4b2e36; + --destructive: #d95c5c; + --destructive-foreground: #f8f7fa; + --border: #cec9d9; + --input: #eae7f0; + --ring: #8a79ab; + --chart-1: #8a79ab; + --chart-2: #e6a5b8; + --chart-3: #77b8a1; + --chart-4: #f0c88d; + --chart-5: #a0bbe3; + --sidebar: #f1eff5; + --sidebar-foreground: #3d3c4f; + --sidebar-primary: #8a79ab; + --sidebar-primary-foreground: #f8f7fa; + --sidebar-accent: #e6a5b8; + --sidebar-accent-foreground: #4b2e36; + --sidebar-border: #d7d2e0; + --sidebar-ring: #8a79ab; + --font-sans: Geist, sans-serif; + --font-serif: "Lora", Georgia, serif; + --font-mono: "Fira Code", "Courier New", monospace; + --radius: 0.5rem; + --shadow-x: 1px; + --shadow-y: 2px; + --shadow-blur: 5px; + --shadow-spread: 1px; + --shadow-opacity: 0.06; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 1px 2px 5px 1px hsl(0 0% 0% / 0.03); + --shadow-xs: 1px 2px 5px 1px hsl(0 0% 0% / 0.03); + --shadow-sm: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 1px 2px 0px hsl(0 0% 0% / 0.06); + --shadow: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 1px 2px 0px hsl(0 0% 0% / 0.06); + --shadow-md: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 2px 4px 0px hsl(0 0% 0% / 0.06); + --shadow-lg: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 4px 6px 0px hsl(0 0% 0% / 0.06); + --shadow-xl: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 8px 10px 0px hsl(0 0% 0% / 0.06); + --shadow-2xl: 1px 2px 5px 1px hsl(0 0% 0% / 0.15); + --tracking-normal: 0em; + --spacing: 0.25rem; +} + +.dark { + --background: #1a1823; + --foreground: #e0ddef; + --card: #232030; + --card-foreground: #e0ddef; + --popover: #232030; + --popover-foreground: #e0ddef; + --primary: #a995c9; + --primary-foreground: #1a1823; + --secondary: #5a5370; + --secondary-foreground: #e0ddef; + --muted: #242031; + --muted-foreground: #a09aad; + --accent: #372e3f; + --accent-foreground: #f2b8c6; + --destructive: #e57373; + --destructive-foreground: #1a1823; + --border: #302c40; + --input: #2a273a; + --ring: #a995c9; + --chart-1: #a995c9; + --chart-2: #f2b8c6; + --chart-3: #77b8a1; + --chart-4: #f0c88d; + --chart-5: #a0bbe3; + --sidebar: #16141e; + --sidebar-foreground: #e0ddef; + --sidebar-primary: #a995c9; + --sidebar-primary-foreground: #1a1823; + --sidebar-accent: #372e3f; + --sidebar-accent-foreground: #f2b8c6; + --sidebar-border: #2a273a; + --sidebar-ring: #a995c9; + --font-sans: Geist, sans-serif; + --font-serif: "Lora", Georgia, serif; + --font-mono: "Fira Code", "Courier New", monospace; + --radius: 0.5rem; + --shadow-x: 1px; + --shadow-y: 2px; + --shadow-blur: 5px; + --shadow-spread: 1px; + --shadow-opacity: 0.06; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 1px 2px 5px 1px hsl(0 0% 0% / 0.03); + --shadow-xs: 1px 2px 5px 1px hsl(0 0% 0% / 0.03); + --shadow-sm: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 1px 2px 0px hsl(0 0% 0% / 0.06); + --shadow: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 1px 2px 0px hsl(0 0% 0% / 0.06); + --shadow-md: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 2px 4px 0px hsl(0 0% 0% / 0.06); + --shadow-lg: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 4px 6px 0px hsl(0 0% 0% / 0.06); + --shadow-xl: 1px 2px 5px 1px hsl(0 0% 0% / 0.06), 1px 8px 10px 0px hsl(0 0% 0% / 0.06); + --shadow-2xl: 1px 2px 5px 1px hsl(0 0% 0% / 0.15); +}`; + +export const Bubblegum = `:root { + --background: #f6e6ee; + --foreground: #5b5b5b; + --card: #fdedc9; + --card-foreground: #5b5b5b; + --popover: #ffffff; + --popover-foreground: #5b5b5b; + --primary: #d04f99; + --primary-foreground: #ffffff; + --secondary: #8acfd1; + --secondary-foreground: #333333; + --muted: #b2e1eb; + --muted-foreground: #7a7a7a; + --accent: #fbe2a7; + --accent-foreground: #333333; + --destructive: #f96f70; + --destructive-foreground: #ffffff; + --border: #d04f99; + --input: #e4e4e4; + --ring: #e670ab; + --chart-1: #e670ab; + --chart-2: #84d2e2; + --chart-3: #fbe2a7; + --chart-4: #f3a0ca; + --chart-5: #d7488e; + --sidebar: #f8d8ea; + --sidebar-foreground: #333333; + --sidebar-primary: #ec4899; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #f9a8d4; + --sidebar-accent-foreground: #333333; + --sidebar-border: #f3e8ff; + --sidebar-ring: #ec4899; + --font-sans: Poppins, sans-serif; + --font-serif: Lora, serif; + --font-mono: Fira Code, monospace; + --radius: 0.4rem; + --shadow-x: 3px; + --shadow-y: 3px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 1.0; + --shadow-color: hsl(325.78 58.18% 56.86% / 0.5); + --shadow-2xs: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 0.50); + --shadow-xs: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 0.50); + --shadow-sm: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 1px 2px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); + --shadow: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 1px 2px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); + --shadow-md: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 2px 4px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); + --shadow-lg: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 4px 6px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); + --shadow-xl: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 1.00), 3px 8px 10px -1px hsl(325.7800 58.1800% 56.8600% / 1.00); + --shadow-2xl: 3px 3px 0px 0px hsl(325.7800 58.1800% 56.8600% / 2.50); + --tracking-normal: 0em; + --spacing: 0.25rem; +} + +.dark { + --background: #12242e; + --foreground: #f3e3ea; + --card: #1c2e38; + --card-foreground: #f3e3ea; + --popover: #1c2e38; + --popover-foreground: #f3e3ea; + --primary: #fbe2a7; + --primary-foreground: #12242e; + --secondary: #e4a2b1; + --secondary-foreground: #12242e; + --muted: #24272b; + --muted-foreground: #e4a2b1; + --accent: #c67b96; + --accent-foreground: #f3e3ea; + --destructive: #e35ea4; + --destructive-foreground: #12242e; + --border: #324859; + --input: #20333d; + --ring: #50afb6; + --chart-1: #50afb6; + --chart-2: #e4a2b1; + --chart-3: #c67b96; + --chart-4: #175c6c; + --chart-5: #24272b; + --sidebar: #101f28; + --sidebar-foreground: #f3f4f6; + --sidebar-primary: #ec4899; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #f9a8d4; + --sidebar-accent-foreground: #1f2937; + --sidebar-border: #374151; + --sidebar-ring: #ec4899; + --font-sans: Poppins, sans-serif; + --font-serif: Lora, serif; + --font-mono: Fira Code, monospace; + --radius: 0.4rem; + --shadow-x: 3px; + --shadow-y: 3px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 1.0; + --shadow-color: #324859; + --shadow-2xs: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 0.50); + --shadow-xs: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 0.50); + --shadow-sm: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 1px 2px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); + --shadow: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 1px 2px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); + --shadow-md: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 2px 4px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); + --shadow-lg: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 4px 6px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); + --shadow-xl: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 1.00), 3px 8px 10px -1px hsl(206.1538 28.0576% 27.2549% / 1.00); + --shadow-2xl: 3px 3px 0px 0px hsl(206.1538 28.0576% 27.2549% / 2.50); +}`; + +export const Candyland = `:root { + --background: #f7f9fa; + --foreground: #333333; + --card: #ffffff; + --card-foreground: #333333; + --popover: #ffffff; + --popover-foreground: #333333; + --primary: #ffc0cb; + --primary-foreground: #000000; + --secondary: #87ceeb; + --secondary-foreground: #000000; + --muted: #ddd9c4; + --muted-foreground: #6e6e6e; + --accent: #ffff00; + --accent-foreground: #000000; + --destructive: #ef4444; + --destructive-foreground: #ffffff; + --border: #d4d4d4; + --input: #d4d4d4; + --ring: #ffc0cb; + --chart-1: #ffc0cb; + --chart-2: #87ceeb; + --chart-3: #ffff00; + --chart-4: #ff99cc; + --chart-5: #33cc33; + --sidebar: #f7f9fa; + --sidebar-foreground: #333333; + --sidebar-primary: #ffc0cb; + --sidebar-primary-foreground: #000000; + --sidebar-accent: #ffff00; + --sidebar-accent-foreground: #000000; + --sidebar-border: #d4d4d4; + --sidebar-ring: #ffc0cb; + --font-sans: Poppins, sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: Roboto Mono, monospace; + --radius: 0.5rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); + --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); + --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --tracking-normal: 0em; + --spacing: 0.25rem; + } + + .dark { + --background: #1a1d23; + --foreground: #e5e5e5; + --card: #2f3436; + --card-foreground: #e5e5e5; + --popover: #2f3436; + --popover-foreground: #e5e5e5; + --primary: #ff99cc; + --primary-foreground: #000000; + --secondary: #33cc33; + --secondary-foreground: #000000; + --muted: #444444; + --muted-foreground: #a3a3a3; + --accent: #87ceeb; + --accent-foreground: #000000; + --destructive: #ef4444; + --destructive-foreground: #ffffff; + --border: #444444; + --input: #444444; + --ring: #ff99cc; + --chart-1: #ff99cc; + --chart-2: #33cc33; + --chart-3: #87ceeb; + --chart-4: #ffff00; + --chart-5: #ffcc00; + --sidebar: #1a1d23; + --sidebar-foreground: #e5e5e5; + --sidebar-primary: #ff99cc; + --sidebar-primary-foreground: #000000; + --sidebar-accent: #87ceeb; + --sidebar-accent-foreground: #000000; + --sidebar-border: #444444; + --sidebar-ring: #ff99cc; + --font-sans: Poppins, sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: Roboto Mono, monospace; + --radius: 0.5rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); + --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); + --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + } +}`; + +export const Doom64 = `:root { + --background: #cccccc; + --foreground: #1f1f1f; + --card: #b0b0b0; + --card-foreground: #1f1f1f; + --popover: #b0b0b0; + --popover-foreground: #1f1f1f; + --primary: #b71c1c; + --primary-foreground: #ffffff; + --secondary: #556b2f; + --secondary-foreground: #ffffff; + --muted: #b8b8b8; + --muted-foreground: #4a4a4a; + --accent: #4682b4; + --accent-foreground: #ffffff; + --destructive: #ff6f00; + --destructive-foreground: #000000; + --border: #505050; + --input: #505050; + --ring: #b71c1c; + --chart-1: #b71c1c; + --chart-2: #556b2f; + --chart-3: #4682b4; + --chart-4: #ff6f00; + --chart-5: #8d6e63; + --sidebar: #b0b0b0; + --sidebar-foreground: #1f1f1f; + --sidebar-primary: #b71c1c; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #4682b4; + --sidebar-accent-foreground: #ffffff; + --sidebar-border: #505050; + --sidebar-ring: #b71c1c; + --font-sans: "Oxanium", sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: "Source Code Pro", monospace; + --radius: 0px; + --shadow-x: 0px; + --shadow-y: 2px; + --shadow-blur: 4px; + --shadow-spread: 0px; + --shadow-opacity: 0.4; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 0px 2px 4px 0px hsl(0 0% 0% / 0.20); + --shadow-xs: 0px 2px 4px 0px hsl(0 0% 0% / 0.20); + --shadow-sm: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow-md: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 2px 4px -1px hsl(0 0% 0% / 0.40); + --shadow-lg: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 4px 6px -1px hsl(0 0% 0% / 0.40); + --shadow-xl: 0px 2px 4px 0px hsl(0 0% 0% / 0.40), 0px 8px 10px -1px hsl(0 0% 0% / 0.40); + --shadow-2xl: 0px 2px 4px 0px hsl(0 0% 0% / 1.00); + --tracking-normal: 0em; + --spacing: 0.25rem; + } + + .dark { + --background: #1a1a1a; + --foreground: #e0e0e0; + --card: #2a2a2a; + --card-foreground: #e0e0e0; + --popover: #2a2a2a; + --popover-foreground: #e0e0e0; + --primary: #e53935; + --primary-foreground: #ffffff; + --secondary: #689f38; + --secondary-foreground: #000000; + --muted: #252525; + --muted-foreground: #a0a0a0; + --accent: #64b5f6; + --accent-foreground: #000000; + --destructive: #ffa000; + --destructive-foreground: #000000; + --border: #4a4a4a; + --input: #4a4a4a; + --ring: #e53935; + --chart-1: #e53935; + --chart-2: #689f38; + --chart-3: #64b5f6; + --chart-4: #ffa000; + --chart-5: #a1887f; + --sidebar: #141414; + --sidebar-foreground: #e0e0e0; + --sidebar-primary: #e53935; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #64b5f6; + --sidebar-accent-foreground: #000000; + --sidebar-border: #4a4a4a; + --sidebar-ring: #e53935; + --font-sans: "Oxanium", sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: "Source Code Pro", monospace; + --radius: 0px; + --shadow-x: 0px; + --shadow-y: 2px; + --shadow-blur: 5px; + --shadow-spread: 0px; + --shadow-opacity: 0.6; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 0px 2px 5px 0px hsl(0 0% 0% / 0.30); + --shadow-xs: 0px 2px 5px 0px hsl(0 0% 0% / 0.30); + --shadow-sm: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 1px 2px -1px hsl(0 0% 0% / 0.60); + --shadow: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 1px 2px -1px hsl(0 0% 0% / 0.60); + --shadow-md: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 2px 4px -1px hsl(0 0% 0% / 0.60); + --shadow-lg: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 4px 6px -1px hsl(0 0% 0% / 0.60); + --shadow-xl: 0px 2px 5px 0px hsl(0 0% 0% / 0.60), 0px 8px 10px -1px hsl(0 0% 0% / 0.60); + --shadow-2xl: 0px 2px 5px 0px hsl(0 0% 0% / 1.50); + } +}`; + +export const NeoBrutalism = `:root { + --background: #ffffff; + --foreground: #000000; + --card: #ffffff; + --card-foreground: #000000; + --popover: #ffffff; + --popover-foreground: #000000; + --primary: #ff3333; + --primary-foreground: #ffffff; + --secondary: #ffff00; + --secondary-foreground: #000000; + --muted: #f0f0f0; + --muted-foreground: #333333; + --accent: #0066ff; + --accent-foreground: #ffffff; + --destructive: #000000; + --destructive-foreground: #ffffff; + --border: #000000; + --input: #000000; + --ring: #ff3333; + --chart-1: #ff3333; + --chart-2: #ffff00; + --chart-3: #0066ff; + --chart-4: #00cc00; + --chart-5: #cc00cc; + --sidebar: #f0f0f0; + --sidebar-foreground: #000000; + --sidebar-primary: #ff3333; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #0066ff; + --sidebar-accent-foreground: #ffffff; + --sidebar-border: #000000; + --sidebar-ring: #ff3333; + --font-sans: DM Sans, sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: Space Mono, monospace; + --radius: 0px; + --shadow-x: 4px; + --shadow-y: 4px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 1; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-sm: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow-md: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 2px 4px -1px hsl(0 0% 0% / 1.00); + --shadow-lg: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 4px 6px -1px hsl(0 0% 0% / 1.00); + --shadow-xl: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 8px 10px -1px hsl(0 0% 0% / 1.00); + --shadow-2xl: 4px 4px 0px 0px hsl(0 0% 0% / 2.50); + --tracking-normal: 0em; + --spacing: 0.25rem; + } + + .dark { + --background: #000000; + --foreground: #ffffff; + --card: #333333; + --card-foreground: #ffffff; + --popover: #333333; + --popover-foreground: #ffffff; + --primary: #ff6666; + --primary-foreground: #000000; + --secondary: #ffff33; + --secondary-foreground: #000000; + --muted: #1a1a1a; + --muted-foreground: #cccccc; + --accent: #3399ff; + --accent-foreground: #000000; + --destructive: #ffffff; + --destructive-foreground: #000000; + --border: #ffffff; + --input: #ffffff; + --ring: #ff6666; + --chart-1: #ff6666; + --chart-2: #ffff33; + --chart-3: #3399ff; + --chart-4: #33cc33; + --chart-5: #cc33cc; + --sidebar: #000000; + --sidebar-foreground: #ffffff; + --sidebar-primary: #ff6666; + --sidebar-primary-foreground: #000000; + --sidebar-accent: #3399ff; + --sidebar-accent-foreground: #000000; + --sidebar-border: #ffffff; + --sidebar-ring: #ff6666; + --font-sans: DM Sans, sans-serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: Space Mono, monospace; + --radius: 0px; + --shadow-x: 4px; + --shadow-y: 4px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 1; + --shadow-color: hsl(0 0% 0%); + --shadow-2xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-sm: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow-md: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 2px 4px -1px hsl(0 0% 0% / 1.00); + --shadow-lg: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 4px 6px -1px hsl(0 0% 0% / 1.00); + --shadow-xl: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 8px 10px -1px hsl(0 0% 0% / 1.00); + --shadow-2xl: 4px 4px 0px 0px hsl(0 0% 0% / 2.50); + } +}`; + +export const SageGarden = `:root { + --background: #f8f7f4; + --foreground: #1a1f2e; + --card: #ffffff; + --card-foreground: #1a1f2e; + --popover: #ffffff; + --popover-foreground: #1a1f2e; + --primary: #7c9082; + --primary-foreground: #ffffff; + --secondary: #ced4bf; + --secondary-foreground: #1a1f2e; + --muted: #e8e6e1; + --muted-foreground: #6b7280; + --accent: #bfc9bb; + --accent-foreground: #1a1f2e; + --destructive: #c73e3a; + --destructive-foreground: #ffffff; + --border: #e8e6e1; + --input: #ffffff; + --ring: #7c9082; + --chart-1: #7c9082; + --chart-2: #a0aa88; + --chart-3: #8b9d83; + --chart-4: #6b7280; + --chart-5: #e8e6e1; + --sidebar: #fafaf8; + --sidebar-foreground: #1a1f2e; + --sidebar-primary: #7c9082; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #e8e6e1; + --sidebar-accent-foreground: #1a1f2e; + --sidebar-border: #e8e6e1; + --sidebar-ring: #7c9082; + --font-sans: Antic, ui-sans-serif, sans-serif, system-ui; + --font-serif: Signifier, Georgia, serif; + --font-mono: JetBrains Mono, Courier New, monospace; + --radius: 0.35rem; + --shadow-x: 0px; + --shadow-y: 1px; + --shadow-blur: 2px; + --shadow-spread: 0px; + --shadow-opacity: 0.04; + --shadow-color: #1a1f2e; + --shadow-2xs: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.02); + --shadow-xs: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.02); + --shadow-sm: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.04), 0px 1px 2px -1px hsl(225 27.7778% 14.1176% / 0.04); + --shadow: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.04), 0px 1px 2px -1px hsl(225 27.7778% 14.1176% / 0.04); + --shadow-md: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.04), 0px 2px 4px -1px hsl(225 27.7778% 14.1176% / 0.04); + --shadow-lg: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.04), 0px 4px 6px -1px hsl(225 27.7778% 14.1176% / 0.04); + --shadow-xl: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.04), 0px 8px 10px -1px hsl(225 27.7778% 14.1176% / 0.04); + --shadow-2xl: 0px 1px 2px 0px hsl(225 27.7778% 14.1176% / 0.10); + --tracking-normal: 0em; + --spacing: 0.23rem; + } + + .dark { + --background: #0a0a0a; + --foreground: #f5f5f5; + --card: #121212; + --card-foreground: #f5f5f5; + --popover: #121212; + --popover-foreground: #f5f5f5; + --primary: #7c9082; + --primary-foreground: #000000; + --secondary: #1a1a1a; + --secondary-foreground: #f5f5f5; + --muted: #1a1a1a; + --muted-foreground: #a0a0a0; + --accent: #36443a; + --accent-foreground: #f5f5f5; + --destructive: #ef4444; + --destructive-foreground: #ffffff; + --border: #2a2a2a; + --input: #121212; + --ring: #7c9082; + --chart-1: #7c9082; + --chart-2: #a0aa88; + --chart-3: #8b9d83; + --chart-4: #6b7280; + --chart-5: #5a6b5e; + --sidebar: #0f0f0f; + --sidebar-foreground: #f5f5f5; + --sidebar-primary: #7c9082; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #1a1a1a; + --sidebar-accent-foreground: #f5f5f5; + --sidebar-border: #2a2a2a; + --sidebar-ring: #7c9082; + --font-sans: Antic, ui-sans-serif, sans-serif, system-ui; + --font-serif: Signifier, Georgia, serif; + --font-mono: JetBrains Mono, Courier New, monospace; + --radius: 0.35rem; + --shadow-x: 0px; + --shadow-y: 1px; + --shadow-blur: 2px; + --shadow-spread: 0px; + --shadow-opacity: 0.04; + --shadow-color: #000000; + --shadow-2xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.02); + --shadow-xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.02); + --shadow-sm: 0px 1px 2px 0px hsl(0 0% 0% / 0.04), 0px 1px 2px -1px hsl(0 0% 0% / 0.04); + --shadow: 0px 1px 2px 0px hsl(0 0% 0% / 0.04), 0px 1px 2px -1px hsl(0 0% 0% / 0.04); + --shadow-md: 0px 1px 2px 0px hsl(0 0% 0% / 0.04), 0px 2px 4px -1px hsl(0 0% 0% / 0.04); + --shadow-lg: 0px 1px 2px 0px hsl(0 0% 0% / 0.04), 0px 4px 6px -1px hsl(0 0% 0% / 0.04); + --shadow-xl: 0px 1px 2px 0px hsl(0 0% 0% / 0.04), 0px 8px 10px -1px hsl(0 0% 0% / 0.04); + --shadow-2xl: 0px 1px 2px 0px hsl(0 0% 0% / 0.10); + } +}`; + +export const SoftPop = `:root { + --background: #f7f9f3; + --foreground: #000000; + --card: #ffffff; + --card-foreground: #000000; + --popover: #ffffff; + --popover-foreground: #000000; + --primary: #4f46e5; + --primary-foreground: #ffffff; + --secondary: #14b8a6; + --secondary-foreground: #ffffff; + --muted: #f0f0f0; + --muted-foreground: #333333; + --accent: #f59e0b; + --accent-foreground: #000000; + --destructive: #ef4444; + --destructive-foreground: #ffffff; + --border: #000000; + --input: #737373; + --ring: #a5b4fc; + --chart-1: #4f46e5; + --chart-2: #14b8a6; + --chart-3: #f59e0b; + --chart-4: #ec4899; + --chart-5: #22c55e; + --sidebar: #f7f9f3; + --sidebar-foreground: #000000; + --sidebar-primary: #4f46e5; + --sidebar-primary-foreground: #ffffff; + --sidebar-accent: #f59e0b; + --sidebar-accent-foreground: #000000; + --sidebar-border: #000000; + --sidebar-ring: #a5b4fc; + --font-sans: DM Sans, sans-serif; + --font-serif: DM Sans, sans-serif; + --font-mono: Space Mono, monospace; + --radius: 1rem; + --shadow-x: 0px; + --shadow-y: 0px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 0.05; + --shadow-color: #1a1a1a; + --shadow-2xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); + --shadow-xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); + --shadow-sm: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); + --shadow: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-md: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 2px 4px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-lg: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 4px 6px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 8px 10px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-2xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.13); + --tracking-normal: normal; + --spacing: 0.25rem; + } + + .dark { + --background: #000000; + --foreground: #ffffff; + --card: #1a212b; + --card-foreground: #ffffff; + --popover: #1a212b; + --popover-foreground: #ffffff; + --primary: #818cf8; + --primary-foreground: #000000; + --secondary: #2dd4bf; + --secondary-foreground: #000000; + --muted: #333333; + --muted-foreground: #cccccc; + --accent: #fcd34d; + --accent-foreground: #000000; + --destructive: #f87171; + --destructive-foreground: #000000; + --border: #545454; + --input: #ffffff; + --ring: #818cf8; + --chart-1: #818cf8; + --chart-2: #2dd4bf; + --chart-3: #fcd34d; + --chart-4: #f472b6; + --chart-5: #4ade80; + --sidebar: #000000; + --sidebar-foreground: #ffffff; + --sidebar-primary: #818cf8; + --sidebar-primary-foreground: #000000; + --sidebar-accent: #fcd34d; + --sidebar-accent-foreground: #000000; + --sidebar-border: #ffffff; + --sidebar-ring: #818cf8; + --font-sans: DM Sans, sans-serif; + --font-serif: DM Sans, sans-serif; + --font-mono: Space Mono, monospace; + --radius: 1rem; + --shadow-x: 0px; + --shadow-y: 0px; + --shadow-blur: 0px; + --shadow-spread: 0px; + --shadow-opacity: 0.05; + --shadow-color: #1a1a1a; + --shadow-2xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); + --shadow-xs: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.03); + --shadow-sm: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); + --shadow: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 1px 2px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-md: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 2px 4px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-lg: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 4px 6px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.05), 0px 8px 10px -1px hsl(0 0% 10.1961% / 0.05); + --shadow-2xl: 0px 0px 0px 0px hsl(0 0% 10.1961% / 0.13); + } +}`; + +export const StarryNight = `:root { + --background: #f5f7fa; + --foreground: #1a2238; + --card: #e3eaf2; + --card-foreground: #1a2238; + --popover: #fffbe6; + --popover-foreground: #1a2238; + --primary: #3a5ba0; + --primary-foreground: #fffbe6; + --secondary: #f7c873; + --secondary-foreground: #1a2238; + --muted: #e5e5df; + --muted-foreground: #3a5ba0; + --accent: #6ea3c1; + --accent-foreground: #fffbe6; + --destructive: #2d1e2f; + --destructive-foreground: #fffbe6; + --border: #b0b8c1; + --input: #6ea3c1; + --ring: #f7c873; + --chart-1: #3a5ba0; + --chart-2: #f7c873; + --chart-3: #6ea3c1; + --chart-4: #b0b8c1; + --chart-5: #2d1e2f; + --sidebar: #e3eaf2; + --sidebar-foreground: #1a2238; + --sidebar-primary: #3a5ba0; + --sidebar-primary-foreground: #fffbe6; + --sidebar-accent: #f7c873; + --sidebar-accent-foreground: #1a2238; + --sidebar-border: #b0b8c1; + --sidebar-ring: #f7c873; + --font-sans: Libre Baskerville, serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --radius: 0.5rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); + --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); + --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --tracking-normal: 0em; + --spacing: 0.25rem; + } + + .dark { + --background: #181a24; + --foreground: #e6eaf3; + --card: #23243a; + --card-foreground: #e6eaf3; + --popover: #23243a; + --popover-foreground: #ffe066; + --primary: #3a5ba0; + --primary-foreground: #ffe066; + --secondary: #ffe066; + --secondary-foreground: #23243a; + --muted: #1d1e2f; + --muted-foreground: #7a88a1; + --accent: #bccdf0; + --accent-foreground: #181a24; + --destructive: #a04a6c; + --destructive-foreground: #ffe066; + --border: #2d2e3e; + --input: #3a5ba0; + --ring: #ffe066; + --chart-1: #3a5ba0; + --chart-2: #ffe066; + --chart-3: #6ea3c1; + --chart-4: #7a88a1; + --chart-5: #a04a6c; + --sidebar: #23243a; + --sidebar-foreground: #e6eaf3; + --sidebar-primary: #3a5ba0; + --sidebar-primary-foreground: #ffe066; + --sidebar-accent: #ffe066; + --sidebar-accent-foreground: #23243a; + --sidebar-border: #2d2e3e; + --sidebar-ring: #ffe066; + --font-sans: Libre Baskerville, serif; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --radius: 0.5rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); + --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); + --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + } +}`; diff --git a/packages/boxel-ui/test-app/app/utils/theme-fonts.ts b/packages/boxel-ui/test-app/app/utils/theme-fonts.ts new file mode 100644 index 00000000000..c1d143404fb --- /dev/null +++ b/packages/boxel-ui/test-app/app/utils/theme-fonts.ts @@ -0,0 +1,67 @@ +// Generic keywords and ubiquitous system fonts that should never be fetched +// from Google Fonts. Anything else unknown is requested anyway — a family +// Google doesn't have just fails its own stylesheet request, which is +// harmless and leaves the theme's fallback stack in effect. +const NON_WEBFONT_FAMILIES = new Set([ + 'sans-serif', + 'serif', + 'monospace', + 'cursive', + 'fantasy', + 'system-ui', + 'math', + 'emoji', + 'ui-sans-serif', + 'ui-serif', + 'ui-monospace', + 'ui-rounded', + 'arial', + 'helvetica', + 'helvetica neue', + 'georgia', + 'times', + 'times new roman', + 'courier', + 'courier new', + 'menlo', + 'monaco', + 'consolas', + 'sfmono-regular', + 'liberation mono', + 'segoe ui', +]); + +export function fontFamiliesFrom(cssVariables: string): string[] { + let families = new Set(); + for (let [, value] of cssVariables.matchAll( + /--font-[a-z-]+\s*:\s*([^;}]+)/g, + )) { + for (let raw of value.split(',')) { + let name = raw.trim().replace(/^['"]+|['"]+$/g, ''); + if (name && !NON_WEBFONT_FAMILIES.has(name.toLowerCase())) { + families.add(name); + } + } + } + return [...families]; +} + +// Requests only the regular (400) face: asking for specific weights 400s the +// whole request when a static family lacks one, whereas a bare family name +// always resolves. Browsers synthesize bold/italic from it if the theme +// needs them. +export function loadThemeFonts(cssVariables: string): void { + for (let family of fontFamiliesFrom(cssVariables)) { + let id = `theme-font-${family.toLowerCase().replace(/\s+/g, '-')}`; + if (document.getElementById(id)) { + continue; + } + let link = document.createElement('link'); + link.id = id; + link.rel = 'stylesheet'; + link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent( + family, + ).replace(/%20/g, '+')}&display=swap`; + document.head.append(link); + } +} diff --git a/packages/boxel-ui/test-app/index.html b/packages/boxel-ui/test-app/index.html index 9e1f5cc4010..2e8526b6db2 100644 --- a/packages/boxel-ui/test-app/index.html +++ b/packages/boxel-ui/test-app/index.html @@ -24,7 +24,7 @@ {{content-for "head-footer"}}