Add bottom navigation, History and Settings pages with improved UI styling
This commit is contained in:
@@ -4,6 +4,9 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Lora:ital,wght@0,400;0,500;1,400&family=Playfair+Display:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<title>Grateful Journal</title>
|
<title>Grateful Journal</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
1275
src/App.css
1275
src/App.css
File diff suppressed because it is too large
Load Diff
18
src/App.tsx
18
src/App.tsx
@@ -2,6 +2,8 @@ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
|
|||||||
import { AuthProvider } from './contexts/AuthContext'
|
import { AuthProvider } from './contexts/AuthContext'
|
||||||
import { ProtectedRoute } from './components/ProtectedRoute'
|
import { ProtectedRoute } from './components/ProtectedRoute'
|
||||||
import HomePage from './pages/HomePage'
|
import HomePage from './pages/HomePage'
|
||||||
|
import HistoryPage from './pages/HistoryPage'
|
||||||
|
import SettingsPage from './pages/SettingsPage'
|
||||||
import LoginPage from './pages/LoginPage'
|
import LoginPage from './pages/LoginPage'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
|
||||||
@@ -18,6 +20,22 @@ function App() {
|
|||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/history"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<HistoryPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/settings"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<SettingsPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route path="*" element={<Navigate to="/login" replace />} />
|
<Route path="*" element={<Navigate to="/login" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
48
src/components/BottomNav.tsx
Normal file
48
src/components/BottomNav.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { useNavigate, useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
|
export default function BottomNav() {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const location = useLocation()
|
||||||
|
|
||||||
|
const isActive = (path: string) => location.pathname === path
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className="bottom-nav">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`bottom-nav-btn ${isActive('/') ? 'bottom-nav-btn-active' : ''}`}
|
||||||
|
onClick={() => navigate('/')}
|
||||||
|
>
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M12 19l7-7 3 3-7 7-3-3z"></path>
|
||||||
|
<path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
|
||||||
|
<path d="M2 2l7.586 7.586"></path>
|
||||||
|
<circle cx="11" cy="11" r="2"></circle>
|
||||||
|
</svg>
|
||||||
|
<span>Write</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`bottom-nav-btn ${isActive('/history') ? 'bottom-nav-btn-active' : ''}`}
|
||||||
|
onClick={() => navigate('/history')}
|
||||||
|
>
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
||||||
|
<polyline points="9 22 9 12 15 12 15 22"></polyline>
|
||||||
|
</svg>
|
||||||
|
<span>History</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`bottom-nav-btn ${isActive('/settings') ? 'bottom-nav-btn-active' : ''}`}
|
||||||
|
onClick={() => navigate('/settings')}
|
||||||
|
>
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="3"></circle>
|
||||||
|
<path d="M12 1v6m0 6v6m5.196-15.804l-4.243 4.243m-5.657 5.657l-4.243 4.243M23 12h-6m-6 0H1m15.804 5.196l-4.243-4.243m-5.657-5.657L2.661 2.661"></path>
|
||||||
|
</svg>
|
||||||
|
<span>Settings</span>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Grateful Journal – green palette from Coolors */
|
/* Grateful Journal – enhanced green palette */
|
||||||
*,
|
*,
|
||||||
*::before,
|
*::before,
|
||||||
*::after {
|
*::after {
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: system-ui, -apple-system, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
/* Responsive base: 16px at 320px, scales up to 18px by 768px */
|
/* Responsive base: 16px at 320px, scales up to 18px by 768px */
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
--color-accent-light: #cff2dc;
|
--color-accent-light: #cff2dc;
|
||||||
--color-accent-bright: #c3fd2f;
|
--color-accent-bright: #c3fd2f;
|
||||||
--color-text: #1a1a1a;
|
--color-text: #1a1a1a;
|
||||||
--color-text-muted: #555;
|
--color-text-muted: #6b7280;
|
||||||
--color-border: #cff2dc;
|
--color-border: #cff2dc;
|
||||||
|
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
|
|||||||
180
src/pages/HistoryPage.tsx
Normal file
180
src/pages/HistoryPage.tsx
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import BottomNav from '../components/BottomNav'
|
||||||
|
|
||||||
|
interface JournalEntry {
|
||||||
|
id: string
|
||||||
|
date: Date
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function HistoryPage() {
|
||||||
|
const [currentMonth, setCurrentMonth] = useState(new Date())
|
||||||
|
|
||||||
|
// Mock data - replace with actual Firebase data later
|
||||||
|
const mockEntries: JournalEntry[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
date: new Date(2026, 1, 12),
|
||||||
|
title: 'Feeling much lighter today',
|
||||||
|
content: 'After the long conversation yesterday, I woke up with a sense of clarity I haven\'t felt in weeks...'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
date: new Date(2026, 1, 5),
|
||||||
|
title: 'Morning thoughts',
|
||||||
|
content: 'The coffee smells amazing this morning. Simple pleasures like this remind me...'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const getDaysInMonth = (date: Date) => {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth()
|
||||||
|
const firstDay = new Date(year, month, 1)
|
||||||
|
const lastDay = new Date(year, month + 1, 0)
|
||||||
|
const daysInMonth = lastDay.getDate()
|
||||||
|
const startingDayOfWeek = firstDay.getDay()
|
||||||
|
|
||||||
|
return { daysInMonth, startingDayOfWeek }
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasEntryOnDate = (day: number) => {
|
||||||
|
return mockEntries.some(entry => {
|
||||||
|
const entryDate = new Date(entry.date)
|
||||||
|
return entryDate.getDate() === day &&
|
||||||
|
entryDate.getMonth() === currentMonth.getMonth() &&
|
||||||
|
entryDate.getFullYear() === currentMonth.getFullYear()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isToday = (day: number) => {
|
||||||
|
const today = new Date()
|
||||||
|
return day === today.getDate() &&
|
||||||
|
currentMonth.getMonth() === today.getMonth() &&
|
||||||
|
currentMonth.getFullYear() === today.getFullYear()
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatDate = (date: Date) => {
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
|
weekday: 'short',
|
||||||
|
month: 'short',
|
||||||
|
day: '2-digit'
|
||||||
|
}).toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatTime = (date: Date) => {
|
||||||
|
return date.toLocaleTimeString('en-US', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
}).toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { daysInMonth, startingDayOfWeek } = getDaysInMonth(currentMonth)
|
||||||
|
const monthName = currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })
|
||||||
|
|
||||||
|
const previousMonth = () => {
|
||||||
|
setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextMonth = () => {
|
||||||
|
setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="history-page">
|
||||||
|
<div className="history-bg-decoration">
|
||||||
|
<div className="bg-orb bg-orb-1"></div>
|
||||||
|
<div className="bg-orb bg-orb-2"></div>
|
||||||
|
<div className="bg-pattern"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<header className="history-header">
|
||||||
|
<div className="history-header-text">
|
||||||
|
<h1>History</h1>
|
||||||
|
<p className="history-subtitle">Your past reflections</p>
|
||||||
|
</div>
|
||||||
|
<button type="button" className="history-search-btn" title="Search entries">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<circle cx="11" cy="11" r="8"></circle>
|
||||||
|
<path d="m21 21-4.35-4.35"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="history-container">
|
||||||
|
<div className="calendar-card">
|
||||||
|
<div className="calendar-header">
|
||||||
|
<h2 className="calendar-month">{monthName}</h2>
|
||||||
|
<div className="calendar-nav">
|
||||||
|
<button type="button" onClick={previousMonth} className="calendar-nav-btn" title="Previous month">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<polyline points="15 18 9 12 15 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button type="button" onClick={nextMonth} className="calendar-nav-btn" title="Next month">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<polyline points="9 18 15 12 9 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="calendar-grid">
|
||||||
|
<div className="calendar-weekday">S</div>
|
||||||
|
<div className="calendar-weekday">M</div>
|
||||||
|
<div className="calendar-weekday">T</div>
|
||||||
|
<div className="calendar-weekday">W</div>
|
||||||
|
<div className="calendar-weekday">T</div>
|
||||||
|
<div className="calendar-weekday">F</div>
|
||||||
|
<div className="calendar-weekday">S</div>
|
||||||
|
|
||||||
|
{Array.from({ length: startingDayOfWeek }).map((_, i) => (
|
||||||
|
<div key={`empty-${i}`} className="calendar-day calendar-day-empty"></div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{Array.from({ length: daysInMonth }).map((_, i) => {
|
||||||
|
const day = i + 1
|
||||||
|
const hasEntry = hasEntryOnDate(day)
|
||||||
|
const isTodayDate = isToday(day)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={day}
|
||||||
|
type="button"
|
||||||
|
className={`calendar-day ${hasEntry ? 'calendar-day-has-entry' : ''} ${isTodayDate ? 'calendar-day-today' : ''}`}
|
||||||
|
onClick={() => console.log('View entries for', day)}
|
||||||
|
>
|
||||||
|
{day}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section className="recent-entries">
|
||||||
|
<h3 className="recent-entries-title">RECENT ENTRIES</h3>
|
||||||
|
|
||||||
|
<div className="entries-list">
|
||||||
|
{mockEntries.map(entry => (
|
||||||
|
<button
|
||||||
|
key={entry.id}
|
||||||
|
type="button"
|
||||||
|
className="entry-card"
|
||||||
|
onClick={() => console.log('Open entry', entry.id)}
|
||||||
|
>
|
||||||
|
<div className="entry-header">
|
||||||
|
<span className="entry-date">{formatDate(entry.date)}</span>
|
||||||
|
<span className="entry-time">{formatTime(entry.date)}</span>
|
||||||
|
</div>
|
||||||
|
<h4 className="entry-title">{entry.title}</h4>
|
||||||
|
<p className="entry-preview">{entry.content}</p>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<BottomNav />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
import { useAuth } from '../contexts/AuthContext'
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import BottomNav from '../components/BottomNav'
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const { user, loading, signOut } = useAuth()
|
const { user, loading, signOut } = useAuth()
|
||||||
|
const [entry, setEntry] = useState('')
|
||||||
|
const [title, setTitle] = useState('')
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@@ -24,11 +28,32 @@ export default function HomePage() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayName =
|
const displayName = user.displayName ?? user.email ?? 'there'
|
||||||
user.displayName ?? user.email ?? 'there'
|
|
||||||
|
// Get current date formatted like "THURSDAY, OCT 24"
|
||||||
|
const today = new Date()
|
||||||
|
const dateString = today.toLocaleDateString('en-US', {
|
||||||
|
weekday: 'long',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric'
|
||||||
|
}).toUpperCase()
|
||||||
|
|
||||||
|
const handleWrite = () => {
|
||||||
|
console.log('Saving entry:', { title, entry })
|
||||||
|
// TODO: Save to Firebase
|
||||||
|
setTitle('')
|
||||||
|
setEntry('')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="home-page">
|
<div className="home-page">
|
||||||
|
<div className="home-bg-decoration">
|
||||||
|
<div className="bg-orb bg-orb-1"></div>
|
||||||
|
<div className="bg-orb bg-orb-2"></div>
|
||||||
|
<div className="bg-orb bg-orb-3"></div>
|
||||||
|
<div className="bg-pattern"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<header className="home-header">
|
<header className="home-header">
|
||||||
<h1>Grateful Journal</h1>
|
<h1>Grateful Journal</h1>
|
||||||
<div className="home-user">
|
<div className="home-user">
|
||||||
@@ -38,10 +63,32 @@ export default function HomePage() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main className="home-main">
|
|
||||||
<p className="home-welcome">Hello, {displayName}.</p>
|
<main className="journal-container">
|
||||||
<p className="home-sub">Your writing space will go here.</p>
|
<div className="journal-card">
|
||||||
|
<div className="journal-date">{dateString}</div>
|
||||||
|
|
||||||
|
<h2 className="journal-prompt">What are you grateful for today?</h2>
|
||||||
|
|
||||||
|
<div className="journal-writing-area">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="journal-title-input"
|
||||||
|
placeholder="Title your thoughts..."
|
||||||
|
value={title}
|
||||||
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
className="journal-entry-textarea"
|
||||||
|
placeholder=""
|
||||||
|
value={entry}
|
||||||
|
onChange={(e) => setEntry(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<BottomNav />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
172
src/pages/SettingsPage.tsx
Normal file
172
src/pages/SettingsPage.tsx
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
|
import BottomNav from '../components/BottomNav'
|
||||||
|
|
||||||
|
export default function SettingsPage() {
|
||||||
|
const { user, signOut } = useAuth()
|
||||||
|
const [passcodeEnabled, setPasscodeEnabled] = useState(false)
|
||||||
|
const [faceIdEnabled, setFaceIdEnabled] = useState(false)
|
||||||
|
|
||||||
|
const displayName = user?.displayName || 'User'
|
||||||
|
const photoURL = user?.photoURL || ''
|
||||||
|
|
||||||
|
const handleClearData = () => {
|
||||||
|
if (window.confirm('Are you sure you want to clear all local data? This action cannot be undone.')) {
|
||||||
|
// TODO: Implement clear local data
|
||||||
|
console.log('Clearing local data...')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="settings-page">
|
||||||
|
<div className="settings-bg-decoration">
|
||||||
|
<div className="bg-orb bg-orb-1"></div>
|
||||||
|
<div className="bg-orb bg-orb-2"></div>
|
||||||
|
<div className="bg-pattern"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<header className="settings-header">
|
||||||
|
<div className="settings-header-text">
|
||||||
|
<h1>Settings</h1>
|
||||||
|
<p className="settings-subtitle">Manage your privacy and preferences.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="settings-container">
|
||||||
|
{/* Profile Section */}
|
||||||
|
<div className="settings-profile">
|
||||||
|
<div className="settings-avatar">
|
||||||
|
{photoURL ? (
|
||||||
|
<img src={photoURL} alt={displayName} className="settings-avatar-img" />
|
||||||
|
) : (
|
||||||
|
<div className="settings-avatar-placeholder">
|
||||||
|
{displayName.charAt(0).toUpperCase()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="settings-profile-info">
|
||||||
|
<h2 className="settings-profile-name">{displayName}</h2>
|
||||||
|
<span className="settings-profile-badge">PRO MEMBER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Privacy & Security */}
|
||||||
|
<section className="settings-section">
|
||||||
|
<h3 className="settings-section-title">PRIVACY & SECURITY</h3>
|
||||||
|
<div className="settings-card">
|
||||||
|
<div className="settings-item">
|
||||||
|
<div className="settings-item-icon settings-item-icon-green">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
||||||
|
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className="settings-item-content">
|
||||||
|
<h4 className="settings-item-title">Passcode Lock</h4>
|
||||||
|
<p className="settings-item-subtitle">Secure your entries</p>
|
||||||
|
</div>
|
||||||
|
<label className="settings-toggle">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={passcodeEnabled}
|
||||||
|
onChange={(e) => setPasscodeEnabled(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span className="settings-toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="settings-divider"></div>
|
||||||
|
|
||||||
|
<div className="settings-item">
|
||||||
|
<div className="settings-item-icon settings-item-icon-gray">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z"></path>
|
||||||
|
<path d="M12 6v6l4 2"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className="settings-item-content">
|
||||||
|
<h4 className="settings-item-title">Face ID</h4>
|
||||||
|
<p className="settings-item-subtitle">Unlock with glance</p>
|
||||||
|
</div>
|
||||||
|
<label className="settings-toggle">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={faceIdEnabled}
|
||||||
|
onChange={(e) => setFaceIdEnabled(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span className="settings-toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Data & Look */}
|
||||||
|
<section className="settings-section">
|
||||||
|
<h3 className="settings-section-title">DATA & LOOK</h3>
|
||||||
|
<div className="settings-card">
|
||||||
|
<button type="button" className="settings-item settings-item-button">
|
||||||
|
<div className="settings-item-icon settings-item-icon-orange">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||||
|
<polyline points="7 10 12 15 17 10"></polyline>
|
||||||
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className="settings-item-content">
|
||||||
|
<h4 className="settings-item-title">Export Journal</h4>
|
||||||
|
<p className="settings-item-subtitle">PDF or Plain Text</p>
|
||||||
|
</div>
|
||||||
|
<svg className="settings-item-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<polyline points="9 18 15 12 9 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="settings-divider"></div>
|
||||||
|
|
||||||
|
<button type="button" className="settings-item settings-item-button">
|
||||||
|
<div className="settings-item-icon settings-item-icon-blue">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<circle cx="13.5" cy="6.5" r=".5"></circle>
|
||||||
|
<circle cx="17.5" cy="10.5" r=".5"></circle>
|
||||||
|
<circle cx="8.5" cy="7.5" r=".5"></circle>
|
||||||
|
<circle cx="6.5" cy="12.5" r=".5"></circle>
|
||||||
|
<path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className="settings-item-content">
|
||||||
|
<h4 className="settings-item-title">Theme</h4>
|
||||||
|
<p className="settings-item-subtitle">Currently: Warm Beige</p>
|
||||||
|
</div>
|
||||||
|
<div className="settings-theme-colors">
|
||||||
|
<span className="settings-theme-dot settings-theme-dot-beige"></span>
|
||||||
|
<span className="settings-theme-dot settings-theme-dot-dark"></span>
|
||||||
|
</div>
|
||||||
|
<svg className="settings-item-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<polyline points="9 18 15 12 9 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Clear Data */}
|
||||||
|
<button type="button" className="settings-clear-btn" onClick={handleClearData}>
|
||||||
|
<span>Clear Local Data</span>
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<polyline points="3 6 5 6 21 6"></polyline>
|
||||||
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Sign Out */}
|
||||||
|
<button type="button" className="settings-signout-btn" onClick={() => signOut()}>
|
||||||
|
Sign Out
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Version */}
|
||||||
|
<p className="settings-version">VERSION 1.0.2</p>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<BottomNav />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user