diff --git a/layouts/nav/editor-nav.tsx b/layouts/nav/editor-nav.tsx index b28f580a..3960e13f 100644 --- a/layouts/nav/editor-nav.tsx +++ b/layouts/nav/editor-nav.tsx @@ -2,8 +2,6 @@ import { chakra, Flex, Button, - IconButton, - useColorMode, useColorModeValue, Box, useRadioGroup, @@ -14,26 +12,50 @@ import { DrawerOverlay, DrawerContent, Divider, - Heading + Heading, + Tag as ChakraTag, + TagLabel, + TagCloseButton } from "@chakra-ui/react" import { useViewportScroll } from "framer-motion" import NextLink from "next/link" -import React from "react" -import { FaMoon, FaSun } from "react-icons/fa" +import React, { useEffect, useState } from "react" import Logo, { LogoIcon } from "src/components/logo" import RadioCard from "components/radio-card" import { EditMode } from "src/types/editor" import Card from "components/card" +import TagInput from "components/tag-input" +import { Tag } from "src/types/tag" +import { cloneDeep, remove } from "lodash" +import { requestApi } from "utils/axios/request" +import DarkMode from "components/dark-mode" function HeaderContent(props: any) { - const { toggleColorMode: toggleMode } = useColorMode() - const text = useColorModeValue("dark", "light") - const SwitchIcon = useColorModeValue(FaMoon, FaSun) + const [tags,setTags]:[Tag[],any] = useState([]) + const [allTags,setAllTags] = useState([]) + const { isOpen, onOpen, onClose } = useDisclosure() + useEffect(() => { + requestApi.get('/tags').then(res => { + setAllTags(res.data) + const t = [] + props.ar.tags?.forEach(id => { + res.data.forEach(tag => { + if (tag.id === id) { + t.push(tag) + } + }) + }) + + setTags(t) + }) + },[props.ar]) + + const editOptions = [EditMode.Edit, EditMode.Preview] const { getRootProps, getRadioProps } = useRadioGroup({ name: "framework", @@ -43,7 +65,24 @@ function HeaderContent(props: any) { }, }) const group = getRootProps() + + const addTag = t => { + setTags(t) + + const ids = [] + t.forEach(tag => ids.push(tag.id)) + props.ar.tags = ids + } + + const removeTag = t => { + const newTags = cloneDeep(tags) + remove(newTags, tag => tag.id === t.id) + setTags(newTags) + const ids = [] + newTags.forEach(tag => ids.push(tag.id)) + props.ar.tags = ids + } return ( <> @@ -76,17 +115,7 @@ function HeaderContent(props: any) { - } - /> + @@ -109,7 +138,24 @@ function HeaderContent(props: any) { 封面图片 - {props.ar.cover = e.target.value; props.onChange()}} mt="4" variant="flushed" size="sm" placeholder="图片链接,你可以用github当图片存储服务" focusBorderColor="teal.400"/> + {props.ar.cover = e.target.value; props.onChange()}} mt="4" variant="unstyled" size="sm" placeholder="输入链接,可以用github或postimg.cc当图片存储服务.." focusBorderColor="teal.400"/> + + + + + 设置标签 + + + + {tags.length > 0&& + { + tags.map(tag => + + {tag.title} + removeTag(tag)}/> + ) + } + } @@ -119,7 +165,6 @@ function HeaderContent(props: any) { } function EditorNav(props) { - const bg = useColorModeValue("white", "gray.800") const ref = React.useRef() const [y, setY] = React.useState(0) const { height = 0 } = ref.current?.getBoundingClientRect() ?? {} @@ -137,7 +182,7 @@ function EditorNav(props) { pos="fixed" top="0" zIndex="3" - // bg={bg} + bg={useColorModeValue('white','gray.800')} left="0" right="0" borderTop="4px solid" diff --git a/layouts/mobile-nav.tsx b/layouts/nav/mobile-nav.tsx similarity index 100% rename from layouts/mobile-nav.tsx rename to layouts/nav/mobile-nav.tsx diff --git a/layouts/nav/nav.tsx b/layouts/nav/nav.tsx index b296a390..baebc059 100644 --- a/layouts/nav/nav.tsx +++ b/layouts/nav/nav.tsx @@ -1,37 +1,26 @@ import { chakra, Flex, - Button, HStack, IconButton, - useColorMode, useColorModeValue, useDisclosure, useUpdateEffect, - Menu, - MenuButton, - MenuList, - MenuItem, - MenuDivider, - Image, Box } from "@chakra-ui/react" import siteConfig from "configs/site-config" import { useViewportScroll } from "framer-motion" import NextLink from "next/link" import React from "react" -import { FaMoon, FaSun, FaUserAlt, FaRegSun, FaSignOutAlt,FaStar, FaGithub, FaBookmark, FaEdit } from "react-icons/fa" +import { FaGithub } from "react-icons/fa" import Logo, { LogoIcon } from "src/components/logo" -import { MobileNavButton, MobileNavContent } from "../mobile-nav" +import { MobileNavButton, MobileNavContent } from "./mobile-nav" import AlgoliaSearch from "src/components/search/algolia-search" -import useSession from "hooks/use-session" -import { Session } from "src/types/session" import { useRouter } from "next/router" -import storage from "utils/localStorage" -import { logout } from "utils/session" -import { isAdmin, isEditor } from "utils/role" import { ReserveUrls } from "src/data/reserve-urls" import Link from "next/link" +import DarkMode from "components/dark-mode" +import AccountMenu from "components/account-menu" const navLinks = [{ title: '主页', @@ -53,22 +42,13 @@ function HeaderContent() { const { asPath } = router const mobileNav = useDisclosure() - const session: Session = useSession() - const { toggleColorMode: toggleMode } = useColorMode() - const text = useColorModeValue("dark", "light") - const SwitchIcon = useColorModeValue(FaMoon, FaSun) const mobileNavBtnRef = React.useRef() useUpdateEffect(() => { mobileNavBtnRef.current?.focus() }, [mobileNav.isOpen]) - const login = () => { - console.log(router) - storage.set("current-page", asPath) - router.push(ReserveUrls.Login) - } return ( <> @@ -86,92 +66,39 @@ function HeaderContent() { - {navLinks.map(link => {link.title})} + {navLinks.map(link => {link.title})} - - - - } - /> - - - } - /> - {session ? - - : - - } - aria-label="Options" - ml={{ base: "0", md: "2" }} - /> - - }> - Sunface - - - {isEditor(session.user.role) && } >创作中心} - {isAdmin(session.user.role) && } >管理员} - }>书签收藏 - - }>偏好设置 - logout()} icon={}>账号登出 - - : - - } + + } + /> + + + - + @@ -201,6 +128,7 @@ function Header(props) { borderTop="4px solid" borderTopColor="teal.400" width="full" + bg={useColorModeValue('white', 'gray.800')} {...props} > diff --git a/layouts/nav/post-nav.tsx b/layouts/nav/post-nav.tsx new file mode 100644 index 00000000..9a44b273 --- /dev/null +++ b/layouts/nav/post-nav.tsx @@ -0,0 +1,127 @@ +import { + chakra, + Flex, + HStack, + IconButton, + useColorModeValue, + useDisclosure, + useUpdateEffect, + Heading, + Button, + Divider, + Text +} from "@chakra-ui/react" +import { useViewportScroll } from "framer-motion" +import React from "react" +import { SearchIcon } from "@chakra-ui/icons" +import DarkMode from "components/dark-mode" +import AccountMenu from "components/account-menu" +import { FaGithub, FaTwitter, FaUserPlus } from "react-icons/fa" + + + +function HeaderContent() { + const mobileNav = useDisclosure() + + const mobileNavBtnRef = React.useRef() + + useUpdateEffect(() => { + mobileNavBtnRef.current?.focus() + }, [mobileNav.isOpen]) + + return ( + <> + + + Sunface的博客 + + + + + + alert('search in this blog')} + icon={} + aria-label="search in this blog" + /> + + + + + + + Home + Badges + + + + } + /> + } + /> + + + + + ) +} + +function PostNav(props) { + const ref = React.useRef() + const [y, setY] = React.useState(0) + const { height = 0 } = ref.current?.getBoundingClientRect() ?? {} + + const { scrollY } = useViewportScroll() + React.useEffect(() => { + return scrollY.onChange(() => setY(scrollY.get())) + }, [scrollY]) + + return ( + height ? "sm" : undefined} + transition="box-shadow 0.2s" + top="0" + zIndex="3" + left="0" + right="0" + borderTop="4px solid" + borderTopColor="teal.400" + width="full" + bg={useColorModeValue('white', 'gray.800')} + {...props} + > + + + + + ) +} + +export default PostNav + diff --git a/layouts/page-container.tsx b/layouts/page-container.tsx index f7a289cc..9603f89e 100644 --- a/layouts/page-container.tsx +++ b/layouts/page-container.tsx @@ -1,4 +1,4 @@ -import { Badge, Box, chakra } from "@chakra-ui/react" +import { Badge, Box, chakra,PropsOf } from "@chakra-ui/react" import { SkipNavContent, SkipNavLink } from "@chakra-ui/skip-nav" import Container from "components/container" import Footer from "./footer" @@ -24,13 +24,14 @@ function useHeadingFocusOnRouteChange() { }, []) } -interface PageContainerProps { +type PageContainerProps = PropsOf & { children: React.ReactNode nav?: any } + function PageContainer(props: PageContainerProps) { - const { children ,nav} = props + const { children ,nav, ...rest} = props useHeadingFocusOnRouteChange() return ( @@ -48,9 +49,10 @@ function PageContainer(props: PageContainerProps) { {children} diff --git a/pages/[username]/[post_slug].tsx b/pages/[username]/[post_slug].tsx index 0951ca30..1a8756de 100644 --- a/pages/[username]/[post_slug].tsx +++ b/pages/[username]/[post_slug].tsx @@ -1,26 +1,136 @@ -import { chakra } from "@chakra-ui/react" +import { Box, chakra, Divider, Flex, Heading, HStack, IconButton, Image, VStack } from "@chakra-ui/react" import Container from "components/container" +import LikeButton from "components/like-button" +import { MarkdownRender } from "components/markdown-editor/render" +import PostAuthor from "components/posts/post-author" import SEO from "components/seo" import siteConfig from "configs/site-config" import Nav from "layouts/nav/nav" +import PostNav from "layouts/nav/post-nav" import PageContainer from "layouts/page-container" +import { cloneDeep } from "lodash" import { useRouter } from "next/router" -import React from "react" +import { title } from "process" +import React, { useEffect, useState } from "react" +import { FaBookmark, FaGithub, FaRegBookmark, FaShare, FaShareAlt } from "react-icons/fa" +import { Post } from "src/types/posts" +import { requestApi } from "utils/axios/request" -const UserPage = () => { +const PostPage = () => { const router = useRouter() + const slug = router.query.post_slug + const [post, setPost]: [Post, any] = useState(null) + + useEffect(() => { + if (slug) { + requestApi.get(`/post/${slug}`).then(res => setPost(res.data)) + } + }, [slug]) + + const onLike = async () => { + await requestApi.post(`/post/like/${post.id}`) + const p = cloneDeep(post) + + if (post.liked) { + p.likes += -1 + p.liked = false + } else { + p.likes += 1 + p.liked = true + } + setPost(p) + } + return ( - <> - -