All files / packages/theme-selector/src theme-mapper.ts

100% Statements 15/15
100% Branches 8/8
100% Functions 5/5
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140                                                            14x             14x               14x                           14x                                       107x             107x   107x 2x     105x 39x     66x             107x             107x                               107x 107x                        
// SPDX-License-Identifier: MIT
/**
 * Maps core theme flavors to UI-specific format
 */
 
import type { ThemeFlavor as CanonicalThemeFlavor } from '@turbocoder13/turbo-themes-core';
import type { ThemeFamily } from './types.js';
 
export interface ThemeColors {
  bg: string;
  surface: string;
  accent: string;
  text: string;
}
 
export interface ThemeFlavor extends Pick<CanonicalThemeFlavor, 'id' | 'appearance' | 'vendor'> {
  id: string;
  name: string;
  description: string;
  cssFile: string;
  icon?: string | undefined;
  family: ThemeFamily;
  colors: ThemeColors;
}
 
// ============================================================================
// Lookup Tables
// ============================================================================
 
/** Vendor to family mapping */
const VENDOR_FAMILY_MAP: Record<string, ThemeFamily> = {
  bulma: 'bulma',
  catppuccin: 'catppuccin',
  github: 'github',
  dracula: 'dracula',
};
 
const DEFAULT_FAMILY: ThemeFamily = 'bulma';
 
/** Icon configuration - string for single icon, object for appearance-specific */
interface AppearanceIcons {
  light: string;
  dark: string;
}
 
const VENDOR_ICON_MAP: Record<string, string | AppearanceIcons> = {
  bulma: 'assets/img/turbo-themes-logo.png',
  catppuccin: {
    light: 'assets/img/catppuccin-logo-latte.png',
    dark: 'assets/img/catppuccin-logo-macchiato.png',
  },
  github: {
    light: 'assets/img/github-logo-light.png',
    dark: 'assets/img/github-logo-dark.png',
  },
  dracula: 'assets/img/dracula-logo.png',
};
 
/** Predefined flavor descriptions */
const FLAVOR_DESCRIPTIONS: Record<string, string> = {
  'bulma-light': 'Classic Bulma look with a bright, neutral palette.',
  'bulma-dark': 'Dark Bulma theme tuned for low-light reading.',
  'catppuccin-latte': 'Light, soft Catppuccin palette for daytime use.',
  'catppuccin-frappe': 'Balanced dark Catppuccin theme for focused work.',
  'catppuccin-macchiato': 'Deep, atmospheric Catppuccin variant with rich contrast.',
  'catppuccin-mocha': 'Cozy, high-contrast Catppuccin theme for late-night sessions.',
  dracula: 'Iconic Dracula dark theme with vibrant accents.',
  'github-light': 'GitHub-inspired light theme suited for documentation and UI heavy pages.',
  'github-dark': 'GitHub dark theme optimized for code-heavy views.',
};
 
// ============================================================================
// Helper Functions
// ============================================================================
 
/**
 * Gets the theme family from vendor name
 */
function getFamily(vendor: string): ThemeFamily {
  return VENDOR_FAMILY_MAP[vendor] ?? DEFAULT_FAMILY;
}
 
/**
 * Gets icon path for a vendor
 */
function getIconForVendor(vendor: string, appearance: 'light' | 'dark'): string | undefined {
  const iconConfig = VENDOR_ICON_MAP[vendor];
 
  if (!iconConfig) {
    return undefined;
  }
 
  if (typeof iconConfig === 'string') {
    return iconConfig;
  }
 
  return iconConfig[appearance];
}
 
/**
 * Gets description for a flavor
 */
function getDescriptionForFlavor(id: string, label: string): string {
  return FLAVOR_DESCRIPTIONS[id] ?? `${label} theme`;
}
 
/**
 * Extracts preview colors from theme tokens
 */
function extractPreviewColors(tokens: CanonicalThemeFlavor['tokens']): ThemeColors {
  return {
    bg: tokens.background.base,
    surface: tokens.background.surface,
    accent: tokens.brand.primary,
    text: tokens.text.primary,
  };
}
 
// ============================================================================
// Public API
// ============================================================================
 
/**
 * Maps a canonical theme flavor to UI-specific format
 */
export function mapFlavorToUI(flavor: CanonicalThemeFlavor): ThemeFlavor {
  const family = getFamily(flavor.vendor);
  return {
    id: flavor.id,
    name: flavor.label,
    description: getDescriptionForFlavor(flavor.id, flavor.label),
    cssFile: `packages/css/dist/themes/${flavor.id}.css`,
    icon: getIconForVendor(flavor.vendor, flavor.appearance),
    family,
    vendor: flavor.vendor,
    appearance: flavor.appearance,
    colors: extractPreviewColors(flavor.tokens),
  };
}