Fix navigation
This commit is contained in:
parent
72653a4ddf
commit
5f30928c64
3 changed files with 65 additions and 61 deletions
|
|
@ -11,10 +11,15 @@ import { ClipboardIcon } from '../ui/icons/ClipboardIcon';
|
||||||
import { BookmarkIcon } from '../ui/icons/BookmarkIcon';
|
import { BookmarkIcon } from '../ui/icons/BookmarkIcon';
|
||||||
import { TrashIcon } from '../ui/icons/TrashIcon';
|
import { TrashIcon } from '../ui/icons/TrashIcon';
|
||||||
import { CloseIcon } from '../ui/icons/CloseIcon';
|
import { CloseIcon } from '../ui/icons/CloseIcon';
|
||||||
import { TabButton } from '../ui/TabButton';
|
import { SubNav } from '../ui/SubNav';
|
||||||
|
|
||||||
type AccountTab = 'saved' | 'settings';
|
type AccountTab = 'saved' | 'settings';
|
||||||
|
|
||||||
|
const ACCOUNT_TABS = [
|
||||||
|
{ key: 'saved', label: 'Saved Searches' },
|
||||||
|
{ key: 'settings', label: 'Settings' },
|
||||||
|
];
|
||||||
|
|
||||||
const SUBSCRIPTION_OPTIONS = ['free', 'licensed'] as const;
|
const SUBSCRIPTION_OPTIONS = ['free', 'licensed'] as const;
|
||||||
|
|
||||||
const SUBSCRIPTION_LABELS: Record<string, string> = {
|
const SUBSCRIPTION_LABELS: Record<string, string> = {
|
||||||
|
|
@ -493,7 +498,8 @@ export default function AccountPage({
|
||||||
return () => window.removeEventListener('hashchange', handleHashChange);
|
return () => window.removeEventListener('hashchange', handleHashChange);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const switchTab = (tab: AccountTab) => {
|
const switchTab = (key: string) => {
|
||||||
|
const tab = key as AccountTab;
|
||||||
setActiveTab(tab);
|
setActiveTab(tab);
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
window.history.state,
|
window.history.state,
|
||||||
|
|
@ -503,25 +509,10 @@ export default function AccountPage({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 overflow-y-auto bg-warm-50 dark:bg-warm-900">
|
<div className="flex-1 overflow-hidden bg-warm-50 dark:bg-warm-900 flex flex-col">
|
||||||
<div className="max-w-5xl mx-auto px-6 py-8">
|
<SubNav tabs={ACCOUNT_TABS} activeTab={activeTab} onTabChange={switchTab} />
|
||||||
<h1 className="text-2xl font-bold text-navy-950 dark:text-warm-100 mb-6">Account</h1>
|
<div className="flex-1 overflow-y-auto">
|
||||||
|
<div className="max-w-5xl mx-auto px-6 py-6">
|
||||||
{/* Tabs */}
|
|
||||||
<div className="flex border-b border-warm-200 dark:border-warm-700 mb-6">
|
|
||||||
<TabButton
|
|
||||||
label="Saved Searches"
|
|
||||||
isActive={activeTab === 'saved'}
|
|
||||||
onClick={() => switchTab('saved')}
|
|
||||||
/>
|
|
||||||
<TabButton
|
|
||||||
label="Settings"
|
|
||||||
isActive={activeTab === 'settings'}
|
|
||||||
onClick={() => switchTab('settings')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Tab content */}
|
|
||||||
{activeTab === 'saved' ? (
|
{activeTab === 'saved' ? (
|
||||||
<SavedSearchesContent
|
<SavedSearchesContent
|
||||||
searches={searches}
|
searches={searches}
|
||||||
|
|
@ -538,5 +529,6 @@ export default function AccountPage({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
import { useEffect, useState, useRef } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { ChevronIcon } from '../ui/icons/ChevronIcon';
|
import { ChevronIcon } from '../ui/icons/ChevronIcon';
|
||||||
|
import { SubNav } from '../ui/SubNav';
|
||||||
|
|
||||||
type LearnTab = 'data-sources' | 'faq' | 'support';
|
type LearnTab = 'data-sources' | 'faq' | 'support';
|
||||||
|
|
||||||
|
const LEARN_TABS = [
|
||||||
|
{ key: 'faq', label: 'FAQ' },
|
||||||
|
{ key: 'data-sources', label: 'Data Sources' },
|
||||||
|
{ key: 'support', label: 'Support' },
|
||||||
|
];
|
||||||
|
|
||||||
const DATA_SOURCES = [
|
const DATA_SOURCES = [
|
||||||
{
|
{
|
||||||
id: 'price-paid',
|
id: 'price-paid',
|
||||||
|
|
@ -288,36 +295,20 @@ export default function LearnPage() {
|
||||||
scrollContainerRef.current?.scrollTo(0, 0);
|
scrollContainerRef.current?.scrollTo(0, 0);
|
||||||
}, [tab]);
|
}, [tab]);
|
||||||
|
|
||||||
const tabClass = (t: LearnTab) =>
|
const switchTab = (key: string) => {
|
||||||
`px-4 py-2 text-sm font-medium rounded-t border-b-2 ${tab === t
|
setTab(key as LearnTab);
|
||||||
? 'border-teal-500 text-teal-700 dark:text-teal-400'
|
setHighlightedId(null);
|
||||||
: 'border-transparent text-warm-500 dark:text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'
|
};
|
||||||
}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 overflow-hidden bg-warm-50 dark:bg-navy-950 flex flex-col">
|
<div className="flex-1 overflow-hidden bg-warm-50 dark:bg-navy-950 flex flex-col">
|
||||||
<div className="max-w-5xl mx-auto w-full px-6 pt-6">
|
<SubNav tabs={LEARN_TABS} activeTab={tab} onTabChange={switchTab} />
|
||||||
<div className="flex gap-2 border-b border-warm-200 dark:border-warm-700">
|
|
||||||
<button className={tabClass('faq')} onClick={() => setTab('faq')}>
|
|
||||||
FAQ
|
|
||||||
</button>
|
|
||||||
<button className={tabClass('data-sources')} onClick={() => setTab('data-sources')}>
|
|
||||||
Data Sources
|
|
||||||
</button>
|
|
||||||
<button className={tabClass('support')} onClick={() => setTab('support')}>
|
|
||||||
Support
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto flex flex-col" ref={scrollContainerRef}>
|
<div className="flex-1 overflow-y-auto flex flex-col" ref={scrollContainerRef}>
|
||||||
{tab === 'data-sources' ? (
|
{tab === 'data-sources' ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="max-w-5xl mx-auto px-6 py-6">
|
<div className="max-w-5xl mx-auto px-6 py-6">
|
||||||
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
|
|
||||||
Data Sources
|
|
||||||
</h1>
|
|
||||||
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
||||||
This application combines {DATA_SOURCES.length} open datasets covering property
|
This application combines {DATA_SOURCES.length} open datasets covering property
|
||||||
prices, energy performance, transport, demographics, crime, environment, and more.
|
prices, energy performance, transport, demographics, crime, environment, and more.
|
||||||
|
|
@ -423,9 +414,6 @@ export default function LearnPage() {
|
||||||
</>
|
</>
|
||||||
) : tab === 'faq' ? (
|
) : tab === 'faq' ? (
|
||||||
<div className="max-w-3xl mx-auto px-6 py-6 w-full">
|
<div className="max-w-3xl mx-auto px-6 py-6 w-full">
|
||||||
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
|
|
||||||
Frequently Asked Questions
|
|
||||||
</h1>
|
|
||||||
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
||||||
Common questions about how Perfect Postcode works, where the data comes from, and how
|
Common questions about how Perfect Postcode works, where the data comes from, and how
|
||||||
to use the map.
|
to use the map.
|
||||||
|
|
@ -438,9 +426,6 @@ export default function LearnPage() {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="max-w-2xl mx-auto px-6 py-6 w-full">
|
<div className="max-w-2xl mx-auto px-6 py-6 w-full">
|
||||||
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
|
|
||||||
Support
|
|
||||||
</h1>
|
|
||||||
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
<p className="text-warm-600 dark:text-warm-400 mb-6">
|
||||||
Have a question? Check our FAQ or reach out to us directly.
|
Have a question? Check our FAQ or reach out to us directly.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
27
frontend/src/components/ui/SubNav.tsx
Normal file
27
frontend/src/components/ui/SubNav.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
interface SubNavProps {
|
||||||
|
tabs: { key: string; label: string }[];
|
||||||
|
activeTab: string;
|
||||||
|
onTabChange: (key: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SubNav({ tabs, activeTab, onTabChange }: SubNavProps) {
|
||||||
|
return (
|
||||||
|
<div className="max-w-5xl mx-auto w-full px-6 pt-4">
|
||||||
|
<div className="flex gap-2 border-b border-warm-200 dark:border-warm-700">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<button
|
||||||
|
key={tab.key}
|
||||||
|
className={`px-4 py-2 text-sm font-medium border-b-2 ${
|
||||||
|
activeTab === tab.key
|
||||||
|
? 'border-teal-500 text-teal-700 dark:text-teal-400'
|
||||||
|
: 'border-transparent text-warm-500 dark:text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'
|
||||||
|
}`}
|
||||||
|
onClick={() => onTabChange(tab.key)}
|
||||||
|
>
|
||||||
|
{tab.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue