Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"scripts": {
"dev": "node --watch src/index.js",
"start": "node src/index.js",
"test": "node --test test/**/*.test.js"
"test": "node scripts/run-tests.mjs"
},
"dependencies": {
"@clerk/express": "^1.0.0",
Expand Down
19 changes: 19 additions & 0 deletions backend/scripts/run-tests.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { readdirSync } from 'node:fs'
import { spawnSync } from 'node:child_process'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'

const root = join(dirname(fileURLToPath(import.meta.url)), '..')
const testDir = join(root, 'test')
const files = readdirSync(testDir)
.filter((name) => name.endsWith('.test.js'))
.map((name) => join(testDir, name))
.sort()

if (files.length === 0) {
console.error('No test files found in backend/test/')
process.exit(1)
}

const result = spawnSync(process.execPath, ['--test', ...files], { stdio: 'inherit' })
process.exit(result.status ?? 1)
6 changes: 3 additions & 3 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#6366f1" />
<meta name="msapplication-TileColor" content="#6366f1" />
<meta name="theme-color" content="#5a7a9e" />
<meta name="msapplication-TileColor" content="#5a7a9e" />

<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
Expand Down Expand Up @@ -137,7 +137,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700;800&display=swap"
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap"
rel="stylesheet">
<!-- Author / Creator Link -->
<link rel="author" href="https://techycsr.dev" />
Expand Down
4 changes: 2 additions & 2 deletions frontend/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"description": "Transform your resume into a stunning, professional portfolio in seconds with AI.",
"start_url": "/",
"display": "standalone",
"background_color": "#0f0f23",
"theme_color": "#6366f1",
"background_color": "#09090b",
"theme_color": "#5a7a9e",
"orientation": "portrait-primary",
"scope": "/",
"lang": "en",
Expand Down
46 changes: 18 additions & 28 deletions frontend/public/og-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
158 changes: 23 additions & 135 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SignIn, SignUp } from '@clerk/clerk-react'
import { ThemeProvider, useTheme } from './context/ThemeContext'
import { ToastProvider } from './context/ToastContext'
import Navbar from './components/Navbar'
import ScrollToTop from './components/ScrollToTop'
import Landing from './pages/Landing'
import UsernameSelection from './pages/UsernameSelection'
import Onboarding from './pages/Onboarding'
Expand All @@ -14,106 +15,8 @@ import Analytics from './pages/Analytics'
import Premium from './pages/Premium'
import Portfolio from './pages/Portfolio'
import ProtectedRoute from './components/ProtectedRoute'

// Clerk appearance config based on theme
const getClerkAppearance = (theme) => ({
baseTheme: theme === 'dark' ? undefined : undefined,
variables: {
colorPrimary: '#6366f1',
colorBackground: theme === 'dark' ? '#1e1e2a' : '#ffffff',
colorText: theme === 'dark' ? '#ffffff' : '#0f172a',
colorTextSecondary: theme === 'dark' ? '#a0a0b0' : '#475569',
colorInputBackground: theme === 'dark' ? '#1a1a25' : '#f1f5f9',
colorInputText: theme === 'dark' ? '#ffffff' : '#0f172a',
colorNeutral: theme === 'dark' ? '#a0a0b0' : '#475569',
borderRadius: '12px',
fontFamily: 'Inter, system-ui, sans-serif'
},
elements: {
rootBox: {
boxShadow: theme === 'dark'
? '0 25px 50px -12px rgba(0, 0, 0, 0.5)'
: '0 25px 50px -12px rgba(0, 0, 0, 0.15)'
},
card: {
backgroundColor: theme === 'dark' ? '#1e1e2a' : '#ffffff',
border: theme === 'dark' ? '1px solid rgba(255,255,255,0.08)' : '1px solid rgba(0,0,0,0.08)',
boxShadow: 'none'
},
headerTitle: {
color: theme === 'dark' ? '#ffffff' : '#0f172a'
},
headerSubtitle: {
color: theme === 'dark' ? '#a0a0b0' : '#475569'
},
socialButtonsBlockButton: {
backgroundColor: theme === 'dark' ? '#12121a' : '#f8fafc',
border: theme === 'dark' ? '1px solid rgba(255,255,255,0.1)' : '1px solid rgba(0,0,0,0.1)',
color: theme === 'dark' ? '#ffffff' : '#0f172a',
'&:hover': {
backgroundColor: theme === 'dark' ? '#1a1a25' : '#f1f5f9'
}
},
formFieldLabel: {
color: theme === 'dark' ? '#a0a0b0' : '#475569'
},
formFieldInput: {
backgroundColor: theme === 'dark' ? '#12121a' : '#f8fafc',
borderColor: theme === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)',
color: theme === 'dark' ? '#ffffff' : '#0f172a',
'&:focus': {
borderColor: '#6366f1',
boxShadow: '0 0 0 3px rgba(99, 102, 241, 0.2)'
}
},
formButtonPrimary: {
background: 'linear-gradient(135deg, #6366f1, #a855f7)',
'&:hover': {
background: 'linear-gradient(135deg, #4f46e5, #9333ea)'
}
},
footerActionLink: {
color: '#6366f1'
},
identityPreviewText: {
color: theme === 'dark' ? '#ffffff' : '#0f172a'
},
identityPreviewEditButton: {
color: '#6366f1'
},
formFieldHintText: {
color: theme === 'dark' ? '#6b6b7b' : '#94a3b8'
},
dividerLine: {
backgroundColor: theme === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'
},
dividerText: {
color: theme === 'dark' ? '#6b6b7b' : '#94a3b8'
},
userButtonPopoverCard: {
backgroundColor: theme === 'dark' ? '#1e1e2a' : '#ffffff',
border: theme === 'dark' ? '1px solid rgba(255,255,255,0.08)' : '1px solid rgba(0,0,0,0.08)'
},
userButtonPopoverActionButton: {
color: theme === 'dark' ? '#ffffff' : '#0f172a',
'&:hover': {
backgroundColor: theme === 'dark' ? '#12121a' : '#f1f5f9'
}
},
userButtonPopoverActionButtonText: {
color: theme === 'dark' ? '#ffffff' : '#0f172a'
},
userButtonPopoverActionButtonIcon: {
color: theme === 'dark' ? '#a0a0b0' : '#475569'
},
userPreviewMainIdentifier: {
color: theme === 'dark' ? '#ffffff' : '#0f172a'
},
userPreviewSecondaryIdentifier: {
color: theme === 'dark' ? '#a0a0b0' : '#475569'
}
}
})
import DashboardLayout from './components/DashboardLayout'
import { getClerkAppearance } from './utils/clerkAppearance'

