diff --git a/enshi/.prettierrc b/enshi/.prettierrc
index 5a938ce..e9e5aa7 100644
--- a/enshi/.prettierrc
+++ b/enshi/.prettierrc
@@ -1,4 +1,7 @@
{
"tabWidth": 4,
- "useTabs": false
+ "useTabs": true,
+ "printWidth": 80,
+ "semi": true,
+ "quoteProps": "consistent"
}
diff --git a/enshi/index.html b/enshi/index.html
index d40a3a5..56af598 100644
--- a/enshi/index.html
+++ b/enshi/index.html
@@ -1,21 +1,21 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
- Enshi
-
-
-
-
-
+ Enshi
+
+
+
+
+
diff --git a/enshi/package-lock.json b/enshi/package-lock.json
index 70ebfc5..c13ae09 100644
--- a/enshi/package-lock.json
+++ b/enshi/package-lock.json
@@ -8,6 +8,7 @@
"name": "enshi",
"version": "0.1.8",
"dependencies": {
+ "@radix-ui/react-aspect-ratio": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-form": "^0.1.0",
"@radix-ui/react-icons": "^1.3.2",
@@ -20,6 +21,7 @@
"@tanstack/react-query-devtools": "^5.61.0",
"@types/quill": "^2.0.14",
"axios": "^1.7.7",
+ "dayjs": "^1.11.13",
"html-react-parser": "^5.1.16",
"i18n": "^0.15.1",
"i18next": "^23.14.0",
@@ -1296,12 +1298,12 @@
}
},
"node_modules/@radix-ui/react-aspect-ratio": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.0.tgz",
- "integrity": "sha512-dP87DM/Y7jFlPgUZTlhx6FF5CEzOiaxp2rBCKlaXlpH5Ip/9Fg5zZ9lDOQ5o/MOfUlf36eak14zoWYpgcgGoOg==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.2.tgz",
+ "integrity": "sha512-TaJxYoCpxJ7vfEkv2PTNox/6zzmpKXT6ewvCuf2tTOIVN45/Jahhlld29Yw4pciOXS2Xq91/rSGEdmEnUWZCqA==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-primitive": "2.0.0"
+ "@radix-ui/react-primitive": "2.0.2"
},
"peerDependencies": {
"@types/react": "*",
@@ -1318,6 +1320,62 @@
}
}
},
+ "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+ "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+ "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+ "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-avatar": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.0.tgz",
@@ -2935,6 +2993,29 @@
}
}
},
+ "node_modules/@radix-ui/themes/node_modules/@radix-ui/react-aspect-ratio": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.0.tgz",
+ "integrity": "sha512-dP87DM/Y7jFlPgUZTlhx6FF5CEzOiaxp2rBCKlaXlpH5Ip/9Fg5zZ9lDOQ5o/MOfUlf36eak14zoWYpgcgGoOg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/themes/node_modules/@radix-ui/react-dialog": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz",
@@ -4216,6 +4297,12 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT"
},
+ "node_modules/dayjs": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+ "license": "MIT"
+ },
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
diff --git a/enshi/package.json b/enshi/package.json
index dcc5e4b..d9a88bc 100644
--- a/enshi/package.json
+++ b/enshi/package.json
@@ -11,6 +11,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "@radix-ui/react-aspect-ratio": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-form": "^0.1.0",
"@radix-ui/react-icons": "^1.3.2",
@@ -23,6 +24,7 @@
"@tanstack/react-query-devtools": "^5.61.0",
"@types/quill": "^2.0.14",
"axios": "^1.7.7",
+ "dayjs": "^1.11.13",
"html-react-parser": "^5.1.16",
"i18n": "^0.15.1",
"i18next": "^23.14.0",
diff --git a/enshi/src/App.tsx b/enshi/src/App.tsx
index 8bec25a..f9d1cfa 100644
--- a/enshi/src/App.tsx
+++ b/enshi/src/App.tsx
@@ -3,6 +3,8 @@ import "@radix-ui/themes/styles.css";
import { QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import "axios";
+import dayjs from "dayjs";
+import relativeTime from 'dayjs/plugin/relativeTime';
import { useAtomValue } from "jotai";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import queryClient from "./api/QueryClient/QueryClient";
@@ -11,6 +13,9 @@ import { themeAtom } from "./AtomStore/AtomStore";
import ToastProvider from "./Components/ToastProvider/ToastProvider";
import { routes } from "./routes/routes";
+
+dayjs.extend(relativeTime)
+
const router = createBrowserRouter(routes);
export default function App() {
diff --git a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx
index fee31f7..6da74db 100644
--- a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx
+++ b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx
@@ -12,65 +12,67 @@ import VoteButton, { DOWNVOTE, UPVOTE } from "./VoteButton/VoteButton";
import VoteCounter from "./VoteCounter/VoteCounter";
type TArticleViewer = {
- htmlToParse?: string;
+ htmlToParse?: string;
};
export default function ArticleViewer(props: TArticleViewer) {
- let queryParams = useParams();
- const user = useAtomValue(userAtom);
+ let queryParams = useParams();
+ const user = useAtomValue(userAtom);
- const { data, isPending } = useQuery({
- queryKey: [`post_${queryParams["postId"]}`],
- queryFn: async () => {
- const response = await axiosLocalhost.get(
- `posts/${queryParams["postId"]}`
- );
+ const { data, isPending } = useQuery({
+ queryKey: [`post_${queryParams["postId"]}`],
+ queryFn: async () => {
+ const response = await axiosLocalhost.get(
+ `posts/${queryParams["postId"]}`
+ );
- return response.data;
- },
- gcTime: 0,
- refetchOnMount: true,
- });
+ return response.data;
+ },
+ gcTime: 0,
+ refetchOnMount: true,
+ });
- if (isPending) return ;
+ if (isPending) return ;
- return (
-
-
-
- {data.title}
-
-
-
-
+ return (
+
+
+
+ {data.title}
+
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
- {user ? : null}
-
-
+ {user ? : null}
+
+
-
+
-
-
- );
+
+
+
+
+ );
}
diff --git a/enshi/src/Components/NavBar/NavigationMenu/NavigationMenu.tsx b/enshi/src/Components/NavBar/NavigationMenu/NavigationMenu.tsx
index 56e8b9a..19259d5 100644
--- a/enshi/src/Components/NavBar/NavigationMenu/NavigationMenu.tsx
+++ b/enshi/src/Components/NavBar/NavigationMenu/NavigationMenu.tsx
@@ -9,8 +9,8 @@ export default function CustomNavigationMenu() {
return (
-
-
+
+
diff --git a/enshi/src/Components/NavBar/RightButtonBar/ThemeChangeButton/ThemeChangeButton.tsx b/enshi/src/Components/NavBar/RightButtonBar/ThemeChangeButton/ThemeChangeButton.tsx
index 5280277..ed42928 100644
--- a/enshi/src/Components/NavBar/RightButtonBar/ThemeChangeButton/ThemeChangeButton.tsx
+++ b/enshi/src/Components/NavBar/RightButtonBar/ThemeChangeButton/ThemeChangeButton.tsx
@@ -4,20 +4,28 @@ import { useAtom } from "jotai";
import { themeAtom } from "../../../../AtomStore/AtomStore";
export default function ThemeChangeButton() {
- const [theme, setTheme] = useAtom(themeAtom);
-
+ const [theme, setTheme] = useAtom(themeAtom);
- const toggleTheme = () => {
- if(theme === 'light') {
- setTheme('dark')
- } else {
- setTheme('light')
- }
- }
-
- return (
-
- {theme === 'light' ? : }
-
- )
+ const toggleTheme = () => {
+ if (theme === "light") {
+ setTheme("dark");
+ } else {
+ setTheme("light");
+ }
+ };
+
+ return (
+
+ {theme === "light" ? (
+
+ ) : (
+
+ )}
+
+ );
}
diff --git a/enshi/src/Components/NavBar/RightButtonBar/UserButton/UserButton.tsx b/enshi/src/Components/NavBar/RightButtonBar/UserButton/UserButton.tsx
index 54cd31f..f80ef40 100644
--- a/enshi/src/Components/NavBar/RightButtonBar/UserButton/UserButton.tsx
+++ b/enshi/src/Components/NavBar/RightButtonBar/UserButton/UserButton.tsx
@@ -26,11 +26,11 @@ export default function UserButton() {
-
+
diff --git a/enshi/src/Pages/RandomPostsPage/PostCard/PostCard.tsx b/enshi/src/Pages/RandomPostsPage/PostCard/PostCard.tsx
index 4736527..edb7c9d 100644
--- a/enshi/src/Pages/RandomPostsPage/PostCard/PostCard.tsx
+++ b/enshi/src/Pages/RandomPostsPage/PostCard/PostCard.tsx
@@ -1,26 +1,74 @@
-import { ImageIcon } from "@radix-ui/react-icons";
-import { Box, Card, Heading } from "@radix-ui/themes";
+import { CalendarIcon } from "@radix-ui/react-icons";
+import {
+ Box,
+ Card,
+ Flex,
+ Heading,
+ Inset,
+ Text,
+ Tooltip,
+} from "@radix-ui/themes";
+import dayjs from "dayjs";
+import "dayjs/locale/ru";
+import { useMemo } from "react";
import { useNavigate } from "react-router-dom";
import { Post } from "../../../@types/PostTypes";
export default function PostCard(props: Post) {
- const navigate = useNavigate()
+ const navigate = useNavigate();
- const clickHandler = () => {
- navigate(`/posts/${props.post_id.toString()}`)
- }
+ const parsedDate = dayjs(props.created_at)
+ .locale("ru")
+ .format("DD MMMM YYYY");
- return (
-
-
-
-
-
+ const clickHandler = () => {
+ navigate(`/posts/${props.post_id.toString()}`);
+ };
-
- {props.title}
-
-
-
- );
+ const seed = useMemo(() => {
+ return Math.floor(Math.random() * (1 + Math.random()) * 100000);
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+ {props.title}
+
+
+
+
+
+
+ {`${parsedDate}`}
+
+
+
+
+
+
+ );
}
diff --git a/enshi/src/Pages/RandomPostsPage/RandomPostsPage.tsx b/enshi/src/Pages/RandomPostsPage/RandomPostsPage.tsx
index 396d27b..fb50206 100644
--- a/enshi/src/Pages/RandomPostsPage/RandomPostsPage.tsx
+++ b/enshi/src/Pages/RandomPostsPage/RandomPostsPage.tsx
@@ -1,11 +1,4 @@
-import {
- Box,
- Flex,
- Heading,
- ScrollArea,
- Separator,
- Text,
-} from "@radix-ui/themes";
+import { Box, Flex, ScrollArea, Text } from "@radix-ui/themes";
import { useInfiniteQuery } from "@tanstack/react-query";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
@@ -14,73 +7,74 @@ import { SelectedPostsResponse } from "../../@types/PostTypes";
import { axiosLocalhost } from "../../api/axios/axios";
import PostCard from "./PostCard/PostCard";
-const LIMIT = 5;
+const LIMIT = 7;
export default function RandomPostsPage() {
- const { t } = useTranslation();
+ const { t } = useTranslation();
- const [ref, inView] = useInView();
+ const [ref, inView] = useInView();
- const { data, isFetching, fetchNextPage, hasNextPage } = useInfiniteQuery({
- queryKey: [`random_post_inf`],
- queryFn: async ({ pageParam }): Promise => {
- const response = await axiosLocalhost.get(
- `/posts/random?limit=${LIMIT}&offset=${pageParam}`
- );
+ const { data, isFetching, fetchNextPage, hasNextPage } = useInfiniteQuery({
+ queryKey: [`random_post_inf`],
+ queryFn: async ({ pageParam }): Promise => {
+ const response = await axiosLocalhost.get(
+ `/posts/random?limit=${LIMIT}&offset=${pageParam}`
+ );
- return response.data as SelectedPostsResponse;
- },
- initialPageParam: 0,
- getPreviousPageParam: (lastPage) =>
- lastPage.prev_page_index < 0 ? undefined : lastPage.prev_page_index,
- getNextPageParam: (lastPage) =>
- lastPage.next_page_index < 0 ? undefined : lastPage.next_page_index,
- });
+ return response.data as SelectedPostsResponse;
+ },
+ initialPageParam: 0,
+ getPreviousPageParam: (lastPage) =>
+ lastPage.prev_page_index < 0 ? undefined : lastPage.prev_page_index,
+ getNextPageParam: (lastPage) =>
+ lastPage.next_page_index < 0 ? undefined : lastPage.next_page_index,
+ });
- useEffect(() => {
- if (inView) {
- if (hasNextPage) fetchNextPage();
- }
- }, [inView]);
+ useEffect(() => {
+ if (inView) {
+ if (hasNextPage) fetchNextPage();
+ }
+ }, [inView]);
- return (
- <>
-
-
- {t("discover")}
-
+ return (
+ <>
+
+
+
+ {data?.pages.map((post, i) => {
+ return (
+
+ {post.selected_posts.map((post, j) => {
+ return (
+
+ );
+ })}
+
+ );
+ })}
-
-
- {data?.pages.map((post, i) => {
- return (
-
- {post.selected_posts.map((post, i) => {
- return (
-
- );
- })}
-
- );
- })}
-
- {isFetching ? (
- Loading more...
- ) : hasNextPage ? (
- fetchNextPage()}
- >
- Load more posts
-
- ) : (
- No more posts to load
- )}
-
-
-
- >
- );
+
+ {isFetching ? (
+ Loading more...
+ ) : hasNextPage ? (
+ fetchNextPage()}
+ >
+ Load more posts
+
+ ) : (
+ No more posts to load
+ )}
+
+
+
+
+ >
+ );
}
diff --git a/enshi/src/index.css b/enshi/src/index.css
index 9195e10..22839b5 100644
--- a/enshi/src/index.css
+++ b/enshi/src/index.css
@@ -1,4 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Edu+AU+VIC+WA+NT+Pre:wght@400..700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Pochaevsk&display=swap');
@tailwind base;
@tailwind components;
@@ -15,9 +16,8 @@
}
.radix-themes {
- --default-font-family: "Times New Roman"; ;
-
- --heading-font-family: "Edu AU VIC WA NT Pre", cursive;
+ --default-font-family: "Pochaevsk", sans-serif;
+ --heading-font-family: "Edu AU VIC WA NT Pre", cursive;
/* Your custom font for components */
--code-font-family:
/* Your custom font for components */
diff --git a/enshi/src/layout/MainPage/MainPage.tsx b/enshi/src/layout/MainPage/MainPage.tsx
index 17f2ebd..a29013d 100644
--- a/enshi/src/layout/MainPage/MainPage.tsx
+++ b/enshi/src/layout/MainPage/MainPage.tsx
@@ -66,7 +66,7 @@ export default function MainPage() {