mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Improve mobile support
This commit is contained in:
+7
-28
@@ -1,10 +1,7 @@
|
||||
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||
import { ElectronTitleBar } from "./Electron";
|
||||
import { useAppState } from "./pages/chat/state";
|
||||
import { useEffect, useState, lazy, Suspense } from "react";
|
||||
import { isElectron } from "./core/electron/electron";
|
||||
import { MINIMUM_WIDTH } from "./core/config";
|
||||
import useWindowSize from "./core/hooks/useWindowSize";
|
||||
import { useEffect, useState, lazy } from "react";
|
||||
import ProtectedRoute from "./pages/ProtectedRoute";
|
||||
import NotFoundPage from "./pages/not-found/NotFoundPage";
|
||||
import DownloadAppPage from "./pages/download-app/DownloadAppPage";
|
||||
@@ -17,7 +14,6 @@ const ChatPage = lazy(() => import("./pages/chat/ui/ChatPage"));
|
||||
|
||||
export default function App() {
|
||||
const { restoreUserFromStorage } = useAppState();
|
||||
const { width } = useWindowSize();
|
||||
const [authReady, setAuthReady] = useState(false);
|
||||
|
||||
// Restore user from localStorage on app initialization
|
||||
@@ -29,28 +25,13 @@ export default function App() {
|
||||
|
||||
return authReady && (
|
||||
<BrowserRouter>
|
||||
{!isElectron && width < MINIMUM_WIDTH && <Navigate to="/download-app" replace />}
|
||||
<ElectronTitleBar />
|
||||
<div id="main-wrapper">
|
||||
<Routes>
|
||||
<Route path="/" element={
|
||||
<Suspense>
|
||||
<HomePage />
|
||||
</Suspense>
|
||||
} />
|
||||
<Route path="/login" element={
|
||||
<Suspense>
|
||||
<LoginPage />
|
||||
</Suspense>
|
||||
} />
|
||||
<Route path="/register" element={
|
||||
<Suspense>
|
||||
<RegisterPage />
|
||||
</Suspense>
|
||||
} />
|
||||
<Route path="/download-app" element={
|
||||
<DownloadAppPage />
|
||||
} />
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route path="/download-app" element={<DownloadAppPage />} />
|
||||
<Route path="/">
|
||||
<Route path="chat" element={
|
||||
<ProtectedRoute>
|
||||
@@ -58,9 +39,7 @@ export default function App() {
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
</Route>
|
||||
<Route path="*" element={
|
||||
<NotFoundPage />
|
||||
} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { MINIMUM_WIDTH } from "../config";
|
||||
import useWindowSize from "./useWindowSize";
|
||||
|
||||
export default function useDownloadAppScreen() {
|
||||
const { width } = useWindowSize();
|
||||
const isMobile = width < MINIMUM_WIDTH;
|
||||
|
||||
return {
|
||||
isMobile,
|
||||
navigate: isMobile ? <Navigate to="/download-app" replace /> : null
|
||||
};
|
||||
}
|
||||
@@ -12,11 +12,14 @@ import { initialize, isSupported, startElectronReceiver, subscribe } from "@/cor
|
||||
import { isElectron } from "@/core/electron/electron";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import "./auth.scss";
|
||||
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
|
||||
|
||||
export default function LoginPage() {
|
||||
const [alerts, updateAlerts] = useImmer<Alert[]>([]);
|
||||
const setUser = useAppState(state => state.setUser);
|
||||
const navigate = useNavigate();
|
||||
const { navigate: navigateDownloadApp } = useDownloadAppScreen();
|
||||
if (navigateDownloadApp) return navigateDownloadApp;
|
||||
|
||||
function showAlert(type: AlertType, message: string) {
|
||||
updateAlerts((alerts) => { alerts.push({type: type, message: message}) });
|
||||
|
||||
@@ -10,11 +10,14 @@ import { MaterialTextField } from "@/core/components/TextField";
|
||||
import { ensureKeysOnLogin } from "@/core/api/authApi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import "./auth.scss";
|
||||
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
|
||||
|
||||
export default function RegisterPage() {
|
||||
const [alerts, updateAlerts] = useImmer<Alert[]>([]);
|
||||
const setUser = useAppState(state => state.setUser);
|
||||
const navigate = useNavigate();
|
||||
const { navigate: navigateDownloadApp } = useDownloadAppScreen();
|
||||
if (navigateDownloadApp) return navigateDownloadApp;
|
||||
|
||||
function showAlert(type: AlertType, message: string) {
|
||||
updateAlerts((alerts) => { alerts.push({type: type, message: message}) });
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
background: $color-dark-surface;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
@@ -269,24 +268,3 @@
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile responsive
|
||||
@media (max-width: 768px) {
|
||||
.reaction-bar {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.reaction-emoji-button,
|
||||
.reaction-expand-button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.reaction-emoji-button {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.reaction-expand-button .material-symbols {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { LeftPanel } from "./left/LeftPanel";
|
||||
import { RightPanel } from "./right/RightPanel";
|
||||
import "@/pages/chat/css/chat.scss";
|
||||
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
|
||||
|
||||
export default function ChatPage() {
|
||||
const { navigate: navigateDownloadApp } = useDownloadAppScreen();
|
||||
if (navigateDownloadApp) return navigateDownloadApp;
|
||||
|
||||
return (
|
||||
<div id="chat-interface">
|
||||
<div className="all-container">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Navigate, useNavigate } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAppState } from "@/pages/chat/state";
|
||||
import { isElectron } from "@/core/electron/electron";
|
||||
import "./home.scss";
|
||||
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
|
||||
|
||||
function GitHubLink({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
@@ -18,18 +18,24 @@ function SupportLink({ children }: { children: React.ReactNode }) {
|
||||
export default function HomePage() {
|
||||
const navigate = useNavigate();
|
||||
const { user } = useAppState();
|
||||
const { isMobile } = useDownloadAppScreen();
|
||||
const isLoggedIn = user.authToken && user.currentUser;
|
||||
|
||||
const handleGetStarted = () => {
|
||||
if (user.authToken && user.currentUser) {
|
||||
function handleGetStarted() {
|
||||
if (isMobile) {
|
||||
navigate("/download-app");
|
||||
} else if (isLoggedIn) {
|
||||
navigate("/chat");
|
||||
} else {
|
||||
navigate("/login");
|
||||
}
|
||||
}
|
||||
|
||||
if (isElectron) {
|
||||
return <Navigate to="/chat" />;
|
||||
}
|
||||
const openBtn = (
|
||||
<mdui-button variant="filled" onClick={handleGetStarted}>
|
||||
{isMobile ? "Скачать приложение" : isLoggedIn ? "Перейти в чат" : "Войти"}
|
||||
</mdui-button>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="homepage">
|
||||
@@ -48,15 +54,7 @@ export default function HomePage() {
|
||||
<mdui-button variant="text">Поддержка</mdui-button>
|
||||
</SupportLink>
|
||||
|
||||
{user.authToken ? (
|
||||
<mdui-button variant="filled" onClick={() => navigate("/chat")}>
|
||||
Перейти в чат
|
||||
</mdui-button>
|
||||
) : (
|
||||
<mdui-button variant="filled" onClick={() => navigate("/login")}>
|
||||
Войти
|
||||
</mdui-button>
|
||||
)}
|
||||
{openBtn}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,18 +72,13 @@ export default function HomePage() {
|
||||
поддержкой файлов и уведомлений. Создан для тех, кто ценит приватность и свободу.
|
||||
</p>
|
||||
<div className="hero-actions">
|
||||
<mdui-button
|
||||
variant="filled"
|
||||
onClick={handleGetStarted}
|
||||
>
|
||||
{user.authToken ? "Перейти в чат" : "Начать общение"}
|
||||
</mdui-button>
|
||||
<mdui-button
|
||||
{openBtn}
|
||||
{!isMobile && <mdui-button
|
||||
variant="outlined"
|
||||
onClick={() => navigate("/register")}
|
||||
>
|
||||
Зарегистрироваться
|
||||
</mdui-button>
|
||||
</mdui-button>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="hero-visual">
|
||||
@@ -129,7 +122,7 @@ export default function HomePage() {
|
||||
<div className="features-grid">
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="security"></mdui-icon>
|
||||
<mdui-icon name="security" />
|
||||
</div>
|
||||
<h4>End-to-End Шифрование</h4>
|
||||
<p>
|
||||
@@ -140,7 +133,7 @@ export default function HomePage() {
|
||||
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="code"></mdui-icon>
|
||||
<mdui-icon name="code" />
|
||||
</div>
|
||||
<h4>100% открытый код</h4>
|
||||
<p>
|
||||
@@ -151,7 +144,7 @@ export default function HomePage() {
|
||||
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="attach_file"></mdui-icon>
|
||||
<mdui-icon name="attach_file" />
|
||||
</div>
|
||||
<h4>Обмен Файлами</h4>
|
||||
<p>
|
||||
@@ -162,7 +155,7 @@ export default function HomePage() {
|
||||
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="notifications"></mdui-icon>
|
||||
<mdui-icon name="notifications" />
|
||||
</div>
|
||||
<h4>Уведомления</h4>
|
||||
<p>
|
||||
@@ -173,7 +166,7 @@ export default function HomePage() {
|
||||
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="edit"></mdui-icon>
|
||||
<mdui-icon name="edit" />
|
||||
</div>
|
||||
<h4>Редактирование</h4>
|
||||
<p>
|
||||
@@ -184,7 +177,7 @@ export default function HomePage() {
|
||||
|
||||
<div className="feature-card">
|
||||
<div className="feature-icon">
|
||||
<mdui-icon name="computer"></mdui-icon>
|
||||
<mdui-icon name="computer" />
|
||||
</div>
|
||||
<h4>Кроссплатформенность</h4>
|
||||
<p>
|
||||
@@ -205,20 +198,28 @@ export default function HomePage() {
|
||||
уведомлений и автономной работы.
|
||||
</p>
|
||||
<div className="download-buttons">
|
||||
{!isMobile ? (
|
||||
<>
|
||||
<a
|
||||
href="https://github.com/Toolbox-io/FromChat/actions/workflows/build.yml"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<mdui-button variant="filled">
|
||||
<mdui-icon name="download" slot="icon"></mdui-icon>
|
||||
<mdui-icon name="download" slot="icon" />
|
||||
Скачать для ПК
|
||||
</mdui-button>
|
||||
</a>
|
||||
<mdui-button variant="outlined" onClick={() => navigate("/login")}>
|
||||
<mdui-icon name="language" slot="icon"></mdui-icon>
|
||||
<mdui-icon name="language" slot="icon" />
|
||||
Веб-версия
|
||||
</mdui-button>
|
||||
</>
|
||||
) : (
|
||||
<mdui-button variant="filled" onClick={() => navigate("/download-app")}>
|
||||
Скачать приложение
|
||||
</mdui-button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,18 +233,24 @@ export default function HomePage() {
|
||||
Присоединяйтесь к FromChat и общайтесь безопасно с друзьями и коллегами.
|
||||
</p>
|
||||
<div className="cta-actions">
|
||||
{isMobile ? (
|
||||
<mdui-button variant="filled" onClick={() => navigate("/download-app")}>
|
||||
Скачать приложение
|
||||
</mdui-button>
|
||||
) : (
|
||||
<>
|
||||
<mdui-button
|
||||
variant="filled"
|
||||
onClick={() => navigate("/register")}
|
||||
>
|
||||
onClick={() => navigate("/register")}>
|
||||
Создать аккаунт
|
||||
</mdui-button>
|
||||
<mdui-button
|
||||
variant="outlined"
|
||||
onClick={() => navigate("/login")}
|
||||
>
|
||||
onClick={() => navigate("/login")}>
|
||||
Войти
|
||||
</mdui-button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user