Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81a3cc5971 |
@ -8,8 +8,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
|
||||||
- /etc/letsencrypt/live/nekiiinkognito.ru:/etc/nginx/ssl:ro
|
|
||||||
|
|
||||||
enshi_back:
|
enshi_back:
|
||||||
build: ./enshi_back
|
build: ./enshi_back
|
||||||
|
|||||||
@ -14,5 +14,9 @@ FROM nginx:alpine
|
|||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Certificates
|
||||||
|
COPY ./nginx/fullchain.pem /etc/nginx/ssl/
|
||||||
|
COPY ./nginx/privkey.pem /etc/nginx/ssl/
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
EXPOSE 443
|
EXPOSE 443
|
||||||
@ -7,8 +7,8 @@ server {
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443 ssl http2;
|
listen 443 ssl http2;
|
||||||
server_name nekiiinkognito.ru www.nekiiinkognito.ru;
|
# server_name nekiiinkognito.ru www.nekiiinkognito.ru;
|
||||||
# server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||||||
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||||
|
|||||||
90
enshi/package-lock.json
generated
90
enshi/package-lock.json
generated
@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "enshi",
|
"name": "enshi",
|
||||||
"version": "0.1.7",
|
"version": "0.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "enshi",
|
"name": "enshi",
|
||||||
"version": "0.1.7",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@radix-ui/react-form": "^0.1.0",
|
"@radix-ui/react-form": "^0.1.0",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.1",
|
"@radix-ui/react-navigation-menu": "^1.2.1",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@radix-ui/themes": "^3.1.3",
|
"@radix-ui/themes": "^3.1.3",
|
||||||
@ -2234,18 +2234,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-scroll-area": {
|
"node_modules/@radix-ui/react-scroll-area": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.1.tgz",
|
||||||
"integrity": "sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==",
|
"integrity": "sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/number": "1.1.0",
|
"@radix-ui/number": "1.1.0",
|
||||||
"@radix-ui/primitive": "1.1.1",
|
"@radix-ui/primitive": "1.1.0",
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
"@radix-ui/react-compose-refs": "1.1.0",
|
||||||
"@radix-ui/react-context": "1.1.1",
|
"@radix-ui/react-context": "1.1.1",
|
||||||
"@radix-ui/react-direction": "1.1.0",
|
"@radix-ui/react-direction": "1.1.0",
|
||||||
"@radix-ui/react-presence": "1.1.2",
|
"@radix-ui/react-presence": "1.1.1",
|
||||||
"@radix-ui/react-primitive": "2.0.1",
|
"@radix-ui/react-primitive": "2.0.0",
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
},
|
},
|
||||||
@ -2264,27 +2264,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@radix-ui/react-scroll-area/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-scroll-area/node_modules/@radix-ui/react-context": {
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
|
||||||
@ -2301,12 +2280,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": {
|
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz",
|
||||||
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
"integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
"@radix-ui/react-compose-refs": "1.1.0",
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@ -2324,47 +2303,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-slot": "1.1.1"
|
|
||||||
},
|
|
||||||
"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-scroll-area/node_modules/@radix-ui/react-slot": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
|
||||||
"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-select": {
|
"node_modules/@radix-ui/react-select": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "enshi",
|
"name": "enshi",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.8",
|
"version": "0.1.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
"@radix-ui/react-form": "^0.1.0",
|
"@radix-ui/react-form": "^0.1.0",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.1",
|
"@radix-ui/react-navigation-menu": "^1.2.1",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@radix-ui/themes": "^3.1.3",
|
"@radix-ui/themes": "^3.1.3",
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
export type Blog = {
|
|
||||||
blog_id: number;
|
|
||||||
user_id: number;
|
|
||||||
title: string;
|
|
||||||
description?: string;
|
|
||||||
category_id?: number;
|
|
||||||
created_at: Date;
|
|
||||||
}
|
|
||||||
@ -13,7 +13,7 @@ const router = createBrowserRouter(routes);
|
|||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<Theme className="h-fit" accentColor="sky" grayColor="slate" appearance="dark">
|
<Theme className="h-fit" accentColor="indigo" grayColor="slate">
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
|
|||||||
@ -1,11 +1,20 @@
|
|||||||
import { Box, Container, Flex, Separator, Text } from "@radix-ui/themes";
|
import * as Dialog from "@radix-ui/react-dialog";
|
||||||
|
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Flex,
|
||||||
|
Select,
|
||||||
|
Separator,
|
||||||
|
Text,
|
||||||
|
} from "@radix-ui/themes";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Interweave } from "interweave";
|
import { Interweave } from "interweave";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { axiosLocalhost } from "../../api/axios/axios";
|
import { axiosLocalhost } from "../../api/axios/axios";
|
||||||
import { userAtom } from "../../AtomStore/AtomStore";
|
import { userAtom } from "../../AtomStore/AtomStore";
|
||||||
import AddPostToBlogDialog from "../Dialogs/AddPostToBlogDialog/AddPostToBlogDialog";
|
|
||||||
import ChangePostButton from "./ChangePostButton/ChangePostButton";
|
import ChangePostButton from "./ChangePostButton/ChangePostButton";
|
||||||
import SkeletonPostLoader from "./SkeletonLoader/SkeletonLoader";
|
import SkeletonPostLoader from "./SkeletonLoader/SkeletonLoader";
|
||||||
import VoteButton, { DOWNVOTE, UPVOTE } from "./VoteButton/VoteButton";
|
import VoteButton, { DOWNVOTE, UPVOTE } from "./VoteButton/VoteButton";
|
||||||
@ -69,7 +78,62 @@ export default function ArticleViewer(props: TArticleViewer) {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{user ? <AddPostToBlogDialog /> : null}
|
<Dialog.Root>
|
||||||
|
<Dialog.Trigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="surface"
|
||||||
|
className="h-5"
|
||||||
|
>
|
||||||
|
Add to blog
|
||||||
|
</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
<Dialog.Portal>
|
||||||
|
<Dialog.Overlay className="fixed inset-0 bg-blackA6 data-[state=open]:animate-overlayShow" />
|
||||||
|
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[450px] -translate-x-1/2 -translate-y-1/2 rounded-md bg-white p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-contentShow">
|
||||||
|
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
|
||||||
|
Add this post to blog
|
||||||
|
</Dialog.Title>
|
||||||
|
<Dialog.Description className="mb-5 mt-2.5 text-[15px] leading-normal text-mauve11">
|
||||||
|
<Flex>
|
||||||
|
<Text>
|
||||||
|
{`Add "${data.title}" to blog...`}
|
||||||
|
</Text>
|
||||||
|
<Select.Root defaultValue="apple">
|
||||||
|
<Select.Trigger />
|
||||||
|
<Select.Content>
|
||||||
|
<Select.Group>
|
||||||
|
<Select.Item value="orange">
|
||||||
|
This
|
||||||
|
</Select.Item>
|
||||||
|
<Select.Item value="apple">
|
||||||
|
This is
|
||||||
|
updated blog
|
||||||
|
</Select.Item>
|
||||||
|
<Select.Item value="grape">
|
||||||
|
This another
|
||||||
|
</Select.Item>
|
||||||
|
</Select.Group>
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</Flex>
|
||||||
|
</Dialog.Description>
|
||||||
|
|
||||||
|
<div className="mt-[25px] flex justify-end">
|
||||||
|
<Dialog.Close asChild>
|
||||||
|
<Button>Confirm</Button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</div>
|
||||||
|
<Dialog.Close asChild>
|
||||||
|
<button
|
||||||
|
className="absolute right-2.5 top-2.5 inline-flex size-[25px] appearance-none items-center justify-center rounded-full text-violet11 hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 focus:outline-none"
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<Cross2Icon />
|
||||||
|
</button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Portal>
|
||||||
|
</Dialog.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Separator size={"4"} className="mb-2" />
|
<Separator size={"4"} className="mb-2" />
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
|
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
|
||||||
import { IconButton } from "@radix-ui/themes";
|
import { IconButton } from "@radix-ui/themes";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useAtomValue } from "jotai";
|
|
||||||
import { axiosLocalhost } from "../../../api/axios/axios";
|
import { axiosLocalhost } from "../../../api/axios/axios";
|
||||||
import { userAtom } from "../../../AtomStore/AtomStore";
|
|
||||||
import useToast from "../../../hooks/useToast";
|
|
||||||
|
|
||||||
export const UPVOTE = true;
|
export const UPVOTE = true;
|
||||||
export const DOWNVOTE = false;
|
export const DOWNVOTE = false;
|
||||||
@ -17,9 +14,6 @@ type TVoteButton = {
|
|||||||
export default function VoteButton(props: TVoteButton) {
|
export default function VoteButton(props: TVoteButton) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const user = useAtomValue(userAtom);
|
|
||||||
const createToast = useToast();
|
|
||||||
|
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: [props.vote + "voteCheck"],
|
queryKey: [props.vote + "voteCheck"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@ -54,7 +48,7 @@ export default function VoteButton(props: TVoteButton) {
|
|||||||
queryKey: [props.vote + "voteCheck"],
|
queryKey: [props.vote + "voteCheck"],
|
||||||
});
|
});
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: [`post_vote_counter_${props.postId}`],
|
queryKey: ["post_vote_counter"],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -63,13 +57,7 @@ export default function VoteButton(props: TVoteButton) {
|
|||||||
<IconButton
|
<IconButton
|
||||||
variant={data ? "solid" : "outline"}
|
variant={data ? "solid" : "outline"}
|
||||||
size={"1"}
|
size={"1"}
|
||||||
onClick={() => {
|
onClick={() => voteMutation.mutate()}
|
||||||
if(!user) {
|
|
||||||
createToast({title: "Please log in to vote", description: "You need to be logged in to vote on a post."});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
voteMutation.mutate();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{props.vote ? <DoubleArrowUpIcon /> : <DoubleArrowDownIcon />}
|
{props.vote ? <DoubleArrowUpIcon /> : <DoubleArrowDownIcon />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@ -8,14 +8,13 @@ type TVoteCounter = {
|
|||||||
|
|
||||||
export default function VoteCounter(props: TVoteCounter) {
|
export default function VoteCounter(props: TVoteCounter) {
|
||||||
const { data, isLoading } = useQuery({
|
const { data, isLoading } = useQuery({
|
||||||
queryKey: [`post_vote_counter_${props.postId}` ],
|
queryKey: ["post_vote_counter"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await axiosLocalhost.get(
|
const response = await axiosLocalhost.get(
|
||||||
`post-votes/${props.postId}`
|
`post-votes/${props.postId}`
|
||||||
);
|
);
|
||||||
return response.data as { upvotes: number; downvotes: number };
|
return response.data as { upvotes: number; downvotes: number };
|
||||||
},
|
},
|
||||||
gcTime: 1000 * 60,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const calculateRating = (upvotes: number, downvotes: number) => {
|
const calculateRating = (upvotes: number, downvotes: number) => {
|
||||||
@ -23,12 +22,12 @@ export default function VoteCounter(props: TVoteCounter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Skeleton className="w-4">
|
return <Skeleton>
|
||||||
{calculateRating(0, 0)}
|
{calculateRating(0, 0)}
|
||||||
</Skeleton>
|
</Skeleton>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Box className="flex justify-center w-4 gap-2">
|
return <Box>
|
||||||
{calculateRating(data?.upvotes || 0, data?.downvotes || 0)}
|
{calculateRating(data?.upvotes || 0, data?.downvotes || 0)}
|
||||||
</Box>;
|
</Box>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,155 +0,0 @@
|
|||||||
import * as Dialog from "@radix-ui/react-dialog";
|
|
||||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
|
||||||
import { Button, Card, Flex, Select, Text, Theme } from "@radix-ui/themes";
|
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
||||||
import { useAtomValue } from "jotai";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
|
||||||
import { Blog } from "../../../@types/BlogTypes";
|
|
||||||
import { axiosLocalhost } from "../../../api/axios/axios";
|
|
||||||
import { userAtom } from "../../../AtomStore/AtomStore";
|
|
||||||
import useToast from "../../../hooks/useToast";
|
|
||||||
import { JSONWithInt64 } from "../../../utils/idnex";
|
|
||||||
|
|
||||||
export default function AddPostToBlogDialog() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const user = useAtomValue(userAtom);
|
|
||||||
const [selectedBlog, setSelectedBlog] = useState<string>("");
|
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const params = useParams();
|
|
||||||
const createToast = useToast();
|
|
||||||
|
|
||||||
const { data, refetch } = useQuery({
|
|
||||||
queryKey: ["userBlogs"],
|
|
||||||
queryFn: async () => {
|
|
||||||
const response = await axiosLocalhost.get("/user/blogs", {
|
|
||||||
transformResponse: [(data) => data],
|
|
||||||
});
|
|
||||||
|
|
||||||
let temp = JSONWithInt64(response.data);
|
|
||||||
|
|
||||||
return temp as Blog[];
|
|
||||||
},
|
|
||||||
enabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const addMutation = useMutation({
|
|
||||||
mutationKey: ["addPostToBlog"],
|
|
||||||
mutationFn: async () => {
|
|
||||||
const response = await axiosLocalhost.put(
|
|
||||||
`posts/${params["postId"]}/blogs/${selectedBlog}`
|
|
||||||
);
|
|
||||||
return response.data;
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
console.error(error);
|
|
||||||
createToast({
|
|
||||||
title: "Error!",
|
|
||||||
description: "Post have not been added",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
console.log("Post added successfully");
|
|
||||||
createToast({
|
|
||||||
title: "Success!",
|
|
||||||
description: "Post added successfully",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
console.log("Add mutation is settled");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
navigate("/login");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog.Root
|
|
||||||
open={isOpen}
|
|
||||||
onOpenChange={(e) => {
|
|
||||||
setIsOpen(e);
|
|
||||||
if (e) {
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Dialog.Trigger asChild>
|
|
||||||
<Button variant="surface" className="h-5">
|
|
||||||
<Text>Add to blog</Text>
|
|
||||||
</Button>
|
|
||||||
</Dialog.Trigger>
|
|
||||||
<Dialog.Portal>
|
|
||||||
<Dialog.Overlay className="fixed inset-0 bg-black/40 data-[state=open]:animate-overlayShow" />
|
|
||||||
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-md shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-contentShow">
|
|
||||||
<Theme panelBackground="solid">
|
|
||||||
<Card className="p-5">
|
|
||||||
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
|
|
||||||
<Text size={"4"}>Add this post to blog</Text>
|
|
||||||
</Dialog.Title>
|
|
||||||
<Dialog.Description className="mb-5 mt-2.5 text-[15px] leading-normal text-mauve11">
|
|
||||||
<Flex gap={"2"} align={"center"}>
|
|
||||||
<Text>{`Add post to `}</Text>
|
|
||||||
<Select.Root
|
|
||||||
value={selectedBlog}
|
|
||||||
onValueChange={(e) => {
|
|
||||||
setSelectedBlog(e);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select.Trigger className="w-40 cursor-pointer" />
|
|
||||||
<Select.Content>
|
|
||||||
<Select.Group>
|
|
||||||
{data?.map((blog, i) => {
|
|
||||||
return (
|
|
||||||
<Select.Item
|
|
||||||
key={i}
|
|
||||||
value={`${blog.blog_id}`}
|
|
||||||
>
|
|
||||||
{blog.title}
|
|
||||||
</Select.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select.Group>
|
|
||||||
</Select.Content>
|
|
||||||
</Select.Root>
|
|
||||||
</Flex>
|
|
||||||
</Dialog.Description>
|
|
||||||
|
|
||||||
<Flex
|
|
||||||
className="items-center justify-between"
|
|
||||||
>
|
|
||||||
{selectedBlog ? <div/> : <Text color="gray">* Please select a blog to attach the post to.</Text>}
|
|
||||||
|
|
||||||
<div className="flex flex-col justify-center">
|
|
||||||
<Dialog.Close asChild>
|
|
||||||
<Button
|
|
||||||
className="cursor-pointer"
|
|
||||||
onClick={() => {
|
|
||||||
addMutation.mutate();
|
|
||||||
}}
|
|
||||||
disabled={!selectedBlog}
|
|
||||||
>
|
|
||||||
<Text>Confirm</Text>
|
|
||||||
</Button>
|
|
||||||
</Dialog.Close>
|
|
||||||
</div>
|
|
||||||
</Flex>
|
|
||||||
<Dialog.Close asChild>
|
|
||||||
<button
|
|
||||||
className="absolute right-2.5 top-2.5 inline-flex size-[25px] appearance-none items-center justify-center rounded-full text-violet11 hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 focus:outline-none"
|
|
||||||
aria-label="Close"
|
|
||||||
>
|
|
||||||
<Cross2Icon />
|
|
||||||
</button>
|
|
||||||
</Dialog.Close>
|
|
||||||
</Card>
|
|
||||||
</Theme>
|
|
||||||
</Dialog.Content>
|
|
||||||
</Dialog.Portal>
|
|
||||||
</Dialog.Root>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
import * as Dialog from "@radix-ui/react-dialog";
|
|
||||||
import { Cross2Icon, PlusIcon } from "@radix-ui/react-icons";
|
|
||||||
import { Box, Button, Card, Text, Theme } from "@radix-ui/themes";
|
|
||||||
import { useMutation } from "@tanstack/react-query";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { axiosLocalhost } from "../../../api/axios/axios";
|
|
||||||
import queryClient from "../../../api/QueryClient/QueryClient";
|
|
||||||
import useToast from "../../../hooks/useToast";
|
|
||||||
|
|
||||||
export default function BlogCreationDialog() {
|
|
||||||
const createToast = useToast();
|
|
||||||
|
|
||||||
const [title, setTitle] = useState<string>("My blog");
|
|
||||||
const [description, setDescription] = useState<string>("");
|
|
||||||
|
|
||||||
const addMutation = useMutation({
|
|
||||||
onMutate: () => {},
|
|
||||||
mutationFn: async () => {
|
|
||||||
await axiosLocalhost.post("/blogs", {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
createToast({
|
|
||||||
title: `Success!`,
|
|
||||||
description: `Blog created successfully!`,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (_error) => {
|
|
||||||
createToast({
|
|
||||||
title: `Error!`,
|
|
||||||
description: `Blog creation failed!`,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: ["userBlogs"],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Dialog.Root>
|
|
||||||
<Dialog.Trigger asChild>
|
|
||||||
<Button onClick={() => {}} className="w-full">
|
|
||||||
<PlusIcon />
|
|
||||||
</Button>
|
|
||||||
</Dialog.Trigger>
|
|
||||||
<Dialog.Portal>
|
|
||||||
<Box>
|
|
||||||
<Theme>
|
|
||||||
<Dialog.Overlay className="fixed inset-0 bg-black/40 backdrop-blur-sm data-[state=open]:animate-appear" />
|
|
||||||
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-md p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-appear">
|
|
||||||
<Card>
|
|
||||||
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
|
|
||||||
<Text size={"4"}>Create blog</Text>
|
|
||||||
</Dialog.Title>
|
|
||||||
<Dialog.Description className="mb-5 mt-2.5 text-[15px] leading-normal text-mauve11">
|
|
||||||
<Text>Create your new blog.</Text>
|
|
||||||
</Dialog.Description>
|
|
||||||
<fieldset className="mb-[15px] flex items-center gap-5">
|
|
||||||
<label
|
|
||||||
className="w-[90px] text-right text-[15px] text-violet11"
|
|
||||||
htmlFor="title"
|
|
||||||
>
|
|
||||||
<Text>Blog title</Text>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="inline-flex h-[35px] w-full flex-1 items-center justify-center rounded px-2.5 text-[15px] leading-none text-violet11 shadow-[0_0_0_1px] shadow-violet7 outline-none focus:shadow-[0_0_0_2px] focus:shadow-violet8"
|
|
||||||
id="title"
|
|
||||||
defaultValue="My blog"
|
|
||||||
onChange={(e) => {
|
|
||||||
setTitle(e.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset className="mb-[15px] flex items-center gap-5">
|
|
||||||
<label
|
|
||||||
className="w-[90px] text-right text-[15px] text-violet11"
|
|
||||||
htmlFor="Description"
|
|
||||||
>
|
|
||||||
<Text>Description</Text>
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
className="pt-2 inline-flex h-[35px] w-full flex-1 items-center justify-center rounded px-2.5 text-[15px] leading-none text-violet11 shadow-[0_0_0_1px] shadow-violet7 outline-none focus:shadow-[0_0_0_2px] focus:shadow-violet8"
|
|
||||||
id="Description"
|
|
||||||
placeholder="Your description..."
|
|
||||||
onChange={(e) => {
|
|
||||||
setDescription(e.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</fieldset>
|
|
||||||
<div className="mt-[25px] flex justify-end">
|
|
||||||
<Dialog.Close
|
|
||||||
asChild
|
|
||||||
onClick={() => {
|
|
||||||
addMutation.mutate();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button className="cursor-pointer">
|
|
||||||
Create blog
|
|
||||||
</Button>
|
|
||||||
</Dialog.Close>
|
|
||||||
</div>
|
|
||||||
<Dialog.Close asChild>
|
|
||||||
<button
|
|
||||||
className="absolute right-2.5 top-2.5 inline-flex size-[25px] appearance-none items-center justify-center rounded-full text-violet11 hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 focus:outline-none"
|
|
||||||
aria-label="Close"
|
|
||||||
>
|
|
||||||
<Cross2Icon />
|
|
||||||
</button>
|
|
||||||
</Dialog.Close>
|
|
||||||
</Card>
|
|
||||||
</Dialog.Content>
|
|
||||||
</Theme>
|
|
||||||
</Box>
|
|
||||||
</Dialog.Portal>
|
|
||||||
</Dialog.Root>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { EnterIcon } from "@radix-ui/react-icons";
|
|
||||||
import { Flex, Text } from "@radix-ui/themes";
|
|
||||||
import { Icon } from "@radix-ui/themes/dist/esm/components/callout.js";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
|
|
||||||
export default function LoginButton() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link to={"/login"}>
|
|
||||||
<Flex className="justify-between gap-2">
|
|
||||||
<Icon>
|
|
||||||
<EnterIcon />
|
|
||||||
</Icon>
|
|
||||||
<Text>{t("signIn")}</Text>
|
|
||||||
</Flex>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
import { ExitIcon } from "@radix-ui/react-icons";
|
|
||||||
import { Flex, Text } from "@radix-ui/themes";
|
|
||||||
import { Icon } from "@radix-ui/themes/dist/esm/components/callout.js";
|
|
||||||
import { useMutation } from "@tanstack/react-query";
|
|
||||||
import { useSetAtom } from "jotai";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import queryClient from "../../../../../api/QueryClient/QueryClient";
|
|
||||||
import { userAtom } from "../../../../../AtomStore/AtomStore";
|
|
||||||
import useToast from "../../../../../hooks/useToast";
|
|
||||||
import { logout } from "../../../../../utils/logout";
|
|
||||||
|
|
||||||
export default function LogoutButton() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const setUserData = useSetAtom(userAtom)
|
|
||||||
|
|
||||||
const createToast = useToast()
|
|
||||||
|
|
||||||
const logoutMutation = useMutation({
|
|
||||||
onMutate: () => {
|
|
||||||
queryClient.cancelQueries({
|
|
||||||
queryKey: ["authKey"],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
mutationFn: async () => {
|
|
||||||
await logout();
|
|
||||||
},
|
|
||||||
onError: () => {},
|
|
||||||
onSuccess: () => {
|
|
||||||
setUserData(undefined)
|
|
||||||
createToast({ title: "Success!", description: "Logged out successfully"})
|
|
||||||
navigate("/");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
className="justify-between gap-2"
|
|
||||||
onClick={() => logoutMutation.mutate()}
|
|
||||||
>
|
|
||||||
<Icon>
|
|
||||||
<ExitIcon />
|
|
||||||
</Icon>
|
|
||||||
<Text>{t("signOut")}</Text>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
|
EnterIcon,
|
||||||
|
ExitIcon,
|
||||||
LaptopIcon,
|
LaptopIcon,
|
||||||
PersonIcon
|
PersonIcon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
import { DropdownMenu, Flex, IconButton, Text } from "@radix-ui/themes";
|
import { DropdownMenu, Flex, IconButton, Text } from "@radix-ui/themes";
|
||||||
import { Icon } from "@radix-ui/themes/dist/esm/components/callout.js";
|
import { Icon } from "@radix-ui/themes/dist/esm/components/callout.js";
|
||||||
@ -8,8 +10,6 @@ import { useAtomValue } from "jotai";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { userAtom } from "../../../../AtomStore/AtomStore";
|
import { userAtom } from "../../../../AtomStore/AtomStore";
|
||||||
import LoginButton from "./LoginButton/LoginButton";
|
|
||||||
import LogoutButton from "./LogoutButton/LogoutButton";
|
|
||||||
|
|
||||||
export default function UserButton() {
|
export default function UserButton() {
|
||||||
const user = useAtomValue(userAtom);
|
const user = useAtomValue(userAtom);
|
||||||
@ -19,7 +19,7 @@ export default function UserButton() {
|
|||||||
<div className="">
|
<div className="">
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<IconButton className="cursor-pointer">
|
<IconButton>
|
||||||
<PersonIcon />
|
<PersonIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
@ -52,9 +52,21 @@ export default function UserButton() {
|
|||||||
|
|
||||||
<DropdownMenu.Item color={user ? "red" : "green"}>
|
<DropdownMenu.Item color={user ? "red" : "green"}>
|
||||||
{user ? (
|
{user ? (
|
||||||
<LogoutButton />
|
<Flex className="justify-between gap-2">
|
||||||
|
<Icon>
|
||||||
|
<ExitIcon />
|
||||||
|
</Icon>
|
||||||
|
<Text>{t("signOut")}</Text>
|
||||||
|
</Flex>
|
||||||
) : (
|
) : (
|
||||||
<LoginButton />
|
<Link to={"/login"}>
|
||||||
|
<Flex className="justify-between gap-2">
|
||||||
|
<Icon>
|
||||||
|
<EnterIcon />
|
||||||
|
</Icon>
|
||||||
|
<Text>{t("signIn")}</Text>
|
||||||
|
</Flex>
|
||||||
|
</Link>
|
||||||
)}
|
)}
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
import * as RadixTooltip from "@radix-ui/react-tooltip";
|
|
||||||
import { Card, Text, Theme } from "@radix-ui/themes";
|
|
||||||
|
|
||||||
type TTooltipProps = {
|
|
||||||
text: string;
|
|
||||||
} & React.PropsWithChildren;
|
|
||||||
|
|
||||||
export default function Tooltip(props: TTooltipProps) {
|
|
||||||
return (
|
|
||||||
<RadixTooltip.Provider>
|
|
||||||
<RadixTooltip.Root>
|
|
||||||
<RadixTooltip.Trigger>{props.children}</RadixTooltip.Trigger>
|
|
||||||
|
|
||||||
<RadixTooltip.Portal>
|
|
||||||
<RadixTooltip.Content side="top">
|
|
||||||
<RadixTooltip.Content>
|
|
||||||
<Theme panelBackground="translucent">
|
|
||||||
<Card className="p-1 -translate-y-1 w-fit h-fit animate-appearTooltip">
|
|
||||||
<Text>{props.text}</Text>
|
|
||||||
</Card>
|
|
||||||
</Theme>
|
|
||||||
</RadixTooltip.Content>
|
|
||||||
</RadixTooltip.Content>
|
|
||||||
</RadixTooltip.Portal>
|
|
||||||
</RadixTooltip.Root>
|
|
||||||
</RadixTooltip.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -10,8 +10,7 @@ export default function AuthPageWrapper(props: React.PropsWithChildren) {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
navigate("/login", { replace: true });
|
navigate("/login");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size={"4"} className="mt-4">
|
<Container size={"4"} className="mt-4">
|
||||||
<Text size={"7"}>{t("errors.unauthorized")}</Text>
|
<Text size={"7"}>{t("errors.unauthorized")}</Text>
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
import * as Dialog from "@radix-ui/react-dialog";
|
||||||
import { Box, Container, Flex, Separator, Text } from "@radix-ui/themes";
|
import { Cross2Icon, PlusIcon } from "@radix-ui/react-icons";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Flex,
|
||||||
|
Separator,
|
||||||
|
Text,
|
||||||
|
} from "@radix-ui/themes";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { axiosLocalhost } from "../../api/axios/axios";
|
import { axiosLocalhost } from "../../api/axios/axios";
|
||||||
import BlogBox from "../../Components/BlogBox/BlogBox";
|
import BlogBox from "../../Components/BlogBox/BlogBox";
|
||||||
import BlogCreationDialog from "../../Components/Dialogs/BlogCreationDialog/BlogCreationDialog";
|
|
||||||
import { JSONWithInt64 } from "../../utils/idnex";
|
import { JSONWithInt64 } from "../../utils/idnex";
|
||||||
import SkeletonBoxes from "./SkeletonBoxes/SkeletonBoxes";
|
import SkeletonBoxes from "./SkeletonBoxes/SkeletonBoxes";
|
||||||
|
|
||||||
const TAGS = Array.from({ length: 50 }).map(
|
|
||||||
(_, i, a) => `v1.2.0-beta.${a.length - i}`
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function UserBlogsPage() {
|
export default function UserBlogsPage() {
|
||||||
const { data, isPending, isFetching } = useQuery({
|
const { data, isPending, isFetching } = useQuery({
|
||||||
queryKey: ["userBlogs"],
|
queryKey: ["userBlogs"],
|
||||||
@ -33,24 +36,15 @@ export default function UserBlogsPage() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="w-full max-h-full overflow-hidden">
|
<Box className="size-full">
|
||||||
{/* <Container size={"2"} className="w-full h-full max-h-full"> */}
|
<Container size={"1"}>
|
||||||
<Flex
|
<Flex direction={"column"} gap={"2"}>
|
||||||
id="currentTestBox"
|
|
||||||
direction={"column"}
|
|
||||||
gap={"2"}
|
|
||||||
className="max-h-full pb-2 mx-80"
|
|
||||||
>
|
|
||||||
<Text size={"9"} className="text-center">
|
<Text size={"9"} className="text-center">
|
||||||
Your blogs
|
Your blogs
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Separator size={"4"} className="my-2" />
|
<Separator size={"4"} className="my-2" />
|
||||||
|
|
||||||
<div className="overflow-hidden">
|
|
||||||
<ScrollArea.Root className="w-full overflow-hidden h-fit max-h-">
|
|
||||||
<ScrollArea.Viewport className="size-full">
|
|
||||||
<Flex direction={"column"} gap={"2"}>
|
|
||||||
{data
|
{data
|
||||||
? data?.map((blog: any, b) => {
|
? data?.map((blog: any, b) => {
|
||||||
return (
|
return (
|
||||||
@ -65,23 +59,68 @@ export default function UserBlogsPage() {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
: null}
|
: null}
|
||||||
</Flex>
|
|
||||||
</ScrollArea.Viewport>
|
<Dialog.Root>
|
||||||
<ScrollArea.Scrollbar
|
<Dialog.Trigger asChild>
|
||||||
orientation="vertical"
|
<Button onClick={() => {}}>
|
||||||
color="gray"
|
<PlusIcon />
|
||||||
className="rounded-xl data-[state=visible]:w-1"
|
</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
<Dialog.Portal>
|
||||||
|
<Dialog.Overlay className="fixed inset-0 bg-blackA6 data-[state=open]:animate-overlayShow" />
|
||||||
|
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[450px] -translate-x-1/2 -translate-y-1/2 rounded-md bg-white p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-contentShow">
|
||||||
|
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
|
||||||
|
Create blog
|
||||||
|
</Dialog.Title>
|
||||||
|
<Dialog.Description className="mb-5 mt-2.5 text-[15px] leading-normal text-mauve11">
|
||||||
|
Create your new blog.
|
||||||
|
</Dialog.Description>
|
||||||
|
<fieldset className="mb-[15px] flex items-center gap-5">
|
||||||
|
<label
|
||||||
|
className="w-[90px] text-right text-[15px] text-violet11"
|
||||||
|
htmlFor="title"
|
||||||
>
|
>
|
||||||
<ScrollArea.Thumb className="relative flex-1 bg-gray-600 rounded-xl" />
|
Blog title
|
||||||
</ScrollArea.Scrollbar>
|
</label>
|
||||||
</ScrollArea.Root>
|
<input
|
||||||
|
className="inline-flex h-[35px] w-full flex-1 items-center justify-center rounded px-2.5 text-[15px] leading-none text-violet11 shadow-[0_0_0_1px] shadow-violet7 outline-none focus:shadow-[0_0_0_2px] focus:shadow-violet8"
|
||||||
|
id="title"
|
||||||
|
defaultValue="My blog"
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset className="mb-[15px] flex items-center gap-5">
|
||||||
|
<label
|
||||||
|
className="w-[90px] text-right text-[15px] text-violet11"
|
||||||
|
htmlFor="Description"
|
||||||
|
>
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
className="pt-2 inline-flex h-[35px] w-full flex-1 items-center justify-center rounded px-2.5 text-[15px] leading-none text-violet11 shadow-[0_0_0_1px] shadow-violet7 outline-none focus:shadow-[0_0_0_2px] focus:shadow-violet8"
|
||||||
|
id="Description"
|
||||||
|
placeholder="Your description..."
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
<div className="mt-[25px] flex justify-end">
|
||||||
|
<Dialog.Close asChild>
|
||||||
|
<Button>
|
||||||
|
Create blog
|
||||||
|
</Button>
|
||||||
|
</Dialog.Close>
|
||||||
</div>
|
</div>
|
||||||
|
<Dialog.Close asChild>
|
||||||
<BlogCreationDialog />
|
<button
|
||||||
|
className="absolute right-2.5 top-2.5 inline-flex size-[25px] appearance-none items-center justify-center rounded-full text-violet11 hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 focus:outline-none"
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<Cross2Icon />
|
||||||
|
</button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Portal>
|
||||||
|
</Dialog.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
{/* </Container> */}
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,6 @@ export default function MainPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Flex
|
<Flex
|
||||||
id="mainFlex"
|
|
||||||
direction={"column"}
|
direction={"column"}
|
||||||
className="min-h-[100vh] max-h-[100vh] overflow-hidden"
|
className="min-h-[100vh] max-h-[100vh] overflow-hidden"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
import { axiosLocalhost } from "../api/axios/axios";
|
|
||||||
|
|
||||||
export async function logout() {
|
|
||||||
try {
|
|
||||||
let response = await axiosLocalhost.delete('/auth/logout')
|
|
||||||
console.log(`Logout successful`)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,7 +11,6 @@ export default {
|
|||||||
'times': "Times New Roman"
|
'times': "Times New Roman"
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
appearTooltip: "appear 0.1s",
|
|
||||||
appear: "appear 0.25s",
|
appear: "appear 0.25s",
|
||||||
widthOut: "widthOut cubic-bezier(0.4, 0, 0.6, 1) 0.4s",
|
widthOut: "widthOut cubic-bezier(0.4, 0, 0.6, 1) 0.4s",
|
||||||
slideFromRight: "slideFromRight cubic-bezier(0.4, 0, 0.6, 1) 0.2s",
|
slideFromRight: "slideFromRight cubic-bezier(0.4, 0, 0.6, 1) 0.2s",
|
||||||
@ -35,7 +34,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
appear: {
|
appear: {
|
||||||
"0%": { opacity: "0" },
|
|
||||||
"100%": { opacity: "1" },
|
"100%": { opacity: "1" },
|
||||||
},
|
},
|
||||||
widthOut: {
|
widthOut: {
|
||||||
|
|||||||
@ -25,15 +25,3 @@ func SetCookie(c *gin.Context, params *CookieParams) {
|
|||||||
params.HttpOnly,
|
params.HttpOnly,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveCookie(c *gin.Context, params *CookieParams) {
|
|
||||||
c.SetCookie(
|
|
||||||
params.Name,
|
|
||||||
params.Value,
|
|
||||||
-1,
|
|
||||||
params.Path,
|
|
||||||
params.Domain,
|
|
||||||
params.Secure,
|
|
||||||
params.HttpOnly,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
FROM golang:1.23.3-alpine3.20 AS builder
|
FROM golang:1.23.3-alpine3.20
|
||||||
|
|
||||||
WORKDIR /enshi_app
|
WORKDIR /enshi_app
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN go build -o enshi_bin .
|
RUN go build -o enshi_bin .
|
||||||
|
|
||||||
FROM alpine
|
|
||||||
COPY --from=builder /enshi_app/enshi_bin /usr/local/bin/enshi_bin
|
|
||||||
EXPOSE 9876
|
EXPOSE 9876
|
||||||
ENTRYPOINT [ "/usr/local/bin/enshi_bin" ]
|
|
||||||
|
CMD [ "./enshi_bin" ]
|
||||||
@ -12,7 +12,7 @@ func CORSMiddleware() gin.HandlerFunc {
|
|||||||
"authorization, Authorization, accept, origin, Cache-Control, "+
|
"authorization, Authorization, accept, origin, Cache-Control, "+
|
||||||
"X-Requested-With, Cookie",
|
"X-Requested-With, Cookie",
|
||||||
)
|
)
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE, PATCH")
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||||
c.Writer.Header().Set("Access-Control-Expose-Headers", "Access-Token, Uid, Authorization")
|
c.Writer.Header().Set("Access-Control-Expose-Headers", "Access-Token, Uid, Authorization")
|
||||||
|
|
||||||
if c.Request.Method == "OPTIONS" {
|
if c.Request.Method == "OPTIONS" {
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
package authRoutes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"enshi/global"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Logout(c *gin.Context) {
|
|
||||||
c.SetCookie("auth_cookie", "", -1, "/", global.DomainForCookies, false, true)
|
|
||||||
c.IndentedJSON(http.StatusOK, gin.H{"message": "you have been logged out"})
|
|
||||||
}
|
|
||||||
@ -123,7 +123,7 @@ func SetupRotes(g *gin.Engine) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
blogGroup := g.Group("/")
|
blogGroup := g.Group("/")
|
||||||
blogGroup.Use(MiddlewareProvider.GetMiddleware(BLOG_MIDDLEWARE))
|
blogGroup.Use(middleware.BlogsMiddleware())
|
||||||
|
|
||||||
blogGroup.POST(
|
blogGroup.POST(
|
||||||
"blogs",
|
"blogs",
|
||||||
@ -204,11 +204,6 @@ func SetupRotes(g *gin.Engine) error {
|
|||||||
authGroup.Use(middleware.AuthMiddleware())
|
authGroup.Use(middleware.AuthMiddleware())
|
||||||
authGroup.GET("check", testAuth)
|
authGroup.GET("check", testAuth)
|
||||||
|
|
||||||
authGroup.DELETE(
|
|
||||||
"logout",
|
|
||||||
authRoutes.Logout,
|
|
||||||
)
|
|
||||||
|
|
||||||
temporal := g.Group("/")
|
temporal := g.Group("/")
|
||||||
temporal.Use(middleware.AuthMiddleware())
|
temporal.Use(middleware.AuthMiddleware())
|
||||||
|
|
||||||
|
|||||||
470
package-lock.json
generated
470
package-lock.json
generated
@ -1,470 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Enshi_v2",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-tooltip": "^1.1.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@floating-ui/core": {
|
|
||||||
"version": "1.6.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz",
|
|
||||||
"integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@floating-ui/utils": "^0.2.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@floating-ui/dom": {
|
|
||||||
"version": "1.6.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz",
|
|
||||||
"integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@floating-ui/core": "^1.6.0",
|
|
||||||
"@floating-ui/utils": "^0.2.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@floating-ui/react-dom": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@floating-ui/dom": "^1.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16.8.0",
|
|
||||||
"react-dom": ">=16.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@floating-ui/utils": {
|
|
||||||
"version": "0.2.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
|
|
||||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@radix-ui/primitive": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@radix-ui/react-arrow": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-primitive": "2.0.1"
|
|
||||||
},
|
|
||||||
"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-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-context": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
|
|
||||||
"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-dismissable-layer": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/primitive": "1.1.1",
|
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
|
||||||
"@radix-ui/react-primitive": "2.0.1",
|
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
|
||||||
"@radix-ui/react-use-escape-keydown": "1.1.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/react-id": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
|
||||||
},
|
|
||||||
"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-popper": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@floating-ui/react-dom": "^2.0.0",
|
|
||||||
"@radix-ui/react-arrow": "1.1.1",
|
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
|
||||||
"@radix-ui/react-context": "1.1.1",
|
|
||||||
"@radix-ui/react-primitive": "2.0.1",
|
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
|
||||||
"@radix-ui/react-use-rect": "1.1.0",
|
|
||||||
"@radix-ui/react-use-size": "1.1.0",
|
|
||||||
"@radix-ui/rect": "1.1.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/react-portal": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-primitive": "2.0.1",
|
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.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/react-presence": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.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/react-primitive": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-slot": "1.1.1"
|
|
||||||
},
|
|
||||||
"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-slot": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
|
||||||
"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-tooltip": {
|
|
||||||
"version": "1.1.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.7.tgz",
|
|
||||||
"integrity": "sha512-ss0s80BC0+g0+Zc53MvilcnTYSOi4mSuFWBPYPuTOFGjx+pUU+ZrmamMNwS56t8MTFlniA5ocjd4jYm/CdhbOg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/primitive": "1.1.1",
|
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
|
||||||
"@radix-ui/react-context": "1.1.1",
|
|
||||||
"@radix-ui/react-dismissable-layer": "1.1.4",
|
|
||||||
"@radix-ui/react-id": "1.1.0",
|
|
||||||
"@radix-ui/react-popper": "1.2.1",
|
|
||||||
"@radix-ui/react-portal": "1.1.3",
|
|
||||||
"@radix-ui/react-presence": "1.1.2",
|
|
||||||
"@radix-ui/react-primitive": "2.0.1",
|
|
||||||
"@radix-ui/react-slot": "1.1.1",
|
|
||||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
||||||
"@radix-ui/react-visually-hidden": "1.1.1"
|
|
||||||
},
|
|
||||||
"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-use-callback-ref": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
|
|
||||||
"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-use-controllable-state": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
|
||||||
},
|
|
||||||
"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-use-escape-keydown": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
|
||||||
},
|
|
||||||
"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-use-layout-effect": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
|
|
||||||
"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-use-rect": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/rect": "1.1.0"
|
|
||||||
},
|
|
||||||
"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-use-size": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
|
||||||
},
|
|
||||||
"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-visually-hidden": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-primitive": "2.0.1"
|
|
||||||
},
|
|
||||||
"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/rect": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/react": {
|
|
||||||
"version": "19.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
|
|
||||||
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-dom": {
|
|
||||||
"version": "19.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
|
||||||
"integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"scheduler": "^0.25.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^19.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/scheduler": {
|
|
||||||
"version": "0.25.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
|
|
||||||
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"@radix-ui/react-tooltip": "^1.1.7"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user