// Layout wrapper that conditionally shows navbar
function AppLayout({ children }) {
Expand All @@ -133,12 +36,14 @@ function AppLayout({ children }) {

return (
<>
{/* Background orbs */}
<div className="bg-orb orb-1" />
<div className="bg-orb orb-2" />
<div className="bg-orb orb-3" />
{/* Background orbs — clipped so they never cause horizontal scroll */}
<div className="orb-container" aria-hidden="true">
<div className="bg-orb orb-1" />
<div className="bg-orb orb-2" />
<div className="bg-orb orb-3" />
</div>

<div className="min-h-screen relative">
<div className="min-h-screen relative overflow-x-clip">
{!isPortfolioPage && <Navbar />}
{children}
</div>
Expand All @@ -152,7 +57,7 @@ function SignInPage() {
const redirectUrl = location.state?.from?.pathname || '/dashboard'

return (
<div className="min-h-screen flex items-center justify-center pt-20">
<div className="min-h-screen flex items-center justify-center pt-navbar">
<SignIn
routing="path"
path="/sign-in"
Expand All @@ -168,7 +73,7 @@ function SignInPage() {
function SignUpPage() {
const { theme } = useTheme()
return (
<div className="min-h-screen flex items-center justify-center pt-20">
<div className="min-h-screen flex items-center justify-center pt-navbar">
<SignUp
routing="path"
path="/sign-up"
Expand Down Expand Up @@ -199,36 +104,18 @@ function AppRoutes() {
<Onboarding />
</ProtectedRoute>
} />
<Route path="/upload" element={
<ProtectedRoute>
<ResumeUpload />
</ProtectedRoute>
} />
<Route path="/editor" element={
<ProtectedRoute>
<ProfileEditor />
</ProtectedRoute>
} />
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
<Route path="/settings" element={
<ProtectedRoute>
<Settings />
</ProtectedRoute>
} />
<Route path="/analytics" element={
<Route element={
<ProtectedRoute>
<Analytics />
<DashboardLayout />
</ProtectedRoute>
} />
<Route path="/premium" element={
<ProtectedRoute>
<Premium />
</ProtectedRoute>
} />
}>
<Route path="/upload" element={<ResumeUpload />} />
<Route path="/editor" element={<ProfileEditor />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
<Route path="/analytics" element={<Analytics />} />
<Route path="/premium" element={<Premium />} />
</Route>

{/* Public portfolio route - must be last */}
<Route path="/:username" element={<Portfolio />} />
Expand All @@ -242,6 +129,7 @@ function App() {
<ThemeProvider>
<ToastProvider>
<Router>
<ScrollToTop />
<AppRoutes />
</Router>
</ToastProvider>
Expand Down
Loading
Loading