Core/ThemeEngine.ps1

# Core\ThemeEngine.ps1
# Centralized theme definitions and CSS export

function Get-PoshThemes {
    <#
    .SYNOPSIS
        List all available PoshDE themes.
    #>

    [CmdletBinding()]
    param()

    @(
        [PSCustomObject]@{ Name = 'samurai';   Description = 'Red/magenta with cyan accents — default' }
        [PSCustomObject]@{ Name = 'cyberpunk'; Description = 'Yellow/cyan — Cyberpunk 2077 inspired' }
        [PSCustomObject]@{ Name = 'matrix';    Description = 'Classic green on black' }
        [PSCustomObject]@{ Name = 'midnight';  Description = 'Deep blue with purple accents' }
        [PSCustomObject]@{ Name = 'hacker';    Description = 'Green/amber old-school terminal' }
        [PSCustomObject]@{ Name = 'default';   Description = 'Clean modern dark' }
    )
}

function Get-PoshTheme {
    <#
    .SYNOPSIS
        Get a theme object by name, or the currently active theme.
    .PARAMETER Name
        Theme name. If omitted, returns the active theme.
    .EXAMPLE
        $theme = Get-PoshTheme
        $theme.colors.primary
    .EXAMPLE
        $theme = Get-PoshTheme -Name matrix
    #>

    [CmdletBinding()]
    param(
        [string]$Name
    )

    if (-not $Name) { $Name = $script:PoshDE.CurrentTheme }

    $theme = switch ($Name.ToLower()) {

        'samurai' {
            @{
                name        = 'samurai'
                description = 'Red/magenta with cyan accents'
                colors = @{
                    primary         = '#ff0064'
                    secondary       = '#00ffff'
                    accent          = '#ff6464'
                    warning         = '#ffc800'
                    success         = '#00ff64'
                    error           = '#ff3232'
                    bgDark          = '#0a0a0a'
                    bgMedium        = '#141414'
                    bgLight         = '#1e1e1e'
                    bgOverlay       = 'rgba(0,0,0,0.85)'
                    textPrimary     = 'rgba(255,255,255,0.9)'
                    textSecondary   = 'rgba(255,255,255,0.6)'
                    textMuted       = 'rgba(255,255,255,0.4)'
                    border          = 'rgba(255,0,100,0.3)'
                    glow            = 'rgba(255,0,100,0.5)'
                    glowSecondary   = 'rgba(0,255,255,0.5)'
                }
                fonts = @{
                    primary = "'Consolas', 'Courier New', monospace"
                    display = "'Segoe UI', sans-serif"
                    mono    = "'Cascadia Code', 'Consolas', monospace"
                    sizes   = @{ xs = '9px'; sm = '11px'; md = '13px'; lg = '16px'; xl = '20px' }
                }
                effects = @{ glowStrength = '10px'; borderRadius = '3px'; transitionSpeed = '0.2s' }
            }
        }

        'cyberpunk' {
            @{
                name        = 'cyberpunk'
                description = 'Yellow/cyan — Cyberpunk 2077 inspired'
                colors = @{
                    primary         = '#fcee0a'
                    secondary       = '#00ffff'
                    accent          = '#ff00ff'
                    warning         = '#ff6600'
                    success         = '#00ff00'
                    error           = '#ff0000'
                    bgDark          = '#0d0d0d'
                    bgMedium        = '#1a1a1a'
                    bgLight         = '#2a2a2a'
                    bgOverlay       = 'rgba(0,0,0,0.9)'
                    textPrimary     = 'rgba(255,255,255,0.95)'
                    textSecondary   = 'rgba(252,238,10,0.8)'
                    textMuted       = 'rgba(255,255,255,0.5)'
                    border          = 'rgba(252,238,10,0.4)'
                    glow            = 'rgba(252,238,10,0.6)'
                    glowSecondary   = 'rgba(0,255,255,0.5)'
                }
                fonts = @{
                    primary = "'Consolas', monospace"
                    display = "'Rajdhani', 'Segoe UI', sans-serif"
                    mono    = "'Cascadia Code', monospace"
                    sizes   = @{ xs = '9px'; sm = '11px'; md = '13px'; lg = '16px'; xl = '20px' }
                }
                effects = @{ glowStrength = '15px'; borderRadius = '0px'; transitionSpeed = '0.15s' }
            }
        }

        'matrix' {
            @{
                name        = 'matrix'
                description = 'Classic green on black'
                colors = @{
                    primary         = '#00ff00'
                    secondary       = '#00cc00'
                    accent          = '#00ff66'
                    warning         = '#ffff00'
                    success         = '#00ff00'
                    error           = '#ff0000'
                    bgDark          = '#000000'
                    bgMedium        = '#0a0a0a'
                    bgLight         = '#141414'
                    bgOverlay       = 'rgba(0,0,0,0.95)'
                    textPrimary     = '#00ff00'
                    textSecondary   = '#00cc00'
                    textMuted       = '#006600'
                    border          = 'rgba(0,255,0,0.3)'
                    glow            = 'rgba(0,255,0,0.5)'
                    glowSecondary   = 'rgba(0,255,0,0.3)'
                }
                fonts = @{
                    primary = "'Courier New', monospace"
                    display = "'Courier New', monospace"
                    mono    = "'Courier New', monospace"
                    sizes   = @{ xs = '10px'; sm = '12px'; md = '14px'; lg = '16px'; xl = '20px' }
                }
                effects = @{ glowStrength = '8px'; borderRadius = '0px'; transitionSpeed = '0.1s' }
            }
        }

        'midnight' {
            @{
                name        = 'midnight'
                description = 'Deep blue with purple accents'
                colors = @{
                    primary         = '#6366f1'
                    secondary       = '#a855f7'
                    accent          = '#ec4899'
                    warning         = '#f59e0b'
                    success         = '#10b981'
                    error           = '#ef4444'
                    bgDark          = '#0f0f1a'
                    bgMedium        = '#1a1a2e'
                    bgLight         = '#252542'
                    bgOverlay       = 'rgba(15,15,26,0.95)'
                    textPrimary     = 'rgba(255,255,255,0.9)'
                    textSecondary   = 'rgba(255,255,255,0.6)'
                    textMuted       = 'rgba(255,255,255,0.4)'
                    border          = 'rgba(99,102,241,0.3)'
                    glow            = 'rgba(99,102,241,0.5)'
                    glowSecondary   = 'rgba(168,85,247,0.5)'
                }
                fonts = @{
                    primary = "'Inter', 'Segoe UI', sans-serif"
                    display = "'Inter', sans-serif"
                    mono    = "'JetBrains Mono', 'Cascadia Code', monospace"
                    sizes   = @{ xs = '10px'; sm = '12px'; md = '14px'; lg = '16px'; xl = '20px' }
                }
                effects = @{ glowStrength = '12px'; borderRadius = '6px'; transitionSpeed = '0.2s' }
            }
        }

        'hacker' {
            @{
                name        = 'hacker'
                description = 'Green/amber old-school terminal'
                colors = @{
                    primary         = '#33ff33'
                    secondary       = '#ffb000'
                    accent          = '#ff6600'
                    warning         = '#ffb000'
                    success         = '#33ff33'
                    error           = '#ff3333'
                    bgDark          = '#0a0a00'
                    bgMedium        = '#0d0d00'
                    bgLight         = '#1a1a00'
                    bgOverlay       = 'rgba(10,10,0,0.95)'
                    textPrimary     = '#33ff33'
                    textSecondary   = '#ffb000'
                    textMuted       = '#666633'
                    border          = 'rgba(51,255,51,0.3)'
                    glow            = 'rgba(51,255,51,0.4)'
                    glowSecondary   = 'rgba(255,176,0,0.4)'
                }
                fonts = @{
                    primary = "'VT323', 'Courier New', monospace"
                    display = "'VT323', monospace"
                    mono    = "'VT323', 'Courier New', monospace"
                    sizes   = @{ xs = '12px'; sm = '14px'; md = '16px'; lg = '18px'; xl = '24px' }
                }
                effects = @{ glowStrength = '6px'; borderRadius = '0px'; transitionSpeed = '0.05s' }
            }
        }

        default {
            @{
                name        = 'default'
                description = 'Clean modern dark'
                colors = @{
                    primary         = '#0078d4'
                    secondary       = '#00b4d8'
                    accent          = '#48cae4'
                    warning         = '#ffc107'
                    success         = '#28a745'
                    error           = '#dc3545'
                    bgDark          = '#1e1e1e'
                    bgMedium        = '#252526'
                    bgLight         = '#333333'
                    bgOverlay       = 'rgba(30,30,30,0.95)'
                    textPrimary     = '#ffffff'
                    textSecondary   = '#cccccc'
                    textMuted       = '#888888'
                    border          = 'rgba(255,255,255,0.1)'
                    glow            = 'rgba(0,120,212,0.5)'
                    glowSecondary   = 'rgba(0,180,216,0.5)'
                }
                fonts = @{
                    primary = "'Segoe UI', sans-serif"
                    display = "'Segoe UI', sans-serif"
                    mono    = "'Cascadia Code', 'Consolas', monospace"
                    sizes   = @{ xs = '10px'; sm = '12px'; md = '14px'; lg = '16px'; xl = '20px' }
                }
                effects = @{ glowStrength = '5px'; borderRadius = '4px'; transitionSpeed = '0.2s' }
            }
        }
    }

    [PSCustomObject]$theme
}

