Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0db2f75a1 |
@ -1,166 +1,305 @@
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import Head from 'next/head';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import * as icon from '@mdi/js';
|
||||
import BaseIcon from '../components/BaseIcon';
|
||||
import BaseButton from '../components/BaseButton';
|
||||
import CardBox from '../components/CardBox';
|
||||
import SectionFullScreen from '../components/SectionFullScreen';
|
||||
import LayoutGuest from '../layouts/Guest';
|
||||
import BaseDivider from '../components/BaseDivider';
|
||||
import BaseButtons from '../components/BaseButtons';
|
||||
import { getPageTitle } from '../config';
|
||||
import { useAppSelector } from '../stores/hooks';
|
||||
import CardBoxComponentTitle from "../components/CardBoxComponentTitle";
|
||||
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
import { fetch as fetchDevices } from '../stores/devices/devicesSlice';
|
||||
|
||||
export default function LandingPage() {
|
||||
const router = useRouter();
|
||||
const dispatch = useAppDispatch();
|
||||
const { currentUser } = useAppSelector((state) => state.auth);
|
||||
const { devices, loading: devicesLoading } = useAppSelector((state) => state.devices);
|
||||
const darkMode = useAppSelector((state) => state.style.darkMode);
|
||||
|
||||
export default function Starter() {
|
||||
const [illustrationImage, setIllustrationImage] = useState({
|
||||
src: undefined,
|
||||
photographer: undefined,
|
||||
photographer_url: undefined,
|
||||
})
|
||||
const [illustrationVideo, setIllustrationVideo] = useState({video_files: []})
|
||||
const [contentType, setContentType] = useState('video');
|
||||
const [contentPosition, setContentPosition] = useState('right');
|
||||
const textColor = useAppSelector((state) => state.style.linkColor);
|
||||
const [activeTab, setActiveTab] = useState('pc');
|
||||
|
||||
const title = 'App Draft'
|
||||
useEffect(() => {
|
||||
if (currentUser) {
|
||||
dispatch(fetchDevices({ query: '?limit=5' }));
|
||||
}
|
||||
}, [currentUser, dispatch]);
|
||||
|
||||
// Fetch Pexels image/video
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
const image = await getPexelsImage();
|
||||
const video = await getPexelsVideo();
|
||||
setIllustrationImage(image);
|
||||
setIllustrationVideo(video);
|
||||
}
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const imageBlock = (image) => (
|
||||
<div
|
||||
className='hidden md:flex flex-col justify-end relative flex-grow-0 flex-shrink-0 w-1/3'
|
||||
style={{
|
||||
backgroundImage: `${
|
||||
image
|
||||
? `url(${image?.src?.original})`
|
||||
: 'linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5))'
|
||||
}`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'left center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
>
|
||||
<div className='flex justify-center w-full bg-blue-300/20'>
|
||||
<a
|
||||
className='text-[8px]'
|
||||
href={image?.photographer_url}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
Photo by {image?.photographer} on Pexels
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const videoBlock = (video) => {
|
||||
if (video?.video_files?.length > 0) {
|
||||
return (
|
||||
<div className='hidden md:flex flex-col justify-end relative flex-grow-0 flex-shrink-0 w-1/3'>
|
||||
<video
|
||||
className='absolute top-0 left-0 w-full h-full object-cover'
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
>
|
||||
<source src={video?.video_files[0]?.link} type='video/mp4'/>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
<div className='flex justify-center w-full bg-blue-300/20 z-10'>
|
||||
<a
|
||||
className='text-[8px]'
|
||||
href={video?.user?.url}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
Video by {video.user.name} on Pexels
|
||||
</a>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
};
|
||||
const features = [
|
||||
{
|
||||
title: 'Real-time Protection',
|
||||
description: 'Continuous monitoring for malware, viruses, and suspicious activities across all your platforms.',
|
||||
icon: icon.mdiShieldCheck,
|
||||
color: 'text-emerald-500',
|
||||
},
|
||||
{
|
||||
title: 'Cross-Device Sync',
|
||||
description: 'Connect your PC and Android devices seamlessly. Share security status and alerts instantly.',
|
||||
icon: icon.mdiSync,
|
||||
color: 'text-indigo-500',
|
||||
},
|
||||
{
|
||||
title: 'Remote Scan',
|
||||
description: 'Trigger a full system scan on your PC directly from your Android phone, or vice-versa.',
|
||||
icon: icon.mdiShieldSearch,
|
||||
color: 'text-blue-500',
|
||||
},
|
||||
{
|
||||
title: 'Privacy Guard',
|
||||
description: 'Protect your sensitive data with advanced encryption and privacy-focused browsing tools.',
|
||||
icon: icon.mdiLock,
|
||||
color: 'text-amber-500',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div
|
||||
style={
|
||||
contentPosition === 'background'
|
||||
? {
|
||||
backgroundImage: `${
|
||||
illustrationImage
|
||||
? `url(${illustrationImage.src?.original})`
|
||||
: 'linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5))'
|
||||
}`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'left center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<div className={`min-h-screen ${darkMode ? 'bg-slate-900 text-white' : 'bg-slate-50 text-slate-900'}`}>
|
||||
<Head>
|
||||
<title>{getPageTitle('Starter Page')}</title>
|
||||
<title>{getPageTitle('SecureGuard - Ultimate Multi-Device Security')}</title>
|
||||
</Head>
|
||||
|
||||
<SectionFullScreen bg='violet'>
|
||||
<div
|
||||
className={`flex ${
|
||||
contentPosition === 'right' ? 'flex-row-reverse' : 'flex-row'
|
||||
} min-h-screen w-full`}
|
||||
>
|
||||
{contentType === 'image' && contentPosition !== 'background'
|
||||
? imageBlock(illustrationImage)
|
||||
: null}
|
||||
{contentType === 'video' && contentPosition !== 'background'
|
||||
? videoBlock(illustrationVideo)
|
||||
: null}
|
||||
<div className='flex items-center justify-center flex-col space-y-4 w-full lg:w-full'>
|
||||
<CardBox className='w-full md:w-3/5 lg:w-2/3'>
|
||||
<CardBoxComponentTitle title="Welcome to your App Draft app!"/>
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className='text-center '>This is a React.js/Node.js app generated by the <a className={`${textColor}`} href="https://flatlogic.com/generator">Flatlogic Web App Generator</a></p>
|
||||
<p className='text-center '>For guides and documentation please check
|
||||
your local README.md and the <a className={`${textColor}`} href="https://flatlogic.com/documentation">Flatlogic documentation</a></p>
|
||||
{/* Navigation */}
|
||||
<nav className={`fixed top-0 w-full z-50 transition-all duration-300 border-b ${darkMode ? 'bg-slate-900/80 border-slate-700' : 'bg-white/80 border-slate-200'} backdrop-blur-md`}>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between h-16 items-center">
|
||||
<div className="flex items-center space-x-2">
|
||||
<BaseIcon path={icon.mdiShieldCheck} size={32} className="text-indigo-600" />
|
||||
<span className="text-xl font-bold tracking-tight">SecureGuard</span>
|
||||
</div>
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButton
|
||||
href='/login'
|
||||
label='Login'
|
||||
color='info'
|
||||
className='w-full'
|
||||
/>
|
||||
|
||||
</BaseButtons>
|
||||
</CardBox>
|
||||
<div className="hidden md:flex space-x-8 items-center">
|
||||
<a href="#features" className="hover:text-indigo-600 transition-colors">Features</a>
|
||||
<a href="#download" className="hover:text-indigo-600 transition-colors">Download</a>
|
||||
{currentUser ? (
|
||||
<BaseButton href="/dashboard" label="Dashboard" color="indigo" roundedFull />
|
||||
) : (
|
||||
<div className="space-x-4">
|
||||
<Link href="/login" className="hover:text-indigo-600 transition-colors">Login</Link>
|
||||
<BaseButton href="/login" label="Get Started" color="indigo" roundedFull />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionFullScreen>
|
||||
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
|
||||
<p className='py-6 text-sm'>© 2026 <span>{title}</span>. All rights reserved</p>
|
||||
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
||||
Privacy Policy
|
||||
</Link>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="pt-32 pb-20 px-4">
|
||||
<div className="max-w-7xl mx-auto text-center">
|
||||
<div className="inline-flex items-center space-x-2 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 px-4 py-2 rounded-full mb-8 text-sm font-medium">
|
||||
<BaseIcon path={icon.mdiCellphoneLock} size={16} />
|
||||
<span>Now with advanced Android protection</span>
|
||||
</div>
|
||||
<h1 className="text-5xl md:text-7xl font-extrabold mb-6 tracking-tight">
|
||||
One security suite for <span className="text-indigo-600">all your devices</span>.
|
||||
</h1>
|
||||
<p className="text-xl text-slate-600 dark:text-slate-400 max-w-3xl mx-auto mb-10">
|
||||
SecureGuard keeps your PC and phone protected with a unified dashboard. Connect, scan, and secure your digital life with one click.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row justify-center space-y-4 sm:space-y-0 sm:space-x-4 mb-16">
|
||||
<BaseButton
|
||||
label="Download for PC"
|
||||
icon={icon.mdiMonitor}
|
||||
color="indigo"
|
||||
className="px-8 py-4 text-lg"
|
||||
/>
|
||||
<BaseButton
|
||||
label="Download for Android"
|
||||
icon={icon.mdiAndroid}
|
||||
color="whiteDark"
|
||||
className="px-8 py-4 text-lg border-2 border-slate-200 dark:border-slate-700"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Logged-in Device Quick View */}
|
||||
{currentUser && (
|
||||
<div className="max-w-4xl mx-auto animate-fade-in">
|
||||
<CardBox className="text-left border-indigo-500/50 shadow-xl shadow-indigo-500/10">
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between mb-6 space-y-4 md:space-y-0">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold">Your Connected Devices</h2>
|
||||
<p className="text-slate-500">Managing {devices?.length || 0} active devices</p>
|
||||
</div>
|
||||
<BaseButton
|
||||
href="/devices/devices-list"
|
||||
label="Manage All Devices"
|
||||
color="indigo"
|
||||
outline
|
||||
small
|
||||
/>
|
||||
</div>
|
||||
|
||||
{devicesLoading ? (
|
||||
<div className="flex justify-center py-8">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600"></div>
|
||||
</div>
|
||||
) : devices && devices.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{devices.slice(0, 3).map((device: any) => (
|
||||
<div key={device.id} className="p-4 border rounded-xl bg-slate-50 dark:bg-slate-800/50 border-slate-200 dark:border-slate-700">
|
||||
<div className="flex items-center space-x-3 mb-2">
|
||||
<BaseIcon
|
||||
path={device.platform === 'android' ? icon.mdiAndroid : icon.mdiMonitor}
|
||||
size={24}
|
||||
className={device.is_connected ? 'text-emerald-500' : 'text-slate-400'}
|
||||
/>
|
||||
<span className="font-semibold truncate">{device.name}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-xs">
|
||||
<span className={`${device.is_connected ? 'text-emerald-500 bg-emerald-100 dark:bg-emerald-900/30' : 'text-slate-400 bg-slate-100 dark:bg-slate-700'} px-2 py-1 rounded-full`}>
|
||||
{device.is_connected ? 'Connected' : 'Offline'}
|
||||
</span>
|
||||
<span className="text-slate-500">Ver: {device.installed_version || '1.0.0'}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-8 bg-slate-50 dark:bg-slate-800/30 rounded-xl border-2 border-dashed border-slate-200 dark:border-slate-700">
|
||||
<BaseIcon path={icon.mdiPlusCircleOutline} size={48} className="text-slate-300 mb-2" />
|
||||
<p className="text-slate-500">No devices connected yet.</p>
|
||||
<BaseButton href="/devices/devices-list" label="Connect first device" color="indigo" outline className="mt-4" />
|
||||
</div>
|
||||
)}
|
||||
</CardBox>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Feature Grid */}
|
||||
<section id="features" className={`py-20 ${darkMode ? 'bg-slate-800/50' : 'bg-white'}`}>
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-4">Complete protection, everywhere.</h2>
|
||||
<p className="text-slate-500 max-w-2xl mx-auto text-lg">
|
||||
SecureGuard provides advanced security features tailored for both desktop and mobile environments.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{features.map((feature, index) => (
|
||||
<div key={index} className={`p-8 rounded-2xl border transition-all duration-300 hover:shadow-lg ${darkMode ? 'bg-slate-900 border-slate-800' : 'bg-slate-50 border-slate-100'}`}>
|
||||
<div className={`${feature.color} mb-6 p-3 bg-white dark:bg-slate-800 rounded-xl inline-block shadow-sm`}>
|
||||
<BaseIcon path={feature.icon} size={32} />
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-3">{feature.title}</h3>
|
||||
<p className="text-slate-500 leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Cross-Platform Tabs */}
|
||||
<section id="download" className="py-20 px-4">
|
||||
<div className="max-w-5xl mx-auto bg-indigo-600 rounded-3xl p-8 md:p-16 text-white overflow-hidden relative shadow-2xl shadow-indigo-600/20">
|
||||
<div className="relative z-10 grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h2 className="text-4xl font-bold mb-6 tracking-tight">Protect both PC and Android devices.</h2>
|
||||
<p className="text-indigo-100 text-lg mb-8">
|
||||
Install SecureGuard on your computer and mobile phone to enable cross-device security monitoring and remote management.
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-4 bg-white/10 p-4 rounded-2xl">
|
||||
<BaseIcon path={icon.mdiCheckCircle} className="text-indigo-200" />
|
||||
<span>Real-time malware scanning</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4 bg-white/10 p-4 rounded-2xl">
|
||||
<BaseIcon path={icon.mdiCheckCircle} className="text-indigo-200" />
|
||||
<span>Remote device lock and wipe</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4 bg-white/10 p-4 rounded-2xl">
|
||||
<BaseIcon path={icon.mdiCheckCircle} className="text-indigo-200" />
|
||||
<span>Cross-platform threat alerts</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-10 flex flex-wrap gap-4">
|
||||
<BaseButton label="Get it on Windows" color="whiteDark" className="text-indigo-600 font-bold" />
|
||||
<BaseButton label="Get it on Play Store" color="whiteDark" className="text-indigo-600 font-bold" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="bg-white/10 backdrop-blur-xl rounded-2xl p-6 border border-white/20 transform rotate-3 scale-105 hidden lg:block">
|
||||
<div className="flex justify-between items-center mb-4 border-b border-white/10 pb-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-3 h-3 rounded-full bg-red-400"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-yellow-400"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-green-400"></div>
|
||||
</div>
|
||||
<span className="text-xs text-white/60">SecureGuard - Desktop v2.4</span>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="h-4 w-3/4 bg-white/20 rounded"></div>
|
||||
<div className="h-32 bg-white/10 rounded-xl flex items-center justify-center">
|
||||
<BaseIcon path={icon.mdiShieldCheck} size={64} className="text-indigo-300" />
|
||||
</div>
|
||||
<div className="h-4 w-1/2 bg-white/20 rounded"></div>
|
||||
<div className="h-4 w-full bg-white/20 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute -bottom-10 -right-10 w-48 bg-slate-900 rounded-3xl p-4 border-8 border-slate-800 shadow-2xl hidden lg:block transform -rotate-6">
|
||||
<div className="h-full w-full bg-slate-800 rounded-2xl overflow-hidden p-4 flex flex-col items-center">
|
||||
<BaseIcon path={icon.mdiShieldAccount} size={48} className="text-emerald-500 mb-4" />
|
||||
<div className="h-2 w-full bg-white/10 rounded mb-2"></div>
|
||||
<div className="h-2 w-3/4 bg-white/10 rounded mb-8"></div>
|
||||
<div className="w-full h-10 bg-indigo-600 rounded-lg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className={`py-12 border-t ${darkMode ? 'bg-slate-900 border-slate-800' : 'bg-white border-slate-200'}`}>
|
||||
<div className="max-w-7xl mx-auto px-4 grid grid-cols-1 md:grid-cols-4 gap-12">
|
||||
<div className="col-span-1 md:col-span-1">
|
||||
<div className="flex items-center space-x-2 mb-6">
|
||||
<BaseIcon path={icon.mdiShieldCheck} size={24} className="text-indigo-600" />
|
||||
<span className="text-lg font-bold tracking-tight">SecureGuard</span>
|
||||
</div>
|
||||
<p className="text-slate-500 text-sm leading-relaxed">
|
||||
Providing enterprise-grade security for individuals and families across all digital touchpoints.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Product</h4>
|
||||
<ul className="space-y-2 text-sm text-slate-500">
|
||||
<li><a href="#" className="hover:text-indigo-600">Features</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Security</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Download</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Updates</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Company</h4>
|
||||
<ul className="space-y-2 text-sm text-slate-500">
|
||||
<li><a href="#" className="hover:text-indigo-600">About</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Contact</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Privacy</a></li>
|
||||
<li><a href="#" className="hover:text-indigo-600">Terms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Subscribe</h4>
|
||||
<p className="text-slate-500 text-sm mb-4">Get the latest security tips and news.</p>
|
||||
<div className="flex">
|
||||
<input type="email" placeholder="Email address" className={`p-2 rounded-l-lg border-y border-l w-full text-sm outline-none focus:ring-1 focus:ring-indigo-500 ${darkMode ? 'bg-slate-800 border-slate-700' : 'bg-slate-50 border-slate-200'}`} />
|
||||
<button className="bg-indigo-600 text-white px-4 rounded-r-lg text-sm font-bold">Join</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-7xl mx-auto px-4 mt-12 pt-8 border-t border-slate-100 dark:border-slate-800 text-center text-slate-400 text-xs">
|
||||
© 2026 SecureGuard. All rights reserved. Built for PC and Android.
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Starter.getLayout = function getLayout(page: ReactElement) {
|
||||
LandingPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutGuest>{page}</LayoutGuest>;
|
||||
};
|
||||
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user