// Gurukool shared components — React + inline styles via CSS variables // All components consume tokens.css. // ─── Iconography ────────────────────────────────────────────────────── // Simple line icons (stroke 1.75), not complex SVG art. function Icon({ name, size = 20, color = 'currentColor', strokeWidth = 1.75, style = {} }) { const s = size; const p = { fill: 'none', stroke: color, strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round' }; const paths = { home: <>>, check: , x: , bell: <>>, calendar: <>>, book: , user: <>>, users: <>>, star: , chart: <>>, settings: <>>, logout: <>>, chevronRight: , chevronDown: , chevronLeft: , plus: , search: <>>, filter: , clock: <>>, pencil: <>>, trash: <>>, upload: <>>, download: <>>, gift: <>>, sparkles: <>>, flame: , trophy: <>>, eye: <>>, lock: <>>, menu: , grid: <>>, building: <>>, tag: <>>, clipboard: <>>, message: , sun: <>>, moon: , globe: <>>, arrowRight: , arrowUp: , target: <>>, play: , megaphone: <>>, shield: , rupee: <>>, focus: <>>, heart: , alert: <>>, arrowDown: , }; return ( {paths[name] || paths.x} ); } // ─── Button ──────────────────────────────────────────────────────────── function Button({ children, variant = 'primary', size = 'md', leftIcon, rightIcon, block, onClick, style = {}, disabled }) { const sizes = { sm: { h: 32, px: 12, fs: 13, gap: 6, r: 8 }, md: { h: 40, px: 16, fs: 14, gap: 8, r: 10 }, lg: { h: 48, px: 20, fs: 15, gap: 10, r: 12 }, }[size]; const variants = { primary: { bg: 'var(--accent)', fg: '#fff', border: 'transparent', hover: 'brightness(1.08)' }, secondary: { bg: 'var(--accent-soft)', fg: 'var(--accent-ink)', border: 'transparent' }, ghost: { bg: 'transparent', fg: 'var(--text)', border: 'transparent' }, outline: { bg: 'transparent', fg: 'var(--text)', border: 'var(--border-strong)' }, danger: { bg: 'var(--gk-danger)', fg: '#fff', border: 'transparent' }, }[variant]; return ( !disabled && (e.currentTarget.style.filter = 'brightness(0.97)')} onMouseLeave={e => e.currentTarget.style.filter = ''} > {leftIcon && } {children} {rightIcon && } ); } // ─── Badge ───────────────────────────────────────────────────────────── function Badge({ children, tone = 'neutral', size = 'md', style = {} }) { const tones = { neutral: { bg: 'var(--gk-stone-100)', fg: 'var(--gk-stone-700)' }, green: { bg: 'var(--accent-soft)', fg: 'var(--accent-ink)' }, success: { bg: 'color-mix(in oklch, var(--gk-success) 15%, transparent)', fg: 'oklch(38% 0.13 145)' }, warn: { bg: 'color-mix(in oklch, var(--gk-warn) 22%, transparent)', fg: 'oklch(40% 0.12 75)' }, danger: { bg: 'color-mix(in oklch, var(--gk-danger) 15%, transparent)', fg: 'oklch(42% 0.15 25)' }, info: { bg: 'color-mix(in oklch, var(--gk-info) 12%, transparent)', fg: 'oklch(38% 0.13 230)' }, lime: { bg: 'color-mix(in oklch, var(--gk-lime-400) 25%, transparent)', fg: 'oklch(32% 0.12 128)' }, accent: { bg: 'var(--accent-soft)', fg: 'var(--accent-ink)' }, }[tone]; const sizes = { sm: { fs: 11, px: 8, h: 20 }, md: { fs: 12, px: 10, h: 24 }, lg: { fs: 13, px: 12, h: 28 }, }[size]; return ( {children} ); } // ─── Card ────────────────────────────────────────────────────────────── function Card({ children, padding = 20, style = {}, interactive, onClick }) { return ( interactive && (e.currentTarget.style.boxShadow = 'var(--sh-md)', e.currentTarget.style.borderColor = 'var(--border-strong)')} onMouseLeave={e => interactive && (e.currentTarget.style.boxShadow = '', e.currentTarget.style.borderColor = 'var(--border)')} > {children} ); } // ─── Avatar ──────────────────────────────────────────────────────────── function Avatar({ name = '?', size = 40, tone }) { const initials = name.split(' ').map(w => w[0]).slice(0, 2).join('').toUpperCase(); // Generate tone from name hash for variety const hash = name.split('').reduce((a, c) => a + c.charCodeAt(0), 0); const hues = [152, 128, 95, 55, 25, 270, 195, 340]; const h = tone !== undefined ? tone : hues[hash % hues.length]; return ( {initials} ); } // ─── Input ───────────────────────────────────────────────────────────── function Input({ label, hint, error, leftIcon, rightIcon, ...props }) { return ( {label && {label}} {leftIcon && } { e.currentTarget.style.borderColor = 'var(--accent)'; e.currentTarget.style.boxShadow = '0 0 0 3px var(--ring)'; }} onBlur={e => { e.currentTarget.style.borderColor = error ? 'var(--gk-danger)' : 'var(--border)'; e.currentTarget.style.boxShadow = ''; }} /> {rightIcon && } {hint && !error && {hint}} {error && {error}} ); } // ─── Progress ────────────────────────────────────────────────────────── function Progress({ value = 0, tone = 'green', height = 8 }) { const toneMap = { green: 'var(--accent)', lime: 'var(--gk-lime-500)', warn: 'var(--gk-warn)', danger: 'var(--gk-danger)' }; return ( ); } // ─── Divider w/ optional jali motif ──────────────────────────────────── function JaliDivider({ label }) { return ( {label && {label}} ); } // ─── Logo ────────────────────────────────────────────────────────────── function GurukoolLogo({ size = 28, withWordmark = true, color }) { const c = color || 'var(--accent)'; return ( {/* stylized lotus/banyan leaf — 3 leaf forms around center, geometric */} {withWordmark && ( Gurukool )} ); } // Export Object.assign(window, { Icon, Button, Badge, Card, Avatar, Input, Progress, JaliDivider, GurukoolLogo });