From 6fb7ab4ca8dd88eb12718fdbfdd561a8b0064490 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 19:05:45 +0000 Subject: [PATCH 1/3] Move theme settings to inside settings view, remove system theme, and replace theme toggle with mobile chat history toggle button Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com> --- .gitignore | 3 + bun.lock | 2 - components/header.tsx | 4 +- components/mobile-icons-bar.tsx | 2 - components/settings/components/settings.tsx | 96 ++++++++++++++++++++- tests/header.spec.ts | 15 ++-- tests/responsive.spec.ts | 17 +++- 7 files changed, 125 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 4d43ddd2..d18a1e51 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ aef_index.csv *.log deno.json edge_function/ + +# clerk configuration (can include secrets) +/.clerk/ diff --git a/bun.lock b/bun.lock index a3356db6..751e6b5f 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "QCX", @@ -72,7 +71,6 @@ "next-themes": "^0.3.0", "open-codex": "^0.1.30", "pg": "^8.22.0", - "postgres": "^3.4.9", "proj4": "^2.20.2", "radix-ui": "^1.3.4", "react": "19.1.2", diff --git a/components/header.tsx b/components/header.tsx index c472bcac..9e5ea92f 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -2,7 +2,7 @@ import React from 'react' import Image from 'next/image' import { useCalendarToggle } from './calendar-toggle-context' -import { ModeToggle } from './mode-toggle' +import { History } from './history' import { cn } from '@/lib/utils' import HistoryContainer from './history-container' import { Button } from '@/components/ui/button' @@ -81,7 +81,7 @@ export const Header = () => { - + diff --git a/components/mobile-icons-bar.tsx b/components/mobile-icons-bar.tsx index 379764bc..48c11651 100644 --- a/components/mobile-icons-bar.tsx +++ b/components/mobile-icons-bar.tsx @@ -16,7 +16,6 @@ import { } from 'lucide-react' import { History } from '@/components/history' import { MapToggle } from './map-toggle' -import { ModeToggle } from './mode-toggle' import { ProfileToggle } from './profile-toggle' import { useCalendarToggle } from './calendar-toggle-context' import { useUsageToggle } from './usage-toggle-context' @@ -68,7 +67,6 @@ export const MobileIconsBar: React.FC = ({ onAttachmentClic - ) } diff --git a/components/settings/components/settings.tsx b/components/settings/components/settings.tsx index b51ba70d..7addf97a 100644 --- a/components/settings/components/settings.tsx +++ b/components/settings/components/settings.tsx @@ -7,7 +7,9 @@ import { useRouter } from 'next/navigation' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import * as z from 'zod' -import { Loader2, Save, RotateCcw } from 'lucide-react' +import { Loader2, Save, RotateCcw, Sun, Moon, Earth } from 'lucide-react' +import { useTheme } from 'next-themes' +import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' @@ -71,6 +73,18 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) { const [currentTab, setCurrentTab] = useState(initialTab); const { mapProvider, setMapProvider } = useSettingsStore(); const { user, loading: authLoading } = useCurrentUser(); + const { theme, setTheme } = useTheme() + const [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) + const { theme, setTheme } = useTheme() + const [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) useEffect(() => { setCurrentTab(initialTab); @@ -153,6 +167,7 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) { function onReset() { form.reset(defaultValues) + setTheme('earth') toast({ title: "Settings reset", description: "Your settings have been reset to default values.", @@ -164,11 +179,12 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) {
- + System Prompt Model Selection User Management Map + Theme + + + + + Theme Selection + Select the theme for your planetary copilot + + +
+ {[ + { name: 'Light', value: 'light', icon: Sun }, + { name: 'Dark', value: 'dark', icon: Moon }, + { name: 'Earth', value: 'earth', icon: Earth }, + ].map((t) => { + const Icon = t.icon + const isActive = mounted && theme === t.value + return ( + + ) + })} +
+
+
+
+ + + + + Theme Selection + Select the theme for your planetary copilot + + +
+ {[ + { name: 'Light', value: 'light', icon: Sun }, + { name: 'Dark', value: 'dark', icon: Moon }, + { name: 'Earth', value: 'earth', icon: Earth }, + ].map((t) => { + const Icon = t.icon + const isActive = mounted && theme === t.value + return ( + + ) + })} +
+
+
+
diff --git a/tests/header.spec.ts b/tests/header.spec.ts index 55065420..e536a097 100644 --- a/tests/header.spec.ts +++ b/tests/header.spec.ts @@ -3,16 +3,21 @@ import { test, expect } from '@playwright/test'; test.describe('Header and Navigation', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); - test('should toggle the theme', async ({ page }) => { - await page.click('[data-testid="theme-toggle"]'); - await page.click('[data-testid="theme-dark"]'); + test('should toggle the theme in settings', async ({ page }) => { + await page.click('[data-testid="profile-toggle"]'); + await page.click('[data-testid="profile-settings"]'); + await page.click('[data-testid="theme-tab-trigger"]'); + + await page.click('[data-testid="theme-select-dark"]'); const html = page.locator('html'); await expect(html).toHaveClass(/(^|\s)dark(\s|$)/); - await page.click('[data-testid="theme-toggle"]'); - await page.click('[data-testid="theme-light"]'); + await page.click('[data-testid="theme-select-light"]'); await expect(html).not.toHaveClass(/(^|\s)dark(\s|$)/); }); diff --git a/tests/responsive.spec.ts b/tests/responsive.spec.ts index a53fcd6e..e3129237 100644 --- a/tests/responsive.spec.ts +++ b/tests/responsive.spec.ts @@ -5,6 +5,9 @@ test.describe('Responsive design - Desktop', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); test('should display desktop layout', async ({ page }) => { @@ -18,7 +21,7 @@ test.describe('Responsive design - Desktop', () => { }); test('should display full header with all elements', async ({ page }) => { - await expect(page.locator('[data-testid="theme-toggle"]')).toBeVisible(); + await expect(page.locator('[data-testid="history-button"]').first()).toBeVisible(); await expect(page.locator('[data-testid="profile-toggle"]')).toBeVisible(); await expect(page.locator('[data-testid="calendar-toggle"]')).toBeVisible(); }); @@ -44,6 +47,9 @@ test.describe('Responsive design - Tablet', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); test('should display tablet layout', async ({ page }) => { @@ -96,6 +102,9 @@ test.describe('Responsive design - Mobile', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); test('should display mobile layout', async ({ page }) => { @@ -195,6 +204,9 @@ test.describe('Responsive design - Small Mobile', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); test('should work on very small screens', async ({ page }) => { @@ -229,6 +241,9 @@ test.describe('Responsive design - Large Desktop', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); + try { + await page.locator('text=Later').click({ timeout: 3000 }); + } catch (e) {} }); test('should utilize large screen space', async ({ page }) => { From 3b722058d4307e79849100b4d417487b65b9147c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 19:32:37 +0000 Subject: [PATCH 2/3] Move theme settings to inside settings view, remove system theme, and replace theme toggle with mobile chat history toggle button Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com> --- .gitignore | 3 -- bun.lock | 2 + components/settings/components/settings.tsx | 44 --------------------- 3 files changed, 2 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index d18a1e51..4d43ddd2 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,3 @@ aef_index.csv *.log deno.json edge_function/ - -# clerk configuration (can include secrets) -/.clerk/ diff --git a/bun.lock b/bun.lock index 751e6b5f..a3356db6 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "QCX", @@ -71,6 +72,7 @@ "next-themes": "^0.3.0", "open-codex": "^0.1.30", "pg": "^8.22.0", + "postgres": "^3.4.9", "proj4": "^2.20.2", "radix-ui": "^1.3.4", "react": "19.1.2", diff --git a/components/settings/components/settings.tsx b/components/settings/components/settings.tsx index 7addf97a..0b94171c 100644 --- a/components/settings/components/settings.tsx +++ b/components/settings/components/settings.tsx @@ -76,12 +76,6 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) { const { theme, setTheme } = useTheme() const [mounted, setMounted] = useState(false) - useEffect(() => { - setMounted(true) - }, []) - const { theme, setTheme } = useTheme() - const [mounted, setMounted] = useState(false) - useEffect(() => { setMounted(true) }, []) @@ -283,44 +277,6 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) { - - - - - Theme Selection - Select the theme for your planetary copilot - - -
- {[ - { name: 'Light', value: 'light', icon: Sun }, - { name: 'Dark', value: 'dark', icon: Moon }, - { name: 'Earth', value: 'earth', icon: Earth }, - ].map((t) => { - const Icon = t.icon - const isActive = mounted && theme === t.value - return ( - - ) - })} -
-
-
-
From a352faabd38d9d4ca8c15a7da007e96716f88e60 Mon Sep 17 00:00:00 2001 From: ngoiyaeric <1.15367894e+08+ngoiyaeric@users.noreply.github.com> Date: Fri, 10 Jul 2026 19:51:19 +0000 Subject: [PATCH 3/3] fix: enable profile icon on mobile, move theme icons above settings, equal icon spacing, fix resolution search - Enable profile toggle on mobile (removed disabled prop, added onClick to open settings) - Move theme selector icons above settings tabs instead of separate Theme tab - Make mobile icons bar icons equally spaced using flex-1 wrappers - Fix resolution search button disabled logic to support Google Maps (check mapProvider) - Update tests to reflect new behavior --- app/globals.css | 9 +++ components/header-search-button.tsx | 2 +- components/mobile-icons-bar.tsx | 10 ++- components/profile-toggle.tsx | 9 ++- components/settings/components/settings.tsx | 78 ++++++++++----------- components/settings/settings-view.tsx | 1 + tests/header.spec.ts | 2 +- tests/mobile.spec.ts | 6 +- 8 files changed, 69 insertions(+), 48 deletions(-) diff --git a/app/globals.css b/app/globals.css index 7f2c280f..692cb0a5 100644 --- a/app/globals.css +++ b/app/globals.css @@ -154,6 +154,15 @@ flex-shrink: 0; } + /* Ensure flex-1 wrappers inside icons bar don't expand too much */ + .mobile-icons-bar-content .flex-1 { + flex: 1 1 0; + min-width: 0; + display: flex; + justify-content: center; + align-items: center; + } + /* .mobile-chat-section { flex: 1; diff --git a/components/header-search-button.tsx b/components/header-search-button.tsx index 7090a52c..66d9dfcc 100644 --- a/components/header-search-button.tsx +++ b/components/header-search-button.tsx @@ -183,7 +183,7 @@ export function HeaderSearchButton() { ) const mobileButton = ( - - - +
+ +
+
+ +
diff --git a/components/profile-toggle.tsx b/components/profile-toggle.tsx index b942facf..1193fc60 100644 --- a/components/profile-toggle.tsx +++ b/components/profile-toggle.tsx @@ -65,9 +65,16 @@ export function ProfileToggle() { return } + // Mobile: show profile icon as a direct button that opens the profile view if (isMobile) { return ( - diff --git a/components/settings/components/settings.tsx b/components/settings/components/settings.tsx index 0b94171c..30992ac2 100644 --- a/components/settings/components/settings.tsx +++ b/components/settings/components/settings.tsx @@ -172,13 +172,49 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) {
+ {/* Theme selector placed above the tabs */} + + + Theme Selection + Select the theme for your planetary copilot + + +
+ {[ + { name: 'Light', value: 'light', icon: Sun }, + { name: 'Dark', value: 'dark', icon: Moon }, + { name: 'Earth', value: 'earth', icon: Earth }, + ].map((t) => { + const Icon = t.icon + const isActive = mounted && theme === t.value + return ( + + ) + })} +
+
+
+ - + System Prompt Model Selection User Management Map - Theme - - - - Theme Selection - Select the theme for your planetary copilot - - -
- {[ - { name: 'Light', value: 'light', icon: Sun }, - { name: 'Dark', value: 'dark', icon: Moon }, - { name: 'Earth', value: 'earth', icon: Earth }, - ].map((t) => { - const Icon = t.icon - const isActive = mounted && theme === t.value - return ( - - ) - })} -
-
-
-
+
diff --git a/components/settings/settings-view.tsx b/components/settings/settings-view.tsx index cddce42f..b9e94844 100644 --- a/components/settings/settings-view.tsx +++ b/components/settings/settings-view.tsx @@ -8,6 +8,7 @@ import { DownloadReportButton } from "@/components/download-report-button" export default function SettingsView() { const { toggleProfileSection, activeView } = useProfileToggle(); + // Appearance now shows the theme selector (above tabs) with system-prompt as default tab const initialTab = activeView === ProfileToggleEnum.Security ? "user-management" : "system-prompt"; const handleClose = () => { diff --git a/tests/header.spec.ts b/tests/header.spec.ts index e536a097..23091a82 100644 --- a/tests/header.spec.ts +++ b/tests/header.spec.ts @@ -9,9 +9,9 @@ test.describe('Header and Navigation', () => { }); test('should toggle the theme in settings', async ({ page }) => { + // Theme selector is now placed above the settings tabs await page.click('[data-testid="profile-toggle"]'); await page.click('[data-testid="profile-settings"]'); - await page.click('[data-testid="theme-tab-trigger"]'); await page.click('[data-testid="theme-select-dark"]'); const html = page.locator('html'); diff --git a/tests/mobile.spec.ts b/tests/mobile.spec.ts index d138f4f6..3cb07d8e 100644 --- a/tests/mobile.spec.ts +++ b/tests/mobile.spec.ts @@ -9,9 +9,9 @@ test.describe('Mobile UI', () => { await page.locator('[data-testid="chat-input"]').waitFor({ state: 'visible', timeout: 30000 }); }); - test('profile toggle button should be disabled', async ({ page }) => { - // Check that the profile toggle is disabled on mobile - await expect(page.locator('.mobile-icons-bar-content [data-testid="profile-toggle"]')).toBeDisabled(); + test('profile toggle button should be enabled on mobile', async ({ page }) => { + // Check that the profile toggle is enabled and clickable on mobile + await expect(page.locator('.mobile-icons-bar-content [data-testid="profile-toggle"]')).toBeEnabled(); }); test('should have an enabled submit button', async ({ page }) => {