diff --git a/backend/package.json b/backend/package.json index a6329ba..4b454d2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -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", diff --git a/backend/scripts/run-tests.mjs b/backend/scripts/run-tests.mjs new file mode 100644 index 0000000..013fecc --- /dev/null +++ b/backend/scripts/run-tests.mjs @@ -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) \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 9706096..5bb059c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -24,8 +24,8 @@ - - + + @@ -137,7 +137,7 @@ diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg index 9301c7d..d359530 100644 --- a/frontend/public/favicon.svg +++ b/frontend/public/favicon.svg @@ -1,8 +1,8 @@ - - + + diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json index e214538..96eea35 100644 --- a/frontend/public/manifest.json +++ b/frontend/public/manifest.json @@ -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", diff --git a/frontend/public/og-image.svg b/frontend/public/og-image.svg index f411fcf..e415920 100644 --- a/frontend/public/og-image.svg +++ b/frontend/public/og-image.svg @@ -1,13 +1,13 @@ - - - + + + - - + + @@ -18,48 +18,38 @@ - - - - - + + + - - + - - P - - Portlify + Portlify - - AI-Powered Resume to Portfolio Builder + AI-Powered Resume to Portfolio Builder - - - ✨ AI Parsing + + ✨ AI Parsing - - ⚡ Instant Portfolio + + ⚡ Instant Portfolio - - 📊 Analytics + + 📊 Analytics - portlify.techycsr.dev - - Transform your resume into a stunning portfolio in seconds + Transform your resume into a stunning portfolio in seconds \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 663820a..5d3ae8d 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -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' @@ -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 }) { @@ -133,12 +36,14 @@ function AppLayout({ children }) { return ( <> - {/* Background orbs */} -
-
-
+ {/* Background orbs — clipped so they never cause horizontal scroll */} +