Refactor UI components and styles for improved consistency and aesthetics
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user