diff --git a/apps/web/check_output.txt b/apps/web/check_output.txt new file mode 100644 index 0000000..50621d6 Binary files /dev/null and b/apps/web/check_output.txt differ diff --git a/apps/web/package.json b/apps/web/package.json index 3601215..4214999 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -18,8 +18,15 @@ "@sveltejs/adapter-auto": "^7.0.0", "@sveltejs/kit": "^2.50.2", "@sveltejs/vite-plugin-svelte": "^6.2.4", + "@tailwindcss/vite": "^4.3.0", + "autoprefixer": "^10.5.0", + "clsx": "^2.1.1", + "lucide-svelte": "^1.0.1", + "postcss": "^8.5.14", "svelte": "^5.51.0", "svelte-check": "^4.4.2", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.0", "typescript": "^5.9.3", "vite": "^7.3.1" } diff --git a/apps/web/src/app.css b/apps/web/src/app.css index 772a760..1ed60f4 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -1,70 +1,144 @@ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'); - -/* light theme — default */ -:root { - /* Primary */ - --primary: #6366f1; - --primary-light: #818cf8; - --primary-dark: #4f46e5; - --accent: #8b5cf6; - - /* Background */ - --bg-primary: #f8fafc; - --bg-secondary: #f1f5f9; - --bg-card: #ffffff; - --bg-elevated: #e2e8f0; - - /* Text */ - --text-primary: #0f172a; - --text-secondary: #475569; - --text-muted: #94a3b8; - - /* Border */ - --border: #e2e8f0; - - /* Spacing */ - --radius: 12px; - --radius-lg: 16px; - --radius-xl: 24px; - - --theme-transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; +@import "tailwindcss"; + +@theme { + --color-primary: #7C3AED; + --color-secondary: #06B6D4; + --color-accent-pink: #EC4899; + --color-accent-blue: #3B82F6; + --color-dark-950: #030712; + --color-dark-900: #0B1020; + + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + --font-display: "Space Grotesk", sans-serif; + + --radius-xl: 1.5rem; + --radius-2xl: 2rem; + --radius-3xl: 3rem; } -/* dark theme */ -html.dark { - --bg-primary: #0f0f1a; - --bg-secondary: #1a1a2e; - --bg-card: #16213e; - --bg-elevated: #1e293b; +@layer base { + :root { + --bg-main: #f8fafc; + --bg-secondary: #ffffff; + --text-main: #0f172a; + --text-muted: #64748b; + --border-main: #e2e8f0; + --glass-bg: rgba(255, 255, 255, 0.7); + --glass-border: rgba(255, 255, 255, 0.5); + --primary-glow: rgba(124, 58, 237, 0.2); + } - --text-primary: #f8fafc; - --text-secondary: #94a3b8; - --text-muted: #64748b; + .dark { + --bg-main: #030712; + --bg-secondary: #0B1020; + --text-main: #f8fafc; + --text-muted: #94a3b8; + --border-main: #1f2937; + --glass-bg: rgba(3, 7, 18, 0.6); + --glass-border: rgba(255, 255, 255, 0.08); + --primary-glow: rgba(124, 58, 237, 0.3); + } - --border: #334155; + body { + @apply bg-(--bg-main) text-(--text-main) transition-colors duration-500 antialiased font-sans overflow-x-hidden; + } } -* { - margin: 0; - padding: 0; - box-sizing: border-box; +@utility glass { + backdrop-filter: blur(20px) saturate(180%); + background-color: var(--glass-bg); + border: 1px solid var(--glass-border); } -body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background-color: var(--bg-primary); - color: var(--text-primary); - transition: var(--theme-transition); - -webkit-font-smoothing: antialiased; - min-height: 100vh; +@utility glass-morphic { + @apply glass shadow-[0_8px_32px_0_rgba(31,38,135,0.07)]; } -a { - color: var(--primary); - text-decoration: none; - transition: color 0.2s; +@utility text-gradient { + @apply bg-clip-text text-transparent bg-linear-to-r from-primary via-secondary to-accent-pink; } -a:hover { - color: var(--primary-dark); +@layer components { + .mesh-bg { + @apply absolute inset-0 -z-20 opacity-40; + background-image: + radial-gradient(at 0% 0%, rgba(124, 58, 237, 0.15) 0px, transparent 50%), + radial-gradient(at 100% 0%, rgba(6, 182, 212, 0.15) 0px, transparent 50%), + radial-gradient(at 100% 100%, rgba(236, 72, 153, 0.15) 0px, transparent 50%), + radial-gradient(at 0% 100%, rgba(59, 130, 246, 0.15) 0px, transparent 50%); + filter: blur(100px); + animation: mesh 20s ease infinite; + } + + .card-cinematic { + @apply glass-morphic rounded-3xl p-8 transition-all duration-700 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/20 relative overflow-hidden; + } + + .btn-premium-primary { + @apply relative inline-flex items-center justify-center rounded-2xl font-black uppercase tracking-widest text-white transition-all duration-500 overflow-hidden; + background: linear-gradient(135deg, var(--color-primary), var(--color-accent-pink)); + box-shadow: 0 4px 15px rgba(124, 58, 237, 0.4); + } + .btn-premium-primary:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: 0 8px 25px rgba(124, 58, 237, 0.6); + } + + .btn-premium-secondary { + @apply relative inline-flex items-center justify-center rounded-2xl font-black uppercase tracking-widest transition-all duration-500 overflow-hidden; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(124, 58, 237, 0.3); + color: var(--color-primary); + backdrop-filter: blur(10px); + } + .btn-premium-secondary:hover { + transform: translateY(-2px) scale(1.02); + background: rgba(124, 58, 237, 0.1); + border-color: rgba(124, 58, 237, 0.6); + } } + +@layer utilities { + .animate-mesh { + animation: mesh 20s ease infinite; + } + + .animate-float { + animation: float 6s ease-in-out infinite; + } + + .animate-pulse-glow { + animation: pulse-glow 4s ease-in-out infinite; + } +} + +@keyframes mesh { + 0%, 100% { background-position: 0% 50%; transform: scale(1); } + 50% { background-position: 100% 50%; transform: scale(1.1); } +} + +@keyframes float { + 0%, 100% { transform: translateY(0) rotate(0deg); } + 50% { transform: translateY(-20px) rotate(2deg); } +} + +@keyframes pulse-glow { + 0%, 100% { box-shadow: 0 0 20px rgba(124, 58, 237, 0.2); } + 50% { box-shadow: 0 0 40px rgba(124, 58, 237, 0.4); } +} + +/* Custom Scrollbar */ +::-webkit-scrollbar { + width: 6px; +} +::-webkit-scrollbar-track { + @apply bg-transparent; +} +::-webkit-scrollbar-thumb { + @apply bg-primary/30 rounded-full hover:bg-primary/50 transition-colors; +} + +/* Fluid Typography Helpers */ +.text-fluid-h1 { font-size: clamp(2.5rem, 8vw, 6rem); } +.text-fluid-h2 { font-size: clamp(2rem, 5vw, 4rem); } +.text-fluid-p { font-size: clamp(1rem, 2vw, 1.25rem); } diff --git a/apps/web/src/app.d.ts b/apps/web/src/app.d.ts index da08e6d..169339f 100644 --- a/apps/web/src/app.d.ts +++ b/apps/web/src/app.d.ts @@ -3,7 +3,12 @@ declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + user?: { + id: string; + username: string; + } + } // interface PageData {} // interface PageState {} // interface Platform {} diff --git a/apps/web/src/hooks.server.ts b/apps/web/src/hooks.server.ts new file mode 100644 index 0000000..c46b375 --- /dev/null +++ b/apps/web/src/hooks.server.ts @@ -0,0 +1,26 @@ +import type { Handle } from '@sveltejs/kit'; + +export const handle: Handle = async ({ event, resolve }) => { + const token = event.cookies.get('token'); + + if (token) { + try { + // Call backend to verify token and get user info + const res = await event.fetch('http://localhost:3000/api/profiles/me'); + + if (res.ok) { + event.locals.user = await res.json(); + } else { + event.cookies.delete('token', { path: '/' }); + event.locals.user = undefined; + } + } catch (err) { + console.error('Auth verification failed:', err); + // Optional: fallback to mock for UI development if backend is not running + // event.locals.user = { id: 'mock-id', username: 'dev-user' }; + } + } + + const response = await resolve(event); + return response; +}; diff --git a/apps/web/src/lib/api.ts b/apps/web/src/lib/api.ts new file mode 100644 index 0000000..0b19c0a --- /dev/null +++ b/apps/web/src/lib/api.ts @@ -0,0 +1,25 @@ +const BASE_URL = 'http://localhost:3000'; + +export async function fetchWithAuth(path: string, options: RequestInit = {}) { + // In SvelteKit, we should handle cookies properly + // For client-side calls, the browser sends the cookie automatically + const res = await fetch(`${BASE_URL}${path}`, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }); + + if (!res.ok) { + throw new Error(`API Error: ${res.statusText}`); + } + + return res.json(); +} + +export const api = { + getMe: () => fetchWithAuth('/api/profiles/me'), + getCards: () => fetchWithAuth('/api/cards'), + getProfiles: (username: string) => fetchWithAuth(`/api/u/${username}`), +}; diff --git a/apps/web/src/lib/components/BrandIcon.svelte b/apps/web/src/lib/components/BrandIcon.svelte new file mode 100644 index 0000000..eaccab4 --- /dev/null +++ b/apps/web/src/lib/components/BrandIcon.svelte @@ -0,0 +1,28 @@ + + + + + diff --git a/apps/web/src/lib/components/Features.svelte b/apps/web/src/lib/components/Features.svelte new file mode 100644 index 0000000..fdc6241 --- /dev/null +++ b/apps/web/src/lib/components/Features.svelte @@ -0,0 +1,140 @@ + + +
+ +
+
+ +
+
+
+ Features +
+

