Set up basic project structure

This commit is contained in:
2025-08-29 21:49:31 +03:00
Unverified
parent a69cf6e5ec
commit 283ed18bc9
9 changed files with 196 additions and 11 deletions
-3
View File
@@ -161,9 +161,6 @@ async function handleRegister(e: Event): Promise<void> {
function init(): void { function init(): void {
id('login-form-element').addEventListener('submit', handleLogin); id('login-form-element').addEventListener('submit', handleLogin);
id('register-form-element').addEventListener('submit', handleRegister); id('register-form-element').addEventListener('submit', handleRegister);
id("login-link").addEventListener("click", showLogin);
id("register-link").addEventListener("click", showRegister);
} }
init(); init();
+31 -1
View File
@@ -1,3 +1,33 @@
import ChatScreen from "./screen/ChatScreen";
import LoginScreen from "./screen/LoginScreen";
import RegisterScreen from "./screen/RegisterScreen";
import { useAppState } from "./state"
export default function App() { export default function App() {
return <></> const { currentPage } = useAppState();
let page = <LoginScreen />;
switch (currentPage) {
case "login": {
page = <LoginScreen />
break;
}
case "register": {
page = <RegisterScreen />
break;
}
case "chat": {
page = <ChatScreen />
break;
}
}
return (
<>
<div id="main-wrapper">
{page}
</div>
</>
)
} }
+11
View File
@@ -0,0 +1,11 @@
import type React from "react";
export function AuthContainer({ children }: { children?: React.ReactNode }) {
return (
<div className="auth-container">
<div className="auth-card fade-in">
{children}
</div>
</div>
)
}
+5
View File
@@ -0,0 +1,5 @@
export default function ChatScreen() {
return (
<h1>test</h1>
)
}
+57
View File
@@ -0,0 +1,57 @@
import { showLogin, showRegister } from "../../navigation";
import { AuthContainer } from "../components/Auth";
export default function LoginScreen() {
return (
<AuthContainer>
<div className="auth-header">
<h2>
<span className="material-symbols filled large">login</span>
Добро пожаловать!
</h2>
<p>Войдите в свой аккаунт</p>
</div>
<div className="auth-body">
<div id="login-alerts"></div>
<form id="login-form-element">
<mdui-text-field
label="Имя пользователя"
id="login-username"
name="username"
variant="outlined"
icon="person--filled"
autocomplete="username"
required>
</mdui-text-field>
<mdui-text-field
label="Пароль"
id="login-password"
name="password"
variant="outlined"
type="password"
toggle-password
icon="password--filled"
autocomplete="current-password"
required>
</mdui-text-field>
<mdui-button type="submit">Войти</mdui-button>
</form>
<div className="text-center">
<p>
Ещё нет аккаунта?
<a
href="#"
id="register-link"
className="link"
onClick={showRegister}>
Зарегистрируйтесь
</a>
</p>
</div>
</div>
</AuthContainer>
)
}
+70
View File
@@ -0,0 +1,70 @@
import { showLogin } from "../../navigation";
import { AuthContainer } from "../components/Auth";
export default function RegisterScreen() {
return (
<AuthContainer>
<div className="auth-header">
<h2>
<span className="material-symbols filled large">person_add</span>
Регистрация
</h2>
<p>Создайте новый аккаунт</p>
</div>
<div className="auth-body">
<div id="register-alerts"></div>
<form id="register-form-element">
<mdui-text-field
label="Имя пользователя"
id="register-username"
name="username"
variant="outlined"
icon="person--filled"
autocomplete="username"
maxlength={20}
counter
required>
</mdui-text-field>
<mdui-text-field
label="Пароль"
id="register-password"
name="password"
variant="outlined"
type="password"
toggle-password
icon="password--filled"
autocomplete="new-password"
required>
</mdui-text-field>
<mdui-text-field
label="Подтвердите пароль"
id="register-confirm-password"
name="confirm_password"
variant="outlined"
type="password"
toggle-password
icon="password--filled"
autocomplete="new-password"
required>
</mdui-text-field>
<mdui-button type="submit">Зарегистрироваться</mdui-button>
</form>
<div className="text-center">
<p>
Уже есть аккаунт?
<a
href="#"
id="login-link"
className="link"
onClick={showLogin}>
Войдите
</a>
</p>
</div>
</div>
</AuthContainer>
)
}
+13
View File
@@ -0,0 +1,13 @@
import { create } from "zustand";
type Page = "login" | "register" | "chat"
interface AppState {
currentPage: Page;
setCurrentPage: (page: Page) => void;
}
export const useAppState = create<AppState>((set) => ({
currentPage: "login", // default page
setCurrentPage: (page: Page) => set({ currentPage: page })
}));
+2 -1
View File
@@ -1 +1,2 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
/// <reference types="mdui/jsx.en.d.ts" />
+7 -6
View File
@@ -29,6 +29,9 @@
"prepare": "husky" "prepare": "husky"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^5.0.2",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"concurrently": "^9.2.0", "concurrently": "^9.2.0",
"dotenv-cli": "^10.0.0", "dotenv-cli": "^10.0.0",
@@ -41,15 +44,13 @@
"vite": "^7.1.2", "vite": "^7.1.2",
"vite-plugin-electron": "^0.29.0", "vite-plugin-electron": "^0.29.0",
"vite-plugin-electron-renderer": "^0.14.6", "vite-plugin-electron-renderer": "^0.14.6",
"vite-plugin-html": "^3.2.2", "vite-plugin-html": "^3.2.2"
"@vitejs/plugin-react": "^5.0.2",
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.9"
}, },
"dependencies": { "dependencies": {
"mdui": "^2.1.4", "mdui": "^2.1.4",
"tweetnacl": "^1.0.3",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1" "react-dom": "^19.1.1",
"tweetnacl": "^1.0.3",
"zustand": "^5.0.8"
} }
} }