function Set-PoshTheme {
    <#
    .SYNOPSIS
        Set the active theme for all Posh apps.
    .DESCRIPTION
        Persists the selection to config.json.
        Apps pick up the new theme next time they call Get-PoshTheme or Export-PoshThemeCSS.
    .PARAMETER Name
        Theme name.
    .EXAMPLE
        Set-PoshTheme -Name matrix
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('samurai','cyberpunk','matrix','midnight','hacker','default')]
        [string]$Name
    )

    $script:PoshDE.CurrentTheme = $Name

    $configPath = Join-Path $script:PoshDE.AppDataPath "config.json"
    @{ CurrentTheme = $Name } | ConvertTo-Json | Set-Content -Path $configPath -Encoding UTF8

    Write-Host "Theme set to '" -NoNewline -ForegroundColor DarkGray
    Write-Host $Name -NoNewline -ForegroundColor Cyan
    Write-Host "'. Restart apps to apply." -ForegroundColor DarkGray
}

function Export-PoshThemeCSS {
    <#
    .SYNOPSIS
        Export the active theme (or a named theme) as a CSS :root block.
    .DESCRIPTION
        Posh apps inject this into their WebView2 frontend via /api/theme.
    .PARAMETER Name
        Theme name. Defaults to active theme.
    .EXAMPLE
        $css = Export-PoshThemeCSS
    .EXAMPLE
        $css = Export-PoshThemeCSS -Name cyberpunk
    #>

    [CmdletBinding()]
    param(
        [string]$Name
    )

    $t = Get-PoshTheme -Name $Name

    @"
:root {
    --color-primary: $($t.colors.primary);
    --color-secondary: $($t.colors.secondary);
    --color-accent: $($t.colors.accent);
    --color-warning: $($t.colors.warning);
    --color-success: $($t.colors.success);
    --color-error: $($t.colors.error);
    --bg-dark: $($t.colors.bgDark);
    --bg-medium: $($t.colors.bgMedium);
    --bg-light: $($t.colors.bgLight);
    --bg-overlay: $($t.colors.bgOverlay);
    --text-primary: $($t.colors.textPrimary);
    --text-secondary: $($t.colors.textSecondary);
    --text-muted: $($t.colors.textMuted);
    --border-color: $($t.colors.border);
    --glow-color: $($t.colors.glow);
    --glow-secondary: $($t.colors.glowSecondary);
    --glow-strength: $($t.effects.glowStrength);
    --border-radius: $($t.effects.borderRadius);
    --transition-speed: $($t.effects.transitionSpeed);
    --font-primary: $($t.fonts.primary);
    --font-display: $($t.fonts.display);
    --font-mono: $($t.fonts.mono);
    --font-size-xs: $($t.fonts.sizes.xs);
    --font-size-sm: $($t.fonts.sizes.sm);
    --font-size-md: $($t.fonts.sizes.md);
    --font-size-lg: $($t.fonts.sizes.lg);
    --font-size-xl: $($t.fonts.sizes.xl);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    font-family: var(--font-primary);
    font-size: var(--font-size-md);
    color: var(--text-primary);
    background: var(--bg-dark);
}
"@

}

Write-Verbose "ThemeEngine loaded"