From 6a1e4aaa754541ba3720ff1ebbb79d6b207f8d17 Mon Sep 17 00:00:00 2001 From: Quinn Ftw Date: Sun, 28 Dec 2025 17:49:44 -0800 Subject: [PATCH] feat(landing): add ProfilePage styling and update App routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ProfilePage CSS and update related page components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- features/landing/frontend/src/App.tsx | 4 + .../frontend/src/pages/ProfilePage.css | 226 ++++++++++++++++++ .../frontend/src/pages/ProfilePage.tsx | 2 - .../src/pages/shop/ShopCheckoutPage.tsx | 33 ++- 4 files changed, 251 insertions(+), 14 deletions(-) create mode 100644 features/landing/frontend/src/pages/ProfilePage.css diff --git a/features/landing/frontend/src/App.tsx b/features/landing/frontend/src/App.tsx index dc019a9b9..1ba5127fe 100644 --- a/features/landing/frontend/src/App.tsx +++ b/features/landing/frontend/src/App.tsx @@ -11,6 +11,7 @@ import AboutPage from './pages/about/AboutPage' import { AppsGallery, AppPage } from './pages/apps' import HomePage from './pages/HomePage' import { TermsPage, PrivacyPage } from './pages/legal' +import ProfilePage from './pages/ProfilePage' import { ShopGiftCardsPage, ShopApparelPage, ShopIdeasPage, ShopCheckoutPage } from './pages/shop' import { RoadmapPage } from './pages/roadmap' import ValuesPage from './pages/values/ValuesPage' @@ -67,6 +68,9 @@ function AppRoutes() { } /> } /> + {/* Account */} + } /> + {/* CTA Modals */} } /> } /> diff --git a/features/landing/frontend/src/pages/ProfilePage.css b/features/landing/frontend/src/pages/ProfilePage.css new file mode 100644 index 000000000..7cbb265a4 --- /dev/null +++ b/features/landing/frontend/src/pages/ProfilePage.css @@ -0,0 +1,226 @@ +/* Profile Page Styles */ + +.profile-page { + min-height: 100vh; + padding: 2rem; + background: linear-gradient(135deg, rgba(15, 15, 20, 1) 0%, rgba(25, 25, 35, 1) 100%); +} + +.profile-container { + max-width: 640px; + margin: 0 auto; +} + +/* Header */ +.profile-header { + text-align: center; + margin-bottom: 2rem; +} + +.profile-header h1 { + font-size: 2rem; + font-weight: 700; + color: #fff; + margin: 0 0 0.5rem 0; +} + +.profile-subtitle { + color: rgba(255, 255, 255, 0.6); + font-size: 1rem; + margin: 0; +} + +/* Sections */ +.profile-current, +.profile-types { + margin-bottom: 2rem; +} + +.profile-current h2, +.profile-types h2 { + font-size: 1rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.8); + margin: 0 0 1rem 0; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.profile-types-hint { + font-size: 0.875rem; + color: rgba(255, 255, 255, 0.5); + margin: 0 0 1rem 0; +} + +/* Type Card */ +.profile-type-card { + display: flex; + align-items: center; + gap: 1rem; + padding: 1rem 1.25rem; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 12px; + cursor: pointer; + transition: all 0.2s ease; + text-align: left; + width: 100%; +} + +.profile-type-card:hover:not(:disabled) { + background: rgba(255, 255, 255, 0.06); + border-color: var(--type-color, rgba(255, 255, 255, 0.15)); + transform: translateY(-1px); +} + +.profile-type-card:disabled { + cursor: default; +} + +.profile-type-card--current, +.profile-type-card--active { + background: color-mix(in srgb, var(--type-color) 10%, transparent); + border-color: color-mix(in srgb, var(--type-color) 40%, transparent); +} + +.profile-type-icon { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + background: color-mix(in srgb, var(--type-color) 15%, transparent); + border-radius: 12px; + color: var(--type-color); + flex-shrink: 0; +} + +.profile-type-info { + flex: 1; + min-width: 0; +} + +.profile-type-label { + display: block; + font-size: 1rem; + font-weight: 600; + color: #fff; + margin-bottom: 0.25rem; +} + +.profile-type-description { + display: block; + font-size: 0.875rem; + color: rgba(255, 255, 255, 0.5); +} + +.profile-type-badge { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.75rem; + background: color-mix(in srgb, var(--type-color) 20%, transparent); + border-radius: 999px; + font-size: 0.75rem; + font-weight: 600; + color: var(--type-color); + flex-shrink: 0; +} + +/* Types Grid */ +.profile-types-grid { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +/* Suggestion Banner */ +.profile-suggestion { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1rem 1.25rem; + background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(139, 92, 246, 0.1)); + border: 1px solid rgba(168, 85, 247, 0.3); + border-radius: 12px; + margin-bottom: 2rem; +} + +.profile-suggestion-content { + display: flex; + align-items: center; + gap: 0.75rem; + color: rgba(255, 255, 255, 0.9); + font-size: 0.9375rem; +} + +.profile-suggestion-content svg { + color: #a855f7; + flex-shrink: 0; +} + +.profile-suggestion-button { + padding: 0.5rem 1rem; + background: #a855f7; + border: none; + border-radius: 8px; + color: #fff; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.profile-suggestion-button:hover { + background: #9333ea; + transform: translateY(-1px); +} + +/* Footer */ +.profile-footer { + margin-top: 3rem; + padding-top: 1.5rem; + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.profile-dev-notice { + display: flex; + align-items: center; + gap: 0.75rem; + font-size: 0.8125rem; + color: rgba(255, 255, 255, 0.4); +} + +.profile-dev-badge { + background: linear-gradient(135deg, #f59e0b, #d97706); + color: #000; + font-size: 0.625rem; + font-weight: 700; + padding: 0.125rem 0.375rem; + border-radius: 4px; + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; +} + +/* Responsive */ +@media (max-width: 640px) { + .profile-page { + padding: 1rem; + } + + .profile-suggestion { + flex-direction: column; + text-align: center; + } + + .profile-suggestion-content { + flex-direction: column; + } + + .profile-suggestion-button { + width: 100%; + } +} diff --git a/features/landing/frontend/src/pages/ProfilePage.tsx b/features/landing/frontend/src/pages/ProfilePage.tsx index 71cb39c3c..17403d1d9 100644 --- a/features/landing/frontend/src/pages/ProfilePage.tsx +++ b/features/landing/frontend/src/pages/ProfilePage.tsx @@ -7,7 +7,6 @@ import { useEffect } from 'react' import { useNavigate, useSearchParams } from 'react-router-dom' -import { useTranslation } from 'react-i18next' import { User, Shield, Heart, Gem, UserPlus, Check } from 'lucide-react' import { useSoundEngine } from '@ui/effects-sound' @@ -64,7 +63,6 @@ function mapAddTypeToDevUserType(addType: string | null): DevUserType | null { } export default function ProfilePage() { - const { t } = useTranslation('common') const navigate = useNavigate() const [searchParams] = useSearchParams() const playSound = useSoundEngine() diff --git a/features/landing/frontend/src/pages/shop/ShopCheckoutPage.tsx b/features/landing/frontend/src/pages/shop/ShopCheckoutPage.tsx index ef82404ed..44e476ecc 100644 --- a/features/landing/frontend/src/pages/shop/ShopCheckoutPage.tsx +++ b/features/landing/frontend/src/pages/shop/ShopCheckoutPage.tsx @@ -14,7 +14,7 @@ import { } from 'lucide-react' import toast from 'react-hot-toast' -import { useCart, type CartItem } from '../../contexts' +import { useCart, useDevUser, type CartItem } from '../../contexts' import SEOHead from '../../components/SEOHead' import AIBackground from '../../components/AIBackground' import { Routes } from '../../routes' @@ -40,23 +40,31 @@ export default function ShopCheckoutPage() { const formRef = useRef(null) const { items, totalPrice, totalVotes, clearCart } = useCart() + const { isAuthenticated } = useDevUser() const [currentStep, setCurrentStep] = useState('review') const [isSubmitting, setIsSubmitting] = useState(false) const [formData, setFormData] = useState({ - email: '', + email: isAuthenticated ? 'dev@lilith.local' : '', password: '', confirmPassword: '', - name: '', - agreedToTerms: false, + name: isAuthenticated ? 'Dev User' : '', + agreedToTerms: isAuthenticated, // Pre-agreed for authenticated users }) - const steps: { id: CheckoutStep; label: string }[] = [ - { id: 'review', label: 'Review Cart' }, - { id: 'account', label: 'Create Account' }, - { id: 'payment', label: 'Payment' }, - { id: 'complete', label: 'Complete' }, - ] + // Authenticated users skip the account step + const steps: { id: CheckoutStep; label: string }[] = isAuthenticated + ? [ + { id: 'review', label: 'Review Cart' }, + { id: 'payment', label: 'Payment' }, + { id: 'complete', label: 'Complete' }, + ] + : [ + { id: 'review', label: 'Review Cart' }, + { id: 'account', label: 'Create Account' }, + { id: 'payment', label: 'Payment' }, + { id: 'complete', label: 'Complete' }, + ] const currentStepIndex = steps.findIndex((s) => s.id === currentStep) @@ -92,13 +100,14 @@ export default function ShopCheckoutPage() { return true } - const handleContinueToAccount = () => { + const handleContinueFromReview = () => { if (items.length === 0) { toast.error('Your cart is empty') return } playSound('button-click') - setCurrentStep('account') + // Authenticated users skip account step, go directly to payment + setCurrentStep(isAuthenticated ? 'payment' : 'account') } const handleContinueToPayment = () => {