This commit is contained in:
TUTOR03 2020-11-29 02:50:16 +00:00
commit ff4e2721c1
39 changed files with 2255 additions and 95 deletions

View File

@ -18,4 +18,9 @@
- Сделали дизайн лэндинга и главной страницы пользователя: https://www.figma.com/file/yic0NHlJAfuSVZlRYm2IuW/%D0%9F%D1%80%D0%BE%D1%84%D0%B8%D0%BB%D1%8C
- Дописали авторизацию на бэкенде
- Спроектировали модель данных https://ibb.co/MSST2kZ
- Начали пилить фронт (немного вёрстки и стэйт через контекст для пользователя)
- Начали пилить фронт (немного вёрстки и стэйт через контекст для пользователя)
# 7:00 Checkpoint
- Дописали бэкенд
- начали деплой проекта с помощью Docker
- Продолжаем (медленно, но верно) пилить фронт

View File

@ -0,0 +1,15 @@
import React from "react";
import styles from "styles/errorMessage.module.css";
interface IErrorMessageProps {
message: string;
}
const ErrorMessage: React.FC<IErrorMessageProps> = ({ message }) => (
<div>
<p className={styles.text}>{message}</p>
</div>
);
export default ErrorMessage;

View File

@ -0,0 +1,18 @@
import { HomeRefContext } from "context/ref";
import React, { useContext } from "react";
import styles from "styles/layout.module.css";
const HomeHeader: React.FC = () => {
const ref = useContext(HomeRefContext);
const scrollToRef = () => ref?.current?.scrollIntoView();
return (
<a onClick={scrollToRef} className={styles.link}>
Регистрация
</a>
);
};
export default HomeHeader;

View File

@ -0,0 +1,33 @@
import React, { useContext, useEffect, useState } from "react";
import styles from "styles/layout.module.css";
import { LoadingContext } from "context/loading";
import HomeHeader from "./HomeHeader";
import UserHeader from "./UserHeader";
const Layout: React.FC<{ pathname: string }> = ({ children, pathname }) => {
const { loading, setLoading } = useContext(LoadingContext);
useEffect(() => setLoading(false), []);
if (loading) return <h1>Loading...</h1>;
return (
<div className={styles.content}>
<nav className={styles.header}>
<div className={styles.logo}>
<img src="logo.svg" alt="" />
<p className={styles.textLogo}>Ko.Map</p>
</div>
<div />
<div>
{pathname == "/" ? <HomeHeader /> : ""}
{pathname == "/user" ? <UserHeader /> : ""}
</div>
</nav>
<div>{children}</div>
</div>
);
};
export default Layout;

View File

@ -0,0 +1,65 @@
import React, { Dispatch, FormEvent, SetStateAction, useContext } from "react";
import { NextRouter, useRouter } from "next/router";
import ErrorMessage from "components/ErrorMessage";
import { UserContext, UserT } from "context/user";
import useErrorHandler from "hooks/ErrorHandler";
import { request } from "utils/index";
const dispatch = (err: Error) => "Error happened";
const setToken = async (
token: string,
setUserState: Dispatch<SetStateAction<UserT>>
) => {
localStorage.setItem("token", token);
try {
const user = await request("user", "GET");
setUserState(user);
} catch (err) {
console.log(err.message);
throw err;
}
};
const handleSubmit = (
resetError: () => void,
setUserState: Dispatch<SetStateAction<UserT>>,
gotError: (err: Error) => void,
router: NextRouter
) => async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const formData = new FormData(e.currentTarget);
const jsonData = Object.fromEntries(formData);
resetError();
const res = await request("login", "POST", jsonData);
setToken(res.token, setUserState);
router.push("/user");
} catch (err) {
gotError(err.message);
}
};
const Login: React.FC = () => {
const router = useRouter();
const { error, gotError, resetError } = useErrorHandler(dispatch);
const { userState, setUserState } = useContext(UserContext);
return (
<form onSubmit={handleSubmit(resetError, setUserState, gotError, router)}>
<input type="email" name="email" id="email" />
<input type="password" name="password" id="password" autoComplete="on" />
<input type="submit" />
{error.has ? <ErrorMessage message={error.message} /> : ""}
</form>
);
};
export default Login;

View File

@ -0,0 +1,48 @@
import React, { FormEvent, useState } from "react";
import ErrorMessage from "components/ErrorMessage";
import useErrorHandler from "hooks/ErrorHandler";
import { request } from "utils/index";
const dispatch = (err: Error) => "Error happened";
const Register: React.FC = () => {
const [successfulAttempt, setSuccessfulAttempt] = useState<boolean>(false);
const { error, gotError, resetError } = useErrorHandler(dispatch);
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const formData = new FormData(e.currentTarget);
const jsonData = Object.fromEntries(formData);
resetError();
const res = await request("register", "POST", jsonData);
if (!res.ok) throw new Error("Couldn't register");
setSuccessfulAttempt(true);
} catch (err) {
gotError(err.message);
}
};
return successfulAttempt ? (
<p>
Для продолжения регистрации перейдите по ссылке, отправленной вам на
введённую почту
</p>
) : (
<form onSubmit={handleSubmit}>
<input type="text" name="username" id="username" />
<input type="email" name="email" id="email" />
<input type="password" name="password" id="password" autoComplete="on" />
<input type="submit" />
{error.has ? <ErrorMessage message={error.message} /> : ""}
</form>
);
};
export default Register;

View File

