import { useNavigate } from "react-router-dom"; import { useState, type ReactNode } from "react"; import styles from "@/pages/home/home.module.scss"; import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen"; import { MaterialButton, MaterialIcon, MaterialIconButton, MaterialList, MaterialListItem } from "@/utils/material"; import generalChatScreenshot from "@/images/screenshots/general-chat.png"; import dmScreenshot from "@/images/screenshots/dm.png"; import windowsIcon from "@/images/windows.svg"; import linuxIcon from "@/images/linux.svg"; import macIcon from "@/images/mac.svg"; import { HomeHeader } from "@/pages/home/HomeHeader"; import { HomeFooter } from "@/pages/home/HomeFooter"; import { SplitButton } from "@/core/components/SplitButton"; import { DownloadDialog } from "@/pages/home/DownloadDialog"; import { OS_CONFIG, ALL_OS, detectOs, type DownloadOs } from "@/pages/home/os"; interface FeatureSectionProps { title: ReactNode; children: ReactNode; screenshot: string; right?: boolean; } function FeatureSection({ title, children, screenshot, right = false, }: FeatureSectionProps) { const featureText = (
{title}
{children}
); const featureScreenshot = (
) return (
{right ? <>{featureText}{featureScreenshot} : <>{featureScreenshot}{featureText}}
) } export default function HomePage() { const navigate = useNavigate(); const { isMobile } = useDownloadAppScreen(); const [dialogOpen, setDialogOpen] = useState(false); const [dialogOs, setDialogOs] = useState(() => detectOs()); const [menuOpen, setMenuOpen] = useState(false); const triggerDownload = (os: DownloadOs): boolean => { if (typeof document === "undefined") { return false; } setDialogOs(os); setDialogOpen(true); const link = document.createElement("a"); link.href = `/api/download/${os}`; link.download = ""; link.style.display = "none"; document.body.appendChild(link); link.click(); document.body.removeChild(link); return true; }; const getButtonVariant = (os: DownloadOs): "filled" | "tonal" | "outlined" => { const detectedOs = detectOs(); if (os === detectedOs) return "filled"; if (!isMobile && ["windows", "linux", "macos"].includes(os)) return "tonal"; if (isMobile && (os === "android" || os === "ios") && os !== detectedOs) return "tonal"; return "outlined"; }; return (
FromChat
100% бесплатный и открытый мессенджер. Поддерживает self-hosted установку на своём сервере.
{isMobile ? null : ( navigate("/auth?mode=login")} icon="devices" > Открыть веб-версию )} triggerDownload(detectOs())} menuOpen={menuOpen} onMenuOpen={setMenuOpen} menu={( {ALL_OS.map((os) => ( { if (triggerDownload(os)) setMenuOpen(false); }} > {["windows", "linux", "macos"].includes(os) && ( )} ))} )} />
Общий чат} screenshot={generalChatScreenshot} right > Открытый форум для всех пользователей сервера. Пишите сообщения, делитесь файлами и общайтесь в реальном времени. Личные сообщения} screenshot={dmScreenshot}> Общайтесь с одним человеком в личной переписке.

Скачайте приложение

Настольное приложение с уведомлениями и автономной работой или мобильное приложение для Android и iOS.

{ALL_OS.map((os) => ( ))}
Платформа Описание
{["windows", "linux", "macos"].includes(os) ? ( ) : ( )} {OS_CONFIG[os].label} {OS_CONFIG[os].description} triggerDownload(os)} > Скачать triggerDownload(os)} title={`Скачать ${OS_CONFIG[os].label}`} />

Готовы начать общение?

Создайте аккаунт за минуту. Общайтесь в общем чате, ведите личную переписку или звоните — всё бесплатно и с открытым кодом.

{isMobile ? ( navigate("/download-app")}> Скачать приложение ) : ( <> navigate("/register")}> Создать аккаунт navigate("/login")}> Войти )}
); }