theme fix

This commit is contained in:
2026-03-26 15:23:08 +05:30
parent fa10677e41
commit 2b293a20b7
7 changed files with 95 additions and 102 deletions

View File

@@ -12,46 +12,29 @@
} }
/* ============================ /* ============================
PROTECTED ROUTE SPINNER PAGE LOADER (swaying tree)
============================ */ ============================ */
.protected-route__loading { .page-loader {
height: 100dvh; height: 100dvh;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 1rem; background: var(--color-bg-soft, #eef6ee);
background: #eef6ee;
color: #9ca3af;
} }
.protected-route__spinner { .page-loader__tree {
width: 28px; transform-origin: center bottom;
height: 28px; animation: tree-sway 1.8s ease-in-out infinite alternate;
border: 3px solid #e5e7eb;
border-top-color: #22c55e;
border-radius: 50%;
animation: spin 0.7s linear infinite;
} }
@keyframes spin { @keyframes tree-sway {
to { from { transform: rotate(-5deg); }
transform: rotate(360deg); to { transform: rotate(5deg); }
}
} }
/* ============================ /* ============================
LOGIN PAGE LOGIN PAGE
============================ */ ============================ */
/* ── Loading state ──────────────────────────────────────── */
.login-page__spinner {
width: 28px;
height: 28px;
border: 3px solid #e5e7eb;
border-top-color: #22c55e;
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
/* ── Login page — two-panel layout ─────────────────────── */ /* ── Login page — two-panel layout ─────────────────────── */
.lp { .lp {
@@ -62,18 +45,6 @@
background: linear-gradient(160deg, #eef6ee 0%, #dcfce7 100%); background: linear-gradient(160deg, #eef6ee 0%, #dcfce7 100%);
} }
/* Loading state wrapper */
.lp--loading {
grid-template-columns: 1fr;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
background: var(--color-bg-soft);
color: #9ca3af;
}
/* ── Left: animated tree hero ───────────────────────────── */ /* ── Left: animated tree hero ───────────────────────────── */
.lp__hero { .lp__hero {
display: flex; display: flex;
@@ -835,6 +806,17 @@
[data-theme="dark"] .sba-overlay { [data-theme="dark"] .sba-overlay {
background: rgba(10, 18, 10, 0.76); background: rgba(10, 18, 10, 0.76);
} }
[data-theme="dark"] .sba-left-group rect {
fill: #1a2e1a;
stroke: #2d4a2d;
}
[data-theme="dark"] .sba-left-group line {
stroke: #2d4a2d;
}
[data-theme="dark"] .sba-right-group rect {
fill: #162416;
stroke: #2d4a2d;
}
/* ============================ /* ============================
BOTTOM NAVIGATION — Static flex item, always at bottom BOTTOM NAVIGATION — Static flex item, always at bottom
@@ -1252,7 +1234,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 50%; border-radius: 50%;
background: linear-gradient(135deg, #f9a8d4 0%, #f472b6 100%); background: linear-gradient(135deg, #86efac 0%, #22c55e 100%);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -2199,6 +2181,24 @@
} }
} }
/* ============================
ALERT MESSAGES
============================ */
.alert-msg {
padding: 0.75rem;
border-radius: 8px;
font-size: 0.875rem;
text-align: center;
}
.alert-msg--error {
background-color: #fef2f2;
color: #b91c1c;
}
.alert-msg--success {
background-color: #f0fdf4;
color: #15803d;
}
/* ============================ /* ============================
DARK THEME DARK THEME
============================ */ ============================ */
@@ -2504,16 +2504,19 @@
color: #4ade80; color: #4ade80;
} }
/* -- Spinners -- */ /* -- Page loader -- */
[data-theme="dark"] .protected-route__spinner, [data-theme="dark"] .page-loader {
[data-theme="dark"] .login-page__spinner { background: #0f0f0f;
border-color: #2a2a2a;
border-top-color: #4ade80;
} }
[data-theme="dark"] .protected-route__loading { /* -- Alert messages -- */
background: #0f0f0f; [data-theme="dark"] .alert-msg--error {
color: #5a6a5a; background-color: rgba(185, 28, 28, 0.18);
color: #fca5a5;
}
[data-theme="dark"] .alert-msg--success {
background-color: rgba(21, 128, 61, 0.18);
color: #86efac;
} }
/* -- Icon btn hover -- */ /* -- Icon btn hover -- */

View File

@@ -0,0 +1,26 @@
export function PageLoader() {
return (
<div className="page-loader" role="status" aria-label="Loading">
<svg
className="page-loader__tree"
viewBox="0 0 60 90"
width="72"
height="72"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
{/* Trunk */}
<rect x="26" y="58" width="8" height="28" rx="4" fill="#A0722A" />
{/* Side canopy depth */}
<circle cx="14" cy="52" r="14" fill="#16a34a" />
<circle cx="46" cy="52" r="14" fill="#16a34a" />
{/* Main canopy */}
<circle cx="30" cy="37" r="22" fill="#22c55e" />
{/* Light highlight */}
<circle cx="20" cy="27" r="10" fill="#4ade80" opacity="0.6" />
{/* Top tip */}
<circle cx="30" cy="17" r="10" fill="#4ade80" />
</svg>
</div>
)
}

View File

@@ -1,6 +1,7 @@
import { type ReactNode } from 'react' import { type ReactNode } from 'react'
import { Navigate, useLocation } from 'react-router-dom' import { Navigate, useLocation } from 'react-router-dom'
import { useAuth } from '../contexts/AuthContext' import { useAuth } from '../contexts/AuthContext'
import { PageLoader } from './PageLoader'
type Props = { type Props = {
children: ReactNode children: ReactNode
@@ -11,12 +12,7 @@ export function ProtectedRoute({ children }: Props) {
const location = useLocation() const location = useLocation()
if (loading) { if (loading) {
return ( return <PageLoader />
<div className="protected-route__loading" aria-live="polite">
<span className="protected-route__spinner" aria-hidden />
<p>Loading</p>
</div>
)
} }
if (!user) { if (!user) {

View File

@@ -5,6 +5,7 @@ import { decryptEntry } from '../lib/crypto'
import { formatIST, getISTDateComponents } from '../lib/timezone' import { formatIST, getISTDateComponents } from '../lib/timezone'
import BottomNav from '../components/BottomNav' import BottomNav from '../components/BottomNav'
import { useOnboardingTour, hasPendingTourStep, clearPendingTourStep } from '../hooks/useOnboardingTour' import { useOnboardingTour, hasPendingTourStep, clearPendingTourStep } from '../hooks/useOnboardingTour'
import { PageLoader } from '../components/PageLoader'
interface DecryptedEntry extends JournalEntry { interface DecryptedEntry extends JournalEntry {
decryptedTitle?: string decryptedTitle?: string
@@ -194,12 +195,7 @@ export default function HistoryPage() {
} }
if (loading) { if (loading) {
return ( return <PageLoader />
<div className="history-page" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<p style={{ color: '#9ca3af' }}>Loading</p>
<BottomNav />
</div>
)
} }
return ( return (
@@ -274,13 +270,13 @@ export default function HistoryPage() {
</h3> </h3>
{loadingEntries ? ( {loadingEntries ? (
<p style={{ color: '#9ca3af', fontSize: '0.875rem', textAlign: 'center', padding: '1.5rem 0', fontFamily: '"Sniglet", system-ui' }}> <p style={{ color: 'var(--color-text-muted)', fontSize: '0.875rem', textAlign: 'center', padding: '1.5rem 0', fontFamily: '"Sniglet", system-ui' }}>
Loading entries Loading entries
</p> </p>
) : ( ) : (
<div className="entries-list"> <div className="entries-list">
{selectedDateEntries.length === 0 ? ( {selectedDateEntries.length === 0 ? (
<p style={{ color: '#9ca3af', fontSize: '0.875rem', textAlign: 'center', padding: '1.5rem 0', fontFamily: '"Sniglet", system-ui' }}> <p style={{ color: 'var(--color-text-muted)', fontSize: '0.875rem', textAlign: 'center', padding: '1.5rem 0', fontFamily: '"Sniglet", system-ui' }}>
No entries for this day yet. Start writing! No entries for this day yet. Start writing!
</p> </p>
) : ( ) : (

View File

@@ -7,6 +7,7 @@ import BottomNav from '../components/BottomNav'
import WelcomeModal from '../components/WelcomeModal' import WelcomeModal from '../components/WelcomeModal'
import { SaveBookAnimation } from '../components/SaveBookAnimation' import { SaveBookAnimation } from '../components/SaveBookAnimation'
import { useOnboardingTour, hasSeenOnboarding, markOnboardingDone } from '../hooks/useOnboardingTour' import { useOnboardingTour, hasSeenOnboarding, markOnboardingDone } from '../hooks/useOnboardingTour'
import { PageLoader } from '../components/PageLoader'
const AFFIRMATIONS = [ const AFFIRMATIONS = [
'You showed up for yourself today 🌱', 'You showed up for yourself today 🌱',
@@ -61,18 +62,14 @@ export default function HomePage() {
} }
if (loading) { if (loading) {
return ( return <PageLoader />
<div className="home-page" style={{ alignItems: 'center', justifyContent: 'center' }}>
<p style={{ color: '#9ca3af' }}>Loading</p>
</div>
)
} }
if (!user) { if (!user) {
return ( return (
<div className="home-page" style={{ alignItems: 'center', justifyContent: 'center', gap: '1rem' }}> <div className="home-page" style={{ alignItems: 'center', justifyContent: 'center', gap: '1rem' }}>
<h1 style={{ fontFamily: '"Sniglet", system-ui', color: '#1a1a1a' }}>Grateful Journal</h1> <h1 style={{ fontFamily: '"Sniglet", system-ui', color: 'var(--color-text)' }}>Grateful Journal</h1>
<p style={{ color: '#6b7280' }}>Sign in to start your journal.</p> <p style={{ color: 'var(--color-text-muted)' }}>Sign in to start your journal.</p>
<Link to="/login" className="home-login-link">Go to login</Link> <Link to="/login" className="home-login-link">Go to login</Link>
</div> </div>
) )
@@ -188,15 +185,7 @@ export default function HomePage() {
</div> </div>
{message && ( {message && (
<div style={{ <div className="alert-msg alert-msg--error" style={{ marginTop: '1rem' }}>
padding: '0.75rem',
marginTop: '1rem',
borderRadius: '8px',
fontSize: '0.875rem',
backgroundColor: '#fef2f2',
color: '#b91c1c',
textAlign: 'center',
}}>
{message.text} {message.text}
</div> </div>
)} )}

View File

@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { GoogleSignInButton } from '../components/GoogleSignInButton' import { GoogleSignInButton } from '../components/GoogleSignInButton'
import { TreeAnimation } from '../components/TreeAnimation' import { TreeAnimation } from '../components/TreeAnimation'
import { PageLoader } from '../components/PageLoader'
export default function LoginPage() { export default function LoginPage() {
const { user, loading, signInWithGoogle, authError } = useAuth() const { user, loading, signInWithGoogle, authError } = useAuth()
@@ -28,12 +29,7 @@ export default function LoginPage() {
} }
if (loading) { if (loading) {
return ( return <PageLoader />
<div className="lp lp--loading" aria-live="polite">
<span className="login-page__spinner" aria-hidden />
<p>Loading</p>
</div>
)
} }
return ( return (

View File

@@ -5,6 +5,7 @@ import { clearDeviceKey, clearEncryptedSecretKey } from '../lib/crypto'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import BottomNav from '../components/BottomNav' import BottomNav from '../components/BottomNav'
import { useOnboardingTour, hasPendingTourStep, clearPendingTourStep } from '../hooks/useOnboardingTour' import { useOnboardingTour, hasPendingTourStep, clearPendingTourStep } from '../hooks/useOnboardingTour'
import { PageLoader } from '../components/PageLoader'
const MAX_PHOTO_SIZE = 200 // px — resize to 200x200 const MAX_PHOTO_SIZE = 200 // px — resize to 200x200
@@ -187,12 +188,7 @@ export default function SettingsPage() {
} }
if (loading) { if (loading) {
return ( return <PageLoader />
<div className="settings-page" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<p style={{ color: '#9ca3af' }}>Loading</p>
<BottomNav />
</div>
)
} }
return ( return (
@@ -211,7 +207,7 @@ export default function SettingsPage() {
{photoURL ? ( {photoURL ? (
<img src={photoURL} alt={displayName} className="settings-avatar-img" /> <img src={photoURL} alt={displayName} className="settings-avatar-img" />
) : ( ) : (
<div className="settings-avatar-placeholder" style={{ fontSize: '1.75rem', background: 'linear-gradient(135deg, #86efac 0%, #22c55e 100%)' }}> <div className="settings-avatar-placeholder" style={{ fontSize: '1.75rem' }}>
{displayName.charAt(0).toUpperCase()} {displayName.charAt(0).toUpperCase()}
</div> </div>
)} )}
@@ -345,15 +341,7 @@ export default function SettingsPage() {
</section> </section>
{message && ( {message && (
<div style={{ <div className={`alert-msg alert-msg--${message.type}`} style={{ marginBottom: '1rem' }}>
padding: '0.75rem',
marginBottom: '1rem',
borderRadius: '8px',
fontSize: '0.875rem',
backgroundColor: message.type === 'success' ? '#f0fdf4' : '#fef2f2',
color: message.type === 'success' ? '#15803d' : '#b91c1c',
textAlign: 'center',
}}>
{message.text} {message.text}
</div> </div>
)} )}
@@ -481,9 +469,8 @@ export default function SettingsPage() {
disabled={saving} disabled={saving}
maxLength={50} maxLength={50}
autoFocus autoFocus
style={{ borderColor: '#d1d5db' }} onFocus={(e) => (e.target.style.borderColor = 'var(--color-primary)')}
onFocus={(e) => (e.target.style.borderColor = '#22c55e')} onBlur={(e) => (e.target.style.borderColor = '')}
onBlur={(e) => (e.target.style.borderColor = '#d1d5db')}
/> />
<div className="confirm-modal-actions" style={{ marginTop: '1rem' }}> <div className="confirm-modal-actions" style={{ marginTop: '1rem' }}>