← Components/Utility

ThemeCustomizer

themecustomizer-1779379195944.tsx
'use client'
import { useState } from 'react'

const PRESETS = [
  { name: 'Gold', primary: '#C9A84C', bg: '#0A0A0A', accent: '#6366f1' },
  { name: 'Neon', primary: '#22d3ee', bg: '#030712', accent: '#a78bfa' },
  { name: 'Crimson', primary: '#ef4444', bg: '#0f0a0a', accent: '#f97316' },
  { name: 'Sage', primary: '#4ade80', bg: '#071a0f', accent: '#34d399' },
]

const RADII = ['0', '4px', '8px', '12px', '20px', '9999px']
const FONTS = [12, 13, 14, 15, 16]

export default function ThemeCustomizer() {
  const [preset, setPreset] = useState(PRESETS[0])
  const [primary, setPrimary] = useState(PRESETS[0].primary)
  const [radius, setRadius] = useState('8px')
  const [fontSize, setFontSize] = useState(14)
  const [copied, setCopied] = useState(false)

  const css = `:root {
  --color-primary: ${primary};
  --color-bg: ${preset.bg};
  --color-accent: ${preset.accent};
  --radius: ${radius};
  --font-size-base: ${fontSize}px;
}`

  function copy() {
    navigator.clipboard.writeText(css)
    setCopied(true)
    setTimeout(() => setCopied(false), 2000)
  }

  return (
    <div style={{ padding: 32, background: '#0A0A0A', display: 'flex', gap: 24, flexWrap: 'wrap' }}>
      {/* Controls */}
      <div style={{ flex: 1, minWidth: 240, display: 'flex', flexDirection: 'column', gap: 20 }}>
        <div style={{ color: '#F5F5F0', fontSize: 16, fontWeight: 700 }}>Theme Customizer</div>

        {/* Presets */}
        <div>
          <div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12, marginBottom: 8 }}>Presets</div>
          <div style={{ display: 'flex', gap: 6 }}>
            {PRESETS.map(p => (
              <button key={p.name} onClick={() => { setPreset(p); setPrimary(p.primary) }}
                style={{ width: 28, height: 28, borderRadius: '50%', background: p.primary, border: preset.name === p.name ? '3px solid white' : '2px solid transparent', cursor: 'pointer', transition: 'border 0.2s' }} title={p.name} />
            ))}
          </div>
        </div>

        {/* Primary color */}
        <div>
          <div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12, marginBottom: 8 }}>Primary color</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <input type="color" value={primary} onChange={e => setPrimary(e.target.value)} style={{ width: 36, height: 36, borderRadius: 8, border: 'none', cursor: 'pointer', background: 'none', padding: 0 }} />
            <span style={{ color: '#F5F5F0', fontSize: 13, fontFamily: 'monospace' }}>{primary.toUpperCase()}</span>
          </div>
        </div>

        {/* Border radius */}
        <div>
          <div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12, marginBottom: 8 }}>Border radius: {radius}</div>
          <div style={{ display: 'flex', gap: 6 }}>
            {RADII.map(r => (
              <button key={r} onClick={() => setRadius(r)} style={{ background: radius === r ? primary + '20' : 'rgba(255,255,255,0.04)', border: '1px solid', borderColor: radius === r ? primary + '40' : 'rgba(255,255,255,0.08)', color: radius === r ? primary : 'rgba(255,255,255,0.4)', borderRadius: 6, padding: '4px 8px', cursor: 'pointer', fontSize: 11 }}>{r || '0'}</button>
            ))}
          </div>
        </div>

        {/* Font size */}
        <div>
          <div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12, marginBottom: 8 }}>Font size: {fontSize}px</div>
          <input type="range" min={12} max={16} value={fontSize} onChange={e => setFontSize(Number(e.target.value))} style={{ width: '100%', accentColor: primary }} />
        </div>
      </div>

      {/* Preview + output */}
      <div style={{ flex: 1, minWidth: 220, display: 'flex', flexDirection: 'column', gap: 16 }}>
        {/* Preview */}
        <div style={{ background: preset.bg, border: '1px solid rgba(255,255,255,0.08)', borderRadius: 14, padding: 20, display: 'flex', flexDirection: 'column', gap: 12 }}>
          <button style={{ background: primary, color: '#0A0A0A', border: 'none', borderRadius: radius, padding: '10px 20px', fontWeight: 700, cursor: 'pointer', fontSize }}>Primary Button</button>
          <button style={{ background: 'transparent', color: primary, border: `1px solid ${primary}`, borderRadius: radius, padding: '10px 20px', fontWeight: 600, cursor: 'pointer', fontSize }}>Outline Button</button>
          <div style={{ background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.08)', borderRadius: radius, padding: '10px 14px', color: '#F5F5F0', fontSize }}>Input field</div>
          <span style={{ background: primary + '20', color: primary, padding: '3px 10px', borderRadius: '9999px', fontSize: fontSize - 2, fontWeight: 600, width: 'fit-content' }}>Badge</span>
        </div>

        {/* CSS output */}
        <div style={{ background: '#111', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 10, padding: 14, fontFamily: 'monospace', fontSize: 12, color: 'rgba(255,255,255,0.6)', whiteSpace: 'pre', flex: 1 }}>{css}</div>
        <button onClick={copy} style={{ background: copied ? 'rgba(34,197,94,0.12)' : primary, color: copied ? '#22c55e' : '#0A0A0A', border: copied ? '1px solid rgba(34,197,94,0.3)' : 'none', borderRadius: 8, padding: '10px', fontWeight: 700, cursor: 'pointer', fontSize: 13, transition: 'all 0.2s' }}>
          {copied ? '✓ CSS Copied' : 'Copy CSS Variables'}
        </button>
      </div>
    </div>
  )
}

Component info

CategoryUtility
Frameworkreact
TierFREE
Views0
Copies0

About

Live theme customizer with color pickers, font scale, radius preset, and CSS variables output

More from Utility

'use client'
import { useState, useCallback } from 'react'

interface UploadedFile {
  id: number
  name: string
  size: number
  type: string
  progress: number
  done: boolean
  error?: string
}

const ALLOWED = ['image/png', 'image/jpeg', 'image/w
FileUploadZone
Utility
'use client'
import { useState } from 'react'

interface ClipItem {
  id: number
  content: string
  type: 'text' | 'code' | 'url' | 'email'
  pinned: boolean
  time: number
}

const INITIAL: ClipItem[] = [
  { id: 1, content: 'npx empire-ui-mcp --st
ClipboardManager
Utility