+ Designed for the
+ Modern Developer +

+

+ Everything you need to showcase your digital presence with zero friction and maximum impact. +

+
+ +
+ {#each features as feature, i} + {@const Icon = feature.icon} + +
+ +
+ +
+
+ +
+ +

+ {feature.title} + +

+

+ {feature.description} +

+ +
+ Learn More + +
+
+
+
+ {/each} +
+
+
+ + diff --git a/apps/web/src/lib/components/Footer.svelte b/apps/web/src/lib/components/Footer.svelte new file mode 100644 index 0000000..908e46e --- /dev/null +++ b/apps/web/src/lib/components/Footer.svelte @@ -0,0 +1,79 @@ + + + + + diff --git a/apps/web/src/lib/components/Hero.svelte b/apps/web/src/lib/components/Hero.svelte new file mode 100644 index 0000000..bcbe7e4 --- /dev/null +++ b/apps/web/src/lib/components/Hero.svelte @@ -0,0 +1,189 @@ + + +
+ +
+ + +
+ +
+
+ +
+ {#if isMounted} +
+ + + The AI Identity Revolution + +
+ +

+ DevCard AI.
+ Intelligent
+ Identity. +

+ +

+ Aggregate your entire professional existence. Use AI to generate recruiter-ready bios, extract technical skills from code, and optimize your visibility for the future of work. +

+ + + +
+
+
+ +
+
+ 95% + Hiring Match +
+
+
+
+ +
+
+ AI + Optimization +
+
+
+ {/if} +
+ + +
+ {#if isMounted} +
+ +
+ +
+ +
+
+
AI
+
+

Identity Score

+

98.4

+
+
+ +
+
+ Profile +
+
+

John Developer

+
+ +

Optimized by AI

+
+
+ +
+
+
+
+ +
+

Smart Bio Generated

+
+
+ +
+
+
+
+
+ +
+

Skills Extracted (12)

+
+
+ +
+
+
+ +
+
+
+ +
+

Handshake Active

+
+
+
+ + +
+
+ +
+

Top 1% Talent

+
+
+ + +
+ {/if} +
+
+
+
+ + diff --git a/apps/web/src/lib/components/Navbar.svelte b/apps/web/src/lib/components/Navbar.svelte new file mode 100644 index 0000000..5eb3a75 --- /dev/null +++ b/apps/web/src/lib/components/Navbar.svelte @@ -0,0 +1,186 @@ + + + + + diff --git a/apps/web/src/routes/+layout.server.ts b/apps/web/src/routes/+layout.server.ts new file mode 100644 index 0000000..a4329a6 --- /dev/null +++ b/apps/web/src/routes/+layout.server.ts @@ -0,0 +1,7 @@ +import type { LayoutServerLoad } from './$types'; + +export const load: LayoutServerLoad = ({ locals }) => { + return { + user: locals.user + }; +}; diff --git a/apps/web/src/routes/+layout.svelte b/apps/web/src/routes/+layout.svelte index ac6dd12..c3d7275 100644 --- a/apps/web/src/routes/+layout.svelte +++ b/apps/web/src/routes/+layout.svelte @@ -1,11 +1,18 @@ - + -{@render children()} +
+
+ +
+ {@render children()} +
+
diff --git a/apps/web/src/routes/+page.svelte b/apps/web/src/routes/+page.svelte index 363a491..52c5855 100644 --- a/apps/web/src/routes/+page.svelte +++ b/apps/web/src/routes/+page.svelte @@ -1,314 +1,146 @@ - - DevCard — One Tap. Every Profile. Every Platform. + DevCard — Premium Developer Identity Platform -
-
- - -

DevCard

-

One Tap. Every Profile. Every Platform.

-

- Stop sharing LinkedIn, GitHub, and Twitter one by one.
- DevCard puts every profile in one shareable QR code. -

- -
- -
-
-
🔗
-

One Card, All Profiles

-

- GitHub, LinkedIn, Twitter/X, Devfolio, GitLab, LeetCode, and 10+ more — - all in one card. -

-
-
-
-

Hybrid Follow Engine

-

- Follow on GitHub silently via API. Connect on LinkedIn with one tap in - WebView. No app switching. -

-
-
-
💳
-

Context Cards

-

- Share your "Professional" card at conferences and "Hackathon" card at - hack events. Same profiles, different contexts. -

-
-
-
📱
-

QR + AirDrop

-

- Generate a QR code or share via AirDrop-style link. Works even if the - receiver doesn't have the app. -

-
-
-
🔒
-

Privacy First

-

- No data monetization. No tracking. Apache 2.0 licensed. You own your - data. -

-
-
-
🌍
-

Open Source

-

- Community-driven development. Contribute, self-host, or extend with your - own platforms. -

-
-
- - -
+
+ + +
+ + +
+
+
+
+ Process +
+

+ Stop the manual
+ Search & Connect dance. +

+

+ DevCard streamlines professional networking by bridging the gap between physical interaction and digital connection. +

+
+ +
+
+
+
+
+
+ 01 +

Connect Your Profiles

+
+

+ Link your GitHub, LinkedIn, Twitter, and 15+ other platforms in seconds. Our API handles the synchronization so your data is always up-to-date. +

+
+
+ +
+
+
+
+ 02 +

Generate Your Card

+
+

+ Customize your card with professional, dark mode, or hackathon-focused layouts. Choose which profiles to share based on the context of your meeting. +

+
+
+ +
+
+
+
+ 03 +

One Tap to Follow

+
+

+ Show your QR code. Your peer scans it and connects with you on everything instantly. No typing, no typos, no friction. +

+
+
+
+ +
+
+ Dashboard Preview + + +
+ +
+
+
+
+
+ + + + +
+
+
+
+
+ +

Ready to upgrade your
developer networking?

+

+ Join the community of developers who are streamlining their social presence with DevCard. +

+ + +
+
+
+
+ +
diff --git a/apps/web/src/routes/analytics/+page.svelte b/apps/web/src/routes/analytics/+page.svelte new file mode 100644 index 0000000..db585ee --- /dev/null +++ b/apps/web/src/routes/analytics/+page.svelte @@ -0,0 +1,74 @@ + + + + Analytics — DevCard AI + + + + +
+
+ +
+
+
+ Identity Analytics +
+

+ Track your
+ Digital Influence. +

+

+ Deep insights into how your identity is performing across the global developer ecosystem. +

+
+ +
+ {#each stats as stat, i} +
+
+ +
+

{stat.label}

+

{stat.value}

+
+ {/each} +
+ +
+
+
+ +
+

Interactive Charts Loading...

+

+ Connect your production accounts to unlock real-time time-series data and audience demographic analysis. +

+ +
+
+
+
+ +