Spaces:
Sleeping
Sleeping
Download frontend/src/components/InterviewModeSelector.jsx from chowdary1/ai-interviewer-version-2: direct link, hf CLI and curl.
- Browser
- Download file 30.4 kB
-
https://huggingface.co/spaces/chowdary1/ai-interviewer-version-2/resolve/main/frontend/src/components/InterviewModeSelector.jsx
- Command line
-
hf download hf://spaces/chowdary1/ai-interviewer-version-2/frontend/src/components/InterviewModeSelector.jsx
-
curl -L -o InterviewModeSelector.jsx https://huggingface.co/spaces/chowdary1/ai-interviewer-version-2/resolve/main/frontend/src/components/InterviewModeSelector.jsx
30.4 kB
| /** | |
| * Interview Mode Selector | |
| * | |
| * FOUR MODES ONLY: | |
| * 1. Friendly - Database questions only | |
| * 2. Balanced - API + video | |
| * 3. Strict - RAG + verdicts | |
| * 4. Final Boss - Full power + personality selection | |
| * | |
| * This component enforces the 4-mode architecture. | |
| * Personality selection only appears for Final Boss mode. | |
| * | |
| * NOTE: All modes currently UNLOCKED. Payment integration pending. | |
| */ | |
| import React, { useState, useEffect } from 'react'; | |
| import { ChevronDown, Check, Lock, Zap, Crown, Skull, Video, Scale, Brain, User, Sparkles, Map } from 'lucide-react'; | |
| import { | |
| INTERVIEW_MODES, | |
| getInterviewModeList, | |
| FINAL_BOSS_PERSONALITIES, | |
| getFinalBossPersonalityList, | |
| modeAllowsPersonality | |
| } from '../services/scoringService'; | |
| // Mode tier badges (visual only - all modes unlocked) | |
| const TIER_BADGES = { | |
| free: { label: 'Free', color: '#10b981', icon: null }, | |
| paid_entry: { label: 'Basic', color: '#3b82f6', icon: <Zap size={12} /> }, | |
| paid_advanced: { label: 'Advanced', color: '#f59e0b', icon: <Crown size={12} /> }, | |
| premium: { label: 'Premium', color: '#ef4444', icon: <Skull size={12} /> }, | |
| }; | |
| // Feature configs with colors and icons | |
| const FEATURE_CONFIG = { | |
| video: { label: 'Video', icon: Video, color: '#3b82f6' }, | |
| verdict: { label: 'Verdict', icon: Scale, color: '#8b5cf6' }, | |
| rag: { label: 'RAG', icon: Brain, color: '#f59e0b' }, | |
| persona: { label: 'Persona', icon: User, color: '#ef4444' }, | |
| llm: { label: 'LLM', icon: Sparkles, color: '#22d3ee' }, | |
| roadmap: { label: 'Roadmap', icon: Map, color: '#a855f7' }, | |
| }; | |
| /** | |
| * Main Mode Card Component | |
| */ | |
| function ModeCard({ mode, isSelected, onSelect, disabled, userTier = 'premium', isDark }) { | |
| const tierInfo = TIER_BADGES[mode.tier] || TIER_BADGES.free; | |
| // Check if user can access this mode | |
| const tierOrder = ['free', 'paid_entry', 'paid_advanced', 'premium']; | |
| const userTierIndex = tierOrder.indexOf(userTier); | |
| const requiredTierIndex = tierOrder.indexOf(mode.tier); | |
| const canAccess = userTierIndex >= requiredTierIndex; | |
| const isLocked = !canAccess; | |
| // Dark mode colors | |
| const cardBg = isDark ? '#1e293b' : '#ffffff'; | |
| const cardBorder = isDark ? '#475569' : '#e2e8f0'; | |
| const textPrimary = isDark ? '#ffffff' : '#1e293b'; | |
| const textSecondary = isDark ? '#cbd5e1' : '#64748b'; | |
| return ( | |
| <div | |
| className={`mode-card ${isSelected ? 'selected' : ''} ${isLocked ? 'locked' : ''} ${disabled ? 'disabled' : ''}`} | |
| onClick={() => !disabled && !isLocked && onSelect(mode.id)} | |
| style={{ | |
| '--mode-color': mode.color, | |
| background: isSelected | |
| ? (isDark | |
| ? `linear-gradient(145deg, rgba(30, 41, 59, 0.95), rgba(15, 23, 42, 0.9))` | |
| : `linear-gradient(145deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.95))`) | |
| : (isDark | |
| ? 'linear-gradient(145deg, rgba(30, 41, 59, 0.8), rgba(15, 23, 42, 0.7))' | |
| : 'linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(248, 250, 252, 0.85))'), | |
| backdropFilter: 'blur(20px)', | |
| WebkitBackdropFilter: 'blur(20px)', | |
| borderColor: isSelected ? mode.color : (isDark ? 'rgba(148, 163, 184, 0.15)' : 'rgba(203, 213, 225, 0.5)'), | |
| borderWidth: isSelected ? '2px' : '1px', | |
| boxShadow: isSelected | |
| ? `0 8px 32px ${mode.color}30, 0 4px 16px rgba(0, 0, 0, 0.15), inset 0 1px 0 ${isDark ? 'rgba(255,255,255,0.08)' : 'rgba(255,255,255,0.9)'}` | |
| : `0 4px 20px rgba(0, 0, 0, ${isDark ? '0.25' : '0.08'}), inset 0 1px 0 ${isDark ? 'rgba(255,255,255,0.05)' : 'rgba(255,255,255,0.7)'}`, | |
| transform: isSelected ? 'scale(1.02)' : 'scale(1)', | |
| transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', | |
| }} | |
| > | |
| <div className="mode-header"> | |
| <div style={{ | |
| width: '72px', | |
| height: '72px', | |
| borderRadius: '16px', | |
| background: isDark | |
| ? `linear-gradient(145deg, ${mode.color}25, ${mode.color}10)` | |
| : `linear-gradient(145deg, ${mode.color}20, ${mode.color}08)`, | |
| boxShadow: `0 4px 16px ${mode.color}30`, | |
| border: `2px solid ${mode.color}40`, | |
| display: 'flex', | |
| alignItems: 'center', | |
| justifyContent: 'center', | |
| position: 'relative', | |
| }}> | |
| <span style={{ | |
| fontSize: '2.5rem', | |
| lineHeight: 1, | |
| filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.3))', | |
| }}>{mode.icon}</span> | |
| </div> | |
| <div className="mode-tier-badge" style={{ | |
| background: isDark | |
| ? `linear-gradient(135deg, ${tierInfo.color}50, ${tierInfo.color}30)` | |
| : `linear-gradient(135deg, ${tierInfo.color}25, ${tierInfo.color}15)`, | |
| color: isDark ? '#fff' : tierInfo.color, | |
| fontWeight: 700, | |
| padding: '8px 16px', | |
| fontSize: '0.7rem', | |
| letterSpacing: '0.5px', | |
| textTransform: 'uppercase', | |
| textShadow: 'none', | |
| border: `1.5px solid ${tierInfo.color}${isDark ? '60' : '40'}`, | |
| borderRadius: '12px', | |
| boxShadow: `0 2px 8px ${tierInfo.color}30`, | |
| }}> | |
| {tierInfo.icon} | |
| <span>{tierInfo.label}</span> | |
| </div> | |
| </div> | |
| <div className="mode-content"> | |
| <h3 className="mode-name" style={{ color: textPrimary, fontWeight: 700, fontSize: '1.15rem', marginBottom: '8px' }}>{mode.name}</h3> | |
| <p className="mode-description" style={{ | |
| color: textSecondary, | |
| lineHeight: 1.5, | |
| fontSize: '0.85rem', | |
| margin: 0, | |
| display: '-webkit-box', | |
| WebkitLineClamp: 2, | |
| WebkitBoxOrient: 'vertical', | |
| overflow: 'hidden', | |
| minHeight: '2.55em', | |
| }}>{mode.description}</p> | |
| </div> | |
| <div className="mode-features" style={{ | |
| display: 'flex', | |
| flexWrap: 'wrap', | |
| gap: '6px', | |
| marginTop: '12px', | |
| minHeight: '32px', | |
| }}> | |
| {mode.config.usesLLM && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.llm.color}30` : `${FEATURE_CONFIG.llm.color}15`, | |
| color: isDark ? '#67e8f9' : FEATURE_CONFIG.llm.color, | |
| border: `1px solid ${FEATURE_CONFIG.llm.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <Sparkles size={11} /> LLM | |
| </span> | |
| )} | |
| {mode.config.hasVideo && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.video.color}30` : `${FEATURE_CONFIG.video.color}15`, | |
| color: isDark ? '#93c5fd' : FEATURE_CONFIG.video.color, | |
| border: `1px solid ${FEATURE_CONFIG.video.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <Video size={11} /> Video | |
| </span> | |
| )} | |
| {mode.config.hasVerdict && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.verdict.color}30` : `${FEATURE_CONFIG.verdict.color}15`, | |
| color: isDark ? '#c4b5fd' : FEATURE_CONFIG.verdict.color, | |
| border: `1px solid ${FEATURE_CONFIG.verdict.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <Scale size={11} /> Verdict | |
| </span> | |
| )} | |
| {mode.config.hasRag && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.rag.color}30` : `${FEATURE_CONFIG.rag.color}15`, | |
| color: isDark ? '#fcd34d' : FEATURE_CONFIG.rag.color, | |
| border: `1px solid ${FEATURE_CONFIG.rag.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <Brain size={11} /> RAG | |
| </span> | |
| )} | |
| {mode.config.hasPersonalitySelection && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.persona.color}30` : `${FEATURE_CONFIG.persona.color}15`, | |
| color: isDark ? '#fca5a5' : FEATURE_CONFIG.persona.color, | |
| border: `1px solid ${FEATURE_CONFIG.persona.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <User size={11} /> Persona | |
| </span> | |
| )} | |
| {mode.config.hasRoadmap && ( | |
| <span className="feature-tag" style={{ | |
| background: isDark ? `${FEATURE_CONFIG.roadmap.color}30` : `${FEATURE_CONFIG.roadmap.color}15`, | |
| color: isDark ? '#d8b4fe' : FEATURE_CONFIG.roadmap.color, | |
| border: `1px solid ${FEATURE_CONFIG.roadmap.color}${isDark ? '60' : '30'}`, | |
| padding: '4px 10px', | |
| borderRadius: '20px', | |
| fontSize: '0.7rem', | |
| fontWeight: 600, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: '4px', | |
| whiteSpace: 'nowrap', | |
| }}> | |
| <Map size={11} /> Roadmap | |
| </span> | |
| )} | |
| </div> | |
| {isSelected && !isLocked && ( | |
| <div className="mode-selected-indicator"> | |
| <Check size={18} /> | |
| </div> | |
| )} | |
| {isLocked && ( | |
| <div className="mode-locked-overlay"> | |
| <Lock size={24} /> | |
| <span>Upgrade to {tierInfo.label}</span> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| /** | |
| * Final Boss Personality Selector | |
| * Only shown when mode = 'final_boss' | |
| */ | |
| function FinalBossPersonalitySelector({ value, onChange, disabled }) { | |
| const [isOpen, setIsOpen] = useState(false); | |
| const personalities = getFinalBossPersonalityList(); | |
| const selected = FINAL_BOSS_PERSONALITIES[value] || FINAL_BOSS_PERSONALITIES.faang_engineer; | |
| return ( | |
| <div className="personality-subselector"> | |
| <label className="subselector-label"> | |
| <Skull size={16} /> | |
| Final Boss Persona | |
| </label> | |
| <p className="subselector-hint"> | |
| Choose your interviewer persona for maximum challenge | |
| </p> | |
| <div className="subselector-container"> | |
| <button | |
| type="button" | |
| className={`subselector-trigger ${isOpen ? 'open' : ''}`} | |
| onClick={() => !disabled && setIsOpen(!isOpen)} | |
| disabled={disabled} | |
| > | |
| <span className="persona-icon">{selected.icon}</span> | |
| <div className="persona-info"> | |
| <span className="persona-name">{selected.name}</span> | |
| <span className="persona-desc">{selected.description}</span> | |
| </div> | |
| <ChevronDown size={18} className={`chevron ${isOpen ? 'rotated' : ''}`} /> | |
| </button> | |
| {isOpen && ( | |
| <> | |
| <div className="subselector-backdrop" onClick={() => setIsOpen(false)} /> | |
| <div className="subselector-dropdown"> | |
| {personalities.map((persona) => ( | |
| <button | |
| key={persona.id} | |
| type="button" | |
| className={`dropdown-option ${persona.id === value ? 'selected' : ''}`} | |
| onClick={() => { | |
| onChange(persona.id); | |
| setIsOpen(false); | |
| }} | |
| > | |
| <span className="persona-icon">{persona.icon}</span> | |
| <div className="persona-info"> | |
| <span className="persona-name">{persona.name}</span> | |
| <span className="persona-desc">{persona.description}</span> | |
| </div> | |
| {persona.id === value && <Check size={18} className="check-icon" />} | |
| </button> | |
| ))} | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| /** | |
| * Main Interview Mode Selector Component | |
| */ | |
| function InterviewModeSelector({ | |
| mode = 'friendly', | |
| onModeChange, | |
| personality = 'faang_engineer', | |
| onPersonalityChange, | |
| disabled = false, | |
| userTier = 'premium' // All modes unlocked - payment integration pending | |
| }) { | |
| const modes = getInterviewModeList(); | |
| const showPersonalitySelector = modeAllowsPersonality(mode); | |
| // Detect dark mode | |
| const [isDark, setIsDark] = useState(() => { | |
| // Initialize from current theme | |
| if (typeof document !== 'undefined') { | |
| return document.documentElement.getAttribute('data-theme') === 'dark'; | |
| } | |
| return false; | |
| }); | |
| useEffect(() => { | |
| if (typeof document === 'undefined') return; | |
| const checkTheme = () => { | |
| try { | |
| const theme = document.documentElement.getAttribute('data-theme'); | |
| setIsDark(theme === 'dark'); | |
| } catch (e) { | |
| console.warn('Theme check error:', e); | |
| } | |
| }; | |
| checkTheme(); | |
| // Watch for theme changes | |
| let observer = null; | |
| try { | |
| observer = new MutationObserver(checkTheme); | |
| observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] }); | |
| } catch (e) { | |
| console.warn('MutationObserver error:', e); | |
| } | |
| return () => { | |
| if (observer) observer.disconnect(); | |
| }; | |
| }, []); | |
| // Theme-aware colors | |
| const headerColor = isDark ? '#ffffff' : '#1e293b'; | |
| const subheaderColor = isDark ? '#94a3b8' : '#64748b'; | |
| return ( | |
| <div className="interview-mode-selector"> | |
| <div className="mode-selector-header"> | |
| <h3 style={{ color: headerColor }}>Choose Interview Mode</h3> | |
| <p style={{ color: subheaderColor }}>Select the interview difficulty and style that matches your preparation level</p> | |
| </div> | |
| <div className="mode-grid"> | |
| {modes.map((m) => ( | |
| <ModeCard | |
| key={m.id} | |
| mode={m} | |
| isSelected={mode === m.id} | |
| onSelect={onModeChange} | |
| disabled={disabled} | |
| userTier={userTier} | |
| isDark={isDark} | |
| /> | |
| ))} | |
| </div> | |
| {/* Final Boss Personality Sub-Selector */} | |
| {showPersonalitySelector && ( | |
| <FinalBossPersonalitySelector | |
| value={personality} | |
| onChange={onPersonalityChange} | |
| disabled={disabled} | |
| /> | |
| )} | |
| <style jsx>{` | |
| .interview-mode-selector { | |
| margin-bottom: var(--space-6); | |
| } | |
| .mode-selector-header { | |
| margin-bottom: var(--space-4); | |
| } | |
| .mode-selector-header h3 { | |
| font-size: var(--text-lg); | |
| font-weight: var(--font-semibold); | |
| color: var(--text-primary); | |
| margin: 0 0 var(--space-1) 0; | |
| } | |
| [data-theme="dark"] .mode-selector-header h3 { | |
| color: #f8fafc; | |
| } | |
| .mode-selector-header p { | |
| font-size: var(--text-sm); | |
| color: var(--text-secondary); | |
| margin: 0; | |
| } | |
| [data-theme="dark"] .mode-selector-header p { | |
| color: #94a3b8; | |
| } | |
| .mode-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: var(--space-4); | |
| } | |
| @media (max-width: 768px) { | |
| .mode-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .mode-card { | |
| position: relative; | |
| padding: var(--space-4); | |
| background: var(--bg-card, #ffffff); | |
| border: 2px solid var(--border-color, #e2e8f0); | |
| border-radius: var(--radius-xl); | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| overflow: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 200px; | |
| } | |
| .mode-card:hover:not(.locked):not(.disabled) { | |
| border-color: var(--mode-color); | |
| transform: translateY(-3px); | |
| box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); | |
| } | |
| [data-theme="dark"] .mode-card:hover:not(.locked):not(.disabled) { | |
| box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 20px var(--mode-color); | |
| } | |
| .mode-card.selected { | |
| border-color: var(--mode-color); | |
| border-width: 2px; | |
| box-shadow: 0 0 0 3px color-mix(in srgb, var(--mode-color) 20%, transparent); | |
| } | |
| [data-theme="dark"] .mode-card.selected { | |
| box-shadow: 0 0 0 3px color-mix(in srgb, var(--mode-color) 30%, transparent), 0 0 30px var(--mode-color); | |
| } | |
| .mode-card.locked { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .mode-card.disabled { | |
| opacity: 0.5; | |
| pointer-events: none; | |
| } | |
| .mode-header { | |
| display: flex; | |
| align-items: flex-start; | |
| justify-content: space-between; | |
| margin-bottom: var(--space-3); | |
| gap: var(--space-2); | |
| } | |
| .mode-icon { | |
| font-size: 2.5rem; | |
| flex-shrink: 0; | |
| } | |
| .mode-tier-badge { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| padding: 4px 10px; | |
| border-radius: var(--radius-full); | |
| font-size: var(--text-xs); | |
| font-weight: var(--font-bold); | |
| flex-shrink: 0; | |
| } | |
| .mode-content { | |
| margin-bottom: var(--space-3); | |
| flex: 1; | |
| min-height: 0; | |
| } | |
| .mode-name { | |
| font-size: 1.1rem; | |
| font-weight: var(--font-bold); | |
| color: var(--text-primary, #1e293b); | |
| margin: 0 0 var(--space-2) 0; | |
| } | |
| .mode-description { | |
| font-size: 0.85rem; | |
| color: var(--text-secondary, #64748b); | |
| margin: 0; | |
| line-height: 1.5; | |
| overflow: hidden; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| } | |
| .mode-features { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| margin-top: auto; | |
| padding-top: var(--space-2); | |
| } | |
| .feature-tag { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 4px; | |
| padding: 4px 10px; | |
| border-radius: var(--radius-full); | |
| font-size: 0.7rem; | |
| font-weight: 600; | |
| letter-spacing: 0.3px; | |
| white-space: nowrap; | |
| } | |
| .mode-selected-indicator { | |
| position: absolute; | |
| top: var(--space-3); | |
| right: var(--space-3); | |
| width: 28px; | |
| height: 28px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: var(--mode-color); | |
| color: white; | |
| border-radius: var(--radius-full); | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.2); | |
| } | |
| .mode-locked-overlay { | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| gap: var(--space-2); | |
| background: rgba(0, 0, 0, 0.7); | |
| color: white; | |
| font-size: var(--text-sm); | |
| font-weight: var(--font-medium); | |
| backdrop-filter: blur(4px); | |
| } | |
| .feature-tag { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 5px; | |
| padding: 4px 10px; | |
| border-radius: var(--radius-full); | |
| font-size: 11px; | |
| font-weight: 600; | |
| letter-spacing: 0.3px; | |
| } | |
| .mode-selected-indicator { | |
| position: absolute; | |
| top: var(--space-3); | |
| right: var(--space-3); | |
| width: 28px; | |
| height: 28px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: var(--mode-color); | |
| color: white; | |
| border-radius: var(--radius-full); | |
| } | |
| .mode-locked-overlay { | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| gap: var(--space-2); | |
| background: rgba(0, 0, 0, 0.6); | |
| color: white; | |
| font-size: var(--text-sm); | |
| font-weight: var(--font-medium); | |
| } | |
| /* Personality Sub-Selector */ | |
| .personality-subselector { | |
| margin-top: var(--space-5); | |
| padding: var(--space-4); | |
| background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05)); | |
| border: 1px solid rgba(239, 68, 68, 0.3); | |
| border-radius: var(--radius-xl); | |
| } | |
| .subselector-label { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--space-2); | |
| font-weight: var(--font-semibold); | |
| font-size: var(--text-sm); | |
| color: #ef4444; | |
| margin-bottom: var(--space-1); | |
| } | |
| .subselector-hint { | |
| font-size: var(--text-xs); | |
| color: var(--text-secondary); | |
| margin: 0 0 var(--space-3) 0; | |
| } | |
| .subselector-container { | |
| position: relative; | |
| } | |
| .subselector-trigger { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--space-3); | |
| width: 100%; | |
| padding: var(--space-3) var(--space-4); | |
| background: var(--bg-card); | |
| border: 2px solid rgba(239, 68, 68, 0.3); | |
| border-radius: var(--radius-lg); | |
| text-align: left; | |
| cursor: pointer; | |
| transition: all var(--transition-fast); | |
| } | |
| .subselector-trigger:hover:not(:disabled) { | |
| border-color: #ef4444; | |
| } | |
| .subselector-trigger.open { | |
| border-color: #ef4444; | |
| border-bottom-left-radius: 0; | |
| border-bottom-right-radius: 0; | |
| } | |
| .persona-icon { | |
| font-size: 1.5rem; | |
| } | |
| .persona-info { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .persona-name { | |
| font-weight: var(--font-semibold); | |
| font-size: var(--text-sm); | |
| color: var(--text-primary); | |
| } | |
| .persona-desc { | |
| font-size: var(--text-xs); | |
| color: var(--text-secondary); | |
| } | |
| .chevron { | |
| transition: transform var(--transition-fast); | |
| color: var(--text-tertiary); | |
| } | |
| .chevron.rotated { | |
| transform: rotate(180deg); | |
| } | |
| .subselector-backdrop { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 10; | |
| } | |
| .subselector-dropdown { | |
| position: absolute; | |
| top: 100%; | |
| left: 0; | |
| right: 0; | |
| background: var(--bg-card); | |
| border: 2px solid #ef4444; | |
| border-top: none; | |
| border-radius: 0 0 var(--radius-lg) var(--radius-lg); | |
| z-index: 20; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| .dropdown-option { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--space-3); | |
| width: 100%; | |
| padding: var(--space-3) var(--space-4); | |
| background: transparent; | |
| border: none; | |
| text-align: left; | |
| cursor: pointer; | |
| transition: background var(--transition-fast); | |
| } | |
| .dropdown-option:hover { | |
| background: rgba(239, 68, 68, 0.1); | |
| } | |
| .dropdown-option.selected { | |
| background: rgba(239, 68, 68, 0.15); | |
| } | |
| .check-icon { | |
| color: #ef4444; | |
| } | |
| `}</style> | |
| </div> | |
| ); | |
| } | |
| export default InterviewModeSelector; | |