86 lines
3.6 KiB
TypeScript
86 lines
3.6 KiB
TypeScript
import { useState } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { ChevronUp, X } from 'lucide-react';
|
|
import { useTranslation } from '@/contexts/language';
|
|
import { useMapFooterHidden } from '@/hooks/useMapFooterHidden';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
/**
|
|
* The site links that live in the desktop footer — surfaced on the map
|
|
* (a full-bleed route where the footer is hidden) without stealing map height.
|
|
*
|
|
* Desktop: a slim full-width bar. Mobile: a tiny collapsed "Links" chip that
|
|
* expands to a compact row. Dismissible, and restorable from Settings →
|
|
* Appearance.
|
|
*/
|
|
export function MapFooterStrip() {
|
|
const { t } = useTranslation();
|
|
const [hidden, setHidden] = useMapFooterHidden();
|
|
const [open, setOpen] = useState(false);
|
|
|
|
if (hidden) return null;
|
|
|
|
const links = [
|
|
{ to: '/diy', label: t('nav.diy') },
|
|
{ to: '/newsletter', label: t('nav.newsletter') },
|
|
{ to: '/license', label: t('chromeUi.license') },
|
|
{ to: '/privacy', label: t('chromeUi.privacy') },
|
|
];
|
|
|
|
return (
|
|
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-[1000]">
|
|
{/* Desktop — slim full-width bar */}
|
|
<div className="pointer-events-auto hidden w-full items-center justify-between gap-4 border-t border-white/10 bg-black/85 px-4 py-1.5 text-[11px] text-gray-400 backdrop-blur md:flex">
|
|
<div className="flex items-center gap-4">
|
|
{links.map((l) => (
|
|
<Link key={l.to} to={l.to} className="font-medium transition-colors hover:text-[#ccff00]">
|
|
{l.label}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="flex items-center gap-1.5 text-gray-500">
|
|
{t('chromeUi.notSponsoredBy')}
|
|
<img src="https://opensats.org/favicon.ico" alt="OpenSats" className="h-3 w-3" />
|
|
<span className="font-medium text-gray-400">OpenSats</span>
|
|
</span>
|
|
<button
|
|
onClick={() => setHidden(true)}
|
|
aria-label={t('mapUi.mapFooter.hide')}
|
|
className="min-h-0 min-w-0 text-gray-500 transition-colors hover:text-white"
|
|
>
|
|
<X className="h-3.5 w-3.5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile — a tiny chip that expands to a compact row */}
|
|
<div className="pointer-events-auto relative mb-1.5 flex justify-center md:hidden">
|
|
{open && (
|
|
<div className="absolute bottom-full left-1/2 mb-1.5 flex max-w-[calc(100vw-1rem)] -translate-x-1/2 items-center gap-3 overflow-x-auto whitespace-nowrap rounded-full border border-white/10 bg-black/85 px-3 py-1.5 text-[10px] text-gray-300 backdrop-blur scrollbar-hide">
|
|
{links.map((l) => (
|
|
<Link key={l.to} to={l.to} className="font-medium hover:text-[#ccff00]">
|
|
{l.label}
|
|
</Link>
|
|
))}
|
|
<button
|
|
onClick={() => setHidden(true)}
|
|
aria-label={t('mapUi.mapFooter.hide')}
|
|
className="min-h-0 min-w-0 text-gray-500 hover:text-white"
|
|
>
|
|
<X className="h-3 w-3" />
|
|
</button>
|
|
</div>
|
|
)}
|
|
<button
|
|
onClick={() => setOpen((v) => !v)}
|
|
aria-expanded={open}
|
|
className="flex min-h-0 items-center gap-1 rounded-full bg-black/45 px-2.5 py-[3px] text-[10px] font-semibold text-gray-400/90 backdrop-blur transition-colors hover:text-gray-200"
|
|
>
|
|
<ChevronUp className={cn('h-3 w-3 transition-transform', open && 'rotate-180')} />
|
|
{t('mapUi.mapFooter.links')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|