'use client';
import { PageWrapper } from '../shared/page-wrapper';
import { useStatus } from '@/context/status';
import { SettingsCard } from '../shared/settings-card';
import { Alert } from '@/components/ui/alert';
import { Button, IconButton } from '@/components/ui/button';
import { TextInput } from '@/components/ui/text-input';
import {
InfoIcon,
GithubIcon,
BookOpenIcon,
HeartIcon,
CoffeeIcon,
MessageCircleIcon,
PencilIcon,
} from 'lucide-react';
import { FaGithub, FaDiscord } from 'react-icons/fa';
import { BiDonateHeart } from 'react-icons/bi';
import { AiOutlineDiscord } from 'react-icons/ai';
import { FiGithub } from 'react-icons/fi';
import Image from 'next/image';
import React, { useState, useEffect } from 'react';
import ReactMarkdown from 'react-markdown';
import { Skeleton } from '@/components/ui/skeleton/skeleton';
import { useDisclosure } from '@/hooks/disclosure';
import { Modal } from '../ui/modal';
import { SiGithubsponsors, SiKofi } from 'react-icons/si';
import { useUserData } from '@/context/userData';
import { toast } from 'sonner';
import { useMenu } from '@/context/menu';
import { DonationModal } from '../shared/donation-modal';
export function AboutMenu() {
return (
<>
>
);
}
function Content() {
const { status, loading, error } = useStatus();
const { nextMenu } = useMenu();
const { userData, setUserData } = useUserData();
const addonName =
userData.addonName || status?.settings?.addonName || 'AIOStreams';
const version = status?.tag || 'Unknown';
const githubUrl = 'https://github.com/Viren070/AIOStreams';
const releasesUrl = 'https://github.com/Viren070/AIOStreams/releases';
const stremioGuideUrl = 'https://guides.viren070.me/stremio/';
const configGuideUrl = 'https://guides.viren070.me/stremio/addons/aiostreams';
const discordUrl = 'https://discord.viren070.me';
const donationModal = useDisclosure(false);
const customizeModal = useDisclosure(false);
const customHtml = status?.settings?.customHtml;
return (
<>
{/* Top section: Responsive logo/name/about layout */}
{/* Donate button - visible only on larger screens */}
}
onClick={donationModal.open}
>
Support Me
{/* Large logo left */}
{/* Name, version, about right */}
{addonName}
}
intent="primary-subtle"
onClick={customizeModal.open}
className="rounded-full flex-shrink-0"
size="sm"
/>
{version}{' '}
{/* {version.includes('nightly') ? `(${status?.commit})` : ''} */}
{version.includes('nightly') ? (
({status?.commit})
) : null}
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.
{/* Custom HTML section, styled like a card, only if present */}
{customHtml && (
)}
{/* 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!
{
nextMenu();
}}
>
Configure
{/* Quick links grid */}
{/* What's New section in its own row */}
{/* Social & donation row */}
Developed by Viren070.
This beautiful UI would not be possible without{' '}
Seanime
>
);
}
function ChangelogBox({ version }: { version: string }) {
const [loading, setLoading] = React.useState(true);
const [markdown, setMarkdown] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
if (!version || version.toLowerCase() === 'unknown') {
setError('No version available.');
setLoading(false);
return;
}
setLoading(true);
setError(null);
setMarkdown(null);
fetch(
`https://api.github.com/repos/viren070/aiostreams/releases/tags/${version}`
)
.then((res) => {
if (!res.ok) throw new Error('Failed to fetch changelog');
return res.json();
})
.then((data) => {
if (!data.body) setError('No changelog found for this version.');
setMarkdown(data.body);
})
.catch((err) => {
setError('Failed to load changelog.');
})
.finally(() => setLoading(false));
}, [version]);
return (
{loading ? (
) : error ? (
{error}
) : markdown ? (
) : null}
);
}
function CustomizeModal({
open,
onOpenChange,
currentName,
currentLogo,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
currentName: string;
currentLogo: string | undefined;
}) {
const { userData, setUserData } = useUserData();
const [name, setName] = useState(currentName);
const [logo, setLogo] = useState(currentLogo);
// Update state when props change
useEffect(() => {
setName(currentName);
setLogo(currentLogo);
}, [currentName, currentLogo]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!name.trim()) {
toast.error('Name cannot be empty');
return;
}
setUserData((prev) => ({
...prev,
addonName: name.trim(),
addonLogo: logo?.trim(),
}));
toast.success('Customization saved');
onOpenChange(false);
};
const handleLogoChange = (value: string) => {
setLogo(value);
};
return (
);
}