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 ( + + + + Bold typography + + + + + {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() {