mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Add "Download app" screen for too small screens, translate strings
# Please enter the commit message for your changes. Lines starting
This commit is contained in:
@@ -27,4 +27,6 @@ export const API_WS_BASE_URL = `${location.host || BASE_DOMAIN}/api`;
|
|||||||
* Application name displayed in UI and document title
|
* Application name displayed in UI and document title
|
||||||
* @constant
|
* @constant
|
||||||
*/
|
*/
|
||||||
export const PRODUCT_NAME = "FromChat";
|
export const PRODUCT_NAME = "FromChat";
|
||||||
|
|
||||||
|
export const MINIMUM_WIDTH = 800;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.download-app-screen {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
@use "common/material" as *;
|
@use "common/material" as *;
|
||||||
@use "electron";
|
@use "electron";
|
||||||
@use "dialogs/reply";
|
@use "dialogs/reply";
|
||||||
|
@use "download-app";
|
||||||
|
|
||||||
@use "lib/fonts/montserrat";
|
@use "lib/fonts/montserrat";
|
||||||
@use "lib/fonts/material-symbols";
|
@use "lib/fonts/material-symbols";
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { MINIMUM_WIDTH } from "../core/config";
|
||||||
import { ElectronTitleBar } from "./components/Electron";
|
import { ElectronTitleBar } from "./components/Electron";
|
||||||
|
import useWindowSize from "./hooks/useWindowSize";
|
||||||
import ChatScreen from "./screen/ChatScreen";
|
import ChatScreen from "./screen/ChatScreen";
|
||||||
|
import DownloadAppScreen from "./screen/DownloadAppScreen";
|
||||||
import LoginScreen from "./screen/LoginScreen";
|
import LoginScreen from "./screen/LoginScreen";
|
||||||
import RegisterScreen from "./screen/RegisterScreen";
|
import RegisterScreen from "./screen/RegisterScreen";
|
||||||
import { useAppState } from "./state";
|
import { useAppState } from "./state";
|
||||||
@@ -7,12 +10,17 @@ import { useEffect } from "react";
|
|||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const { currentPage, restoreUserFromStorage } = useAppState();
|
const { currentPage, restoreUserFromStorage } = useAppState();
|
||||||
|
const { width } = useWindowSize();
|
||||||
|
|
||||||
// Restore user from localStorage on app initialization
|
// Restore user from localStorage on app initialization
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
restoreUserFromStorage();
|
restoreUserFromStorage();
|
||||||
}, [restoreUserFromStorage]);
|
}, [restoreUserFromStorage]);
|
||||||
|
|
||||||
|
if (width < MINIMUM_WIDTH) {
|
||||||
|
return <DownloadAppScreen />
|
||||||
|
}
|
||||||
|
|
||||||
let page = <LoginScreen />;
|
let page = <LoginScreen />;
|
||||||
|
|
||||||
switch (currentPage) {
|
switch (currentPage) {
|
||||||
|
|||||||
@@ -176,17 +176,17 @@ export function MessageContextMenu({
|
|||||||
>
|
>
|
||||||
<div className="context-menu-item" onClick={() => handleAction("reply")}>
|
<div className="context-menu-item" onClick={() => handleAction("reply")}>
|
||||||
<span className="material-symbols">reply</span>
|
<span className="material-symbols">reply</span>
|
||||||
Reply
|
Ответить
|
||||||
</div>
|
</div>
|
||||||
{isAuthor && (
|
{isAuthor && (
|
||||||
<>
|
<>
|
||||||
<div className="context-menu-item" onClick={() => handleAction("edit")}>
|
<div className="context-menu-item" onClick={() => handleAction("edit")}>
|
||||||
<span className="material-symbols">edit</span>
|
<span className="material-symbols">edit</span>
|
||||||
Edit
|
Редактировать
|
||||||
</div>
|
</div>
|
||||||
<div className="context-menu-item" onClick={() => handleAction("delete")}>
|
<div className="context-menu-item" onClick={() => handleAction("delete")}>
|
||||||
<span className="material-symbols">delete</span>
|
<span className="material-symbols">delete</span>
|
||||||
Delete
|
Удалить
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
|
|||||||
|
|
||||||
// Cleanup function
|
// Cleanup function
|
||||||
return () => {
|
return () => {
|
||||||
if (panel && (panel as any).onStateChange) {
|
if (panel && panel.onStateChange) {
|
||||||
(panel as any).onStateChange = null;
|
panel.onStateChange = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [panel]);
|
}, [panel]);
|
||||||
@@ -72,10 +72,10 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
|
|||||||
<img src={defaultAvatar} alt="Avatar" className="chat-header-avatar" />
|
<img src={defaultAvatar} alt="Avatar" className="chat-header-avatar" />
|
||||||
<div className="chat-header-info">
|
<div className="chat-header-info">
|
||||||
<div className="info-chat">
|
<div className="info-chat">
|
||||||
<h4 id="chat-name">Select a chat</h4>
|
<h4 id="chat-name">Выбор чата</h4>
|
||||||
<p>
|
<p>
|
||||||
<span className="online-status"></span>
|
<span className="online-status"></span>
|
||||||
Choose a chat to start messaging
|
Выберите чат, чтобы начать переписку
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,7 +88,7 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
color: "var(--mdui-color-on-surface-variant)"
|
color: "var(--mdui-color-on-surface-variant)"
|
||||||
}}>
|
}}>
|
||||||
Select a chat from the sidebar to start messaging
|
Выберите чат на боковой панели, чтобы начать переписку
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,7 +128,7 @@ export function MessagePanelRenderer({ panel, isChatSwitching }: MessagePanelRen
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
color: "var(--mdui-color-on-surface-variant)"
|
color: "var(--mdui-color-on-surface-variant)"
|
||||||
}}>
|
}}>
|
||||||
Loading messages...
|
Загрузка сообщений...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
): (
|
): (
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function ReplyMessageDialog({ isOpen, onOpenChange, replyToMessage, onSen
|
|||||||
return (
|
return (
|
||||||
<MaterialDialog open={isOpen} onOpenChange={onOpenChange} close-on-overlay-click close-on-esc className="reply-dialog">
|
<MaterialDialog open={isOpen} onOpenChange={onOpenChange} close-on-overlay-click close-on-esc className="reply-dialog">
|
||||||
<div className="dialog-content">
|
<div className="dialog-content">
|
||||||
<h3>Reply to Message</h3>
|
<h3>Ответить на сообщение</h3>
|
||||||
<div className="reply-preview-dialog">
|
<div className="reply-preview-dialog">
|
||||||
<div className="reply-content">
|
<div className="reply-content">
|
||||||
<span className="reply-username">{replyToMessage.username}</span>
|
<span className="reply-username">{replyToMessage.username}</span>
|
||||||
|
|||||||
@@ -28,24 +28,24 @@ export function UserProfileDialog({ isOpen, onOpenChange, userProfile }: UserPro
|
|||||||
<div className={`online-status ${userProfile.online ? "online" : "offline"}`}>
|
<div className={`online-status ${userProfile.online ? "online" : "offline"}`}>
|
||||||
{userProfile.online ? (
|
{userProfile.online ? (
|
||||||
<>
|
<>
|
||||||
<span className="online-indicator"></span> Online
|
<span className="online-indicator"></span> Онлайн
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="offline-indicator"></span> Last seen {formatTime(userProfile.last_seen)}
|
<span className="offline-indicator"></span> Последний заход {formatTime(userProfile.last_seen)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bio-section">
|
<div className="bio-section">
|
||||||
<label>Bio:</label>
|
<label>О себе:</label>
|
||||||
<div className="bio-display">
|
<div className="bio-display">
|
||||||
{userProfile.bio || "No bio available."}
|
{userProfile.bio || "No bio available."}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="profile-stats">
|
<div className="profile-stats">
|
||||||
<div className="stat">
|
<div className="stat">
|
||||||
<span className="stat-label">Member since:</span>
|
<span className="stat-label">Зарегистрирован:</span>
|
||||||
<span className="stat-value member-since">{formatTime(userProfile.created_at)}</span>
|
<span className="stat-value member-since">{formatTime(userProfile.created_at)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="stat">
|
<div className="stat">
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export interface WindowSize {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useWindowSize(): WindowSize {
|
||||||
|
const [width, setWidth] = useState(innerWidth);
|
||||||
|
const [height, setHeight] = useState(innerHeight);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function listener() {
|
||||||
|
setWidth(innerWidth);
|
||||||
|
setHeight(innerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("resize", listener);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
removeEventListener("resize", listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export default function DownloadAppScreen() {
|
||||||
|
return (
|
||||||
|
<div className="download-app-screen">
|
||||||
|
<div className="inner">
|
||||||
|
<h1>Чтобы пользоваться мессенджером, скачайте приложение</h1>
|
||||||
|
<p>
|
||||||
|
Этот сайт <b>не предназначен</b> для работы на маленьких экранах, поэтому
|
||||||
|
вам нужно скачать приложение мессенджера.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://github.com/denis0001-dev/FromChat-android/releases/latest">
|
||||||
|
<mdui-button>Скачать на GitHub</mdui-button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Если возникнут сложности или есть вопросы, нажмите кнопку!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://t.me/denis0001-dev">
|
||||||
|
<mdui-button>Написать в поддержку</mdui-button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user