feat(landing): add ProfilePage styling and update App routes
Add ProfilePage CSS and update related page components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
205fc67f24
commit
6a1e4aaa75
4 changed files with 251 additions and 14 deletions
|
|
@ -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() {
|
|||
<Route path={RoutePatterns.shopIdeas} element={<ShopIdeasPage />} />
|
||||
<Route path={RoutePatterns.shopCheckout} element={<ShopCheckoutPage />} />
|
||||
|
||||
{/* Account */}
|
||||
<Route path={RoutePatterns.profile} element={<ProfilePage />} />
|
||||
|
||||
{/* CTA Modals */}
|
||||
<Route path={RoutePatterns.register} element={<HomePage />} />
|
||||
<Route path={RoutePatterns.invest} element={<HomePage />} />
|
||||
|
|
|
|||
226
features/landing/frontend/src/pages/ProfilePage.css
Normal file
226
features/landing/frontend/src/pages/ProfilePage.css
Normal file
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<HTMLFormElement>(null)
|
||||
|
||||
const { items, totalPrice, totalVotes, clearCart } = useCart()
|
||||
const { isAuthenticated } = useDevUser()
|
||||
|
||||
const [currentStep, setCurrentStep] = useState<CheckoutStep>('review')
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [formData, setFormData] = useState<AccountFormData>({
|
||||
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 = () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue