diff --git a/BUILD.bazel b/BUILD.bazel index 030b481..51abc09 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -144,7 +144,7 @@ npm_package( ":tinyvectors", ], package = "@tummycrypt/tinyvectors", - version = "0.3.0", + version = "0.3.1", visibility = ["//visibility:public"], ) diff --git a/MODULE.bazel b/MODULE.bazel index 128fa67..1b253b3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,7 +7,7 @@ Usage from external repo: module( name = "tummycrypt_tinyvectors", - version = "0.3.0", + version = "0.3.1", compatibility_level = 1, ) diff --git a/package.json b/package.json index 9b73641..9451dbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tummycrypt/tinyvectors", - "version": "0.3.0", + "version": "0.3.1", "description": "Animated vector blob backgrounds with physics simulation for Svelte 5", "type": "module", "packageManager": "pnpm@9.15.9", diff --git a/src/index.ts b/src/index.ts index 9bbf0fb..4ca1381 100644 --- a/src/index.ts +++ b/src/index.ts @@ -97,6 +97,12 @@ export { generateThemeCSS, isDarkMode, watchDarkMode, + getThemePreviewColors, + getThemeVectorColors, + getThemeCatalogEntry, + getThemeCatalog, + type PackageThemeName, + type ThemeCatalogEntry, } from './themes/index.js'; export { diff --git a/src/themes/index.ts b/src/themes/index.ts index 46ead4d..0361267 100644 --- a/src/themes/index.ts +++ b/src/themes/index.ts @@ -2,7 +2,11 @@ -import { THEME_PRESETS, type ThemePreset } from '../core/theme-presets.js'; +import { + THEME_PRESETS, + type ThemePreset, + type ThemePresetName, +} from '../core/theme-presets.js'; export { THEME_PRESETS, @@ -22,6 +26,84 @@ export function getThemePreset(name: string): ThemePreset | undefined { return THEME_PRESETS[name as keyof typeof THEME_PRESETS]; } +// Theme catalog — the package-curated set of presets with derived preview/ +// vector color swatches. Hub/spoke consumers (e.g. @tummycrypt/tinyland-stores +// themeStore) render this catalog; keeping it here makes the package the +// single source of truth for which themes ship and how they preview. +export type PackageThemeName = Exclude; + +export interface ThemeCatalogEntry { + name: PackageThemeName; + label: string; + description: string; + hasVectors: boolean; + colors: string[]; + previewColors: string[]; + vectorColors: string[]; + source: 'tinyvectors'; +} + +const PACKAGE_THEME_ORDER = [ + 'tinyland', + 'trans', + 'pride', + 'high-contrast', +] as const satisfies readonly PackageThemeName[]; + +const THEME_DESCRIPTIONS: Record = { + tinyland: 'Soft violet, blue, and pink glow', + trans: 'Soft trans pride palette', + pride: 'Rainbow signal colors with diffuse vectors', + 'high-contrast': 'WCAG AAA compliant for maximum readability', +}; + +const THEME_PREVIEW_OVERRIDES: Partial> = { + 'high-contrast': ['#000000', '#FFFFFF', '#0040FF'], +}; + +function getThemePalette(name: string, count?: number): string[] { + const preset = getThemePreset(name); + if (!preset?.hasVectors) return []; + + const colors = preset.colors.map((entry) => entry.color); + return count === undefined ? colors : colors.slice(0, count); +} + +export function getThemePreviewColors(name: string, count = 3): string[] { + return getThemePalette(name, count); +} + +export function getThemeVectorColors(name: string, count = 5): string[] { + return getThemePalette(name, count); +} + +export function getThemeCatalogEntry( + name: PackageThemeName, +): ThemeCatalogEntry | undefined { + const preset = getThemePreset(name); + if (!preset) return undefined; + + const previewColors = + THEME_PREVIEW_OVERRIDES[name] ?? getThemePreviewColors(name); + + return { + name, + label: preset.label, + description: THEME_DESCRIPTIONS[name], + hasVectors: preset.hasVectors, + colors: previewColors, + previewColors, + vectorColors: getThemeVectorColors(name), + source: 'tinyvectors', + }; +} + +export function getThemeCatalog(): ThemeCatalogEntry[] { + return PACKAGE_THEME_ORDER.map((name) => getThemeCatalogEntry(name)).filter( + (theme): theme is ThemeCatalogEntry => theme !== undefined, + ); +} +