@ -2,10 +2,12 @@ import React from "react";
import { IRouteView } from "types/user";
import RouteCard from "./RouteCard";
import styles from "styles/RouteView.module.css";
const RouteView: React.FC<IRouteView> = ({ header, routes }) => {
return (
<>
<h1>{header}</h1>
<h1 className={styles.header}>{header}</h1>
{routes.map((route) => (
<RouteCard key={route.id} route={route} />
))}

View File

@ -1,12 +1,13 @@
import React from "react";
import { UserContext } from "context/user";
import Link from "next/link";
import React, { useContext } from "react";
import { IHeaderProps } from "types/user";
const UserHeader: React.FC = () => {
const user = useContext(UserContext);
const Header: React.FC<IHeaderProps> = ({ points }) => {
return (
<header>
<div>Очки: {points}</div>
<>
<div>Очки: {user?.userState?.points || 0}</div>
<nav>
<ul>
<li>
@ -21,8 +22,8 @@ const Header: React.FC<IHeaderProps> = ({ points }) => {
</li>
</ul>
</nav>
</header>
</>
);
};
export default Header;
export default UserHeader;

22
front/context/loading.tsx Normal file
View File

@ -0,0 +1,22 @@
import React, { Dispatch, SetStateAction, useMemo, useState } from "react";
const LoadingContext = React.createContext<LoadingContextT>(null);
type LoadingContextT = {
loading: boolean;
setLoading: Dispatch<SetStateAction<boolean>>;
};
const LoadingProvider: React.FC = ({ children }) => {
const [loading, setLoading] = useState<boolean>(true);
const value = useMemo<LoadingContextT>(() => ({ loading, setLoading }), [
loading,
]);
return (
<LoadingContext.Provider value={value}>{children}</LoadingContext.Provider>
);
};
export { LoadingContext, LoadingProvider };

15
front/context/ref.tsx Normal file
View File

@ -0,0 +1,15 @@
import React, { MutableRefObject, useRef } from "react";
const HomeRefContext = React.createContext<MutableRefObject<HTMLDivElement>>(
null
);
const HomeRefProvider: React.FC = ({ children }) => {
const value = useRef<HTMLDivElement>(null);
return (
<HomeRefContext.Provider value={value}>{children}</HomeRefContext.Provider>
);
};
export { HomeRefContext, HomeRefProvider };

View File

@ -2,17 +2,10 @@ import React, { useMemo, useState } from "react";
import { UserContextT, UserT } from "types/userContext";
const UserContext = React.createContext<UserContextT>(null);
const initialContext: UserT = {
username: "",
email: "",
points: 0,
id: 0,
};
const UserContext = React.createContext<UserContextT | null>(null);
const UserProvider: React.FC = ({ children }) => {
const [state, setState] = useState<UserT>(initialContext);
const [state, setState] = useState<UserT>();
const value = useMemo(() => ({ userState: state, setUserState: setState }), [
state,

View File

@ -0,0 +1,25 @@
import { useState } from "react";
type ErrorT = {
message?: string;
has: boolean;
};
const useErrorHandler = <T extends Function>(
dispatcher: T
): {
error: ErrorT;
gotError: (err: Error) => void;
resetError: () => void;
} => {
const [error, setError] = useState<ErrorT>({ has: false });
const gotError = (err: Error) =>
setError({ has: true, message: dispatcher(err) });
const resetError = () => setError({ has: false });
return { error, gotError, resetError };
};
export default useErrorHandler;

View File

@ -1,7 +0,0 @@
import React from "react";
const EmptyLayout: React.FC = ({ children }) => {
return <>{children}</>;
};
export default EmptyLayout;

View File

@ -1,14 +0,0 @@
import React from "react";
import styles from "styles/layout.module.css";
import { UserProvider } from "context/user";
const Layout: React.FC = ({ children }) => {
return (
<UserProvider>
<div className={styles.content}>{children}</div>
</UserProvider>
);
};
export default Layout;

View File

@ -1,16 +0,0 @@
import React, { useContext } from "react";
import Header from "components/User/header";
import { UserContext } from "context/user";
const UserLayout: React.FC = ({ children }) => {
const { userState } = useContext(UserContext);
return (
<>
<Header points={userState.points} />
<main>{children}</main>
</>
);
};
export default UserLayout;

4
front/next-env.d.ts vendored
View File

@ -1,2 +1,6 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
declare module "*.svg" {
const content: any;
export default content;
}

8
front/next.conf.js Normal file
View File

@ -0,0 +1,8 @@
// export function webpack(config) {
// config.module.rules.push({
// test: /\.svg$/,
// use: ["@svgr/webpack"]
// });
// return config;
// }

View File

@ -9,6 +9,8 @@
"format": "prettier --write \"**/*.+(js|jsx|json|css|md)\""
},
"dependencies": {
"@svgr/webpack": "^5.5.0",
"framer-motion": "^2.9.4",
"next": "10.0.3",
"react": "17.0.1",
"react-dom": "17.0.1",

View File

@ -1,17 +1,38 @@
import React from "react";
import { motion } from "framer-motion";
import "styles/globals.css";
import Layout from "layouts/MainLayout";
import EmptyLayout from "layouts/EmptyLayout";
import Layout from "components/Layout";
import { AppProps } from "next/dist/next-server/lib/router/router";
import { UserProvider } from "context/user";
import { HomeRefProvider } from "context/ref";
import { LoadingProvider } from "context/loading";
function MyApp({ Component, pageProps }) {
const ComponentLayout = Component.Layout || EmptyLayout;
function MyApp({ Component, pageProps, router }: AppProps) {
return (
<Layout>
<ComponentLayout>
<Component {...pageProps} />
</ComponentLayout>
</Layout>
<LoadingProvider>
<UserProvider>
<HomeRefProvider>
<Layout pathname={router.pathname}>
<motion.div
initial="pageInitial"
animate="pageAnimate"
variants={{
pageInitial: {
opacity: 0,
},
pageAnimate: {
opacity: 1,
},
}}
key={router.route}
>
<Component {...pageProps} />
</motion.div>
</Layout>
</HomeRefProvider>
</UserProvider>
</LoadingProvider>
);
}

View File

@ -0,0 +1,9 @@
import { NextPage } from "next";
import React from "react";
const ComingSoon: NextPage = () => {
return <h1>Coming Soon</h1>;
};
export default ComingSoon;

85
front/pages/index.tsx Normal file
View File

@ -0,0 +1,85 @@
import React, { useContext, useEffect, useState } from "react";
import HomeLayout from "layouts/HomeLayout";
import styles from "styles/home.module.css";
import { HomeRefContext } from "context/ref";
import Register from "components/Register";
import Login from "components/Login";
import { UserContext } from "context/user";
import { useRouter } from "next/router";
import { LoadingContext } from "context/loading";
const advantagesList = [
{
icon: "home/map.svg",
alt: "Map",
text:
"Поиск маршрутов для прогулки по знаковым местам незнакомомого города",
},
{
icon: "home/coin.svg",
alt: "Coin",
text: "Бесплатный сервис по всей Югре",
},
{
icon: "home/dialog.svg",
alt: "Dialog",
text: "Новые знакомства и общение",
},
];
const Home: React.FC & { Layout: React.ReactNode } = () => {
const { setLoading } = useContext(LoadingContext);
const { userState } = useContext(UserContext);
const router = useRouter();
useEffect(() => {
if (userState) {
router.push("/user");
return null;
} else setLoading(false);
}, []);
const scrollRef = useContext(HomeRefContext);
const [newUser, setNewUser] = useState<boolean>(true);
return (
<>
<div className={styles.picCard}>
<p className={styles.picMainText}>
Туристический
<br />
квест
</p>
<p className={styles.picSubText}>
Увлекательное путешествие в форме квеста без скучного поиска новых,
интересных мест
</p>
</div>
<ul className={styles.advantages}>
{advantagesList.map((element, key) => (
<li className={styles.advantage} key={key}>
<img
className={styles.advantageIcon}
src={element.icon}
alt={element.alt}
/>
<p className={styles.advantageText}>{element.text}</p>
</li>
))}
</ul>
<div ref={scrollRef} className={styles.authContainer}>
<h2 className={styles.authHeader}>
Поле для <a onClick={() => setNewUser(true)}>регистрации</a>/
<a onClick={() => setNewUser(false)}>входа</a>
</h2>
{newUser ? <Register /> : <Login />}
</div>
</>
);
};
Home.Layout = HomeLayout;
export default Home;

9
front/pages/profile.tsx Normal file
View File

@ -0,0 +1,9 @@
import { NextPage } from "next";
import React from "react";
const ComingSoon: NextPage = () => {
return <h1>Coming Soon</h1>;
};
export default ComingSoon;

View File

@ -0,0 +1,8 @@
import React from "react";
import Login from "components/Login";
const LoginContainer: React.FC = () => {
return <Login />;
};
export default LoginContainer;

View File

@ -1,8 +1,8 @@
import UserLayout from "layouts/UserLayout";
import { UserContext } from "context/user";
import React, { useContext } from "react";
import RouteView from "components/User/RouteView";
import { RouteT } from "types/main";
import { useRouter } from "next/router";
const routes: RouteT[] = [
{
@ -19,6 +19,7 @@ const routes: RouteT[] = [
const User = () => {
const { userState, setUserState } = useContext(UserContext);
return (
<>
<RouteView header={"Новые маршруты"} routes={routes} />
@ -26,6 +27,4 @@ const User = () => {
);
};
User.Layout = UserLayout;
export default User;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,4 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="48" stroke="#200808" stroke-width="4"/>
<path d="M60.7972 38.992C60.0772 37.6 59.2612 36.28 58.3492 35.032C57.4372 33.736 56.3332 32.704 55.0372 31.936C53.7412 31.12 52.1572 30.712 50.2852 30.712C47.4052 30.712 45.2932 31.312 43.9492 32.512C42.6532 33.664 42.0052 35.344 42.0052 37.552C42.0052 39.376 42.5572 40.888 43.6612 42.088C44.7652 43.24 46.2052 44.248 47.9812 45.112C49.7572 45.928 51.6532 46.72 53.6692 47.488C54.9652 47.968 56.3572 48.592 57.8452 49.36C59.3332 50.128 60.7252 51.088 62.0212 52.24C63.3172 53.344 64.3732 54.736 65.1892 56.416C66.0052 58.048 66.4132 60.016 66.4132 62.32C66.4132 66.304 65.2852 69.592 63.0292 72.184C60.7732 74.776 57.4612 76.264 53.0932 76.648V84.064H47.7652V76.432C44.4052 75.76 41.4532 74.224 38.9092 71.824C36.3652 69.376 34.4212 66.376 33.0772 62.824L38.2612 59.728C39.7972 63.184 41.5972 65.92 43.6612 67.936C45.7252 69.952 48.3172 70.96 51.4372 70.96C54.3172 70.96 56.4772 70.24 57.9172 68.8C59.3572 67.312 60.0772 65.32 60.0772 62.824C60.0772 60.664 59.4772 58.888 58.2772 57.496C57.1252 56.104 55.6372 54.952 53.8132 54.04C52.0372 53.128 50.1892 52.336 48.2692 51.664C47.0212 51.232 45.6532 50.656 44.1652 49.936C42.7252 49.216 41.3572 48.304 40.0612 47.2C38.7652 46.048 37.6852 44.656 36.8212 43.024C36.0052 41.392 35.5972 39.424 35.5972 37.12C35.5972 35.056 36.1252 33.184 37.1812 31.504C38.2372 29.776 39.6772 28.36 41.5012 27.256C43.3252 26.104 45.4132 25.36 47.7652 25.024V17.104H53.0932V25.096C55.2532 25.48 57.1732 26.224 58.8532 27.328C60.5812 28.432 62.0212 29.728 63.1732 31.216C64.3252 32.704 65.1892 34.192 65.7652 35.68L60.7972 38.992Z" fill="#200808"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="77" viewBox="0 0 100 77" fill="none">
<mask id="path-1-inside-1" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M93.4247 54.5752C96.2862 49.6831 97.8819 44.2382 97.8819 38.5C97.8819 17.237 75.9703 0 48.941 0C21.9116 0 0 17.237 0 38.5C0 59.763 21.9116 77 48.941 77C60.2523 77 70.6674 73.9813 78.9554 68.9121L99.9999 76.0131L93.4247 54.5752Z"/>
</mask>
<path d="M93.4247 54.5752L89.9719 52.5557L89.0859 54.0704L89.6005 55.7481L93.4247 54.5752ZM78.9554 68.9121L80.2343 65.1221L78.4631 64.5244L76.8684 65.4998L78.9554 68.9121ZM99.9999 76.0131L98.721 79.8031L106.111 82.2967L103.824 74.8402L99.9999 76.0131ZM93.8819 38.5C93.8819 43.4764 92.5022 48.2299 89.9719 52.5557L96.8774 56.5948C100.07 51.1364 101.882 44.9999 101.882 38.5H93.8819ZM48.941 4C74.7086 4 93.8819 20.2872 93.8819 38.5H101.882C101.882 14.1868 77.232 -4 48.941 -4V4ZM4 38.5C4 20.2872 23.1733 4 48.941 4V-4C20.6499 -4 -4 14.1868 -4 38.5H4ZM48.941 73C23.1733 73 4 56.7128 4 38.5H-4C-4 62.8132 20.6499 81 48.941 81V73ZM76.8684 65.4998C69.2384 70.1665 59.5514 73 48.941 73V81C60.9532 81 72.0964 77.7961 81.0425 72.3245L76.8684 65.4998ZM101.279 72.223L80.2343 65.1221L77.6766 72.7022L98.721 79.8031L101.279 72.223ZM89.6005 55.7481L96.1757 77.186L103.824 74.8402L97.2488 53.4023L89.6005 55.7481Z" fill="#200808" mask="url(#path-1-inside-1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M87 4V4.17734L91.1636 4.00686C91.2746 4.00232 91.3867 4 91.5 4C93.12 4 94.4168 4.4698 95.2037 5.02523C96.001 5.58807 96 5.9915 96 6C96 6.02976 95.9999 6.22312 95.6799 6.56639C95.3423 6.92853 94.7201 7.35973 93.7831 7.65896L91 8.54777V11.4694V88.5306V91.4522L93.7831 92.341C94.7201 92.6403 95.3423 93.0715 95.6799 93.4336C95.9999 93.7769 96 93.9702 96 94C96 94.0085 96.001 94.4119 95.2037 94.9748C94.4168 95.5302 93.12 96 91.5 96C91.3867 96 91.2746 95.9977 91.1637 95.9931L87 95.8226V96H13V95.8226L8.83634 95.9931C8.72545 95.9977 8.61331 96 8.5 96C6.88005 96 5.58319 95.5302 4.79633 94.9748C3.99897 94.4119 4 94.0085 4 94C4 93.9702 4.00014 93.7769 4.32014 93.4336C4.65774 93.0715 5.27994 92.6403 6.21689 92.341L9 91.4522V88.5306V11.4694V8.54777L6.21689 7.65896C5.27993 7.35973 4.65774 6.92853 4.32014 6.56639C4.00014 6.22312 4 6.02976 4 6V5.99997C4 5.99052 3.99994 5.58738 4.79633 5.02523C5.58319 4.4698 6.88004 4 8.5 4C8.61329 4 8.72544 4.00232 8.83635 4.00686L13 4.17734V4H87ZM91.5 100C91.6678 100 91.8345 99.9966 92 99.9898C96.4617 99.8071 100 97.1952 100 94C100 91.567 97.9485 89.4723 95 88.5306V11.4694C97.9485 10.5277 100 8.43297 100 6C100 2.80477 96.4617 0.192897 92 0.0102083C91.8346 0.00343414 91.6678 0 91.5 0C91.3322 0 91.1654 0.00343414 91 0.0102083V0H90.9996H87H13H9V0.0102083C8.83456 0.00343414 8.66785 0 8.5 0C8.33215 0 8.16544 0.00343414 8 0.0102083C3.53831 0.192897 0 2.80477 0 6C0 8.43297 2.05148 10.5277 5 11.4694V88.5306C2.05148 89.4723 0 91.567 0 94C0 97.1952 3.53831 99.8071 8 99.9898C8.16544 99.9966 8.33215 100 8.5 100C8.66785 100 8.83456 99.9966 9 99.9898V100H9.00042H13H87H91V99.9898C91.1654 99.9966 91.3322 100 91.5 100ZM82.5806 8.86811L86.5496 5.95848L86.6024 10.8794L87.0003 47.9006L87.0486 52.397L83.0268 50.3857L53.1167 35.4277L49.0949 33.4164L52.7215 30.7577L82.5806 8.86811ZM56.7433 32.7691L82.6335 13.7891L82.9785 45.8892L56.7433 32.7691ZM56.0001 62.5552L67.6921 44L71.0763 46.1325L59.3842 64.6877L56.0001 62.5552ZM36.8354 74.0538L15.0001 72L14.6255 75.9824L36.4609 78.0362L36.8354 74.0538ZM37 74.2109L55.8499 63L57.8945 66.4379L39.0447 77.6488L37 74.2109ZM38 44.5C38 49.1944 34.1944 53 29.5 53C24.8056 53 21 49.1944 21 44.5C21 39.8056 24.8056 36 29.5 36C34.1944 36 38 39.8056 38 44.5ZM42 44.5C42 51.4036 36.4036 57 29.5 57C22.5964 57 17 51.4036 17 44.5C17 37.5964 22.5964 32 29.5 32C36.4036 32 42 37.5964 42 44.5Z" fill="#200808"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,25 @@
<svg width="370" height="370" viewBox="0 0 370 370" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<rect width="370" height="370" rx="50" fill="white" fill-opacity="0.8"/>
<path d="M247.13 86.5C244.33 97.7 216.63 119.167 203.13 128.5C201.13 133.667 196.53 144 194.13 144C191.13 144 241.13 156.5 233.13 158C226.73 159.2 290.13 166.5 322.63 170L387.63 144C390.13 127.833 393.63 95.2 387.63 94C380.13 92.5 379.13 83 374.63 78.5C370.13 74 377.13 64 368.63 64C361.83 64 352.13 68 348.13 70C348.797 62.8333 348.83 48.6 343.63 49C338.43 49.4 334.463 36.1667 333.13 29.5C332.797 33.5 332.33 46 333.13 64C333.93 82 326.463 100.5 322.63 107.5L312.63 78.5C308.963 71.6667 299.83 58 292.63 58C285.43 58 283.63 29.3333 283.63 15C280.963 21.3333 275.43 33.1 274.63 29.5C273.83 25.9 268.297 28 265.63 29.5C263.63 36.3333 259.33 51.6 258.13 58C256.63 66 250.63 72.5 247.13 86.5Z" fill="#EBEFF3"/>
<path d="M19.3862 142.46C18.7448 137.645 12.3143 140.135 0.0945851 149.931L-8.74892 153.831L-14.6483 195.458L4.73562 340.995L399.733 291.652L398.494 200.333L383.964 134.199L378.853 134.88L367.503 123.867L357.804 121.347L349.806 112.066L338.574 109.75L329.089 108.835L325.796 111.451L324.251 115.469L318.759 121.102L318.118 116.286C315.566 115.355 310.406 113.066 310.178 111.353L308.824 101.187L300.033 90.5253C299.855 90.2648 299.679 90.0562 299.519 89.902L300.033 90.5253C300.955 91.8813 301.896 94.644 300.659 98.463C298.816 104.154 291.447 103.502 287.358 104.046L279.18 105.136L276.625 105.476L271.573 110.505C269.982 107.027 267.299 100.692 267.012 98.3597C267.423 97.7602 267.56 97.4259 267.236 97.4691C267.007 97.4996 266.946 97.8241 267.012 98.3597C265.478 100.598 260.12 106.532 260.626 110.33C261.139 114.182 255.388 112.661 252.448 111.419L244.485 114.113C243.553 116.234 241.441 120.944 240.443 122.82C239.194 125.164 233.157 118.889 231.112 119.161C229.068 119.434 229.424 122.109 229.198 124.317C229.017 126.084 226.476 131.215 225.227 133.559L222.554 125.202L219.475 129.424L213.354 126.428L210.157 121.952L205.071 115.006L202.063 119.763L200.471 115.619L191.116 119.588L190.07 127.351L185.742 133.917L185.244 130.172L179.098 134.802C177.509 137.192 174.127 141.999 173.309 142.108C172.287 142.244 169.446 140.444 169.22 142.652C169.039 144.419 162.314 149.381 158.974 151.641C156.414 153.252 151.395 157.224 151.794 160.221C152.193 163.217 145.162 157.292 141.596 153.955C139.548 155.499 135.142 159.389 133.905 162.603C132.669 165.818 128.628 162.036 126.762 159.743L111.429 161.785C108.873 162.125 95.6215 152.455 94.5871 156.405C93.5526 160.354 68.2826 165.898 66.4643 163.962C65.0096 162.413 57.3888 149.197 53.7602 142.783L27.8243 151.138C25.2254 149.851 19.8993 146.313 19.3862 142.46Z" fill="#E0E9F0"/>
<path d="M19 265.084C14.5 268.584 8.5 261.584 -3 257.084L-5 363.084L256 378.084L351.5 371.5L373 349.584C374 308.417 375.8 224.184 375 216.584C374 207.084 355 212.584 351.5 212.584C348 212.584 343 216.584 332.5 216.584C322 216.584 325.5 220.584 320.5 222.584C315.5 224.584 298 216.584 285 216.584C272 216.584 259.5 220.084 256 222.584C252.5 225.084 230.5 216.084 204 216.584C177.5 217.084 191 221.084 176.5 226.084C162.204 231.013 152.769 228.653 142.922 226.189L142.5 226.084C132.5 223.584 109 239.084 105 238.084C101 237.084 82.5 245.584 79.5 248.584C77.1 250.984 63.5 253.584 57 254.584L38.5 260.584C33.5 260.917 22.6 262.284 19 265.084Z" fill="#9BB4CA"/>
<path d="M20 318.866C17.5 320.033 11.5 323.066 7.5 325.866L-5 354.866L41 377.866H109.5L281.5 372.866C302 377.866 283.5 367.8 281.5 367C279 366 260.5 350.366 253 357.366C245.5 364.366 251 356.366 245 357.366C239 358.366 240 357.366 232.5 350.366C225 343.366 230.5 343.5 221 339.5C211.5 335.5 209.371 325.315 202 334.366C194.629 343.417 203.5 331.866 202 330.366C200.5 328.866 186 325.866 186 325.866C186 325.866 156 295.366 149.5 298.366C144.3 300.766 146 301.866 142.5 291.866C140.333 288.699 136.4 282.366 138 282.366C140 282.366 134 278.366 133.5 272.866C133 267.366 115 272.866 115 269.866C115 266.866 110.5 272.866 109.5 269.866C108.5 266.866 104 272.866 102 272.866C100 272.866 95 274.366 93 272.866C91 271.366 67.5 282.366 65.5 282.366C63.9 282.366 58.8333 285.699 56.5 287.366C52 290.366 42.6 296.766 41 298.366C39 300.366 29 308.866 26 308.866C23.6 308.866 21 315.533 20 318.866Z" fill="#8A7E6E"/>
<path d="M54.3266 222.5C55.1266 219.7 53.9932 217.333 53.3266 216.5L68.3266 210V216.5V221C68.3266 222.2 67.3266 224.5 66.8266 225.5L65.8266 232L66.8266 237.5V246.5C66.8266 250.676 67.3266 254.167 66.8266 255.5V261C66.9933 262.667 67.2266 266.1 66.8266 266.5C66.3266 267 67.8266 270.5 68.3266 272C68.8266 273.5 69.8267 276 70.3267 277.5C70.8267 279 69.8266 279.5 68.8266 279.5H65.8266L62.3266 283C61.4933 282.833 59.8266 282.6 59.8266 283C59.8266 283.5 58.8266 281.5 57.8266 279.5C56.8266 277.5 59.8266 274.5 59.8266 271.5C59.8266 268.5 57.8266 263 57.8266 262C57.8266 261.2 55.4933 255.333 54.3266 252.5C53.9932 252.5 53.0266 250.3 51.8266 241.5C50.3266 230.5 51.3265 233.5 51.3265 231.5C51.3265 229.5 53.3266 226 54.3266 222.5Z" fill="#F3E5DF"/>
<path d="M105 213.5C105 212.5 99.5 209 99 208.5V207.5V205.5L107.5 197C109 198.333 112.1 201 112.5 201C112.874 201 116.485 206.54 118.587 209.848C118.657 209.858 118.843 210.187 119 210.5C118.871 210.295 118.732 210.077 118.587 209.848C118.508 209.836 118.576 210.228 119 211.5C119.8 213.9 118.667 216.833 118 218V232.5V247C118 250.5 119 256 119 258C119 259.6 121 260.667 122 261L122.5 264L120 269.5L114 268C112.333 267.167 109 265.2 109 264C109 262.5 110 262 110.5 260.5C111 259 109 252 109 250.5C109 249 106 241.5 105 240.5C104 239.5 102.5 233 102.5 231C102.5 229 103.5 222.5 104 221.5C104.5 220.5 105 214.5 105 213.5Z" fill="#F3E5DF"/>
<path d="M85.5001 88.5C84.3001 88.1 84.3334 86 84.5001 85L81.5 81.5L73 79V80.5L70.5 81.5V86.5V90L75.5 92H87C87 91 86.7001 88.9 85.5001 88.5Z" fill="#EAD7CF"/>
<path d="M89 69C89 67.5 87.5 64.5 87.5 64L81.5 62.5L75.5 66L71 68.5L73 77C73.6667 78 75 80.1 75 80.5C75 81 76.3972 83.3162 77.5 83.5C80.5 84 82.5 84.5 86 85.5C88.8 86.3 88.8333 85.6667 89 85.5C89.3333 85.3333 90.9 84.9 90.5 82.5C90.1 81.7 90.6667 81.1667 91 81H90V80.5L91 80L90.5 77.5L92 77C92.1667 76.6667 92.3 75.8 91.5 75L88.5 72C88.1 71.6 88.3333 71.1667 88.5 71C88.6667 70.8333 89 70.2 89 69Z" fill="#F3E5DF"/>
<path d="M75.5 59.3284C71.9 59.7284 70.8333 60.6618 70.5 61.3284L68 63.3284L66.5 66.3284L66 68.8284V72.3284L67.5 75.3284L70.5 82.3284H73.5H74.5L75 79.3284C75.1667 78.1618 75.4 75.7284 75 75.3284C74.5 74.8284 76.5 73.3284 77.5 72.8284C78.5 72.3284 78.5 74.8284 79.5 75.8284C80.5 76.8284 82 73.8284 81.5 73.8284C81 73.8284 80 69.8284 80 68.8284C80 67.8284 83 66.8284 83.5 66.3284C84 65.8284 87 66.3284 87.5 66.8284C88 67.3284 92 67.3284 89 63.8284C86 60.3284 86 60.8284 85 59.8284C84 58.8284 80 58.8284 75.5 59.3284Z" fill="#672626"/>
<path d="M99.0545 105.523L93.5545 105.023C93.5545 104.88 92.8904 105.352 90.4211 108.023H88.0544C88.3878 108.523 89.1545 109.723 89.5544 110.523C90.0544 111.523 92.4999 114.5 94.5 115.5C96.5001 116.5 98.5 124 100 126C101.2 127.6 101.333 129.5 101 131.5C101 137.333 100.5 142.1 100.5 144.5C100.5 147.5 97.5544 157.023 97.5544 158.523C97.5544 160.023 93.5545 162.523 93.0544 162.023C92.5544 161.523 87.5545 164.523 87.0545 164.523C86.6545 164.523 88.5545 166.856 89.5545 168.023L93.5545 173.523C95.3878 174.19 99.1545 175.423 99.5545 175.023C100.054 174.523 102.054 170.023 102.554 169.023C103.054 168.023 104.554 162.023 104.554 160.023C104.554 158.023 108.5 146 108.5 145C108.5 144 109.339 143 109.839 134C110.339 125 109.5 126.5 109.5 124C109.5 122 102.554 110.69 100.554 106.023L99.0545 105.523Z" fill="#F3E5DF"/>
<path d="M95 165C93.4 164.2 92.3333 159 92 156.5H86H75H61.5C60.7 156.5 52.5 158.833 48.5 160C47.3333 161.167 44.8 164 44 166C43.2 168 44.3333 177.833 45 182.5V194L45.5 204L45 212C45.5 213.667 46.9 217.2 48.5 218C50.5 219 54.5 216 56 215.5C57.2 215.1 63.1667 214.333 66 214H75C79 214 77 212.5 77 209.5C77 207.1 75.6667 200.167 75 197L80 206.5C81.5 208 84.5 211.6 84.5 214C84.5 216.4 88.1667 215 90 214C93.6667 212.667 101 209.9 101 209.5C101 209 110.5 206 110.5 205C110.5 204.2 114.833 202.333 117 201.5C115 197.833 110.9 190.1 110.5 188.5C110 186.5 106 180.5 105 180C104 179.5 102 174 101 171.5C100 169 97 166 95 165Z" fill="#D6C495"/>
<path d="M76 89.7209C74 89.7209 73.1667 88.0542 73 87.2209C70.8333 87.0542 66.6 86.8209 67 87.2209C67.4 87.6209 61.8333 90.7209 59 92.2209L58 126.221L65 142.221C67.3333 148.221 72.2 160.221 73 160.221C73.8 160.221 76.3333 160.554 77.5 160.721C79.3333 160.388 83.6 159.821 86 160.221C88.4 160.621 92.3333 162.054 94 162.721C95 161.221 93.5 149.221 93 138.221C92.6 129.421 91 118.833 89.5 113.5C91.1667 116.833 91.7622 121.5 93 120.721C100.5 116 93.8333 118.667 94 118C104 110 106.5 117 106.5 116.5C106.5 116 105.5 111.5 101 104.5C96.5 97.5 96 96 95 94.5C94 93 89.5 90.7209 87.5 89.7209C85.9 88.9209 83.5 89.3875 82.5 89.7209H76Z" fill="#A4D18F"/>
<path d="M108 264.5C107.657 263.471 108.271 262.858 108.768 262.6C108.793 262.775 108.853 262.932 109 263C109.5 263.231 108.5 265.5 110 265C110.667 265 112.3 265.3 113.5 266.5C115 268 117.5 266.5 118.5 266.5C119.5 266.5 122 265.5 121.5 264.5C121 263.5 120.5 263.5 121.5 261.5C122.5 259.5 122 261.5 124 262.5C126 263.5 125 264 126.5 265C128 266 128 267 130 268C132 269 131 269 135 270.5C139 272 139 271 140.5 271C142 271 141.5 272.5 142.5 274C143.5 275.5 141.5 276 140.5 276.5C139.5 277 139.5 280 131 278C122.5 276 127.5 278.5 123 278.5C118.5 278.5 121 279.5 119.5 280C118 280.5 116 280 114.5 280.5C113 281 111.5 279.5 110 280C108.5 280.5 108 278.5 107 278C106 277.5 106.5 275 107 274.5C107.5 274 109 269.5 108.5 269C108 268.5 108.5 266 108 264.5Z" fill="#A05C5C"/>
<path d="M57 279C57.4975 278.668 58.6881 277.809 59.488 277.012C59.9428 277.305 60.4714 277.943 61 279C62 281 62 280 63 279C64 278 65 278 65 279C65 280 67 278 67.5 277C68 276 69 276 69.5 277C70 278 70 278 71 279C72 280 71 280.5 70 281.5C69 282.5 70 284 69.5 284.5C69 285 70 286 71 286.5C72 287 71 288 71 289C71 290 70.5 290.5 69 292C67.5 293.5 66.5 293 65 293.5C63.5 294 63 293.5 61 293C59 292.5 59.5 290.5 58.5 289C57.5 287.5 57 288 55.5 288C54 288 55 286 55.5 285C56 284 55.5 283 56 281.5C56.4 280.3 56.8333 279.333 57 279Z" fill="#A05C5C"/>
<path d="M74 123.5C74 116.5 72.5 103 74 95.5C74.2508 94 74 92.5 74 89.5C74 86.5 74 85.5 72 81.5C70 77.5 70.5 78.5 67 74C63.5 69.5 64 70 61 68.5C58 67 56.5 65 52.5 63.5C48.5 62 47 62 41.5 63.5C36.0001 65 36 65 30.0003 68.4999L30 68.5C24 72 25.5 78 22 83.5C18.5 89 23 91.5 22 97C21 102.5 22 105.5 20.5 112.5C19 119.5 23.5 121.5 25.5 130C27.5001 138.5 27 139 25.5 145.5C24 152 28 151.5 30 157.5C32 163.5 31 162.5 36 169.5C41 176.5 43 174.5 49.5 174.5C56 174.5 58.5 175.5 65 174.5C71.5 173.5 71.5 170.5 76.5 166C81.5 161.5 80 160.5 81 155C82 149.5 80.5 146.5 76.5 139C72.5 131.5 74 130.5 74 123.5Z" fill="#524444"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="370" height="370" rx="50" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

10
front/public/logo.svg Normal file
View File

@ -0,0 +1,10 @@
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse rx="1.95568" ry="1.4972" transform="matrix(0.958164 0.28622 -0.273653 0.961828 18.8744 14.9998)" fill="#200808" />
<ellipse cx="14.6391" cy="13.5" rx="2.92781" ry="2.5" fill="#200808" />
<ellipse rx="4.50953" ry="1.37657" transform="matrix(0.890738 -0.454516 0.437116 0.899405 8.52234 15.2878)" fill="#200808" />
<path d="M12.1993 14.5C12.1993 16.5 12.1017 20.6 11.7113 21" stroke="#200808" />
<path d="M14.672 14.2483C14.6714 16.2553 15.3351 20.0119 17.9937 18.9828" stroke="#200808" />
<path d="M13.6631 11.5L9.75939 6.5M9.75939 6.5L6.34361 5L5.36768 8.5L7.31955 12L11.7113 13L14.6391 11.5L16.5909 7L14.1511 3.5L10.2474 3L9.75939 6.5Z" stroke="#200808" />
<path d="M9.75923 15C9.92188 17 9.56404 20.8 6.83142 20" stroke="#200808" />
<path d="M23.3984 12.5C23.3984 18.8744 18.3615 24 12.1992 24C6.03687 24 1 18.8744 1 12.5C1 6.12562 6.03687 1 12.1992 1C18.3615 1 23.3984 6.12562 23.3984 12.5Z" stroke="#FFD600" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,4 +0,0 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
.header {
border-radius: 30px;
background: #cff9ec;
text-align: center;
}

View File

@ -0,0 +1,3 @@
.text {
color: red;
}

View File

@ -0,0 +1,21 @@
@import url("https://fonts.googleapis.com/css2?family=Jost:wght@300;400;500;800;900&display=swap");
:root {
--main-font-color: #000000;
}
* {
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
}
body {
background-color: #5fd4b1;
padding: 0.8rem;
font-family: Jost;
}

View File

@ -0,0 +1,65 @@
.picCard {
margin-top: 3rem;
width: 100%;
background-image: url("public/home/turist.svg");
height: calc(100vw - 3.2rem);
background-size: cover;
border-radius: 50px;
filter: drop-shadow(0px 0px 45px rgba(23, 21, 21, 0.3));
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 50px;
}
.picMainText {
position: absolute;
text-align: right;
font-style: normal;
font-weight: 800;
font-size: 24px;
line-height: 25px;
align-items: center;
letter-spacing: 0.08em;
right: 0.8rem;
top: 8.5rem;
color: #000000;
}
.picSubText {
position: absolute;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 20px;
text-align: right;
letter-spacing: 0.08em;
width: 198px;
color: #000000;
right: 0.8rem;
bottom: 2.3rem;
}
.advantage {
display: grid;
margin: 3.2rem 0;
align-self: center;
}
.advantageIcon {
display: block;
margin: 0.8rem auto;
}
.advantageText {
text-align: center;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 20px;
align-items: center;
letter-spacing: 0.1em;
color: #000000;
}
.authHeader {
text-align: center;
}

View File

@ -0,0 +1,42 @@
.content {
padding: 0.8rem;
background-color: #ffffff;
border-radius: 30px;
}
.header {
display: grid;
grid-template-columns: auto 1fr auto;
}
.logo {
display: grid;
gap: 0.5rem;
align-self: center;
grid-template-columns: auto auto;
}
.link {
font-style: normal;
font-weight: 500;
font-size: 0.8rem;
letter-spacing: 0.07em;
color: var(--main-font-color);
align-self: center;
padding: 0 0.8rem;
text-align: center;
border: 2px solid #ffd600;
box-sizing: border-box;
border-radius: 10px;
}
.textLogo {
align-self: center;
font-style: normal;
font-weight: 500;
font-size: 1.2rem;
align-items: center;
text-align: right;
letter-spacing: 0.07em;
color: var(--main-font-color);
}

View File

@ -1,3 +1,5 @@
type FCL = React.FC & { Layout: React.ReactNode };
type RouteT = {
id: number;
name: string;
@ -13,4 +15,4 @@ type CoordinatesT = {
longitude: number;
};
export type { RouteT, CoordinatesT };
export type { FCL, RouteT, CoordinatesT };

View File

@ -2,4 +2,30 @@ const formatTimeLength = (minutes: number) =>
(Math.floor(minutes / 60) > 0 ? `${Math.floor(minutes / 60)} ч. ` : "") +
(minutes % 60 > 0 ? `${minutes % 60} мин.` : "");
export { formatTimeLength };
const request = async (uri: string, method: "POST" | "GET", body = null) => {
const url = "http://localhost:4000/api/" + uri;
const headers = {
"Content-Type": "application/json",
method,
body: method == "POST" ? body : undefined,
};
const options = {
headers,
body: method == "GET" ? body : undefined,
};
try {
if (process.env.NODE_ENV == "development") {
return JSON.parse(`{ "token": "fhjighdfjgjdfigbvhbsdfuyt47" }`);
}
const res = await fetch(url, options);
return await res.json();
} catch (err) {
console.log(err.message);
throw err;
}
};
export { formatTimeLength, request };

File diff suppressed because it is too large Load Diff