@@ -186,11 +155,11 @@ function Onboarding() {
style={step >= s ? { background: 'var(--gradient-primary)' } : {}}
animate={{ scale: step === s ? 1.1 : 1 }}
>
- {step > s ? icons.check : s}
+ {step > s ?
: s}
{s < 3 && (
s ? 'bg-indigo-500' : 'bg-border'
+ className={`hidden sm:block w-24 md:w-40 h-1 mx-2 rounded transition-all ${step > s ? 'bg-primary-500' : 'bg-border'
}`}
/>
)}
@@ -222,7 +191,8 @@ function Onboarding() {
{portfolioTypes.map((type, i) => (
-
handleSelect('portfolioType', type.id)}
- className={`relative glass-card rounded-3xl p-8 cursor-pointer transition-all overflow-hidden ${preferences.portfolioType === type.id
- ? 'ring-2 ring-indigo-500'
+ aria-pressed={preferences.portfolioType === type.id}
+ className={`relative glass-card rounded-3xl p-8 cursor-pointer transition-all overflow-hidden hover:bg-surface-hover w-full text-left ${preferences.portfolioType === type.id
+ ? 'ring-2 ring-primary-500/40'
: ''
}`}
>
@@ -241,22 +212,20 @@ function Onboarding() {
- {icons.check}
+
)}
-
- {type.icon}
-
+
{type.title}
{type.description}
Examples: {type.examples}
-
+
))}
@@ -280,7 +249,8 @@ function Onboarding() {
{experienceLevels.map((level, i) => (
-
handleSelect('experienceLevel', level.id)}
- className={`relative glass-card rounded-3xl p-8 cursor-pointer transition-all ${preferences.experienceLevel === level.id
- ? 'ring-2 ring-indigo-500'
+ aria-pressed={preferences.experienceLevel === level.id}
+ className={`relative glass-card rounded-3xl p-8 cursor-pointer transition-all hover:bg-surface-hover w-full text-left ${preferences.experienceLevel === level.id
+ ? 'ring-2 ring-primary-500/40'
: ''
}`}
>
@@ -298,22 +269,20 @@ function Onboarding() {
- {icons.check}
+
)}
-
- {level.icon}
-
+
{level.title}
{level.description}
Highlights: {level.highlights}
-
+
))}
@@ -337,7 +306,8 @@ function Onboarding() {
{themes.map((theme, i) => (
- handleSelect('themePreference', theme.id)}
- className={`relative cursor-pointer transition-all ${preferences.themePreference === theme.id
- ? 'ring-2 ring-indigo-500 ring-offset-2 ring-offset-background'
+ aria-pressed={preferences.themePreference === theme.id}
+ className={`relative cursor-pointer transition-all w-full text-left ${preferences.themePreference === theme.id
+ ? 'ring-2 ring-primary-500 ring-offset-2 ring-offset-background'
: ''
}`}
>
@@ -390,12 +361,12 @@ function Onboarding() {
- {icons.check}
+
)}
-
+
))}
diff --git a/frontend/src/pages/Portfolio.jsx b/frontend/src/pages/Portfolio.jsx
index f720a02..40bf756 100644
--- a/frontend/src/pages/Portfolio.jsx
+++ b/frontend/src/pages/Portfolio.jsx
@@ -1,308 +1,58 @@
-import { useState, useEffect, useMemo, useRef } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'
-import { motion, AnimatePresence } from 'framer-motion'
import { getPublicProfile, API_URL } from '../utils/api'
-import { getAppUrl } from '../utils/appUrl'
-import { safeHref, safeMailto } from '../utils/safeUrl'
import { useTheme } from '../context/ThemeContext'
-import {
- User, Briefcase, Rocket, GraduationCap,
- Award, BookOpen, Heart, Users,
- Github, Linkedin, Twitter, Globe, Mail,
- MapPin, ExternalLink, Code, Calendar,
- Building, ChevronRight, Sparkles, Moon, Sun,
- Terminal, Layers, Database, Wrench, Cloud, MessageCircle, Info
-} from 'lucide-react'
+import { getThemeColors } from '../portfolio/theme'
+import PortfolioTemplate from '../portfolio/PortfolioTemplate'
+import LoadingState from '../portfolio/components/LoadingState'
+import ErrorState from '../portfolio/components/ErrorState'
-// ==================== THEME UTILS ====================
-const hexToRgb = (hex) => {
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
- return result ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : '0, 0, 0';
-}
-
-const getThemeColors = (themeName, mode) => {
- const palettes = {
- modern: { primary: '#6366f1', secondary: '#a855f7', accent: 'linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%)' },
- minimal: { primary: '#18181b', secondary: '#52525b', accent: 'linear-gradient(135deg, #18181b, #52525b)' },
- creative: { primary: '#ec4899', secondary: '#8b5cf6', accent: 'linear-gradient(135deg, #ec4899 0%, #8b5cf6 50%, #06b6d4 100%)' },
- professional: { primary: '#0d9488', secondary: '#0891b2', accent: 'linear-gradient(135deg, #0d9488, #0891b2)' }
- }
-
- const palette = palettes[themeName] || palettes.modern
- const isDark = mode === 'dark'
-
- // Adjust minimal theme primary for dark mode
- if (themeName === 'minimal' && isDark) {
- palette.primary = '#f8fafc'
- palette.secondary = '#94a3b8'
- palette.accent = 'linear-gradient(135deg, #f8fafc, #94a3b8)'
- }
-
- return {
- ...palette,
- bg: isDark ? '#030712' : '#ffffff',
- surface: isDark ? 'rgba(15, 23, 42, 0.8)' : 'rgba(255, 255, 255, 0.85)',
- surfaceSolid: isDark ? '#0f172a' : '#f8fafc',
- text: isDark ? '#f8fafc' : '#0f172a',
- textSecondary: isDark ? '#94a3b8' : '#475569',
- border: isDark ? `rgba(${hexToRgb(palette.primary)}, 0.2)` : `rgba(${hexToRgb(palette.primary)}, 0.1)`,
- glow: isDark ? `rgba(${hexToRgb(palette.primary)}, 0.4)` : `rgba(${hexToRgb(palette.primary)}, 0.15)`
- }
-}
-
-// ==================== ANIMATION VARIANTS ====================
-const containerVariants = {
- hidden: { opacity: 0 },
- visible: { opacity: 1, transition: { staggerChildren: 0.08, delayChildren: 0.1 } }
-}
-
-const itemVariants = {
- hidden: { opacity: 0, y: 20 },
- visible: { opacity: 1, y: 0, transition: { type: 'spring', stiffness: 100, damping: 15 } }
-}
-
-const cardHover = {
- rest: { scale: 1, rotateX: 0, rotateY: 0 },
- hover: { scale: 1.02, transition: { type: 'spring', stiffness: 400, damping: 17 } }
-}
-
-// ==================== GLASSMORPHIC CARD COMPONENT ====================
-const GlassCard = ({ children, className = '', hover = true, style = {} }) => (
-
- {children}
- {hover && (
-
- )}
-
-)
-
-// ==================== SKILL BAR COMPONENT ====================
-const SkillChip = ({ skill, index }) => (
-
-
- {skill}
-
-
-
-)
-
-// ==================== TIMELINE ITEM COMPONENT ====================
-const TimelineItem = ({ item, type, index, isLast }) => (
-
- {/* Timeline connector */}
- {!isLast && (
-
- )}
-
- {/* Timeline dot */}
-
-
-
-
-
-
- {type === 'experience' ? item.title : item.degree}
-
-
-
-
- {type === 'experience' ? item.company : item.institution}
-
-
-
-
-
- {type === 'experience' ? item.duration : item.year}
-
-
-
- {/* GPA/Score for Education */}
- {type === 'education' && item.gpa && (
-
-
- Score: {item.gpa}
-
- )}
-
- {item.location && (
-
-
- {item.location}
-
- )}
-
- {item.description && (
-
- {item.description}
-
- )}
-
- {item.achievements?.length > 0 && (
-
- {item.achievements.map((achievement, i) => (
- -
-
- {achievement}
-
- ))}
-
- )}
-
-
-)
-
-// ==================== PROJECT CARD COMPONENT ====================
-const ProjectCard = ({ project, index }) => (
-
-
-
-
-
-
-
- {safeHref(project.githubUrl) && (
-
-
-
- )}
- {safeHref(project.demoUrl) && (
-
-
-
- )}
-
-
-
-
- {project.title}
-
-
-
- {project.description}
-
-
- {project.techStack?.length > 0 && (
-
- {project.techStack.map((tech, i) => (
-
- {tech}
-
- ))}
-
- )}
-
-
-)
-
-// ==================== MAIN PORTFOLIO COMPONENT ====================
function Portfolio() {
- const [showPremiumInfo, setShowPremiumInfo] = useState(false)
- const timeoutRef = useRef(null)
-
- const handleMouseEnter = () => {
- if (timeoutRef.current) clearTimeout(timeoutRef.current)
- setShowPremiumInfo(true)
- }
-
- const handleMouseLeave = () => {
- timeoutRef.current = setTimeout(() => {
- setShowPremiumInfo(false)
- }, 3000)
- }
-
- // Cleanup timeout on unmount
- useEffect(() => {
- return () => {
- if (timeoutRef.current) clearTimeout(timeoutRef.current)
- }
- }, [])
const { username } = useParams()
- const { theme, toggleTheme } = useTheme()
+ const { theme } = useTheme()
const [profile, setProfile] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
- const [activeTab, setActiveTab] = useState('about')
- const [portfolioTheme, setPortfolioTheme] = useState('modern')
-
-
+ const fallbackColors = useMemo(() => getThemeColors('modern', theme), [theme])
useEffect(() => {
+ let cancelled = false
+
const fetchProfile = async () => {
+ setLoading(true)
+ setError('')
+
try {
const { data } = await getPublicProfile(username)
+ if (cancelled) return
+
setProfile(data)
- if (data.theme) setPortfolioTheme(data.theme)
- // Dynamic SEO — set page title and meta description
const name = data.basicDetails?.name || username
- const headline = data.basicDetails?.headline || data.basicDetails?.about?.substring(0, 60) || 'Professional'
+ const headline = data.basicDetails?.headline
+ || data.basicDetails?.about?.substring(0, 60)
+ || 'Professional'
+
document.title = `${name} — ${headline} | Portlify by TechyCSR`
+
const metaDesc = document.querySelector('meta[name="description"]')
if (metaDesc) {
- metaDesc.setAttribute('content',
+ metaDesc.setAttribute(
+ 'content',
`${name}'s professional portfolio — ${headline}. Built with Portlify by TechyCSR.`
)
}
+
const ogTitle = document.querySelector('meta[property="og:title"]')
if (ogTitle) ogTitle.setAttribute('content', `${name} — ${headline} | Portlify`)
+
const ogDesc = document.querySelector('meta[property="og:description"]')
- if (ogDesc) ogDesc.setAttribute('content', `${name}'s professional portfolio — ${headline}. Built with Portlify.`)
+ if (ogDesc) {
+ ogDesc.setAttribute(
+ 'content',
+ `${name}'s professional portfolio — ${headline}. Built with Portlify.`
+ )
+ }
const viewKey = `viewed_${username}`
if (!sessionStorage.getItem(viewKey)) {
@@ -310,933 +60,33 @@ function Portfolio() {
fetch(`${API_URL}/api/analytics/track/${encodeURIComponent(username)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ referrer: document.referrer || 'direct' })
- }).catch(() => { /* silent */ })
+ body: JSON.stringify({ referrer: document.referrer || 'direct' }),
+ }).catch(() => {})
}
} catch (err) {
+ if (cancelled) return
setError(err.response?.status === 404 ? 'Profile not found' : 'Failed to load profile')
} finally {
- setLoading(false)
+ if (!cancelled) setLoading(false)
}
}
- fetchProfile()
- }, [username])
-
- const colors = useMemo(() => getThemeColors(portfolioTheme, theme), [portfolioTheme, theme])
-
- // Extract profile data
- const { basicDetails, skills, experience, education, projects, achievements,
- certifications, publications, volunteering, socialLinks, customSections } = profile || {}
- // Skill categories configuration with animated icons
- const skillCategories = useMemo(() => [
- { key: 'programmingLanguages', label: 'Programming Languages', icon: Terminal, gradient: 'from-blue-500 to-cyan-500' },
- { key: 'frameworks', label: 'Frameworks & Libraries', icon: Layers, gradient: 'from-purple-500 to-pink-500' },
- { key: 'databases', label: 'Databases', icon: Database, gradient: 'from-emerald-500 to-teal-500' },
- { key: 'tools', label: 'Tools', icon: Wrench, gradient: 'from-orange-500 to-amber-500' },
- { key: 'cloudSystems', label: 'Cloud & Systems', icon: Cloud, gradient: 'from-indigo-500 to-violet-500' },
- { key: 'softSkills', label: 'Soft Skills', icon: MessageCircle, gradient: 'from-rose-500 to-pink-500' }
- ], [])
-
- const allSkills = useMemo(() => [
- ...(skills?.programmingLanguages || []),
- ...(skills?.frameworks || []),
- ...(skills?.databases || []),
- ...(skills?.tools || []),
- ...(skills?.cloudSystems || []),
- ...(skills?.softSkills || [])
- ], [skills])
-
- // Build tabs only for sections with data
- const tabs = useMemo(() => {
- const tabConfig = [
- { id: 'about', label: 'About', icon: User, show: true },
- { id: 'experience', label: 'Experience', icon: Briefcase, show: experience?.length > 0 },
- { id: 'projects', label: 'Projects', icon: Rocket, show: projects?.length > 0 },
- { id: 'education', label: 'Education', icon: GraduationCap, show: education?.length > 0 },
- { id: 'achievements', label: 'Achievements', icon: Award, show: achievements?.length > 0 },
- { id: 'certifications', label: 'Certifications', icon: Award, show: certifications?.length > 0 },
- { id: 'publications', label: 'Publications', icon: BookOpen, show: publications?.length > 0 },
- { id: 'volunteering', label: 'Volunteering', icon: Heart, show: volunteering?.length > 0 }
- ]
-
- // Add custom sections
- const customTabs = (customSections || [])
- .filter(s => s.title && s.content)
- .map((s, i) => ({
- id: `custom-${i}`,
- label: s.title,
- icon: Code,
- show: true,
- content: s.content
- }))
-
- return [...tabConfig.filter(t => t.show), ...customTabs]
- }, [experience, projects, education, achievements, certifications, publications, volunteering, customSections])
+ fetchProfile()
- // CSS Variables injection
- const cssVars = {
- '--primary': colors.primary,
- '--secondary': colors.secondary,
- '--bg': colors.bg,
- '--surface': colors.surface,
- '--surfaceSolid': colors.surfaceSolid,
- '--text': colors.text,
- '--textSecondary': colors.textSecondary,
- '--border': colors.border,
- '--glow': colors.glow,
- '--accent': colors.accent
- }
+ return () => {
+ cancelled = true
+ }
+ }, [username])
- // Loading state
if (loading) {
- return (
-
-
-
- )
+ return
}
- // Error state
- if (error) {
- return (
-
-
-
-
-
- {error}
- The portfolio you're looking for doesn't exist.
-
-
- )
+ if (error || !profile) {
+ return
}
- return (
-
- {/* Animated Background */}
-
-
-
-
-
- {/* Theme Toggle - 3D Switch */}
-
-
-
-
-
- {theme === 'dark' ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
- {/* Hero Section */}
-
-
- {/* Avatar with 3D effect */}
-
-
-
- {basicDetails?.profilePhoto ? (
-

- ) : (
-
- {basicDetails?.name?.charAt(0)?.toUpperCase() || username?.charAt(0)?.toUpperCase()}
-
- )}
-
- {/* Glow ring */}
-
-
-
-
- {/* Name */}
-
- {basicDetails?.name || username}
-
-
- {/* Headline */}
- {basicDetails?.headline && (
-
- {basicDetails.headline}
-
- )}
-
- {/* Location */}
- {basicDetails?.location && (
-
-
- {basicDetails.location}
-
- )}
-
- {/* Social Links */}
- {socialLinks && Object.values(socialLinks).some(v => v) && (
-
- {safeHref(socialLinks.github) && (
-
-
-
- )}
- {safeHref(socialLinks.linkedin) && (
-
-
-
- )}
- {safeHref(socialLinks.twitter) && (
-
-
-
- )}
- {safeHref(socialLinks.website) && (
-
-
-
- )}
- {safeMailto(socialLinks.email || basicDetails?.email) && (
-
-
-
- )}
-
- )}
-
-
-
- {/* Floating Navigation */}
-
-
- {/* Content Section */}
-
-
- {/* About Tab */}
- {activeTab === 'about' && (
-
- {/* About Text */}
- {basicDetails?.about && (
-
-
-
- About
-
-
- {basicDetails.about}
-
-
- )}
-
- {/* Skills - Categorized Display */}
- {allSkills.length > 0 && (
-
-
-
- Skills
-
-
- {skillCategories.map((category, catIndex) => {
- const categorySkills = skills?.[category.key] || []
- if (categorySkills.length === 0) return null
-
- return (
-
- {/* Glow effect on hover */}
-
-
-
-
-
-
-
- {category.label}
-
-
-
- {categorySkills.map((skill, i) => (
-
- {skill}
-
- ))}
-
-
- )
- })}
-
-
- )}
-
- )}
-
- {/* Experience Tab */}
- {activeTab === 'experience' && experience?.length > 0 && (
-
-
-
-
-
- Work Experience
-
-
- {experience.map((exp, i) => (
-
- ))}
-
-
- )}
-
- {/* Projects Tab */}
- {activeTab === 'projects' && projects?.length > 0 && (
-
-
-
-
-
- Projects
-
-
- {projects.map((project, i) => (
-
- ))}
-
-
- )}
-
- {/* Education Tab */}
- {activeTab === 'education' && education?.length > 0 && (
-
-
-
-
-
- Education
-
-
- {education.map((edu, i) => (
-
- ))}
-
-
- )}
-
- {/* Achievements Tab */}
- {activeTab === 'achievements' && achievements?.length > 0 && (
-
-
-
- Achievements
-
-
- {achievements.map((achievement, i) => (
-
-
-
-
-
-
- {achievement.title}
-
- {achievement.date && (
-
-
- {achievement.date}
-
- )}
-
-
- {achievement.description && (
-
- {achievement.description}
-
- )}
-
-
- ))}
-
-
- )}
-
- {/* Certifications Tab */}
- {activeTab === 'certifications' && certifications?.length > 0 && (
-
-
-
- Certifications
-
-
- {certifications.map((cert, i) => (
-
- {cert.name}
- {cert.issuer}
- {cert.date && (
-
-
- {cert.date}
-
- )}
- {safeHref(cert.credentialUrl) && (
-
- View Credential
-
- )}
-
- ))}
-
-
- )}
-
- {/* Publications Tab */}
- {activeTab === 'publications' && publications?.length > 0 && (
-
-
-
-
-
- Publications
-
-
- {publications.map((pub, i) => (
-
- {pub.title}
-
- {pub.publisher} {pub.date && `• ${pub.date}`}
-
- {pub.description && (
- {pub.description}
- )}
- {safeHref(pub.url) && (
-
- Read Publication
-
- )}
-
- ))}
-
-
- )}
-
- {/* Volunteering Tab */}
- {activeTab === 'volunteering' && volunteering?.length > 0 && (
-
-
-
-
-
- Volunteering
-
-
- {volunteering.map((vol, i) => (
-
- {vol.role}
- {vol.organization}
- {vol.duration && (
-
-
- {vol.duration}
-
- )}
- {vol.description && (
- {vol.description}
- )}
-
- ))}
-
-
- )}
-
- {/* Custom Sections */}
- {activeTab.startsWith('custom-') && (
-
- {(() => {
- const customTab = tabs.find(t => t.id === activeTab)
- if (!customTab) return null
- return (
-
-
-
-
-
- {customTab.label}
-
-
- {customTab.content}
-
-
- )
- })()}
-
- )}
-
-
-
- {/* Footer - Glassy Portlify Branding or Custom Branding */}
-
-
- )
+ return
}
-export default Portfolio
+export default Portfolio
\ No newline at end of file
diff --git a/frontend/src/pages/Premium.jsx b/frontend/src/pages/Premium.jsx
index 8305974..4b033da 100644
--- a/frontend/src/pages/Premium.jsx
+++ b/frontend/src/pages/Premium.jsx
@@ -4,59 +4,17 @@ import { useUser } from '@clerk/clerk-react'
import { motion } from 'framer-motion'
import { getPremiumStatus, createPaymentOrder, verifyPayment, getCurrentUser } from '../utils/api'
import { useToast } from '../context/ToastContext'
+import { Check, Heart, Lock, Pencil, ShieldCheck, Sparkles, Star, Tag, Zap } from 'lucide-react'
+import { IconTile, InlineIcon, ICON_STROKE } from '../components/IconTile'
+import PageHeader from '../components/PageHeader'
+import { ErrorState, LoadingState } from '../components/AsyncState'
-// Premium Features
const premiumFeatures = [
- {
- icon: (
-
- ),
- title: 'Change Username',
- description: 'Update your portfolio URL anytime',
- color: 'from-blue-500 to-cyan-500'
- },
- {
- icon: (
-
- ),
- title: 'Custom Branding',
- description: 'Replace footer with your own text & link',
- color: 'from-purple-500 to-pink-500'
- },
- {
- icon: (
-
- ),
- title: 'Premium Badge',
- description: 'Show your supporter status proudly',
- color: 'from-amber-500 to-orange-500'
- },
- {
- icon: (
-
- ),
- title: 'Priority Support',
- description: 'Get faster responses to your queries',
- color: 'from-green-500 to-emerald-500'
- },
- {
- icon: (
-
- ),
- title: 'Support the Project',
- description: 'Help us build more amazing features',
- color: 'from-rose-500 to-red-500'
- }
+ { icon: Pencil, title: 'Change Username', description: 'Update your portfolio URL anytime' },
+ { icon: Tag, title: 'Custom Branding', description: 'Replace footer with your own text & link' },
+ { icon: Sparkles, title: 'Premium Badge', description: 'Show your supporter status proudly' },
+ { icon: Zap, title: 'Priority Support', description: 'Get faster responses to your queries' },
+ { icon: Heart, title: 'Support the Project', description: 'Help us build more amazing features' },
]
function Premium() {
@@ -164,7 +122,7 @@ function Premium() {
email: userData?.email || ''
},
theme: {
- color: '#6366f1'
+ color: '#5a7a9e'
},
modal: {
ondismiss: () => {
@@ -183,53 +141,29 @@ function Premium() {
}
if (loading) {
- return (
-
- )
+ return
}
if (loadError) {
return (
-
-
-
{loadError}
-
-
-
+
{ setLoading(true); window.location.reload() }}
+ />
)
}
return (
-
-
- {/* Header */}
-
- navigate('/dashboard')}
- className="p-3 rounded-xl bg-surface border border-border text-secondary hover:text-primary hover:border-indigo-500/30 transition-all"
- >
-
-
-
-
Go Premium
-
Unlock all features with a one-time payment
-
-
+
+
+
+
{/* Main Content */}
@@ -249,22 +183,15 @@ function Premium() {
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 + index * 0.08 }}
whileHover={{ x: 4 }}
- className="group relative p-5 rounded-2xl bg-surface border border-border hover:border-indigo-500/30 transition-all"
+ className="group relative p-5 rounded-2xl bg-surface hover:bg-surface-hover transition-colors"
>
- {/* Icon */}
-
- {feature.icon}
-
-
- {/* Content */}
+
{feature.title}
{isPremium && (
-
+
)}
{feature.description}
@@ -281,11 +208,11 @@ function Premium() {
transition={{ delay: 0.2 }}
className="lg:col-span-2"
>
-
+
{/* Pricing Card */}
{/* Premium gradient top bar */}
-
+
{/* Status Badge for Premium users */}
@@ -295,11 +222,9 @@ function Premium() {
animate={{ scale: 1 }}
className="mb-6"
>
-
-
-
Premium Member
+
+
+ Premium Member
)}
@@ -323,9 +248,7 @@ function Premium() {
@@ -384,16 +303,15 @@ function Premium() {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.5 }}
- className="mt-4 p-4 rounded-xl bg-indigo-500/5 border border-indigo-500/10"
+ className="mt-4 p-4 rounded-xl bg-primary-500/5 border border-primary-500/10"
>
- "Shagun" — A token of appreciation 💜
+ "Shagun" — A token of appreciation 💜
-
)
}
diff --git a/frontend/src/pages/ProfileEditor.jsx b/frontend/src/pages/ProfileEditor.jsx
index d0b5456..ed8cb5f 100644
--- a/frontend/src/pages/ProfileEditor.jsx
+++ b/frontend/src/pages/ProfileEditor.jsx
@@ -13,6 +13,10 @@ import {
Linkedin, Github, Twitter, Rocket, Sparkles,
Terminal, Layers, Database, Wrench, Cloud, MessageCircle
} from 'lucide-react'
+import { IconTile } from '../components/IconTile'
+import PageHeader from '../components/PageHeader'
+import MobileTabBar from '../components/MobileTabBar'
+import { LoadingState } from '../components/AsyncState'
function ProfileEditor() {
const navigate = useNavigate()
@@ -277,45 +281,24 @@ function ProfileEditor() {
// Show loading spinner while fetching data
if (loading) {
- return (
-
- )
+ return
}
return (
-
-
- {/* Header */}
-
- {/* Back button */}
-
-
-
-
- {isEditing ? 'Edit Your Profile' : 'Review Your Profile'}
-
-
- {isEditing
- ? 'Update your information and save changes to your portfolio.'
- : 'AI has extracted your information. Review and edit before generating your portfolio.'
- }
-
-
-
+
+
+
+
{/* Sidebar Navigation - Desktop */}
@@ -324,7 +307,7 @@ function ProfileEditor() {
animate={{ opacity: 1, x: 0 }}
className="hidden lg:block lg:w-64 flex-shrink-0"
>
-
+