Compare commits
2 Commits
84019c3881
...
816476ed02
| Author | SHA1 | Date | |
|---|---|---|---|
| 816476ed02 | |||
| 6e906436cc |
279
src/App.css
279
src/App.css
@@ -1580,6 +1580,12 @@
|
|||||||
.settings-theme-dot-dark {
|
.settings-theme-dot-dark {
|
||||||
background: #1a1a1a;
|
background: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
.settings-theme-dot-glass {
|
||||||
|
background: linear-gradient(135deg, rgba(255,255,255,0.9) 0%, rgba(209,250,229,0.7) 50%, rgba(167,243,208,0.5) 100%);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
-webkit-backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
.settings-theme-dot:hover:not(:disabled) {
|
.settings-theme-dot:hover:not(:disabled) {
|
||||||
transform: scale(1.15);
|
transform: scale(1.15);
|
||||||
}
|
}
|
||||||
@@ -2997,6 +3003,279 @@
|
|||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
LIQUID GLASS THEME
|
||||||
|
============================ */
|
||||||
|
|
||||||
|
/* -- Pages must be transparent so body background shows through -- */
|
||||||
|
[data-theme="liquid-glass"] .home-page,
|
||||||
|
[data-theme="liquid-glass"] .history-page,
|
||||||
|
[data-theme="liquid-glass"] .settings-page {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Glass surface applied to all card/surface elements -- */
|
||||||
|
[data-theme="liquid-glass"] .journal-card,
|
||||||
|
[data-theme="liquid-glass"] .calendar-card,
|
||||||
|
[data-theme="liquid-glass"] .entry-card,
|
||||||
|
[data-theme="liquid-glass"] .entry-modal,
|
||||||
|
[data-theme="liquid-glass"] .confirm-modal,
|
||||||
|
[data-theme="liquid-glass"] .settings-profile,
|
||||||
|
[data-theme="liquid-glass"] .settings-card,
|
||||||
|
[data-theme="liquid-glass"] .settings-tutorial-btn,
|
||||||
|
[data-theme="liquid-glass"] .settings-clear-btn,
|
||||||
|
[data-theme="liquid-glass"] .settings-signout-btn,
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav,
|
||||||
|
[data-theme="liquid-glass"] .lp__form {
|
||||||
|
background: var(--glass-bg);
|
||||||
|
backdrop-filter: var(--glass-blur);
|
||||||
|
-webkit-backdrop-filter: var(--glass-blur);
|
||||||
|
border: var(--glass-border);
|
||||||
|
box-shadow: var(--glass-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Unified shadow (no individual overrides needed) -- */
|
||||||
|
[data-theme="liquid-glass"] .journal-card,
|
||||||
|
[data-theme="liquid-glass"] .calendar-card,
|
||||||
|
[data-theme="liquid-glass"] .entry-card,
|
||||||
|
[data-theme="liquid-glass"] .settings-profile,
|
||||||
|
[data-theme="liquid-glass"] .settings-card {
|
||||||
|
box-shadow: var(--glass-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Bottom nav glass -- */
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav {
|
||||||
|
box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.5), 0 -8px 32px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Text colors — dark & crisp for readability on glass -- */
|
||||||
|
[data-theme="liquid-glass"] .journal-prompt,
|
||||||
|
[data-theme="liquid-glass"] .settings-header-text h1,
|
||||||
|
[data-theme="liquid-glass"] .history-header-text h1,
|
||||||
|
[data-theme="liquid-glass"] .settings-profile-name,
|
||||||
|
[data-theme="liquid-glass"] .settings-item-title,
|
||||||
|
[data-theme="liquid-glass"] .calendar-month,
|
||||||
|
[data-theme="liquid-glass"] .entry-title {
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .journal-date {
|
||||||
|
color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .settings-subtitle,
|
||||||
|
[data-theme="liquid-glass"] .history-subtitle,
|
||||||
|
[data-theme="liquid-glass"] .settings-item-subtitle,
|
||||||
|
[data-theme="liquid-glass"] .settings-section-title,
|
||||||
|
[data-theme="liquid-glass"] .entry-preview,
|
||||||
|
[data-theme="liquid-glass"] .entry-date,
|
||||||
|
[data-theme="liquid-glass"] .entry-time,
|
||||||
|
[data-theme="liquid-glass"] .recent-entries-title,
|
||||||
|
[data-theme="liquid-glass"] .calendar-weekday {
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .journal-title-input,
|
||||||
|
[data-theme="liquid-glass"] .journal-entry-textarea {
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .journal-title-input::placeholder,
|
||||||
|
[data-theme="liquid-glass"] .journal-entry-textarea::placeholder {
|
||||||
|
color: rgba(30, 41, 59, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .journal-title-input {
|
||||||
|
border-bottom-color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .journal-title-input:focus {
|
||||||
|
border-bottom-color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings buttons text -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-tutorial-btn {
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .settings-clear-btn {
|
||||||
|
color: #b91c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="liquid-glass"] .settings-signout-btn {
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings buttons hover -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-tutorial-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.35);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-clear-btn:hover {
|
||||||
|
background: rgba(254, 202, 202, 0.35);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-signout-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings item hover -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-item-button:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings divider -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-divider {
|
||||||
|
background: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings theme dot -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-theme-dot {
|
||||||
|
border-color: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-theme-dot-active {
|
||||||
|
border-color: #16a34a;
|
||||||
|
box-shadow: 0 0 0 2px #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings icon backgrounds -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-item-icon-green {
|
||||||
|
background: rgba(34, 197, 94, 0.2);
|
||||||
|
color: #15803d;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-item-icon-gray {
|
||||||
|
background: rgba(100, 116, 139, 0.18);
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-item-icon-orange {
|
||||||
|
background: rgba(251, 146, 60, 0.2);
|
||||||
|
color: #c2410c;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-item-icon-blue {
|
||||||
|
background: rgba(59, 130, 246, 0.18);
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-item-icon-purple {
|
||||||
|
background: rgba(139, 92, 246, 0.18);
|
||||||
|
color: #6d28d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Settings misc -- */
|
||||||
|
[data-theme="liquid-glass"] .settings-toggle-slider {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-toggle input:checked + .settings-toggle-slider {
|
||||||
|
background: #16a34a;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-item-arrow {
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-enc {
|
||||||
|
color: rgba(15, 23, 42, 0.45);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .settings-edit-btn {
|
||||||
|
background: rgba(34, 197, 94, 0.2);
|
||||||
|
color: #15803d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Calendar -- */
|
||||||
|
[data-theme="liquid-glass"] .calendar-day {
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .calendar-day:not(.calendar-day-empty):hover {
|
||||||
|
background: rgba(255, 255, 255, 0.4);
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .calendar-day-has-entry {
|
||||||
|
background: rgba(34, 197, 94, 0.22);
|
||||||
|
color: #15803d;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .calendar-day-today {
|
||||||
|
background: #16a34a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .calendar-nav-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.35);
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Entry card -- */
|
||||||
|
[data-theme="liquid-glass"] .entry-card {
|
||||||
|
border-left-color: rgba(22, 163, 74, 0.5);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-card:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.28);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.14), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Entry modal -- */
|
||||||
|
[data-theme="liquid-glass"] .entry-modal {
|
||||||
|
border-top-color: #16a34a;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-title {
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-content {
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-date,
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-time {
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-badge {
|
||||||
|
background: rgba(34, 197, 94, 0.2);
|
||||||
|
color: #15803d;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-close {
|
||||||
|
background: rgba(255, 255, 255, 0.35);
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-close:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Confirm/modal overlays -- */
|
||||||
|
[data-theme="liquid-glass"] .confirm-modal-overlay,
|
||||||
|
[data-theme="liquid-glass"] .entry-modal-overlay {
|
||||||
|
background: rgba(15, 23, 42, 0.2);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
-webkit-backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Bottom nav -- */
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav-btn {
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav-btn:hover {
|
||||||
|
color: #15803d;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav-btn-active {
|
||||||
|
background: #16a34a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Write button -- */
|
||||||
|
[data-theme="liquid-glass"] .journal-write-btn {
|
||||||
|
background: #16a34a;
|
||||||
|
box-shadow: 0 4px 16px rgba(22, 163, 74, 0.35);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .journal-write-btn:hover:not(:disabled) {
|
||||||
|
background: #15803d;
|
||||||
|
box-shadow: 0 6px 24px rgba(22, 163, 74, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Desktop sidebar nav glass -- */
|
||||||
|
@media (min-width: 860px) {
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav {
|
||||||
|
background: var(--glass-bg);
|
||||||
|
border-right-color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
[data-theme="liquid-glass"] .bottom-nav-brand {
|
||||||
|
border-bottom-color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .clock-picker__mode-btn--active {
|
[data-theme="dark"] .clock-picker__mode-btn--active {
|
||||||
background: #4ade80;
|
background: #4ade80;
|
||||||
border-color: #4ade80;
|
border-color: #4ade80;
|
||||||
|
|||||||
@@ -96,3 +96,28 @@ button:focus-visible {
|
|||||||
[data-theme="dark"] body {
|
[data-theme="dark"] body {
|
||||||
background: #0a0a0a;
|
background: #0a0a0a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Liquid Glass theme root overrides ───────────────────── */
|
||||||
|
[data-theme="liquid-glass"] {
|
||||||
|
--glass-bg: rgba(255, 255, 255, 0.18);
|
||||||
|
--glass-blur: blur(28px) saturate(200%) brightness(1.05);
|
||||||
|
--glass-border: 1px solid rgba(255, 255, 255, 0.55);
|
||||||
|
--glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
|
||||||
|
--color-primary: #16a34a;
|
||||||
|
--color-primary-hover: #15803d;
|
||||||
|
--color-bg-soft: transparent;
|
||||||
|
--color-surface: var(--glass-bg);
|
||||||
|
--color-accent-light: rgba(220, 252, 231, 0.4);
|
||||||
|
--color-text: #0f172a;
|
||||||
|
--color-text-muted: #334155;
|
||||||
|
--color-border: rgba(255, 255, 255, 0.4);
|
||||||
|
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: transparent;
|
||||||
|
caret-color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Same bg as light theme when no custom image is set */
|
||||||
|
[data-theme="liquid-glass"] body:not(.gj-has-bg) {
|
||||||
|
background: #eef6ee;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import './index.css'
|
|||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import { listenForegroundMessages } from './hooks/useReminder'
|
import { listenForegroundMessages } from './hooks/useReminder'
|
||||||
|
|
||||||
|
// Apply saved theme immediately to avoid flash
|
||||||
|
const savedTheme = localStorage.getItem('gj-theme') || 'light'
|
||||||
|
document.documentElement.setAttribute('data-theme', savedTheme)
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
navigator.serviceWorker.register('/sw.js')
|
navigator.serviceWorker.register('/sw.js')
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default function AboutPage() {
|
|||||||
|
|
||||||
<h2>Features</h2>
|
<h2>Features</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>End-to-end encrypted</strong> — your entries are encrypted before leaving your device. We cannot read them.</li>
|
<li><strong>End-to-end encrypted entries</strong> — your journal content is encrypted before leaving your device. We cannot read it.</li>
|
||||||
<li><strong>No ads, no tracking</strong> — we don't sell your data or show you ads.</li>
|
<li><strong>No ads, no tracking</strong> — we don't sell your data or show you ads.</li>
|
||||||
<li><strong>Works offline</strong> — installable as a PWA on Android, iOS, and desktop.</li>
|
<li><strong>Works offline</strong> — installable as a PWA on Android, iOS, and desktop.</li>
|
||||||
<li><strong>Daily prompts</strong> — gentle nudges to keep your practice consistent.</li>
|
<li><strong>Daily prompts</strong> — gentle nudges to keep your practice consistent.</li>
|
||||||
@@ -48,7 +48,10 @@ export default function AboutPage() {
|
|||||||
<h2>Privacy first</h2>
|
<h2>Privacy first</h2>
|
||||||
<p>
|
<p>
|
||||||
We built Grateful Journal because we believe your inner thoughts deserve a private space.
|
We built Grateful Journal because we believe your inner thoughts deserve a private space.
|
||||||
Read our full <Link to="/privacy">Privacy Policy</Link> to understand exactly how your data is protected.
|
Your journal entries are end-to-end encrypted — only you can read them. App preferences
|
||||||
|
such as your display name, profile photo, and background images are stored as plain account
|
||||||
|
settings and are not encrypted. Read our full <Link to="/privacy">Privacy Policy</Link> for
|
||||||
|
a complete breakdown of what is and isn't encrypted.
|
||||||
</p>
|
</p>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { usePageMeta } from '../hooks/usePageMeta'
|
|||||||
export default function PrivacyPage() {
|
export default function PrivacyPage() {
|
||||||
usePageMeta({
|
usePageMeta({
|
||||||
title: 'Privacy Policy — Grateful Journal',
|
title: 'Privacy Policy — Grateful Journal',
|
||||||
description: 'Grateful Journal\'s privacy policy. Your journal entries are end-to-end encrypted — we cannot read them. No ads, no tracking, no data selling.',
|
description: 'Grateful Journal\'s privacy policy. Your journal entries are end-to-end encrypted — we cannot read them. App preferences are stored unencrypted. No ads, no tracking.',
|
||||||
canonical: 'https://gratefuljournal.online/privacy',
|
canonical: 'https://gratefuljournal.online/privacy',
|
||||||
ogTitle: 'Privacy Policy — Grateful Journal',
|
ogTitle: 'Privacy Policy — Grateful Journal',
|
||||||
ogDescription: 'Your journal entries are end-to-end encrypted and private. We cannot read them, we don\'t sell your data, and we use no advertising cookies.',
|
ogDescription: 'Your journal entries are end-to-end encrypted and private. App preferences like background images are stored unencrypted. No ads, no tracking, no data selling.',
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<div className="static-page">
|
<div className="static-page">
|
||||||
@@ -17,7 +17,7 @@ export default function PrivacyPage() {
|
|||||||
|
|
||||||
<main className="static-page__content">
|
<main className="static-page__content">
|
||||||
<h1>Privacy Policy</h1>
|
<h1>Privacy Policy</h1>
|
||||||
<p className="static-page__updated">Last updated: April 8, 2026</p>
|
<p className="static-page__updated">Last updated: April 14, 2026</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Grateful Journal is built on a simple promise: your journal entries are yours alone.
|
Grateful Journal is built on a simple promise: your journal entries are yours alone.
|
||||||
@@ -28,13 +28,21 @@ export default function PrivacyPage() {
|
|||||||
<ul>
|
<ul>
|
||||||
<li><strong>Account info</strong> — your name and email address via Google Sign-In, used solely to identify your account.</li>
|
<li><strong>Account info</strong> — your name and email address via Google Sign-In, used solely to identify your account.</li>
|
||||||
<li><strong>Journal entries</strong> — stored encrypted in our database. We do not have access to the content of your entries.</li>
|
<li><strong>Journal entries</strong> — stored encrypted in our database. We do not have access to the content of your entries.</li>
|
||||||
|
<li><strong>App preferences</strong> — your display name, profile photo, background images, and theme are stored unencrypted as account settings. See the Encryption section below for the full breakdown.</li>
|
||||||
<li><strong>Usage data</strong> — no analytics, no tracking pixels, no third-party advertising SDKs.</li>
|
<li><strong>Usage data</strong> — no analytics, no tracking pixels, no third-party advertising SDKs.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Encryption</h2>
|
<h2>Encryption</h2>
|
||||||
<p>
|
<p>
|
||||||
Your journal entries are end-to-end encrypted. They are encrypted on your device before being sent to our servers.
|
Encryption is applied selectively based on the sensitivity of each type of data:
|
||||||
We store only the encrypted ciphertext — decryption happens locally in your browser using your account key.
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Journal entries — end-to-end encrypted.</strong> Entries are encrypted on your device using XSalsa20-Poly1305 before being sent to our servers. We store only ciphertext. Decryption happens locally in your browser using a key derived from your account. We cannot read your entries.</li>
|
||||||
|
<li><strong>App preferences — not encrypted.</strong> Your display name, profile photo, background images, and theme setting are stored as plain data. These are appearance and account settings, not personal journal content. They are accessible to us at the database level.</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
If you upload a personal photo as a background image, be aware that it is stored unencrypted on our servers.
|
||||||
|
For maximum privacy, use abstract or non-personal images as backgrounds.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Data sharing</h2>
|
<h2>Data sharing</h2>
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ export default function SettingsPage() {
|
|||||||
const { user, userId, mongoUser, signOut, loading, refreshMongoUser } = useAuth()
|
const { user, userId, mongoUser, signOut, loading, refreshMongoUser } = useAuth()
|
||||||
// const [passcodeEnabled, setPasscodeEnabled] = useState(false) // Passcode lock — disabled for now
|
// const [passcodeEnabled, setPasscodeEnabled] = useState(false) // Passcode lock — disabled for now
|
||||||
// const [faceIdEnabled, setFaceIdEnabled] = useState(false) // Face ID — disabled for now
|
// const [faceIdEnabled, setFaceIdEnabled] = useState(false) // Face ID — disabled for now
|
||||||
const [theme, setTheme] = useState<'light' | 'dark'>(() => {
|
const [theme, setTheme] = useState<'light' | 'dark' | 'liquid-glass'>(() => {
|
||||||
return (localStorage.getItem('gj-theme') as 'light' | 'dark') || 'light'
|
return (localStorage.getItem('gj-theme') as 'light' | 'dark' | 'liquid-glass') || 'light'
|
||||||
})
|
})
|
||||||
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null)
|
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null)
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ export default function SettingsPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply theme to DOM
|
// Apply theme to DOM
|
||||||
const applyTheme = useCallback((t: 'light' | 'dark') => {
|
const applyTheme = useCallback((t: 'light' | 'dark' | 'liquid-glass') => {
|
||||||
document.documentElement.setAttribute('data-theme', t)
|
document.documentElement.setAttribute('data-theme', t)
|
||||||
localStorage.setItem('gj-theme', t)
|
localStorage.setItem('gj-theme', t)
|
||||||
}, [])
|
}, [])
|
||||||
@@ -239,10 +239,11 @@ export default function SettingsPage() {
|
|||||||
applyTheme(theme)
|
applyTheme(theme)
|
||||||
}, [theme, applyTheme])
|
}, [theme, applyTheme])
|
||||||
|
|
||||||
const handleThemeChange = (newTheme: 'light' | 'dark') => {
|
const handleThemeChange = (newTheme: 'light' | 'dark' | 'liquid-glass') => {
|
||||||
setTheme(newTheme)
|
setTheme(newTheme)
|
||||||
applyTheme(newTheme)
|
applyTheme(newTheme)
|
||||||
setMessage({ type: 'success', text: `Switched to ${newTheme === 'light' ? 'Light' : 'Dark'} theme` })
|
const label = newTheme === 'light' ? 'Light' : newTheme === 'dark' ? 'Dark' : 'Liquid Glass'
|
||||||
|
setMessage({ type: 'success', text: `Switched to ${label} theme` })
|
||||||
setTimeout(() => setMessage(null), 2000)
|
setTimeout(() => setMessage(null), 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +561,9 @@ export default function SettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="settings-item-content">
|
<div className="settings-item-content">
|
||||||
<h4 className="settings-item-title">Theme</h4>
|
<h4 className="settings-item-title">Theme</h4>
|
||||||
<p className="settings-item-subtitle">Currently: {theme === 'light' ? 'Light' : 'Dark'}</p>
|
<p className="settings-item-subtitle">
|
||||||
|
Currently: {theme === 'light' ? 'Light' : theme === 'dark' ? 'Dark' : 'Liquid Glass'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-theme-colors">
|
<div className="settings-theme-colors">
|
||||||
<button
|
<button
|
||||||
@@ -575,6 +578,12 @@ export default function SettingsPage() {
|
|||||||
className={`settings-theme-dot settings-theme-dot-dark${theme === 'dark' ? ' settings-theme-dot-active' : ''}`}
|
className={`settings-theme-dot settings-theme-dot-dark${theme === 'dark' ? ' settings-theme-dot-active' : ''}`}
|
||||||
title="Dark theme"
|
title="Dark theme"
|
||||||
></button>
|
></button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleThemeChange('liquid-glass')}
|
||||||
|
className={`settings-theme-dot settings-theme-dot-glass${theme === 'liquid-glass' ? ' settings-theme-dot-active' : ''}`}
|
||||||
|
title="Liquid Glass theme"
|
||||||
|
></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ export default function TermsOfServicePage() {
|
|||||||
<h2>3. Your Content</h2>
|
<h2>3. Your Content</h2>
|
||||||
<p>
|
<p>
|
||||||
You own all journal entries and content you create. We do not claim any ownership over your
|
You own all journal entries and content you create. We do not claim any ownership over your
|
||||||
content. Your entries are end-to-end encrypted and inaccessible to us. You are solely
|
content. Your journal entries are end-to-end encrypted and inaccessible to us. App preferences
|
||||||
responsible for the content you store in the app.
|
such as your display name, profile photo, and background images are stored as plain account
|
||||||
|
settings and are accessible to us at the database level. You are solely responsible for the
|
||||||
|
content you store in the app, including any images you upload as backgrounds.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>4. Prohibited Conduct</h2>
|
<h2>4. Prohibited Conduct</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user