Refactor UI components and styles for improved consistency and aesthetics

This commit is contained in:
M1ngdaXie
2026-02-08 12:32:02 -08:00
parent 81855a144e
commit 02908171be
17 changed files with 1024 additions and 832 deletions

View File

@@ -6,6 +6,7 @@ import UserList from "../components/Presence/UserList.tsx";
import ShareModal from "../components/Share/ShareModal.tsx";
import VersionHistoryPanel from "../components/VersionHistory/VersionHistoryPanel.tsx";
import { useYjsDocument } from "../hooks/useYjsDocument.ts";
import { Eye } from "lucide-react";
const EditorPage = () => {
const { id } = useParams<{ id: string }>();
@@ -27,14 +28,11 @@ const EditorPage = () => {
<button onClick={() => navigate("/")}> Back to Home</button>
<div className="header-actions">
{permission !== "edit" && permission !== null && (
<div className="view-only-badge" style={{ display: 'flex', alignItems: 'center', gap: '4px', padding: '4px 12px', backgroundColor: '#f0f0f0', borderRadius: '4px', fontSize: '14px' }}>
<span>👁</span>
<div className="view-only-badge">
<Eye className="view-only-icon" />
<span>View only</span>
</div>
)}
<div className="sync-status">
{synced ? "✓ Synced" : "⟳ Syncing..."}
</div>
{!shareToken && (
<button className="share-btn" onClick={() => setShowShareModal(true)}>
Share

View File

@@ -6,8 +6,8 @@ import { documentsApi } from '@/api/document';
import Navbar from '@/components/Navbar';
import { DocumentCard } from '@/components/Home/DocumentCard';
import { CreateButton } from '@/components/Home/CreateButton';
import FloatingGem from '@/components/PixelSprites/FloatingGem';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import PixelIcon from '@/components/PixelIcon/PixelIcon';
const Home = () => {
const { user } = useAuth();
@@ -64,8 +64,8 @@ const Home = () => {
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-pixel-bg-light">
<div className="font-pixel text-pixel-purple-bright animate-pixel-bounce">
<div className="min-h-screen flex items-center justify-center bg-background">
<div className="text-brand text-base font-medium">
Loading...
</div>
</div>
@@ -75,15 +75,11 @@ const Home = () => {
return (
<>
<Navbar />
<div className="max-w-7xl mx-auto px-8 py-12 relative min-h-screen bg-pixel-bg-light">
{/* Decorative floating gems */}
<FloatingGem position={{ top: '20px', right: '40px' }} delay={0} size={40} />
<FloatingGem position={{ top: '60px', left: '60px' }} delay={1.5} size={32} />
<FloatingGem position={{ bottom: '100px', right: '100px' }} delay={3} size={36} />
<div className="max-w-7xl mx-auto px-8 py-12 relative min-h-screen bg-background">
{/* Page Header */}
<div className="mb-12">
<h1 className="font-pixel text-4xl text-pixel-purple-bright mb-6 tracking-wide">
<h1 className="font-display text-3xl text-text-primary mb-4">
My Workspace
</h1>
@@ -109,10 +105,10 @@ const Home = () => {
{/* Tabbed Interface */}
<Tabs defaultValue="owned" className="w-full">
<TabsList className="
bg-pixel-panel
border-[3px]
border-pixel-outline
shadow-pixel-sm
bg-surface-muted
border
border-border
shadow-soft
p-1
mb-8
">
@@ -121,9 +117,9 @@ const Home = () => {
className="
font-sans
font-semibold
data-[state=active]:bg-pixel-cyan-bright
data-[state=active]:text-white
data-[state=active]:shadow-pixel-sm
data-[state=active]:bg-surface
data-[state=active]:text-text-primary
data-[state=active]:shadow-soft
transition-all
duration-100
"
@@ -135,9 +131,9 @@ const Home = () => {
className="
font-sans
font-semibold
data-[state=active]:bg-pixel-cyan-bright
data-[state=active]:text-white
data-[state=active]:shadow-pixel-sm
data-[state=active]:bg-surface
data-[state=active]:text-text-primary
data-[state=active]:shadow-soft
transition-all
duration-100
"
@@ -150,9 +146,10 @@ const Home = () => {
<TabsContent value="owned">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{ownedDocuments.length === 0 ? (
<p className="col-span-full text-center text-pixel-text-muted font-sans py-12">
No documents yet. Create one to get started!
</p>
<div className="col-span-full flex flex-col items-center gap-3 text-text-muted font-sans py-12">
<PixelIcon name="gem" size={20} color="hsl(var(--brand-teal))" />
<p>No documents yet. Create one to get started!</p>
</div>
) : (
ownedDocuments.map((doc) => (
<DocumentCard
@@ -170,9 +167,10 @@ const Home = () => {
<TabsContent value="shared">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{sharedDocuments.length === 0 ? (
<p className="col-span-full text-center text-pixel-text-muted font-sans py-12">
No shared documents yet.
</p>
<div className="col-span-full flex flex-col items-center gap-3 text-text-muted font-sans py-12">
<PixelIcon name="gem" size={20} color="hsl(var(--brand-teal))" />
<p>No shared documents yet.</p>
</div>
) : (
sharedDocuments.map((doc) => (
<DocumentCard

View File

@@ -24,9 +24,6 @@ const KanbanPage = () => {
<div className="page-header">
<button onClick={() => navigate("/")}> Back to Home</button>
<div className="header-actions">
<div className="sync-status">
{synced ? "✓ Synced" : "⟳ Syncing..."}
</div>
{!shareToken && (
<button className="share-btn" onClick={() => setShowShareModal(true)}>
Share

View File

@@ -2,7 +2,8 @@
.landing-page {
min-height: 100vh;
overflow-x: hidden;
color: hsl(var(--text-primary));
background: hsl(var(--background));
}
/* ========================================
@@ -10,248 +11,313 @@
======================================== */
.landing-hero {
min-height: 100vh;
min-height: 90vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
padding: 2rem;
/* Animated gradient background */
background: linear-gradient(
135deg,
var(--pixel-purple-deep) 0%,
var(--pixel-purple-bright) 40%,
var(--pixel-pink-vibrant) 100%
);
background-size: 200% 200%;
animation: gradient-shift 12s ease infinite;
padding: 6rem 2rem 5rem;
background: var(--gradient-hero);
}
@keyframes gradient-shift {
0%, 100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
.hero-gem svg {
opacity: 0.18;
filter: drop-shadow(0 10px 20px rgba(15, 23, 42, 0.2));
}
.hero-grid {
width: 100%;
max-width: 1200px;
margin: 0 auto;
display: grid;
gap: 3rem;
align-items: center;
}
.hero-content {
text-align: center;
z-index: 10;
max-width: 800px;
text-align: left;
}
.hero-logo {
display: flex;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-bottom: 2rem;
gap: 12px;
padding: 0.4rem 0.85rem;
border-radius: 999px;
background: hsl(var(--surface));
border: 1px solid hsl(var(--border));
box-shadow: var(--shadow-sm);
margin-bottom: 1.5rem;
}
.hero-brand {
font-size: 3rem;
font-weight: 800;
color: var(--pixel-white);
text-shadow:
4px 4px 0 var(--pixel-shadow-dark),
-1px -1px 0 var(--pixel-shadow-dark),
1px -1px 0 var(--pixel-shadow-dark),
-1px 1px 0 var(--pixel-shadow-dark);
margin: 0;
letter-spacing: -1px;
font-size: 0.95rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: hsl(var(--text-secondary));
}
.hero-headline {
font-size: 2.5rem;
font-size: 2.75rem;
font-weight: 700;
color: var(--pixel-white);
margin: 0 0 1.5rem 0;
text-shadow: 2px 2px 0 var(--pixel-shadow-dark);
line-height: 1.2;
color: hsl(var(--text-primary));
margin: 0 0 1.25rem 0;
line-height: 1.1;
}
.hero-tagline {
font-size: 1.25rem;
color: var(--pixel-bg-light);
margin: 0 0 3rem 0;
line-height: 1.6;
opacity: 0.95;
font-size: 1.1rem;
color: hsl(var(--text-secondary));
margin: 0 0 2rem 0;
line-height: 1.7;
}
.hero-login-buttons {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
}
.hero-scroll-hint {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
color: var(--pixel-white);
opacity: 0.6;
animation: bounce-hint 2s ease-in-out infinite;
.hero-note {
font-size: 0.9rem;
color: hsl(var(--text-muted));
margin: 0;
}
@keyframes bounce-hint {
0%, 100% {
transform: translateX(-50%) translateY(0);
}
50% {
transform: translateX(-50%) translateY(10px);
}
.provider-buttons {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
/* ========================================
Login Buttons
======================================== */
.landing-login-button {
display: flex;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 1rem 2rem;
gap: 10px;
padding: 0.9rem 1.4rem;
font-size: 1rem;
font-weight: 600;
border: 3px solid var(--pixel-outline);
border: 1px solid hsl(var(--border));
border-radius: var(--radius-md);
background: hsl(var(--surface));
color: hsl(var(--text-primary));
cursor: pointer;
transition: transform 0.05s ease, box-shadow 0.05s ease;
min-width: 260px;
box-shadow: var(--shadow-sm);
transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.landing-login-button.google {
background: var(--pixel-white);
color: var(--pixel-text-primary);
box-shadow: 4px 4px 0 var(--pixel-shadow-dark);
.landing-login-button:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.landing-login-button.google:hover {
transform: translate(-2px, -2px);
box-shadow: 6px 6px 0 var(--pixel-shadow-dark);
background: var(--pixel-panel);
.landing-login-button.primary {
background: var(--gradient-accent);
color: white;
border: none;
gap: 12px;
}
.landing-login-button.google:active {
transform: translate(2px, 2px);
box-shadow: 2px 2px 0 var(--pixel-shadow-dark);
.landing-login-button.primary:hover {
filter: brightness(0.98);
}
.landing-login-button.github {
background: var(--pixel-bg-dark);
color: var(--pixel-white);
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.5);
}
.landing-login-button.github:hover {
transform: translate(-2px, -2px);
box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.5);
background: var(--pixel-bg-medium);
}
.landing-login-button.github:active {
transform: translate(2px, 2px);
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.5);
.landing-login-button.provider {
background: hsl(var(--surface));
}
.landing-login-button.large {
padding: 1.25rem 2.5rem;
font-size: 1.125rem;
min-width: 300px;
padding: 1rem 2rem;
font-size: 1.05rem;
}
.oauth-icon {
flex-shrink: 0;
}
.hero-mock {
background: hsl(var(--surface));
border: 1px solid hsl(var(--border));
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
overflow: hidden;
}
.mock-topbar {
display: flex;
gap: 6px;
padding: 12px 16px;
border-bottom: 1px solid hsl(var(--border));
background: hsl(var(--surface-muted));
}
.mock-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: hsl(var(--border));
}
.mock-body {
padding: 20px 22px 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.mock-tabs {
display: flex;
gap: 12px;
font-size: 0.85rem;
color: hsl(var(--text-muted));
}
.mock-tab {
padding-bottom: 6px;
border-bottom: 2px solid transparent;
}
.mock-tab.active {
color: hsl(var(--text-primary));
border-bottom-color: hsl(var(--primary));
font-weight: 600;
}
.mock-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.mock-card {
background: hsl(var(--surface-muted));
border-radius: var(--radius-md);
padding: 14px;
border: 1px solid hsl(var(--border));
}
.mock-line {
height: 8px;
background: hsl(var(--border));
border-radius: 999px;
margin-bottom: 8px;
}
.mock-line.wide {
width: 90%;
}
.mock-line.short {
width: 55%;
margin-bottom: 0;
}
.mock-rows {
display: flex;
flex-direction: column;
gap: 10px;
}
.mock-row {
display: grid;
grid-template-columns: 24px 1fr 80px;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: var(--radius-md);
border: 1px solid hsl(var(--border));
}
.mock-pill {
width: 18px;
height: 18px;
border-radius: 999px;
background: hsl(var(--secondary));
}
/* ========================================
Features Section
======================================== */
.landing-features {
padding: 6rem 2rem;
background: var(--pixel-bg-light);
position: relative;
padding: 5rem 2rem;
background: hsl(var(--background));
}
.section-divider {
display: flex;
align-items: center;
gap: 12px;
padding: 0 2rem;
background: hsl(var(--background));
max-width: 1200px;
margin: 0 auto;
height: 32px;
}
.divider-line {
flex: 1;
height: 1px;
background: hsl(var(--border));
}
.section-title {
text-align: center;
font-size: 2.5rem;
font-size: 2.25rem;
font-weight: 700;
color: var(--pixel-text-primary);
margin: 0 0 4rem 0;
text-shadow: 2px 2px 0 var(--pixel-white);
color: hsl(var(--text-primary));
margin: 0 0 3rem 0;
}
.features-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
gap: 1.75rem;
max-width: 1200px;
margin: 0 auto;
}
.feature-card {
background: var(--pixel-white);
padding: 2.5rem 2rem;
border: 3px solid var(--pixel-outline);
box-shadow:
0 0 0 3px var(--pixel-outline),
6px 6px 0 var(--pixel-shadow-dark),
6px 6px 0 3px var(--pixel-outline);
text-align: center;
transition: transform 0.1s ease, box-shadow 0.1s ease;
opacity: 0;
animation: fade-in-up 0.6s ease forwards;
}
.feature-card:nth-child(1) { animation-delay: 0.1s; }
.feature-card:nth-child(2) { animation-delay: 0.2s; }
.feature-card:nth-child(3) { animation-delay: 0.3s; }
.feature-card:nth-child(4) { animation-delay: 0.4s; }
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
background: hsl(var(--surface));
padding: 2rem;
border: 1px solid hsl(var(--border));
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
text-align: left;
transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.feature-card:hover {
transform: translate(-3px, -3px);
box-shadow:
0 0 0 3px var(--pixel-outline),
9px 9px 0 var(--pixel-shadow-dark),
9px 9px 0 3px var(--pixel-outline);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.feature-icon {
margin-bottom: 1.5rem;
width: 52px;
height: 52px;
border-radius: 14px;
background: hsl(var(--surface-muted));
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.25rem;
border: 1px solid hsl(var(--border));
}
.feature-title {
font-size: 1.25rem;
font-size: 1.15rem;
font-weight: 700;
color: var(--pixel-text-primary);
margin: 0 0 0.75rem 0;
color: hsl(var(--text-primary));
margin: 0 0 0.6rem 0;
}
.feature-description {
font-size: 1rem;
color: var(--pixel-text-secondary);
color: hsl(var(--text-secondary));
margin: 0;
line-height: 1.5;
line-height: 1.6;
}
/* ========================================
@@ -259,44 +325,39 @@
======================================== */
.landing-footer {
padding: 6rem 2rem;
background: var(--pixel-bg-dark);
position: relative;
overflow: hidden;
padding: 4.5rem 2rem;
background: hsl(var(--surface-muted));
border-top: 1px solid hsl(var(--border));
}
.footer-content {
text-align: center;
max-width: 600px;
margin: 0 auto;
position: relative;
z-index: 10;
}
.footer-headline {
font-size: 2rem;
font-size: 1.9rem;
font-weight: 700;
color: var(--pixel-white);
margin: 0 0 1rem 0;
text-shadow: 2px 2px 0 var(--pixel-shadow-dark);
color: hsl(var(--text-primary));
margin: 0 0 0.75rem 0;
}
.footer-tagline {
font-size: 1.125rem;
color: var(--pixel-bg-light);
margin: 0 0 2.5rem 0;
opacity: 0.9;
font-size: 1.05rem;
color: hsl(var(--text-secondary));
margin: 0 0 2rem 0;
}
.footer-login-buttons {
display: flex;
justify-content: center;
margin-bottom: 3rem;
margin-bottom: 2.5rem;
}
.footer-tech {
font-size: 0.875rem;
color: var(--pixel-text-muted);
font-size: 0.9rem;
color: hsl(var(--text-muted));
margin: 0;
}
@@ -304,23 +365,17 @@
Responsive Design
======================================== */
/* Tablet (768px+) */
@media (min-width: 768px) {
.hero-brand {
font-size: 4rem;
}
.hero-headline {
font-size: 3rem;
font-size: 3.25rem;
}
.hero-tagline {
font-size: 1.5rem;
font-size: 1.2rem;
}
.hero-login-buttons {
.provider-buttons {
flex-direction: row;
gap: 1.5rem;
}
.features-grid {
@@ -328,48 +383,23 @@
}
.section-title {
font-size: 3rem;
font-size: 2.5rem;
}
}
/* Desktop (1024px+) */
@media (min-width: 1024px) {
.hero-brand {
font-size: 4.5rem;
}
.hero-headline {
font-size: 3.5rem;
.hero-grid {
grid-template-columns: 1.05fr 0.95fr;
}
.features-grid {
grid-template-columns: repeat(4, 1fr);
}
.feature-card {
padding: 2rem 1.5rem;
}
}
/* Large Desktop (1280px+) */
@media (min-width: 1280px) {
.hero-headline {
font-size: 4rem;
}
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.landing-hero {
animation: none;
}
.hero-scroll-hint {
animation: none;
}
.landing-login-button,
.feature-card {
animation: none;
opacity: 1;
transition: none;
}
}

View File

@@ -16,43 +16,93 @@ function LandingPage() {
<div className="landing-page">
{/* Hero Section */}
<section className="landing-hero">
<FloatingGem position={{ top: '10%', left: '8%' }} delay={0} size={44} />
<FloatingGem position={{ top: '15%', right: '12%' }} delay={1.5} size={36} />
<FloatingGem position={{ top: '45%', left: '5%' }} delay={2.5} size={28} />
<FloatingGem position={{ bottom: '25%', right: '8%' }} delay={3.5} size={40} />
<FloatingGem position={{ bottom: '15%', left: '15%' }} delay={4} size={32} />
<FloatingGem position={{ top: '60%', right: '20%' }} delay={1} size={24} />
<div className="hero-content">
<div className="hero-logo">
<PixelIcon name="gem" size={56} color="var(--pixel-yellow-gold)" />
<h1 className="hero-brand">DocNest</h1>
</div>
<h2 className="hero-headline">Create Together. In Real-Time.</h2>
<p className="hero-tagline">
Collaborative documents and Kanban boards that sync instantly.
<br />
Work with your team from anywhere, even offline.
</p>
<div className="hero-login-buttons">
<button className="landing-login-button google" onClick={handleGoogleLogin}>
<GoogleIcon />
<span>Sign in with Google</span>
</button>
<button className="landing-login-button github" onClick={handleGitHubLogin}>
<GitHubIcon />
<span>Sign in with GitHub</span>
</button>
</div>
<div className="hero-gem hero-gem-one">
<FloatingGem position={{ top: '12%', left: '8%' }} delay={0} size={28} />
</div>
<div className="hero-gem hero-gem-two">
<FloatingGem position={{ bottom: '18%', right: '10%' }} delay={1.5} size={24} />
</div>
<div className="hero-scroll-hint">
<PixelIcon name="back-arrow" size={24} style={{ transform: 'rotate(-90deg)' }} />
<div className="hero-grid">
<div className="hero-content">
<div className="hero-logo">
<PixelIcon name="gem" size={28} color="hsl(var(--brand-teal))" />
<span className="hero-brand">DocNest</span>
</div>
<h1 className="hero-headline">Create together. In real time.</h1>
<p className="hero-tagline">
Collaborative documents and Kanban boards that sync instantly.
<br />
Work with your team from anywhere, even offline.
</p>
<div className="hero-login-buttons">
<button className="landing-login-button primary" onClick={handleGoogleLogin}>
Get started free
<PixelIcon name="gem" size={16} color="white" />
</button>
<div className="provider-buttons">
<button className="landing-login-button provider" onClick={handleGoogleLogin}>
<GoogleIcon />
<span>Continue with Google</span>
</button>
<button className="landing-login-button provider" onClick={handleGitHubLogin}>
<GitHubIcon />
<span>Continue with GitHub</span>
</button>
</div>
<p className="hero-note">No credit card required.</p>
</div>
</div>
<div className="hero-mock">
<div className="mock-topbar">
<div className="mock-dot" />
<div className="mock-dot" />
<div className="mock-dot" />
</div>
<div className="mock-body">
<div className="mock-tabs">
<span className="mock-tab active">Docs</span>
<span className="mock-tab">Boards</span>
<span className="mock-tab">History</span>
</div>
<div className="mock-grid">
<div className="mock-card">
<div className="mock-line wide" />
<div className="mock-line" />
<div className="mock-line short" />
</div>
<div className="mock-card">
<div className="mock-line wide" />
<div className="mock-line" />
<div className="mock-line short" />
</div>
</div>
<div className="mock-rows">
<div className="mock-row">
<span className="mock-pill" />
<span className="mock-line" />
<span className="mock-line short" />
</div>
<div className="mock-row">
<span className="mock-pill" />
<span className="mock-line" />
<span className="mock-line short" />
</div>
</div>
</div>
</div>
</div>
</section>
<div className="section-divider">
<span className="divider-line" />
<PixelIcon name="gem" size={16} color="hsl(var(--brand-teal))" />
<span className="divider-line" />
</div>
{/* Features Section */}
<section className="landing-features">
<h2 className="section-title">Why DocNest?</h2>
@@ -61,42 +111,44 @@ function LandingPage() {
icon="sync-arrows"
title="Real-Time Collaboration"
description="See changes as they happen. Multiple cursors show who's working where."
color="var(--pixel-cyan-bright)"
color="hsl(var(--brand-teal))"
/>
<FeatureCard
icon="document"
title="Rich Documents"
description="Create formatted documents with headings, lists, and more."
color="var(--pixel-purple-bright)"
color="hsl(var(--brand))"
/>
<FeatureCard
icon="kanban"
title="Kanban Boards"
description="Drag-and-drop task management with real-time updates."
color="var(--pixel-orange-warm)"
color="hsl(var(--accent))"
/>
<FeatureCard
icon="shield"
title="Offline Support"
description="Your work syncs automatically when you're back online."
color="var(--pixel-green-lime)"
color="hsl(var(--secondary))"
/>
</div>
</section>
<div className="section-divider">
<span className="divider-line" />
<PixelIcon name="gem" size={16} color="hsl(var(--brand-teal))" />
<span className="divider-line" />
</div>
{/* Footer CTA */}
<footer className="landing-footer">
<FloatingGem position={{ top: '20%', left: '10%' }} delay={0.5} size={28} />
<FloatingGem position={{ bottom: '30%', right: '12%' }} delay={2} size={32} />
<div className="footer-content">
<h3 className="footer-headline">Ready to collaborate?</h3>
<p className="footer-tagline">Join thousands of teams creating together.</p>
<p className="footer-tagline">Join teams building together in DocNest.</p>
<div className="footer-login-buttons">
<button className="landing-login-button google large" onClick={handleGoogleLogin}>
<GoogleIcon />
<span>Get Started Free</span>
<button className="landing-login-button primary large" onClick={handleGoogleLogin}>
Get started free
</button>
</div>

View File

@@ -3,14 +3,15 @@
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
background: var(--gradient-hero);
padding: 24px;
}
.login-container {
background: white;
border-radius: 16px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
background: hsl(var(--surface));
border-radius: var(--radius-lg);
border: 1px solid hsl(var(--border));
box-shadow: var(--shadow-lg);
padding: 48px 40px;
max-width: 440px;
width: 100%;
@@ -20,20 +21,20 @@
.login-title {
font-size: 32px;
font-weight: 700;
color: #1a202c;
color: hsl(var(--text-primary));
margin: 0 0 8px 0;
}
.login-subtitle {
font-size: 16px;
color: #718096;
color: hsl(var(--text-secondary));
margin: 0 0 32px 0;
}
.login-buttons {
display: flex;
flex-direction: column;
gap: 16px;
gap: 14px;
}
.login-button {
@@ -41,14 +42,22 @@
align-items: center;
justify-content: center;
gap: 12px;
padding: 14px 24px;
font-size: 16px;
padding: 12px 20px;
font-size: 15px;
font-weight: 600;
border: none;
border-radius: 8px;
border: 1px solid hsl(var(--border));
border-radius: var(--radius-md);
cursor: pointer;
transition: all 0.2s ease;
transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
width: 100%;
background: hsl(var(--surface));
color: hsl(var(--text-primary));
box-shadow: var(--shadow-sm);
}
.login-button:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.button-icon {
@@ -57,27 +66,20 @@
}
.google-button {
background: #4285f4;
background: var(--gradient-accent);
color: white;
border: none;
}
.google-button:hover {
background: #357ae8;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(66, 133, 244, 0.3);
filter: brightness(0.98);
}
.github-button {
background: #24292e;
color: white;
}
.github-button:hover {
background: #1a1f23;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(36, 41, 46, 0.3);
background: hsl(var(--surface));
}
.login-button:active {
transform: translateY(0);
box-shadow: var(--shadow-sm);
}

View File

@@ -35,8 +35,8 @@ function LoginPage() {
return (
<div className="login-page">
<div className="login-container">
<h1 className="login-title">Realtime Collab</h1>
<p className="login-subtitle">Collaborate in real-time with your team</p>
<h1 className="login-title">DocNest</h1>
<p className="login-subtitle">Collaborate in real time with your team</p>
<div className="login-buttons">
<button
@@ -61,7 +61,7 @@ function LoginPage() {
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign in with Google
Continue with Google
</button>
<button
@@ -74,7 +74,7 @@ function LoginPage() {
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34-.46-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.87 1.52 2.34 1.07 2.91.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.92 0-1.11.38-2 1.03-2.71-.1-.25-.45-1.29.1-2.64 0 0 .84-.27 2.75 1.02.79-.22 1.65-.33 2.5-.33.85 0 1.71.11 2.5.33 1.91-1.29 2.75-1.02 2.75-1.02.55 1.35.2 2.39.1 2.64.65.71 1.03 1.6 1.03 2.71 0 3.82-2.34 4.66-4.57 4.91.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2z"
/>
</svg>
Sign in with GitHub
Continue with GitHub
</button>
</div>
</div>