From 750ebc1f42c03e4bbbfc3f4f7e1dca20e55ad06c Mon Sep 17 00:00:00 2001 From: Viren070 Date: Sat, 11 Oct 2025 16:26:20 +0100 Subject: [PATCH] feat(frontend): redesign about menu Release-As: 2.15.0 --- packages/frontend/src/app/main-sidebar.tsx | 34 +- packages/frontend/src/app/top-navbar.tsx | 49 +- .../frontend/src/components/menu/about.tsx | 428 +++++++++++------- .../components/shared/mode-select-modal.tsx | 4 +- .../components/ui/mode-switch/mode-switch.tsx | 18 +- 5 files changed, 321 insertions(+), 212 deletions(-) diff --git a/packages/frontend/src/app/main-sidebar.tsx b/packages/frontend/src/app/main-sidebar.tsx index fa50c343..22e0bd6d 100644 --- a/packages/frontend/src/app/main-sidebar.tsx +++ b/packages/frontend/src/app/main-sidebar.tsx @@ -17,11 +17,10 @@ import { BiFilterAlt, BiSave, BiSort, - BiLogInCircle, - BiLogOutCircle, BiCog, BiServer, BiSmile, + BiHeart, } from 'react-icons/bi'; import { useRouter, usePathname } from 'next/navigation'; import { useDisclosure } from '@/hooks/disclosure'; @@ -35,6 +34,7 @@ import { toast } from 'sonner'; import { Tooltip } from '@/components/ui/tooltip'; import { useOptions } from '@/context/options'; import { useMode } from '@/context/mode'; +import { DonationModal } from '@/components/shared/donation-modal'; type MenuItem = VerticalMenuItem & { id: MenuId; @@ -47,6 +47,7 @@ export function MainSidebar() { const { selectedMenu, setSelectedMenu } = useMenu(); const pathname = usePathname(); const { isOptionsEnabled, enableOptions } = useOptions(); + const donationModal = useDisclosure(false); const user = useUserData(); const signInModal = useDisclosure(false); @@ -229,7 +230,7 @@ export function MainSidebar() { : user.userData.addonLogo || '/logo.png' } alt="logo" - className="w-22.5 h-15" + className="max-w-[90px] max-h-[60px] object-contain" /> {status?.settings.alternateDesign === false && ( @@ -259,35 +260,22 @@ export function MainSidebar() { side="right" trigger={ } > - {user.uuid && user.password ? 'Log Out' : 'Log In'} + Donate @@ -307,6 +295,10 @@ export function MainSidebar() { /> + ); } diff --git a/packages/frontend/src/app/top-navbar.tsx b/packages/frontend/src/app/top-navbar.tsx index 642a993f..5ffbd81d 100644 --- a/packages/frontend/src/app/top-navbar.tsx +++ b/packages/frontend/src/app/top-navbar.tsx @@ -8,9 +8,16 @@ import React from 'react'; import { PageControls } from '@/components/shared/page-controls'; import { useMenu } from '@/context/menu'; import { Button } from '@/components/ui/button'; -import { HeartIcon } from 'lucide-react'; import { useDisclosure } from '@/hooks/disclosure'; import { DonationModal } from '@/components/shared/donation-modal'; +import { BiLogInCircle, BiLogOutCircle } from 'react-icons/bi'; +import { ConfigModal } from '@/components/config-modal'; +import { useUserData } from '@/context/userData'; +import { toast } from 'sonner'; +import { + ConfirmationDialog, + useConfirmationDialog, +} from '@/components/shared/confirmation-dialog'; type TopNavbarProps = { children?: React.ReactNode; @@ -20,8 +27,18 @@ export function TopNavbar(props: TopNavbarProps) { const { children, ...rest } = props; const { selectedMenu } = useMenu(); const donationModal = useDisclosure(false); + const signInModal = useDisclosure(false); const serverStatus = useStatus(); const isOffline = !serverStatus.status; + const { userData, setUserData, uuid, password } = useUserData(); + + const confirmClearConfig = useConfirmationDialog({ + title: 'Sign Out', + description: 'Are you sure you want to sign out?', + onConfirm: () => { + setUserData(null); + }, + }); return ( <> @@ -52,12 +69,21 @@ export function TopNavbar(props: TopNavbarProps) { ) : (
)} @@ -67,6 +93,19 @@ export function TopNavbar(props: TopNavbarProps) { open={donationModal.isOpen} onOpenChange={donationModal.toggle} /> + { + signInModal.close(); + toast.success('Signed in successfully'); + }} + onOpenChange={(v) => { + if (!v) { + signInModal.close(); + } + }} + /> + diff --git a/packages/frontend/src/components/menu/about.tsx b/packages/frontend/src/components/menu/about.tsx index 726cfd9b..f56401dd 100644 --- a/packages/frontend/src/components/menu/about.tsx +++ b/packages/frontend/src/components/menu/about.tsx @@ -14,8 +14,8 @@ import { MessageCircleIcon, PencilIcon, } from 'lucide-react'; -import { FaGithub, FaDiscord } from 'react-icons/fa'; -import { BiDonateHeart } from 'react-icons/bi'; +import { FaGithub, FaDiscord, FaChevronRight } from 'react-icons/fa'; +import { BiDonateHeart, BiLogInCircle, BiLogOutCircle } from 'react-icons/bi'; import { AiOutlineDiscord } from 'react-icons/ai'; import { FiGithub } from 'react-icons/fi'; import Image from 'next/image'; @@ -32,6 +32,11 @@ import { useMode } from '@/context/mode'; import { DonationModal } from '../shared/donation-modal'; import { ModeSwitch } from '../ui/mode-switch/mode-switch'; import { ModeSelectModal } from '../shared/mode-select-modal'; +import { ConfigModal } from '../config-modal'; +import { + ConfirmationDialog, + useConfirmationDialog, +} from '../shared/confirmation-dialog'; import { Card, CardHeader, @@ -43,6 +48,59 @@ import { import { Select } from '@/components/ui/select'; import { cn } from '@/components/ui/core/styling'; import { Textarea } from '../ui/textarea'; +import { FaPlay } from 'react-icons/fa6'; + +interface QuickLinkProps { + href?: string; + onClick?: () => void; + className?: string; + icon: React.ReactNode; + children: React.ReactNode; +} + +function QuickLink({ + href, + onClick, + icon, + children, + className, +}: QuickLinkProps) { + className = cn( + 'group relative flex flex-col justify-between p-4 h-32 rounded-lg bg-gray-800/60 hover:bg-gray-800/60 transition-all duration-200 hover:scale-[1.02] hover:shadow-lg border border-transparent hover:border-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:border-white', + className + ); + + const content = ( + <> +
+ {icon} +
+ + {children} + + + + ); + + if (href) { + return ( + + {content} + + ); + } + + return ( + + ); +} export function AboutMenu() { return ( @@ -57,17 +115,13 @@ export function AboutMenu() { function Content() { const { status, loading, error } = useStatus(); const { nextMenu } = useMenu(); - const { userData, setUserData } = useUserData(); + const { userData, setUserData, uuid, password, setPassword } = useUserData(); const { mode, setMode, isFirstTime } = useMode(); const modeSelectModal = useDisclosure(isFirstTime); const addonName = userData.addonName || status?.settings?.addonName || 'AIOStreams'; const defaultDescription = ` - AIOStreams consolidates multiple Stremio addons and debrid - services into a single, easily configurable addon. It allows - highly customisable filtering, sorting, and formatting of results - and supports proxying all your streams through MediaFlow Proxy or - StremThru for improved compatibility and IP restriction bypassing. +AIOStreams consolidates multiple Stremio addons and debrid services - including its own suite of exclusive built-in addons - into a single, highly customisable super-addon. `; const addonDescription = userData.addonDescription || defaultDescription; const version = status?.tag || 'Unknown'; @@ -78,22 +132,40 @@ function Content() { const discordUrl = 'https://discord.viren070.me'; const donationModal = useDisclosure(false); const customizeModal = useDisclosure(false); + const signInModal = useDisclosure(false); const customHtml = status?.settings?.customHtml; + const confirmClearConfig = useConfirmationDialog({ + title: 'Sign Out', + description: 'Are you sure you want to sign out?', + onConfirm: () => { + setUserData(null); + }, + }); + return ( <>
{/* Top section: Responsive logo/name/about layout */}
- {/* Donate button - visible only on larger screens */} + {/* Login/Logout button - visible only on larger screens */}
@@ -142,6 +214,7 @@ function Content() {
+ {/* Custom HTML section, styled like a card, only if present */} {customHtml && ( @@ -152,148 +225,139 @@ function Content() { )} - {/* Main content: Getting Started */} - -
- {/* Welcome section */} -
- Welcome to AIOStreams!
-
- - Click the Configure button below to start customizing AIOStreams - to your preferences. You'll be guided through each section where - you can set up your configuration. Once complete, you'll create - a password-protected configuration that you can install in - Stremio or other compatible apps. - -
-
- - Need to make changes later? Simply click configure within your - app and enter your password. You can update your settings at any - time, and in most cases - you won't need to reinstall - AIOStreams! - -
+ {/* Setup Mode Row */} +
+
+ + Setup Mode + + +
+
+ + +
+
+ +
+
-
-
- - + {/* Main content: Get Started and What's New sections */} +
+ {/* Get Started section */} +
+
+
+

+ Welcome to AIOStreams! +

+
+ +
+ {/* Welcome section */} +
+ + Click the Start Setup button above to start customising + AIOStreams to your preferences. You'll be guided through + each section where you can set up your configuration. Once + complete, you'll create a password-protected configuration + that you can install in Stremio or other compatible apps. + +
+
+ + Need to make changes later? Simply click configure within + your app and enter your password. You can update your + settings at any time, and in most cases - you won't need to + reinstall AIOStreams! + +
+
+ + Got an existing configuration already? Click the login + button in the top right corner to access it. + +
+ +
+
+
+ + {/* Quick links grid */} +
+

+ Resources & Support +

+
+ } + > + Configuration Guide + + } + > + Wiki + + } + > + Stremio Guide + + } + > + Discord + + } + > + GitHub + + } + className="bg-gradient-to-br from-red-500/20 to-pink-500/20 hover:from-red-500/30 hover:to-pink-500/30 border-red-400/30 hover:border-red-400/50" + > + Donate + +
+
- - - - {/* What's New section in its own row */} -
- + {/* What's New section */} +
+ +
{/* Social & donation row */}
-
- Developed by Viren070. + + © {new Date().getFullYear()} AIOStreams. Developed by Viren070. + This beautiful UI would not be possible without{' '} + { + signInModal.close(); + toast.success('Signed in successfully'); + }} + onOpenChange={(v) => { + if (!v) { + signInModal.close(); + } + }} + /> + ); } @@ -597,23 +674,16 @@ function ChangelogBox({ version }: { version: string }) { ); return ( - 0 ? ( - - {newerReleases.length} available update - {newerReleases.length > 1 ? 's' : ''} +
+
+

What's New?

+ {newerReleases.length > 0 && ( + + {newerReleases.length} update + {newerReleases.length > 1 ? 's' : ''} available - ) : undefined - } - > + )} +
- +
); } diff --git a/packages/frontend/src/components/shared/mode-select-modal.tsx b/packages/frontend/src/components/shared/mode-select-modal.tsx index ef92e6e2..ec1b5809 100644 --- a/packages/frontend/src/components/shared/mode-select-modal.tsx +++ b/packages/frontend/src/components/shared/mode-select-modal.tsx @@ -33,13 +33,13 @@ export function ModeSelectModal({ open, onOpenChange }: ModeSelectModalProps) {

-

Noob

+

Simple

Perfect for beginners! Essential options only.

-

Pro

+

Advanced

For advanced users who want full control. Access all configuration options and advanced features for maximum diff --git a/packages/frontend/src/components/ui/mode-switch/mode-switch.tsx b/packages/frontend/src/components/ui/mode-switch/mode-switch.tsx index 367fb9c5..9163dcd8 100644 --- a/packages/frontend/src/components/ui/mode-switch/mode-switch.tsx +++ b/packages/frontend/src/components/ui/mode-switch/mode-switch.tsx @@ -43,14 +43,14 @@ export function ModeSwitch({

{/* Animated highlight */}
@@ -59,23 +59,21 @@ export function ModeSwitch({ onClick={() => onChange('noob')} className={cn( 'relative flex-1 flex items-center justify-center font-medium transition-colors duration-200', - value === 'noob' - ? 'text-[--brand]' - : 'text-gray-400 hover:text-gray-300' + value === 'noob' ? 'text-black' : 'text-gray-400 hover:text-gray-300' )} > - Noob Mode +
+ SIMPLE +
);