205 lines
8.4 KiB
TypeScript
205 lines
8.4 KiB
TypeScript
'use client';
|
|
|
|
import { useRef, useState, useEffect } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import PageLayout from './components/PageLayout';
|
|
import Crosshair from './components/Crosshair';
|
|
import Waves from './components/background/waves';
|
|
import { usePublicDashboardPlatforms } from './hooks/usePublicDashboardPlatforms';
|
|
import {
|
|
LinkIcon,
|
|
ShoppingBagIcon,
|
|
UserCircleIcon,
|
|
UsersIcon,
|
|
} from '@heroicons/react/24/outline';
|
|
import type { ComponentType, SVGProps } from 'react';
|
|
import type { DashboardPlatformIconName } from './utils/dashboardPlatforms';
|
|
|
|
export default function HomePage() {
|
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
const [isMobile, setIsMobile] = useState(() => {
|
|
if (typeof window === 'undefined') return false;
|
|
return window.matchMedia('(max-width: 768px)').matches;
|
|
});
|
|
const router = useRouter();
|
|
const isShopEnabled = process.env.NEXT_PUBLIC_SHOW_SHOP !== 'false';
|
|
const { platforms, loading, error } = usePublicDashboardPlatforms();
|
|
|
|
// Keep breakpoint updated (resize/orientation)
|
|
useEffect(() => {
|
|
const mq = window.matchMedia('(max-width: 768px)');
|
|
const apply = () => setIsMobile(mq.matches);
|
|
mq.addEventListener?.('change', apply);
|
|
window.addEventListener('resize', apply, { passive: true });
|
|
return () => {
|
|
mq.removeEventListener?.('change', apply);
|
|
window.removeEventListener('resize', apply);
|
|
};
|
|
}, []);
|
|
|
|
const icons: Record<DashboardPlatformIconName, ComponentType<SVGProps<SVGSVGElement>>> = {
|
|
ShoppingBagIcon,
|
|
LinkIcon,
|
|
UsersIcon,
|
|
UserCircleIcon,
|
|
};
|
|
|
|
const goTo = (href: string) => {
|
|
const trimmed = (href || '').trim();
|
|
if (!trimmed) return;
|
|
if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
|
window.location.href = trimmed;
|
|
return;
|
|
}
|
|
router.push(trimmed);
|
|
};
|
|
|
|
return (
|
|
<PageLayout>
|
|
<div
|
|
ref={containerRef}
|
|
className="min-h-screen relative overflow-hidden bg-transparent text-gray-900"
|
|
>
|
|
{/* Waves background */}
|
|
<Waves
|
|
className="pointer-events-none"
|
|
lineColor="#0f172a"
|
|
backgroundColor="rgba(245, 245, 240, 1)"
|
|
waveSpeedX={0.02}
|
|
waveSpeedY={0.01}
|
|
waveAmpX={40}
|
|
waveAmpY={20}
|
|
friction={0.9}
|
|
tension={0.01}
|
|
maxCursorMove={120}
|
|
xGap={12}
|
|
yGap={36}
|
|
animate={!isMobile}
|
|
interactive={!isMobile}
|
|
/>
|
|
|
|
<div className="relative z-10 min-h-screen flex items-center px-4 py-10 sm:py-14">
|
|
<div className="w-full max-w-7xl mx-auto">
|
|
<div className="flex flex-col gap-6">
|
|
<div className="rounded-3xl bg-white/70 backdrop-blur-md border border-white/60 shadow-lg p-6 sm:p-8">
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-5 sm:gap-6">
|
|
<img
|
|
src="/images/logos/PP_Logo_BW_round.png"
|
|
alt="Profit Planet"
|
|
className="h-16 w-16 sm:h-20 sm:w-20 object-contain"
|
|
/>
|
|
<div className="min-w-0 flex-1">
|
|
<div className="inline-flex items-center rounded-full border border-gray-200 bg-white/60 px-3 py-1 text-xs font-semibold text-gray-700">
|
|
Welcome
|
|
</div>
|
|
<h1 className="mt-3 text-5xl sm:text-6xl md:text-7xl font-black tracking-tight leading-none text-transparent bg-clip-text bg-gradient-to-r from-gray-900 via-gray-700 to-amber-700">
|
|
Profit Planet
|
|
</h1>
|
|
<p className="mt-3 text-sm sm:text-base text-gray-700">
|
|
Pick a platform to continue.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="rounded-3xl bg-white/70 backdrop-blur-md border border-white/60 shadow-lg p-6 sm:p-8">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div>
|
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-900">Platforms</h2>
|
|
<p className="mt-1 text-sm text-gray-700">Navigation shortcuts</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-6">
|
|
{loading && (
|
|
<div className="rounded-2xl border border-gray-200 bg-white p-6 text-center text-sm text-gray-600">
|
|
Loading…
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className="rounded-2xl border border-red-200 bg-red-50 p-6 text-center text-sm text-red-800">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
{!loading && !error && (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{platforms.map((platform) => {
|
|
const Icon = icons[platform.icon] || LinkIcon;
|
|
const disabledByEnv = platform.href === '/shop' && !isShopEnabled;
|
|
const isDisabled = Boolean(platform.disabled) || disabledByEnv;
|
|
const disabledText = disabledByEnv ? 'This is currently disabled.' : platform.disabledText;
|
|
|
|
return (
|
|
<button
|
|
key={platform.id}
|
|
onClick={() => {
|
|
if (!isDisabled) {
|
|
goTo(platform.href);
|
|
}
|
|
}}
|
|
disabled={isDisabled}
|
|
className={`rounded-2xl border text-left p-5 transition-all duration-200 ${
|
|
isDisabled
|
|
? 'border-gray-200 bg-white opacity-60 cursor-not-allowed'
|
|
: 'group border-gray-200 bg-white shadow-sm hover:shadow-md hover:-translate-y-0.5'
|
|
}`}
|
|
>
|
|
<div className="flex items-start gap-4">
|
|
<div
|
|
className={`${platform.color} rounded-xl p-3 ${
|
|
isDisabled
|
|
? 'grayscale'
|
|
: 'transition-transform group-hover:scale-105'
|
|
}`}
|
|
>
|
|
<Icon className="h-6 w-6 text-white" />
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex items-center justify-between gap-3">
|
|
<h3
|
|
className={`text-base font-semibold transition-colors ${
|
|
isDisabled
|
|
? 'text-gray-500'
|
|
: 'text-gray-900 hover:text-amber-700'
|
|
}`}
|
|
>
|
|
{platform.title}
|
|
</h3>
|
|
</div>
|
|
|
|
<p className="mt-1 text-sm text-gray-600">
|
|
{platform.description}
|
|
</p>
|
|
|
|
{isDisabled && disabledText && (
|
|
<p className="mt-3 text-xs font-medium text-amber-700">
|
|
{disabledText}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
})}
|
|
|
|
{platforms.length === 0 && (
|
|
<div className="sm:col-span-2 lg:col-span-3 rounded-2xl border border-gray-200 bg-white p-8 text-center text-sm text-gray-600">
|
|
No platforms available.
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* No parallax/crosshair on mobile */}
|
|
{!isMobile && <Crosshair containerRef={containerRef} color="#0f172a" />}
|
|
</div>
|
|
</PageLayout>
|
|
);
|
|
} |