Quick save
This commit is contained in:
parent
e5d5819098
commit
2906b01734
25 changed files with 1070 additions and 237 deletions
|
|
@ -1,14 +1,16 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import type { AuthUser } from '../../hooks/useAuth';
|
||||
import { DownloadIcon } from './icons/DownloadIcon';
|
||||
import { BookmarkIcon } from './icons/BookmarkIcon';
|
||||
import { MapPinIcon } from './icons/MapPinIcon';
|
||||
import { CheckIcon } from './icons/CheckIcon';
|
||||
import { ClipboardIcon } from './icons/ClipboardIcon';
|
||||
import { SunIcon } from './icons/SunIcon';
|
||||
import { MoonIcon } from './icons/MoonIcon';
|
||||
import { SpinnerIcon } from './icons/SpinnerIcon';
|
||||
import UserMenu from './UserMenu';
|
||||
|
||||
export type Page = 'home' | 'dashboard' | 'data-sources' | 'faq';
|
||||
export type Page = 'home' | 'dashboard' | 'data-sources' | 'faq' | 'saved-searches';
|
||||
|
||||
export default function Header({
|
||||
activePage,
|
||||
|
|
@ -17,8 +19,11 @@ export default function Header({
|
|||
onToggleTheme,
|
||||
onExport,
|
||||
exporting,
|
||||
onSaveSearch,
|
||||
savingSearch,
|
||||
user,
|
||||
onLoginClick,
|
||||
onRegisterClick,
|
||||
onLogout,
|
||||
}: {
|
||||
activePage: Page;
|
||||
|
|
@ -27,17 +32,34 @@ export default function Header({
|
|||
onToggleTheme: () => void;
|
||||
onExport: (() => void) | null;
|
||||
exporting: boolean;
|
||||
onSaveSearch: (() => void) | null;
|
||||
savingSearch: boolean;
|
||||
user: AuthUser | null;
|
||||
onLoginClick: () => void;
|
||||
onRegisterClick: () => void;
|
||||
onLogout: () => void;
|
||||
}) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleShare = useCallback(() => {
|
||||
navigator.clipboard.writeText(window.location.href).then(() => {
|
||||
const url = window.location.href;
|
||||
const onSuccess = () => {
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
});
|
||||
};
|
||||
if (navigator.clipboard?.writeText) {
|
||||
navigator.clipboard.writeText(url).then(onSuccess);
|
||||
} else {
|
||||
const ta = document.createElement('textarea');
|
||||
ta.value = url;
|
||||
ta.style.position = 'fixed';
|
||||
ta.style.opacity = '0';
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
onSuccess();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const tabClass = (page: Page) =>
|
||||
|
|
@ -67,20 +89,30 @@ export default function Header({
|
|||
<button className={tabClass('faq')} onClick={() => onPageChange('faq')}>
|
||||
FAQ
|
||||
</button>
|
||||
{user && (
|
||||
<button className={tabClass('saved-searches')} onClick={() => onPageChange('saved-searches')}>
|
||||
Saved
|
||||
</button>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{activePage === 'dashboard' && (
|
||||
<>
|
||||
<button
|
||||
onClick={onExport ?? undefined}
|
||||
disabled={!onExport || exporting}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm disabled:opacity-50 disabled:cursor-wait"
|
||||
title="Export to Excel"
|
||||
>
|
||||
<DownloadIcon className="w-4 h-4" />
|
||||
{exporting ? 'Exporting...' : 'Export'}
|
||||
</button>
|
||||
{onSaveSearch && (
|
||||
<button
|
||||
onClick={onSaveSearch}
|
||||
disabled={savingSearch}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm disabled:opacity-50 disabled:cursor-wait"
|
||||
>
|
||||
{savingSearch ? (
|
||||
<SpinnerIcon className="w-4 h-4 animate-spin" />
|
||||
) : (
|
||||
<BookmarkIcon className="w-4 h-4" />
|
||||
)}
|
||||
Save
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={handleShare}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm"
|
||||
|
|
@ -97,17 +129,34 @@ export default function Header({
|
|||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={onExport ?? undefined}
|
||||
disabled={!onExport || exporting}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm disabled:opacity-50 disabled:cursor-wait"
|
||||
title="Export to Excel"
|
||||
>
|
||||
<DownloadIcon className="w-4 h-4" />
|
||||
{exporting ? 'Exporting...' : 'Export'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{user ? (
|
||||
<UserMenu user={user} onLogout={onLogout} />
|
||||
) : (
|
||||
<button
|
||||
onClick={onLoginClick}
|
||||
className="px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
<>
|
||||
<button
|
||||
onClick={onLoginClick}
|
||||
className="px-3 py-1.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
<button
|
||||
onClick={onRegisterClick}
|
||||
className="px-3 py-1.5 rounded bg-teal-600 hover:bg-teal-700 transition-colors text-sm font-medium"
|
||||
>
|
||||
Register
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
onClick={onToggleTheme}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue