From 10c2aaa6caa92f3e818ee6e1803aa008bcda8ef1 Mon Sep 17 00:00:00 2001 From: denis0001-dev Date: Thu, 2 Oct 2025 19:36:39 +0300 Subject: [PATCH] Implement the new homepage --- frontend/src/App.tsx | 5 +- frontend/src/pages/HomePage.tsx | 267 +++++++ .../pages/app/resources/css/_homepage.scss | 657 ++++++++++++++++++ .../src/pages/app/resources/css/style.scss | 1 + 4 files changed, 929 insertions(+), 1 deletion(-) create mode 100644 frontend/src/pages/HomePage.tsx create mode 100644 frontend/src/pages/app/resources/css/_homepage.scss diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 275b2e0..8177b51 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,9 +2,11 @@ import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import { ElectronTitleBar } from "./pages/app/ui/components/Electron"; import { useAppState } from "./pages/app/ui/state"; import { useEffect, useState } from "react"; +import HomePage from "./pages/HomePage"; import LoginPage from "./pages/LoginPage"; import RegisterPage from "./pages/RegisterPage"; import ChatPage from "./pages/ChatPage"; +import DownloadAppPage from "./pages/DownloadAppPage"; import NotFoundPage from "./pages/NotFoundPage"; import ProtectedRoute from "./pages/ProtectedRoute"; import { isElectron } from "./pages/app/electron/electron"; @@ -29,9 +31,10 @@ export default function App() {
- } /> + } /> } /> } /> + } /> diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx new file mode 100644 index 0000000..4ab16a4 --- /dev/null +++ b/frontend/src/pages/HomePage.tsx @@ -0,0 +1,267 @@ +import { useNavigate } from "react-router-dom"; +import { useAppState } from "./app/ui/state"; + +function GitHubLink({ children }: { children: React.ReactNode }) { + return ( + {children} + ); +} + +function SupportLink({ children }: { children: React.ReactNode }) { + return ( + {children} + ); +} + +export default function HomePage() { + const navigate = useNavigate(); + const { user } = useAppState(); + + const handleGetStarted = () => { + if (user.authToken && user.currentUser) { + navigate("/chat"); + } else { + navigate("/login"); + } + }; + + return ( +
+
+
+
+
+

FromChat

+ 100% открытый мессенджер +
+ +
+
+
+ +
+
+
+
+

+ Безопасный мессенджер с открытым исходным кодом +

+

+ FromChat — это полностью открытый мессенджер с end-to-end шифрованием, + поддержкой файлов и уведомлений. Создан для тех, кто ценит приватность и свободу. +

+
+ + {user.authToken ? "Перейти в чат" : "Начать общение"} + + navigate("/register")} + > + Зарегистрироваться + +
+
+
+
+
+
+
Общий чат
+
+
+
+
+
А
+
+
Привет! Как дела?
+
14:30
+
+
+
+
+
Всё отлично! А у тебя как?
+
14:32
+
+
+
+
Б
+
+
Отправляю файл 📎
+
14:35
+
+
+
+
+
+
+
+
+ +
+
+

Возможности

+
+
+
+ +
+

End-to-End Шифрование

+

+ Ваши личные сообщения защищены современным шифрованием X25519 + AES-GCM. + Только вы и получатель можете прочитать сообщения. +

+
+ +
+
+ +
+

100% открытый код

+

+ Весь исходный код доступен на GitHub. Вы можете проверить безопасность, + внести изменения или развернуть свой сервер. +

+
+ +
+
+ +
+

Обмен Файлами

+

+ Отправляйте файлы до 4 ГБ. Файлы в личных сообщениях шифруются. + В общем чате шифрования нет, так как ваши сообщения могут читать все пользователи FromChat. +

+
+ +
+
+ +
+

Уведомления

+

+ Получайте push-уведомления в браузере и настольном приложении. + Никогда не пропустите важное сообщение. +

+
+ +
+
+ +
+

Редактирование

+

+ Редактируйте и удаляйте свои сообщения. Отвечайте на сообщения + для лучшего контекста общения. +

+
+ +
+
+ +
+

Кроссплатформенность

+

+ Работает в браузере и как настольное приложение для Windows, + macOS и Linux. Единый интерфейс везде. +

+
+
+
+
+ +
+
+
+

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

+

+ Для лучшего опыта используйте настольное приложение с поддержкой + уведомлений и автономной работы. +

+
+ + + + Скачать для ПК + + + navigate("/login")}> + + Веб-версия + +
+
+
+
+ +
+
+
+

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

+

+ Присоединяйтесь к FromChat и общайтесь безопасно с друзьями и коллегами. +

+
+ navigate("/register")} + > + Создать аккаунт + + navigate("/login")} + > + Войти + +
+
+
+
+
+ + +
+ ); +} diff --git a/frontend/src/pages/app/resources/css/_homepage.scss b/frontend/src/pages/app/resources/css/_homepage.scss new file mode 100644 index 0000000..15aee92 --- /dev/null +++ b/frontend/src/pages/app/resources/css/_homepage.scss @@ -0,0 +1,657 @@ +@use "common/material" as *; + +.homepage { + min-height: 100vh; + background: linear-gradient(135deg, $color-dark-background 0%, $color-dark-surface-container 50%, $color-dark-primary-container 100%); + color: $color-dark-on-background; + font-family: 'Montserrat', sans-serif; + position: relative; + + &::before { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: + radial-gradient(circle at 20% 80%, rgba($color-dark-primary, 0.3) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba($color-dark-tertiary, 0.3) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba($color-dark-secondary, 0.2) 0%, transparent 50%); + pointer-events: none; + z-index: 0; + } + + // Cascaded styles for all child elements + * { + position: relative; + z-index: 1; + } + + // Container styles + .container { + max-width: 1200px; + margin: 0 auto; + padding: 0 2rem; + } + + // Header styles + .homepage-header { + padding: 1rem 0; + background: rgba($color-dark-surface-container, 0.8); + backdrop-filter: blur(20px); + border-bottom: 1px solid rgba($color-dark-primary, 0.3); + box-shadow: 0 4px 20px rgba($color-dark-primary, 0.1); + position: sticky; + top: 0; + z-index: 1000; + transition: all 0.3s ease; + + .header-content { + display: flex; + justify-content: space-between; + align-items: center; + + .logo { + h1 { + font-size: 2rem; + font-weight: 700; + margin: 0; + background: linear-gradient(45deg, $color-dark-primary, $color-dark-tertiary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 20px rgba($color-dark-primary, 0.5); + } + + .tagline { + font-size: 0.9rem; + } + } + + .header-nav { + display: flex; + align-items: center; + gap: 10px; + + a { + display: flex; + } + } + } + } + + // Hero section + .hero { + padding: 4rem 0; + display: flex; + align-items: center; + min-height: 80vh; + margin-top: 0; + + .hero-content { + flex: 1; + max-width: 600px; + + .hero-title { + font-size: 3.5rem; + font-weight: 800; + line-height: 1.1; + margin-bottom: 1.5rem; + background: linear-gradient(45deg, $color-dark-primary, $color-dark-tertiary, $color-dark-secondary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 30px rgba($color-dark-primary, 0.5); + animation: neonGlow 3s ease-in-out infinite alternate; + } + + .hero-description { + font-size: 1.25rem; + line-height: 1.6; + margin-bottom: 2.5rem; + opacity: 0.9; + } + + .hero-actions { + display: flex; + gap: 1rem; + flex-wrap: wrap; + } + } + + .hero-visual { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + padding: 2rem; + + .chat-preview { + perspective: 1000px; + + .chat-window { + background: rgba($color-dark-surface-container, 0.95); + border-radius: 20px; + padding: 1.5rem; + box-shadow: + 0 20px 40px rgba(0, 0, 0, 0.5), + 0 0 20px rgba($color-dark-primary, 0.3), + inset 0 1px 0 rgba($color-dark-primary, 0.2); + transform: rotateY(-5deg) rotateX(5deg); + color: $color-dark-on-surface; + max-width: 400px; + width: 100%; + border: 1px solid rgba($color-dark-primary, 0.3); + + .chat-header { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 1rem; + border-bottom: 1px solid rgba($color-dark-primary, 0.3); + margin-bottom: 1rem; + + .chat-title { + font-weight: 600; + font-size: 1.1rem; + } + + .online-indicator { + color: $color-dark-primary; + font-size: 0.8rem; + text-shadow: 0 0 10px rgba($color-dark-primary, 0.8); + animation: pulse 2s ease-in-out infinite; + } + } + + .chat-messages { + display: flex; + flex-direction: column; + gap: 1rem; + + .message { + display: flex; + gap: 0.75rem; + align-items: flex-start; + + &.sent { + flex-direction: row-reverse; + + .message-content { + background: linear-gradient(135deg, $color-dark-primary, $color-dark-primary-container); + color: $color-dark-on-primary; + box-shadow: 0 0 15px rgba($color-dark-primary, 0.3); + } + } + + &.received { + .message-content { + background: rgba($color-dark-surface-variant, 0.8); + color: $color-dark-on-surface-variant; + border: 1px solid rgba($color-dark-outline-variant, 0.3); + } + } + + .message-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + background: linear-gradient(135deg, $color-dark-primary, $color-dark-tertiary); + color: $color-dark-on-primary; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + font-size: 0.8rem; + flex-shrink: 0; + box-shadow: 0 0 10px rgba($color-dark-primary, 0.4); + } + + .message-content { + max-width: 70%; + padding: 0.75rem 1rem; + border-radius: 18px; + position: relative; + + .message-text { + font-size: 0.9rem; + line-height: 1.4; + } + + .message-time { + font-size: 0.75rem; + opacity: 0.7; + margin-top: 0.25rem; + } + } + } + } + } + } + } + } + + // Features section + .features { + padding: 6rem 0; + background: rgba($color-dark-surface-container, 0.3); + backdrop-filter: blur(20px); + border-top: 1px solid rgba($color-dark-primary, 0.2); + border-bottom: 1px solid rgba($color-dark-primary, 0.2); + + .section-title { + text-align: center; + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 3rem; + background: linear-gradient(45deg, $color-dark-primary, $color-dark-tertiary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 20px rgba($color-dark-primary, 0.5); + } + + .features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 2rem; + + .feature-card { + background: rgba($color-dark-surface-container, 0.6); + backdrop-filter: blur(20px); + border-radius: 20px; + padding: 2rem; + border: 1px solid rgba($color-dark-primary, 0.3); + transition: all 0.3s ease; + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba($color-dark-primary, 0.1), rgba($color-dark-tertiary, 0.1)); + opacity: 0; + transition: opacity 0.3s ease; + z-index: 0; + } + + > * { + position: relative; + z-index: 1; + } + + &:hover { + transform: translateY(-5px); + box-shadow: + 0 20px 40px rgba(0, 0, 0, 0.3), + 0 0 30px rgba($color-dark-primary, 0.2); + border-color: rgba($color-dark-primary, 0.5); + + &::before { + opacity: 1; + } + } + + .feature-icon { + width: 60px; + height: 60px; + background: linear-gradient(135deg, rgba($color-dark-primary, 0.3), rgba($color-dark-tertiary, 0.3)); + border-radius: 15px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1.5rem; + border: 1px solid rgba($color-dark-primary, 0.4); + box-shadow: 0 0 15px rgba($color-dark-primary, 0.2); + user-select: none; + + mdui-icon { + font-size: 1.5rem; + color: $color-dark-primary; + text-shadow: 0 0 10px rgba($color-dark-primary, 0.8); + } + } + + h4 { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 1rem; + color: $color-dark-on-surface; + text-shadow: 0 0 10px rgba($color-dark-primary, 0.3); + } + + p { + line-height: 1.6; + opacity: 0.9; + color: $color-dark-on-surface-variant; + } + } + } + } + + // Download section + .download { + padding: 6rem 0; + + .download-content { + text-align: center; + max-width: 600px; + margin: 0 auto; + + h3 { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1.5rem; + background: linear-gradient(45deg, $color-dark-primary, $color-dark-tertiary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 20px rgba($color-dark-primary, 0.5); + } + + p { + font-size: 1.25rem; + line-height: 1.6; + margin-bottom: 2.5rem; + opacity: 0.9; + } + + .download-buttons { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; + } + } + } + + // CTA section + .cta { + padding: 6rem 0; + background: rgba($color-dark-surface-container, 0.3); + backdrop-filter: blur(20px); + border-top: 1px solid rgba($color-dark-primary, 0.2); + + .cta-content { + text-align: center; + max-width: 600px; + margin: 0 auto; + + h3 { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1.5rem; + background: linear-gradient(45deg, $color-dark-primary, $color-dark-tertiary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 0 0 20px rgba($color-dark-primary, 0.5); + } + + p { + font-size: 1.25rem; + line-height: 1.6; + margin-bottom: 2.5rem; + opacity: 0.9; + } + + .cta-actions { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; + } + } + } + + // Footer + .homepage-footer { + background: rgba($color-dark-surface-container, 0.8); + backdrop-filter: blur(20px); + padding: 3rem 0 1rem; + border-top: 1px solid rgba($color-dark-primary, 0.3); + box-shadow: 0 -4px 20px rgba($color-dark-primary, 0.1); + + .footer-content { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + margin-bottom: 2rem; + + .footer-section { + h4 { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 1rem; + color: $color-dark-on-surface; + text-shadow: 0 0 10px rgba($color-dark-primary, 0.3); + } + + p { + opacity: 0.8; + line-height: 1.6; + color: $color-dark-on-surface-variant; + } + + a { + color: $color-dark-on-surface; + text-decoration: none; + opacity: 0.8; + display: block; + margin-bottom: 0.5rem; + transition: all 0.3s ease; + padding: 0.25rem 0; + border-radius: 4px; + + &:hover { + opacity: 1; + color: $color-dark-primary; + text-shadow: 0 0 10px rgba($color-dark-primary, 0.5); + background: rgba($color-dark-primary, 0.1); + } + } + } + } + + .footer-bottom { + text-align: center; + padding-top: 2rem; + border-top: 1px solid rgba($color-dark-primary, 0.3); + + p { + opacity: 0.7; + margin: 0; + color: $color-dark-on-surface-variant; + } + } + } +} + +// Keyframes for animations +@keyframes neonGlow { + 0% { + text-shadow: 0 0 20px rgba($color-dark-primary, 0.5), 0 0 40px rgba($color-dark-primary, 0.3); + } + 100% { + text-shadow: 0 0 30px rgba($color-dark-primary, 0.8), 0 0 60px rgba($color-dark-primary, 0.5); + } +} + +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +// Responsive Design +@media (min-width: 1024px) { + .homepage { + .homepage-header { + position: fixed; + top: 1rem; + left: 50%; + transform: translateX(-50%); + width: calc(100% - 2rem); + max-width: 1200px; + border-radius: 20px; + border: 1px solid rgba($color-dark-primary, 0.3); + box-shadow: + 0 8px 32px rgba(0, 0, 0, 0.3), + 0 0 20px rgba($color-dark-primary, 0.2); + backdrop-filter: blur(30px); + background: rgba($color-dark-surface-container, 0.9); + } + + .hero { + margin-top: 6rem; + } + } +} + +@media (max-width: 1023px) { + .homepage { + .homepage-header { + position: sticky; + top: 0; + border-radius: 0; + margin: 0; + width: 100%; + transform: none; + } + } +} + +@media (max-width: 768px) { + .homepage { + .container { + padding: 0 1rem; + } + + .homepage-header { + .header-content { + flex-direction: column; + gap: 1rem; + } + } + + .hero { + flex-direction: column; + text-align: center; + padding: 2rem 0; + + .hero-content { + .hero-title { + font-size: 2.5rem; + } + + .hero-description { + font-size: 1.1rem; + } + } + + .hero-visual { + padding: 1rem; + + .chat-preview { + .chat-window { + transform: none; + max-width: 100%; + } + } + } + } + + .features { + .features-grid { + grid-template-columns: 1fr; + + .feature-card { + padding: 1.5rem; + } + } + + .section-title { + font-size: 2rem; + } + } + + .download { + .download-content { + h3 { + font-size: 2rem; + } + + .download-buttons { + flex-direction: column; + align-items: center; + } + } + } + + .cta { + .cta-content { + h3 { + font-size: 2rem; + } + + .cta-actions { + flex-direction: column; + align-items: center; + } + } + } + + .homepage-footer { + .footer-content { + grid-template-columns: 1fr; + text-align: center; + } + } + } +} + +@media (max-width: 480px) { + .homepage { + .hero { + .hero-content { + .hero-title { + font-size: 2rem; + } + + .hero-description { + font-size: 1rem; + } + } + } + + .features { + .section-title { + font-size: 1.75rem; + } + } + + .download { + .download-content { + h3 { + font-size: 1.75rem; + } + } + } + + .cta { + .cta-content { + h3 { + font-size: 1.75rem; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/pages/app/resources/css/style.scss b/frontend/src/pages/app/resources/css/style.scss index 3e06041..225262c 100644 --- a/frontend/src/pages/app/resources/css/style.scss +++ b/frontend/src/pages/app/resources/css/style.scss @@ -11,6 +11,7 @@ @use "dialogs/reply"; @use "download-app"; @use "404" as not-found; +@use "homepage"; @use "lib/fonts/montserrat"; @use "lib/fonts/material-symbols";