From da00413171f2d81bf29c64fb3a754f53d6e8c0bf Mon Sep 17 00:00:00 2001 From: sunface Date: Mon, 1 Feb 2021 17:57:52 +0800 Subject: [PATCH] nextjs based first commit --- .eslintrc | 7 + .gitignore | 3 + configs/site-config.js | 63 + layouts/footer.tsx | 48 + layouts/mobile-nav.tsx | 184 + layouts/nav.tsx | 186 + layouts/page-container.tsx | 66 + next-env.d.ts | 2 + next-redirect.js | 18 + next.config.js | 23 + package.json | 42 + pages/_app.tsx | 37 + pages/index.tsx | 23 + public/favicon.png | Bin 0 -> 84062 bytes public/fonts/Inter.woff2 | Bin 0 -> 36532 bytes src/analytics/ga-script.tsx | 22 + src/analytics/track-event.ts | 33 + src/components/container.tsx | 16 + src/components/font-face.tsx | 80 + src/components/logo.tsx | 74 + src/components/page-transition.tsx | 12 + src/components/search/algolia-search.tsx | 168 + src/components/search/search.styles.tsx | 467 +++ src/components/seo.tsx | 16 + src/hooks/use-route-changed.ts | 20 + src/utils/seo.ts | 18 + theme.ts | 133 + tsconfig.json | 27 + yarn.lock | 4213 ++++++++++++++++++++++ 29 files changed, 6001 insertions(+) create mode 100644 .eslintrc create mode 100644 configs/site-config.js create mode 100644 layouts/footer.tsx create mode 100644 layouts/mobile-nav.tsx create mode 100644 layouts/nav.tsx create mode 100644 layouts/page-container.tsx create mode 100644 next-env.d.ts create mode 100644 next-redirect.js create mode 100644 next.config.js create mode 100644 package.json create mode 100644 pages/_app.tsx create mode 100644 pages/index.tsx create mode 100644 public/favicon.png create mode 100644 public/fonts/Inter.woff2 create mode 100644 src/analytics/ga-script.tsx create mode 100644 src/analytics/track-event.ts create mode 100644 src/components/container.tsx create mode 100644 src/components/font-face.tsx create mode 100644 src/components/logo.tsx create mode 100644 src/components/page-transition.tsx create mode 100644 src/components/search/algolia-search.tsx create mode 100644 src/components/search/search.styles.tsx create mode 100644 src/components/seo.tsx create mode 100644 src/hooks/use-route-changed.ts create mode 100644 src/utils/seo.ts create mode 100644 theme.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..1deca0d3 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,7 @@ +{ + "extends": "../eslintrc.json", + "parserOptions": { + "project": "tsconfig.json" + } + } + \ No newline at end of file diff --git a/.gitignore b/.gitignore index e43b0f98..e38e8e18 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ +node_modules +yarn-error.log +.next/ .DS_Store diff --git a/configs/site-config.js b/configs/site-config.js new file mode 100644 index 00000000..2d9b80b6 --- /dev/null +++ b/configs/site-config.js @@ -0,0 +1,63 @@ +const baseUrl = "https://github.com/imdotdev/im.dev" + +const siteConfig = { + copyright: `Copyright © ${new Date().getFullYear()} Segun Adebayo. All Rights Reserved.`, + algolia: { + apiKey: "df1dcc41f7b8e5d68e73dd56d1e19701", + indexName: "chakra-ui", + inputSelector: "#algolia-search", + }, + author: { + name: "Segun Adebayo", + github: "https://github.com/segunadebayo", + twitter: "https://twitter.com/thesegunadebayo", + linkedin: "https://linkedin.com/in/thesegunadebayo", + email: "sage@adebayosegun.com", + }, + repo: { + url: baseUrl, + editUrl: `${baseUrl}/edit/develop/website`, + blobUrl: `${baseUrl}/blob/develop`, + }, + openCollective: { + url: "https://opencollective.com/chakra-ui", + }, + discord: { + url: "https://discord.gg/dQHfcWF", + }, + seo: { + title: "im.dev", + titleTemplate: "%s - im.dev", + description: + "千挑万选,只为把高质量的内容呈现给你。我是开发,我为技术代言", + siteUrl: "https://im.dev", + openGraph: { + type: "website", + locale: "en_US", + url: "https://chakra-ui.com", + title: "Chakra UI", + description: + "Simple, Modular and Accessible UI Components for your React Applications.", + site_name: + "Chakra UI: Simple, Modular and Accessible UI Components for your React Applications.", + images: [ + { + url: "/og-image.png", + width: 1240, + height: 480, + alt: + "Chakra UI: Simple, Modular and Accessible UI Components for your React Applications.", + }, + { + url: "/twitter-og-image.png", + width: 1012, + height: 506, + alt: + "Chakra UI: Simple, Modular and Accessible UI Components for your React Applications.", + }, + ], + }, + }, +} + +export default siteConfig diff --git a/layouts/footer.tsx b/layouts/footer.tsx new file mode 100644 index 00000000..25deb719 --- /dev/null +++ b/layouts/footer.tsx @@ -0,0 +1,48 @@ +import React from "react" +import { Box, Icon, Text, Stack, Link, chakra } from "@chakra-ui/react" +import { IoLogoTwitter, IoLogoLinkedin } from "react-icons/io" +import { MdEmail } from "react-icons/md" +import { DiGithubBadge } from "react-icons/di" + +type FooterLinkProps = { + icon?: React.ElementType + href?: string + label?: string +} + +const FooterLink: React.FC = ({ icon, href, label }) => ( + + + +) + +const links = [ + { + icon: DiGithubBadge, + label: "GitHub", + href: "https://github.com/imdotdev/imdev", + }, + { + icon: MdEmail, + label: "Email", + href: "mailto:cto@188.com", + }, +] + + +export const Footer = () => ( + + + Proudly made in + 🇨🇳 + by codecc.com + + + {links.map((link) => ( + + ))} + + +) + +export default Footer diff --git a/layouts/mobile-nav.tsx b/layouts/mobile-nav.tsx new file mode 100644 index 00000000..b574a675 --- /dev/null +++ b/layouts/mobile-nav.tsx @@ -0,0 +1,184 @@ +import { + Box, + BoxProps, + Center, + CloseButton, + Flex, + HStack, + IconButton, + IconButtonProps, + useBreakpointValue, + useColorModeValue, + useUpdateEffect, + } from "@chakra-ui/react" + import { AnimatePresence, motion, useElementScroll } from "framer-motion" + import useRouteChanged from "src/hooks/use-route-changed" + import NextLink from "next/link" + import { useRouter } from "next/router" + import * as React from "react" + import { AiOutlineMenu } from "react-icons/ai" + import { RemoveScroll } from "react-remove-scroll" + import Logo from "src/components/logo" + + function NavLink({ href, children }) { + const { pathname } = useRouter() + + const [, group] = href.split("/") + const isActive = pathname.includes(group) + + return ( + +
+ {children} +
+
+ ) + } + + interface MobileNavContentProps { + isOpen?: boolean + onClose?: () => void + } + + export function MobileNavContent(props: MobileNavContentProps) { + const { isOpen, onClose } = props + const closeBtnRef = React.useRef() + const { pathname } = useRouter() + + useRouteChanged(onClose) + + /** + * Scenario: Menu is open on mobile, and user resizes to desktop/tablet viewport. + * Result: We'll close the menu + */ + const showOnBreakpoint = useBreakpointValue({ base: true, lg: false }) + + React.useEffect(() => { + if (showOnBreakpoint == false) { + onClose() + } + }, [showOnBreakpoint]) + + useUpdateEffect(() => { + if (isOpen) { + requestAnimationFrame(() => { + closeBtnRef.current?.focus() + }) + } + }, [isOpen]) + + const [shadow, setShadow] = React.useState() + + return ( + + {isOpen && ( + + + + + + + + + + + + + Docs + + Guides + + Team + + + + + { + setShadow(scrolled ? "md" : undefined) + }} + > + + + + + + )} + + ) + } + + const ScrollView = (props: BoxProps & { onScroll?: any }) => { + const { onScroll, ...rest } = props + const [y, setY] = React.useState(0) + const elRef = React.useRef() + const { scrollY } = useElementScroll(elRef) + React.useEffect(() => { + return scrollY.onChange(() => setY(scrollY.get())) + }, [scrollY]) + + useUpdateEffect(() => { + onScroll?.(y > 5 ? true : false) + }, [y]) + + return ( + + ) + } + + export const MobileNavButton = React.forwardRef( + (props: IconButtonProps, ref: React.Ref) => { + return ( + } + {...props} + /> + ) + }, + ) + \ No newline at end of file diff --git a/layouts/nav.tsx b/layouts/nav.tsx new file mode 100644 index 00000000..4104d8bb --- /dev/null +++ b/layouts/nav.tsx @@ -0,0 +1,186 @@ +import { + chakra, + Flex, + Box, + HStack, + Icon, + IconButton, + Link, + useColorMode, + useColorModeValue, + useDisclosure, + useUpdateEffect, + Menu, + MenuButton, + MenuList, + MenuItem, + MenuDivider, + Image +} 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, FaRegBookmark, FaChartBar, FaHome } from "react-icons/fa" +import Logo, { LogoIcon } from "src/components/logo" +import { MobileNavButton, MobileNavContent } from "./mobile-nav" +import AlgoliaSearch from "src/components/search/algolia-search" + + +const DiscordIcon = (props) => ( + + + +) + +const GithubIcon = (props) => ( + + + +) + +function HeaderContent() { + const mobileNav = useDisclosure() + + const { toggleColorMode: toggleMode } = useColorMode() + const text = useColorModeValue("dark", "light") + const SwitchIcon = useColorModeValue(FaMoon, FaSun) + const mobileNavBtnRef = React.useRef() + + useUpdateEffect(() => { + mobileNavBtnRef.current?.focus() + }, [mobileNav.isOpen]) + + return ( + <> + + + + + + + + + + + + + Home + Tags + + + + + + + + + + + } + /> + + } + aria-label="Options" + ml={{ base: "0", md: "2" }} + /> + + + Fluffybuns the destroyer + Sunface + + + }>Dashboard + }>Bookmarks + + }>Account Settings + }>Log out + + + + + + + + ) +} + +function Header(props) { + const bg = useColorModeValue("white", "gray.800") + 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" + pos="fixed" + top="0" + zIndex="3" + bg={bg} + left="0" + right="0" + borderTop="4px solid" + borderTopColor="teal.400" + width="full" + {...props} + > + + + + + ) +} + +export default Header diff --git a/layouts/page-container.tsx b/layouts/page-container.tsx new file mode 100644 index 00000000..d8e9cf02 --- /dev/null +++ b/layouts/page-container.tsx @@ -0,0 +1,66 @@ +import { Badge, Box, chakra } from "@chakra-ui/react" +import { SkipNavContent, SkipNavLink } from "@chakra-ui/skip-nav" +import Container from "components/container" +import Footer from "./footer" +import Nav from "./nav" +import SEO from "components/seo" +import { useRouter } from "next/router" +import * as React from "react" +import PageTransition from "src/components/page-transition" +import siteConfig from "configs/site-config" + +function useHeadingFocusOnRouteChange() { + const router = useRouter() + + React.useEffect(() => { + const onRouteChange = () => { + const [heading] = Array.from(document.getElementsByTagName("h1")) + heading?.focus() + } + router.events.on("routeChangeComplete", onRouteChange) + return () => { + router.events.off("routeChangeComplete", onRouteChange) + } + }, []) +} + +interface PageContainerProps { + children: React.ReactNode +} + +function PageContainer(props: PageContainerProps) { + const { children } = props + useHeadingFocusOnRouteChange() + + return ( + <> + + Skip to Content +