mirror of
https://github.com/pheralb/svgl.git
synced 2024-11-10 14:46:54 +08:00
⚒️ Create header & layout config.
This commit is contained in:
parent
457a6c64f7
commit
4d366f8c25
24
src/animations/show.tsx
Normal file
24
src/animations/show.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React, { FC } from "react";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
type ShowProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
delay?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Show = ({ children, delay }: ShowProps) => {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ y: 10, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
transition={{
|
||||||
|
duration: 0.4,
|
||||||
|
delay: delay,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Show;
|
@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { getCategorySvgs } from "@/services";
|
import { getCategorySvgs } from "@/services";
|
||||||
import CustomLink from "@/common/link";
|
import CustomLink from "@/common/link";
|
||||||
import { Text } from "@chakra-ui/react";
|
import { Box, Text } from "@chakra-ui/react";
|
||||||
|
|
||||||
const Categories = () => {
|
const Categories = () => {
|
||||||
const { data, error } = useSWR(getCategorySvgs);
|
const { data, error } = useSWR(getCategorySvgs);
|
||||||
@ -11,13 +11,13 @@ const Categories = () => {
|
|||||||
if (!data) return <div>loading...</div>;
|
if (!data) return <div>loading...</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{data.map((category: string) => (
|
{data.map((category: string) => (
|
||||||
<CustomLink key={category} href={`/category/${category}`}>
|
<Box key={category} p="4" borderRadius="5px" borderWidth="1px">
|
||||||
<Text mb="2">{category}</Text>
|
<CustomLink href={`/category/${category}`}>{category}</CustomLink>
|
||||||
</CustomLink>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
73
src/layout/header/index.tsx
Normal file
73
src/layout/header/index.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
useColorModeValue,
|
||||||
|
HStack,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Heading,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { Sticker } from "phosphor-react";
|
||||||
|
import Theme from "./theme";
|
||||||
|
import Tap from "@/animations/tap";
|
||||||
|
import Mobile from "./mobile";
|
||||||
|
import { Links } from "./links";
|
||||||
|
import CustomLink from "@/common/link";
|
||||||
|
import Categories from "./categories";
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
const bg = useColorModeValue("bg.light", "bg.dark");
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
position="sticky"
|
||||||
|
top="0"
|
||||||
|
bg={bg}
|
||||||
|
borderBottomWidth="1px"
|
||||||
|
w="full"
|
||||||
|
py={6}
|
||||||
|
shadow="sm"
|
||||||
|
>
|
||||||
|
<Container maxW={{ base: "full", md: "70%" }}>
|
||||||
|
<Flex alignItems="center" justifyContent="space-between" mx="auto">
|
||||||
|
<CustomLink href="/">
|
||||||
|
<Tap>
|
||||||
|
<HStack spacing={3} cursor="pointer">
|
||||||
|
<Sticker size={32} color="#4343e5" weight="bold" />
|
||||||
|
<Heading fontSize="19px">svgl</Heading>
|
||||||
|
</HStack>
|
||||||
|
</Tap>
|
||||||
|
</CustomLink>
|
||||||
|
<HStack display="flex" alignItems="center" spacing={1}>
|
||||||
|
<HStack
|
||||||
|
spacing={1}
|
||||||
|
mr={1}
|
||||||
|
display={{ base: "none", md: "inline-flex" }}
|
||||||
|
>
|
||||||
|
{Links.map((link) => (
|
||||||
|
<CustomLink
|
||||||
|
key={link.title}
|
||||||
|
href={link.slug}
|
||||||
|
external={link.external}
|
||||||
|
>
|
||||||
|
<Button variant="ghost">{link.title}</Button>
|
||||||
|
</CustomLink>
|
||||||
|
))}
|
||||||
|
<Theme />
|
||||||
|
</HStack>
|
||||||
|
<Box display={{ base: "inline-flex", md: "none" }}>
|
||||||
|
<Mobile />
|
||||||
|
</Box>
|
||||||
|
</HStack>
|
||||||
|
</Flex>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
<HStack p="4" spacing={4} overflowY="hidden" bg={bg} borderBottomWidth="1px">
|
||||||
|
<Categories />
|
||||||
|
</HStack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
12
src/layout/header/links.ts
Normal file
12
src/layout/header/links.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const Links = [
|
||||||
|
{
|
||||||
|
title: "Github",
|
||||||
|
slug: "https://github.com/pheralb/svgl",
|
||||||
|
external: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Twitter",
|
||||||
|
slug: "https://twitter.com/pheralb_",
|
||||||
|
external: true,
|
||||||
|
},
|
||||||
|
];
|
56
src/layout/header/mobile.tsx
Normal file
56
src/layout/header/mobile.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import CustomLink from "@/common/link";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
CloseButton,
|
||||||
|
IconButton,
|
||||||
|
useColorModeValue,
|
||||||
|
useDisclosure,
|
||||||
|
VStack,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { List } from "phosphor-react";
|
||||||
|
import { Links } from "./links";
|
||||||
|
|
||||||
|
const Mobile = () => {
|
||||||
|
const bg = useColorModeValue("bg.light", "bg.dark");
|
||||||
|
const mobileNav = useDisclosure();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconButton
|
||||||
|
display={{ base: "flex", md: "none" }}
|
||||||
|
aria-label="Open menu navbar"
|
||||||
|
variant="ghost"
|
||||||
|
icon={<List size={22} />}
|
||||||
|
onClick={mobileNav.onOpen}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VStack
|
||||||
|
pos="absolute"
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
right={0}
|
||||||
|
display={mobileNav.isOpen ? "flex" : "none"}
|
||||||
|
flexDirection="column"
|
||||||
|
p={2}
|
||||||
|
pb={4}
|
||||||
|
m={2}
|
||||||
|
bg={bg}
|
||||||
|
spacing={3}
|
||||||
|
rounded="sm"
|
||||||
|
shadow="sm"
|
||||||
|
>
|
||||||
|
<CloseButton aria-label="Close menu" onClick={mobileNav.onClose} />
|
||||||
|
{Links.map((link) => (
|
||||||
|
<CustomLink
|
||||||
|
key={link.title}
|
||||||
|
href={link.slug}
|
||||||
|
external={link.external}
|
||||||
|
>
|
||||||
|
<Button variant="ghost">{link.title}</Button>
|
||||||
|
</CustomLink>
|
||||||
|
))}
|
||||||
|
</VStack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Mobile;
|
@ -2,19 +2,18 @@ import React from "react";
|
|||||||
import { AnimatePresence, motion } from "framer-motion";
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import { useColorMode, useColorModeValue } from "@chakra-ui/react";
|
import { useColorMode, useColorModeValue } from "@chakra-ui/react";
|
||||||
import CustomIconBtn from "@/common/iconBtn";
|
import CustomIconBtn from "@/common/iconBtn";
|
||||||
import { IoMoonOutline, IoSunnyOutline } from "react-icons/io5";
|
import { Moon, Sun } from "phosphor-react";
|
||||||
|
|
||||||
const Theme = () => {
|
const Theme = () => {
|
||||||
const { toggleColorMode } = useColorMode();
|
const { toggleColorMode } = useColorMode();
|
||||||
const key = useColorModeValue("light", "dark");
|
const key = useColorModeValue("light", "dark");
|
||||||
const icon = useColorModeValue(
|
const icon = useColorModeValue(
|
||||||
<IoMoonOutline size={20} />,
|
<Moon size={22} />,
|
||||||
<IoSunnyOutline size={20} />
|
<Sun size={22} />
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<AnimatePresence exitBeforeEnter initial={false}>
|
<AnimatePresence exitBeforeEnter initial={false}>
|
||||||
<motion.div
|
<motion.div
|
||||||
style={{ display: "inline-block" }}
|
|
||||||
key={key}
|
key={key}
|
||||||
initial={{ y: -20, opacity: 0 }}
|
initial={{ y: -20, opacity: 0 }}
|
||||||
animate={{ y: 0, opacity: 1 }}
|
animate={{ y: 0, opacity: 1 }}
|
@ -1,9 +1,15 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { LayoutProps } from "@/interfaces/components";
|
import { LayoutProps } from "@/interfaces/components";
|
||||||
import Sidebar from "@/layout/sidebar";
|
import { Container } from "@chakra-ui/react";
|
||||||
|
import Header from "./header";
|
||||||
|
|
||||||
const Index = ({ children }: LayoutProps) => {
|
const Index = ({ children }: LayoutProps) => {
|
||||||
return <Sidebar>{children}</Sidebar>;
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<Container maxW="70%">{children}</Container>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Index;
|
export default Index;
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { SidebarContentProps } from "@/interfaces/components";
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Divider,
|
|
||||||
Flex,
|
|
||||||
Heading,
|
|
||||||
useColorModeValue,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import { HandGrabbing } from "phosphor-react";
|
|
||||||
import CustomLink from "@/common/link";
|
|
||||||
import Categories from "./categories";
|
|
||||||
|
|
||||||
const Content = (props: SidebarContentProps) => {
|
|
||||||
const bg = useColorModeValue("bg.light", "bg.dark");
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
as="nav"
|
|
||||||
pos="fixed"
|
|
||||||
left="0"
|
|
||||||
zIndex="sticky"
|
|
||||||
h="full"
|
|
||||||
pb="10"
|
|
||||||
overflowX="hidden"
|
|
||||||
overflowY="auto"
|
|
||||||
w="240px"
|
|
||||||
bg={bg}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
as="nav"
|
|
||||||
mt="5"
|
|
||||||
ml="7"
|
|
||||||
mr="6"
|
|
||||||
direction="column"
|
|
||||||
aria-label="Main Sidenav"
|
|
||||||
>
|
|
||||||
<CustomLink href="/">
|
|
||||||
<HandGrabbing size={50} />
|
|
||||||
</CustomLink>
|
|
||||||
<Box mt="6" ml="1">
|
|
||||||
<Divider mb="4" />
|
|
||||||
<Heading fontSize="16px" mt="3" mb="3">
|
|
||||||
Categories
|
|
||||||
</Heading>
|
|
||||||
<Categories />
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Content;
|
|
@ -1,59 +0,0 @@
|
|||||||
import { SidebarContentProps } from "@/interfaces/components";
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Drawer,
|
|
||||||
DrawerContent,
|
|
||||||
DrawerOverlay,
|
|
||||||
Flex,
|
|
||||||
IconButton,
|
|
||||||
useColorModeValue,
|
|
||||||
useDisclosure,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import React from "react";
|
|
||||||
import { IoApps } from "react-icons/io5";
|
|
||||||
import Content from "./content";
|
|
||||||
|
|
||||||
const Index = ({ children }: SidebarContentProps) => {
|
|
||||||
const sidebar = useDisclosure();
|
|
||||||
return (
|
|
||||||
<Box as="section">
|
|
||||||
<Content display={{ base: "none", md: "unset" }} />
|
|
||||||
<Drawer
|
|
||||||
isOpen={sidebar.isOpen}
|
|
||||||
onClose={sidebar.onClose}
|
|
||||||
placement="left"
|
|
||||||
>
|
|
||||||
<DrawerOverlay />
|
|
||||||
<DrawerContent>
|
|
||||||
<Content w="full" borderRight="none" />
|
|
||||||
</DrawerContent>
|
|
||||||
</Drawer>
|
|
||||||
<Box ml={{ base: 0, md: "90px" }} transition=".3s ease">
|
|
||||||
<Flex
|
|
||||||
as="header"
|
|
||||||
display={{ base: "inline-flex", md: "none" }}
|
|
||||||
align="center"
|
|
||||||
justify="space-between"
|
|
||||||
w="full"
|
|
||||||
px="4"
|
|
||||||
borderBottomWidth="1px"
|
|
||||||
borderColor="blackAlpha.300"
|
|
||||||
h="14"
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
aria-label="Menu"
|
|
||||||
onClick={sidebar.onOpen}
|
|
||||||
icon={<IoApps />}
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Box as="main" p="4">
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Index;
|
|
@ -1,5 +1,5 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
|
||||||
import db from "data/svgs";
|
import db from "data/svgs";
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { SvgData } from "@/interfaces/svgData";
|
import { SvgData } from "@/interfaces/svgData";
|
||||||
|
|
||||||
export default function handler(
|
export default function handler(
|
||||||
|
@ -13,18 +13,11 @@ const Home: NextPage = () => {
|
|||||||
if (!data) return <div>loading...</div>;
|
if (!data) return <div>loading...</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxW="85%">
|
|
||||||
<Grid>
|
<Grid>
|
||||||
{data.map((svg: SvgData) => (
|
{data.map((svg: SvgData) => (
|
||||||
<SVGCard
|
<SVGCard key={svg.id} title={svg.title} url={svg.href} svg={svg.href} />
|
||||||
key={svg.id}
|
|
||||||
title={svg.title}
|
|
||||||
url={svg.href}
|
|
||||||
svg={svg.href}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user