From 14ef343cdade5c8cb94ea25b0e2e68ad316e8917 Mon Sep 17 00:00:00 2001 From: Chester How Date: Sat, 11 Mar 2023 15:15:23 +0800 Subject: [PATCH] 2.0: Foldaway (#16) --- .babelrc | 15 - .env.example | 1 - .eslintrc.js | 33 - .eslintrc.json | 12 + .gitignore | 112 +- .prettierrc | 5 + .prettierrc.js | 6 - README.md | 46 +- components/Paragraph.tsx | 11 + components/Project.tsx | 61 + components/Section.tsx | 15 + components/ThemePicker.tsx | 74 + components/Tooltip.tsx | 53 + components/User.tsx | 39 + components/icons/ArrowRightIcon.tsx | 18 + components/icons/MoonIcon.tsx | 18 + components/icons/SunIcon.tsx | 26 + components/icons/SystemIcon.tsx | 20 + components/logo/Logo.tsx | 18 + content/post/2020-11-15-a-whole-new-post.mdx | 10 - .../site_configuration/site-configuration.mdx | 43 - lib/useHasMounted.ts | 11 + netlify.toml | 8 - next-env.d.ts | 4 +- next.config.js | 43 +- package.json | 84 +- pages/_app.tsx | 15 + pages/_document.tsx | 13 + pages/index.tsx | 268 + postcss.config.js | 6 + public/android-chrome-192x192.png | Bin 0 -> 2039 bytes public/android-chrome-384x384.png | Bin 0 -> 4610 bytes public/apple-touch-icon.png | Bin 0 -> 1672 bytes public/browserconfig.xml | 9 + public/favicon-16x16.png | Bin 0 -> 622 bytes public/favicon-32x32.png | Bin 0 -> 861 bytes public/favicon.ico | Bin 15086 -> 15086 bytes public/favicon.png | Bin 1571 -> 0 bytes public/mstile-150x150.png | Bin 0 -> 2428 bytes public/og.png | Bin 32348 -> 15381 bytes public/robots.txt | 2 - public/safari-pinned-tab.svg | 21 + public/site.webmanifest | 19 + src/assets/images/computer-guy.svg | 242 - src/assets/images/ie9.svg | 1 - src/assets/images/logo.svg | 23 - src/assets/images/triangle.svg | 1 - src/buildCache.ts | 41 - src/cms/CMSContextWrapper.tsx | 19 - src/cms/ErrorFallback.tsx | 16 - src/cms/MDX.tsx | 93 - src/cms/config.yml | 73 - src/cms/oauth/provider.ts | 23 - src/cms/types.d.ts | 19 - src/cms/util.ts | 53 - src/components/ComponentWithSVG.tsx | 29 - src/components/Footer.tsx | 36 - src/components/Header.tsx | 69 - src/components/Link.tsx | 19 - src/components/Member.tsx | 57 - src/components/Project.tsx | 98 - src/components/SEO.tsx | 52 - src/components/StyleInjector.tsx | 26 - src/components/styled.tsx | 44 - src/config.tsx | 9 - src/constants.ts | 20 - src/contexts/SiteConfigurationContext.ts | 7 - src/layouts/Layout.tsx | 18 - src/lib/GraphQL.d.ts | 23 - src/lib/api.ts | 122 - src/mdxComponents.tsx | 3 - src/pages/_app.tsx | 19 - src/pages/_document.tsx | 59 - src/pages/admin.tsx | 72 - src/pages/api/cms-auth.ts | 13 - src/pages/api/cms-auth/auth.ts | 14 - src/pages/api/cms-auth/callback.ts | 61 - src/pages/api/cms-auth/success.ts | 7 - src/pages/index.tsx | 61 - src/pages/post/[slug].tsx | 94 - src/pages/projects.tsx | 40 - src/styled.d.ts | 8 - src/styles/global-styles.ts | 35 - src/styles/theme.ts | 32 - src/types.d.ts | 21 - src/util/generateSlug.tsx | 8 - styles/globals.css | 26 + tailwind.config.js | 70 + tsconfig.json | 86 +- types/github.d.ts | 41 + yarn.lock | 9533 ++++------------- 91 files changed, 3283 insertions(+), 9392 deletions(-) delete mode 100644 .babelrc delete mode 100644 .env.example delete mode 100644 .eslintrc.js create mode 100644 .eslintrc.json create mode 100644 .prettierrc delete mode 100644 .prettierrc.js create mode 100644 components/Paragraph.tsx create mode 100644 components/Project.tsx create mode 100644 components/Section.tsx create mode 100644 components/ThemePicker.tsx create mode 100644 components/Tooltip.tsx create mode 100644 components/User.tsx create mode 100644 components/icons/ArrowRightIcon.tsx create mode 100644 components/icons/MoonIcon.tsx create mode 100644 components/icons/SunIcon.tsx create mode 100644 components/icons/SystemIcon.tsx create mode 100644 components/logo/Logo.tsx delete mode 100644 content/post/2020-11-15-a-whole-new-post.mdx delete mode 100644 content/site_configuration/site-configuration.mdx create mode 100644 lib/useHasMounted.ts delete mode 100644 netlify.toml create mode 100644 pages/_app.tsx create mode 100644 pages/_document.tsx create mode 100644 pages/index.tsx create mode 100644 postcss.config.js create mode 100644 public/android-chrome-192x192.png create mode 100644 public/android-chrome-384x384.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/browserconfig.xml create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png delete mode 100644 public/favicon.png create mode 100644 public/mstile-150x150.png delete mode 100644 public/robots.txt create mode 100644 public/safari-pinned-tab.svg create mode 100644 public/site.webmanifest delete mode 100644 src/assets/images/computer-guy.svg delete mode 100644 src/assets/images/ie9.svg delete mode 100644 src/assets/images/logo.svg delete mode 100644 src/assets/images/triangle.svg delete mode 100644 src/buildCache.ts delete mode 100644 src/cms/CMSContextWrapper.tsx delete mode 100644 src/cms/ErrorFallback.tsx delete mode 100644 src/cms/MDX.tsx delete mode 100644 src/cms/config.yml delete mode 100644 src/cms/oauth/provider.ts delete mode 100644 src/cms/types.d.ts delete mode 100644 src/cms/util.ts delete mode 100644 src/components/ComponentWithSVG.tsx delete mode 100644 src/components/Footer.tsx delete mode 100644 src/components/Header.tsx delete mode 100644 src/components/Link.tsx delete mode 100644 src/components/Member.tsx delete mode 100644 src/components/Project.tsx delete mode 100644 src/components/SEO.tsx delete mode 100644 src/components/StyleInjector.tsx delete mode 100644 src/components/styled.tsx delete mode 100644 src/config.tsx delete mode 100644 src/constants.ts delete mode 100644 src/contexts/SiteConfigurationContext.ts delete mode 100644 src/layouts/Layout.tsx delete mode 100644 src/lib/GraphQL.d.ts delete mode 100644 src/lib/api.ts delete mode 100644 src/mdxComponents.tsx delete mode 100644 src/pages/_app.tsx delete mode 100644 src/pages/_document.tsx delete mode 100644 src/pages/admin.tsx delete mode 100644 src/pages/api/cms-auth.ts delete mode 100644 src/pages/api/cms-auth/auth.ts delete mode 100644 src/pages/api/cms-auth/callback.ts delete mode 100644 src/pages/api/cms-auth/success.ts delete mode 100644 src/pages/index.tsx delete mode 100644 src/pages/post/[slug].tsx delete mode 100644 src/pages/projects.tsx delete mode 100644 src/styled.d.ts delete mode 100644 src/styles/global-styles.ts delete mode 100644 src/styles/theme.ts delete mode 100644 src/types.d.ts delete mode 100644 src/util/generateSlug.tsx create mode 100644 styles/globals.css create mode 100644 tailwind.config.js create mode 100644 types/github.d.ts diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 94d73af..0000000 --- a/.babelrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "presets": [ - "next/babel" - ], - "plugins": [ - [ - "styled-components", - { - "ssr": true, - "displayName": true, - "preprocess": false - } - ] - ] -} diff --git a/.env.example b/.env.example deleted file mode 100644 index f9dac60..0000000 --- a/.env.example +++ /dev/null @@ -1 +0,0 @@ -GITHUB_API_TOKEN= diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 6342560..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,33 +0,0 @@ -// Based on https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project - -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - }, - plugins: ['simple-import-sort'], - settings: { - react: { - version: 'detect', - }, - }, - extends: [ - 'plugin:react-hooks/recommended', - 'plugin:react/recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - ], - rules: { - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'sort-imports': 'off', - 'import/order': 'off', - 'react/prop-types': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/ban-ts-comment': 'warn', - }, -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..a9815f3 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "plugins": ["simple-import-sort"], + "extends": ["next/core-web-vitals", "plugin:prettier/recommended"], + "rules": { + // Import formatting. + "simple-import-sort/imports": "warn", + "simple-import-sort/exports": "warn", + "import/first": "warn", + "import/newline-after-import": "warn", + "import/no-duplicates": "warn" + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0b47ec7..c87c9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,96 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# Created by https://www.gitignore.io/api/node -# Edit at https://www.gitignore.io/?templates=node +# dependencies +/node_modules +/.pnp +.pnp.js -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache +# testing +/coverage -# Optional REPL history -.node_repl_history +# next.js +/.next/ +/out/ -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# End of https://www.gitignore.io/api/node +# production +/build +# misc .DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* -# gatsby files -dist/ +# local env files +.env*.local +# vercel .vercel -buildCache.json +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..530dd7e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": true +} \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index f89f162..0000000 --- a/.prettierrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - trailingComma: 'es5', - tabWidth: 2, - semi: true, - singleQuote: true -} diff --git a/README.md b/README.md index fd24fd8..965a122 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,38 @@ -# landing -[![Netlify Status](https://api.netlify.com/api/v1/badges/744c7980-7a7c-4642-bc4e-7ebd7ffe83f0/deploy-status)](https://app.netlify.com/sites/fch-landing/deploys) +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). -### Developing -```shell -$ yarn dev -``` +## Getting Started -and +First, run the development server: -```shell -$ npx netlify-cms-proxy-server +```bash +npm run dev +# or +yarn dev +# or +pnpm dev ``` +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! -### Deployment -Create a GitHub App (this is an alternative to GitHub OAuth Apps and allow for scoping to a single repo). +## Deploy on Vercel -Generate the client secret and then set these env vars in your production deployment host: -- `OAUTH_CLIENT_ID` -- `OAUTH_CLIENT_SECRET` -- `URL` (Netlify sets this automatically) +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. -If necessary, this should work with BitBucket and GitLab as well, although you will need to set `OAUTH_PROVIDER` as well. +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/components/Paragraph.tsx b/components/Paragraph.tsx new file mode 100644 index 0000000..e06faf0 --- /dev/null +++ b/components/Paragraph.tsx @@ -0,0 +1,11 @@ +type ParagraphProps = { + children: React.ReactNode; +}; + +export function Paragraph(props: ParagraphProps) { + return ( +

+ {props.children} +

+ ); +} diff --git a/components/Project.tsx b/components/Project.tsx new file mode 100644 index 0000000..3b26931 --- /dev/null +++ b/components/Project.tsx @@ -0,0 +1,61 @@ +import classNames from "classnames"; +import Image from "next/image"; + +import { Tooltip } from "./Tooltip"; + +type ProjectProps = { + project: GitHub.GraphQL.API.PinnableItemEdge; + contributors: GitHub.GraphQL.API.User[]; +}; + +export default function Project(props: ProjectProps) { + return ( +
+ +
+

+ + {props.project.node.name} + + +  ↗ + +

+

+ {props.project.node.description} +

+
+
+ {props.contributors.map((contributor) => ( + + {contributor.login} + + ))} +
+
+
+ ); +} diff --git a/components/Section.tsx b/components/Section.tsx new file mode 100644 index 0000000..d99a386 --- /dev/null +++ b/components/Section.tsx @@ -0,0 +1,15 @@ +type SectionProps = { + heading: string; + children: React.ReactNode; +}; +4; +export function Section(props: SectionProps) { + return ( +
+

+ {props.heading} +

+ {props.children} +
+ ); +} diff --git a/components/ThemePicker.tsx b/components/ThemePicker.tsx new file mode 100644 index 0000000..8b35938 --- /dev/null +++ b/components/ThemePicker.tsx @@ -0,0 +1,74 @@ +import classNames from "classnames"; +import { useTheme } from "next-themes"; + +import { useHasMounted } from "@/lib/useHasMounted"; + +import { MoonIcon } from "./icons/MoonIcon"; +import { SunIcon } from "./icons/SunIcon"; +import { SystemIcon } from "./icons/SystemIcon"; + +type ThemeToggleProps = { + icon: () => JSX.Element; + onClick: () => void; + active: boolean; +}; + +function ThemePickerToggle(props: ThemeToggleProps) { + const { icon: Icon } = props; + + return ( + + ); +} + +export default function ThemePicker() { + const { theme, setTheme } = useTheme(); + const hasMounted = useHasMounted(); + + if (!hasMounted) return null; + + return ( +
+ setTheme("light")} + active={theme === "light"} + /> + setTheme("dark")} + active={theme === "dark"} + /> + setTheme("system")} + active={theme === "system"} + /> +
+ ); +} diff --git a/components/Tooltip.tsx b/components/Tooltip.tsx new file mode 100644 index 0000000..0dc6fe0 --- /dev/null +++ b/components/Tooltip.tsx @@ -0,0 +1,53 @@ +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import classNames from "classnames"; + +type TooltipProps = { + children: React.ReactNode; + content: string; +} & Pick< + React.ComponentProps, + "side" | "align" +>; + +export function Tooltip(props: TooltipProps) { + return ( + + + {props.children} + + + {typeof window !== "undefined" && ( + + + {props.content} + + + )} + + ); +} diff --git a/components/User.tsx b/components/User.tsx new file mode 100644 index 0000000..a6e995a --- /dev/null +++ b/components/User.tsx @@ -0,0 +1,39 @@ +import classNames from "classnames"; +import Image from "next/image"; + +type UserProps = { + user: GitHub.GraphQL.API.User; +}; + +export function User(props: UserProps) { + return ( + +
+ {props.user.login} + + {props.user.name} + +
+
+ ); +} diff --git a/components/icons/ArrowRightIcon.tsx b/components/icons/ArrowRightIcon.tsx new file mode 100644 index 0000000..127c2f2 --- /dev/null +++ b/components/icons/ArrowRightIcon.tsx @@ -0,0 +1,18 @@ +export function ArrowRightIcon() { + return ( + + + + + ); +} diff --git a/components/icons/MoonIcon.tsx b/components/icons/MoonIcon.tsx new file mode 100644 index 0000000..42f9bc6 --- /dev/null +++ b/components/icons/MoonIcon.tsx @@ -0,0 +1,18 @@ +export function MoonIcon() { + return ( + + + + ); +} diff --git a/components/icons/SunIcon.tsx b/components/icons/SunIcon.tsx new file mode 100644 index 0000000..e5392ec --- /dev/null +++ b/components/icons/SunIcon.tsx @@ -0,0 +1,26 @@ +export function SunIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/components/icons/SystemIcon.tsx b/components/icons/SystemIcon.tsx new file mode 100644 index 0000000..735bcce --- /dev/null +++ b/components/icons/SystemIcon.tsx @@ -0,0 +1,20 @@ +export function SystemIcon() { + return ( + + + + + + ); +} diff --git a/components/logo/Logo.tsx b/components/logo/Logo.tsx new file mode 100644 index 0000000..c112ff1 --- /dev/null +++ b/components/logo/Logo.tsx @@ -0,0 +1,18 @@ +type LogoProps = { + width?: number; + height?: number; +}; + +export function Logo(props: LogoProps) { + return ( + + + + ); +} diff --git a/content/post/2020-11-15-a-whole-new-post.mdx b/content/post/2020-11-15-a-whole-new-post.mdx deleted file mode 100644 index a959c50..0000000 --- a/content/post/2020-11-15-a-whole-new-post.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: A Whole New Post -content: >- - # Lorem ipsum dolor sit amet! - - - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -pub_date: 2020-11-15T07:36:39.415Z -author: John Smith ---- diff --git a/content/site_configuration/site-configuration.mdx b/content/site_configuration/site-configuration.mdx deleted file mode 100644 index 36e0bd6..0000000 --- a/content/site_configuration/site-configuration.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Site Configuration -menu_items: - - name: About Us - link: /# - children: - - children: - - name: Apple - link: /apple - - name: Banana - link: /banana - - name: Cherry - link: /cherry - - name: Durian - link: /durian - name: Amazing - link: /amazing - - name: Yes - link: /yes - - name: Membership - link: /membership-application - - name: Cabbage - link: /cabbage - - name: Events - link: /events - - name: Lettuce - link: /lettuce - children: - - name: Tomato - link: /tomato - - name: Potato - link: /#potato - children: - - name: French Fries - link: /french-fries - - name: Potato Salad - link: /potato-salad - - name: News - link: /news - - name: Contact Us - link: /contact-us - ---- diff --git a/lib/useHasMounted.ts b/lib/useHasMounted.ts new file mode 100644 index 0000000..fed8c26 --- /dev/null +++ b/lib/useHasMounted.ts @@ -0,0 +1,11 @@ +import { useEffect, useState } from "react"; + +export function useHasMounted() { + const [hasMounted, setHasMounted] = useState(false); + + useEffect(() => { + setHasMounted(true); + }, []); + + return hasMounted; +} diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index f108349..0000000 --- a/netlify.toml +++ /dev/null @@ -1,8 +0,0 @@ -[build] - command = "yarn build" - -[dev] - command = "yarn dev" - -[[plugins]] - package = "@netlify/plugin-nextjs" diff --git a/next-env.d.ts b/next-env.d.ts index c6643fd..4f11a03 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,3 +1,5 @@ /// -/// /// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js index ff5b0b5..fd2b230 100644 --- a/next.config.js +++ b/next.config.js @@ -1,33 +1,14 @@ -module.exports = { - target: 'serverless', - - webpack(config) { - config.module.rules.push({ - test: /\.svg$/, - use: ['@svgr/webpack', 'url-loader'], - }); - - config.module.rules.push({ - test: /\.mdx?$/, - use: 'raw-loader', - }); - - config.module.rules.push({ - test: /\.ya?ml$/, - type: 'json', // Required by Webpack v4 - use: 'yaml-loader', - }); - - config.resolve.fallback = { - fs: false, - path: require.resolve('path-browserify'), - }; - - return config; - }, - - env: { - URL: process.env.URL, - GITHUB_API_TOKEN: process.env.GITHUB_API_TOKEN, +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "avatars.githubusercontent.com", + }, + ], }, }; + +module.exports = nextConfig; diff --git a/package.json b/package.json index 14ae1a0..34c1a76 100644 --- a/package.json +++ b/package.json @@ -1,59 +1,39 @@ { - "name": "next-base", - "version": "1.0.0", - "main": "index.js", - "repository": "git@github.com:fourthclasshonours/landing.git", - "license": "UNLICENSED", - "devDependencies": { - "@svgr/webpack": "^5.5.0", - "@types/node": "^14.14.21", - "@types/react": "^17.0.0", - "@typescript-eslint/eslint-plugin": "^4.28.0", - "@typescript-eslint/parser": "^4.28.0", - "babel-plugin-styled-components": "^1.12.0", - "css-loader": "^5.1.2", - "eslint": "^7.29.0", - "eslint-config-next": "^11.0.1", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "eslint-plugin-react": "^7.24.0", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-simple-import-sort": "^7.0.0", - "raw-loader": "^4.0.2", - "typescript": "^4.3.4", - "url-loader": "^4.1.1", - "yaml-loader": "^0.6.0" - }, + "name": "landing", + "version": "0.1.0", + "private": true, "scripts": { - "build": "next build", "dev": "next dev", - "start": "next start" + "build": "next build", + "start": "next start", + "lint": "next lint", + "vercel:env-pull": "vercel env pull .env.local" }, "dependencies": { - "@mdx-js/mdx": "^1.6.22", - "@mdx-js/react": "^1.6.22", - "@types/js-yaml": "^4.0.0", - "@types/lodash": "^4.14.167", - "@types/mdx-js__react": "^1.5.3", - "@types/proper-lockfile": "^4.1.1", - "@types/simple-oauth2": "^4.1.0", - "@types/styled-components": "^5.1.7", - "buble-jsx-only": "^0.19.8", - "client-oauth2": "^4.3.3", - "gray-matter": "^4.0.2", - "lodash": "^4.17.19", - "netlify-cms-app": "^2.15.20", - "next": "^11.0.1", - "path-browserify": "^1.0.1", - "prettier": "^1.19.1", - "prop-types": "^15.7.2", - "proper-lockfile": "^4.1.2", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-error-boundary": "^3.1.0", - "sass": "^1.16.0", - "simple-oauth2": "^4.2.0", - "styled-components": "^5.0.1", - "styled-components-breakpoint": "^3.0.0-preview.20" + "@next/font": "13.1.6", + "@radix-ui/react-tooltip": "^1.0.3", + "@types/node": "18.14.0", + "@types/react": "18.0.28", + "@types/react-dom": "18.0.11", + "classnames": "^2.3.2", + "eslint": "8.34.0", + "eslint-config-next": "13.1.6", + "next": "13.1.6", + "next-themes": "^0.2.1", + "octokit": "^2.0.14", + "react": "18.2.0", + "react-dom": "18.2.0", + "typescript": "4.9.5" + }, + "devDependencies": { + "@tailwindcss/line-clamp": "^0.4.2", + "autoprefixer": "^10.4.13", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-simple-import-sort": "^10.0.0", + "postcss": "^8.4.21", + "prettier": "^2.8.4", + "prettier-plugin-tailwindcss": "^0.2.3", + "tailwindcss": "^3.2.7" } } diff --git a/pages/_app.tsx b/pages/_app.tsx new file mode 100644 index 0000000..bf59329 --- /dev/null +++ b/pages/_app.tsx @@ -0,0 +1,15 @@ +import "@/styles/globals.css"; + +import * as RadixTooltip from "@radix-ui/react-tooltip"; +import type { AppProps } from "next/app"; +import { ThemeProvider } from "next-themes"; + +export default function App({ Component, pageProps }: AppProps) { + return ( + + + + + + ); +} diff --git a/pages/_document.tsx b/pages/_document.tsx new file mode 100644 index 0000000..ffc3f3c --- /dev/null +++ b/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Head, Html, Main, NextScript } from "next/document"; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 0000000..79e0ec7 --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,268 @@ +import { Inter } from "@next/font/google"; +import classNames from "classnames"; +import { InferGetStaticPropsType } from "next"; +import Head from "next/head"; +import { Octokit } from "octokit"; + +import { ArrowRightIcon } from "@/components/icons/ArrowRightIcon"; +import { Logo } from "@/components/logo/Logo"; +import { Paragraph } from "@/components/Paragraph"; +import Project from "@/components/Project"; +import { Section } from "@/components/Section"; +import ThemePicker from "@/components/ThemePicker"; +import { User } from "@/components/User"; + +const inter = Inter({ + subsets: ["latin"], + variable: "--font-inter", + display: "swap", +}); + +export default function Home( + props: InferGetStaticPropsType +) { + return ( + <> + + Foldaway + + + {/* Open graph */} + + + + + + + + {/* twitter */} + + + + + + {/* Favicon */} + + + + + + + + + {/* Others */} + + + +
+
+ + +
+ + It all started from the foldaway table in Duncan's room. Back + then, on the occasional weekend, we'll all cram in his room, + assemble the foldaway table, and start hacking at silly projects + that are, more often than not, just plain pointless. +
+
+ Pointless yes, but also fun. It's been a while since + we've all gathered at our foldaway table, but its spirit + lives on in the silly pointless projects we continue hacking on. +
+
+ +
+
+ {props.organization.membersWithRole.edges + .filter((edge) => !edge.node.login.endsWith("-bot")) + .map((edge) => ( + + ))} +
+
+ +
+
+ {props.organization.pinnedItems.edges.map((pinnableItemEdge) => ( + + ))} + +
+
+ +
+ +
+
+
+ + ); +} + +export async function getStaticProps() { + if (process.env.NEXT_PUBLIC_ORG_NAME === undefined) return; + + const octokit = new Octokit({ auth: process.env.GITHUB_API_TOKEN }); + + const { organization } = await octokit.graphql<{ + organization: GitHub.GraphQL.API.Organization; + }>(` + query PinnedReposQuery { + organization(login: "${process.env.NEXT_PUBLIC_ORG_NAME}") { + url + membersWithRole(first: 50) { + edges { + node { + name + login + avatarUrl + websiteUrl + url + } + cursor + } + } + pinnedItems(types: [REPOSITORY], first: 10) { + edges { + node { + ... on Repository { + name + description + url + } + } + cursor + } + } + } + } + `); + + /** + * Map of org member login (a.k.a. handle) to {@link GitHub.GraphQL.API.User} + */ + const orgMembersMap: Record = {}; + + for (const orgMemberEdge of organization.membersWithRole.edges) { + orgMembersMap[orgMemberEdge.node.login] = orgMemberEdge.node; + } + + /** + * Map of repo name to its contributors + */ + const repoContributorsMap: Record = {}; + + for (const pinnableItemEdge of organization.pinnedItems.edges) { + const repo = pinnableItemEdge.node.name; + + /** + * Use REST API to query for {@link repo}'s contributors + */ + const contributorsResponse = await octokit.request( + "GET /repos/{owner}/{repo}/contributors", + { + owner: process.env.NEXT_PUBLIC_ORG_NAME, + repo, + } + ); + + const repoContributors: GitHub.GraphQL.API.User[] = []; + + for (const contributor of contributorsResponse.data) { + /** + * Filter out non-user contributors such as dependabot + */ + if (contributor.type !== "User") continue; + + /** + * Attempt to retrieve GraphQL user information from Organisation members + */ + const orgMember = orgMembersMap[contributor.login!]; + + if (orgMember != null) { + repoContributors.push(orgMember); + continue; + } + + /** + * Put together a shell GraphQL user for outside contributor + */ + repoContributors.push({ + login: contributor.login!, + name: contributor.name ?? contributor.login!, + avatarUrl: contributor.avatar_url!, + websiteUrl: contributor.url!, + url: "", + }); + } + + repoContributorsMap[repo] = repoContributors; + } + + return { + props: { + organization, + repoContributorsMap, + }, + }; +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..3b51366104279fcd62c261cd12271cd1325408cd GIT binary patch literal 2039 zcmbtVYdF;V7XJO`VlXj8$R(4>DA#emwVs}*0*)tafEZ9=cJ6inJYrylr_o}L4|ef%2jC|n0B{-r>*5wX13)YZfZ0F* z$OQl>(~6!Ru@MW1AU9_RAj)8L^27{7r@A|0rjb|)E7|+S+2UamMN|hnulNu1gC`Gq zIjdlnBC{Ri${za%H)y4DIY*Q(MQH6>+Zu3(*xUOXasEJJw^^fEd+Lo$OD#nsYTh!ipCrS>C%UlIwgku*XZl{MX|}7CzS2hQ|>f=YKW4B8dymy1^Tx9CvP)T z-?`B9e_Tm3v9%!!%h?&AJHf`4smWgTVG$_K`y!Iy7|XlRf+upJ+8WV>QsD5`7pxJ# zJ>@`#&vo(u>E!{LrGrtZ0^G@q9gP{C*K z`q3q(3W#5|XwWkpRLYs!^sVm`>|E|U6lveD)`n)JGK(Ov(lffh|doA zi=sV}z!ZWv4J{WEpTCi{I!4UX#QSb?$th%h88@PDE;xB)_+l)A`LT6k<#v!@Xl@ic zFAY^=(i*eH*q(do>9ItrRi>}hX%Egv#vqX3R1)v_&2H@1Tj!BI=a1PtphR&F6kYCCe6Xtumx@`wc%ftdUnwyIeME1bb0$zOev?L987o? zDFjgb@$16cvd>~Qzu{x{$u?Q^ArQZr8ymVkUi1ik%DsSX5w=4L&KBKe5Fg)KLTyhK ztfAMS-c?ido0$GubS-pqHCe;R7S`#Dg~A&H3Uint;v)vEb(R^csEd|_t~b{P`>E)M zD~osZ$#1LFw+)sDoIM(1* z`vB6q=VT-DDi=WY&tlSV^ou9@O$TgvrS3*B3 zg+K<{VdfKI(ibfzsnWY3?oPT+`nd3*-3FRhM3L?GOr1(D{reS~R>B@JxfIiQzs>0D z=x%i2O;Nk6w%ZF+Y2Qk%uKBJM>Q?6tpfWC6X}RI8y@9xG{5*5&%5|*16gV$DHi=n6 zckg{N?1wK#8dJV~$4QErp)tmua-J&F`+z3IpuVd+q{ZM7)gywuTOyc0r7j8Dwu>Mr zSQfSDc!e_E`_89oWm!{hB!YhdPcY2?fk_`IDe6r{ z5>SH!3x2TeX+4f;#C}KsMdOH)HkWH5^os!9JpxFH*lFjV5&=ivk8G_9ZEM42B?QhC z92W9h<~n(~t?B{qSHDDUZaRt;QtXL|=65X$t{*34O*FF}?|L?WNFDI&&Qz`?^RAk6 zIn%BX!ep`K6STFy)qBGH_)b!lpGu# zDh6OeGBGtEnHm@ydyy>2<`!gQGd&WCOd_2$Cl&pNAtEv){LJP5ZqPmZGhS>s{*#vv z-Sc!Do)#T>Cj3Guo_?7YiVvsJg8_&y8eiEW8Rflucl+UvPU@s5KoYQq!B_=?f?JLv zQUUJ(o4p7@5~{rL9eq8mO`T2ZO_&bYh3#qxW|igXEB5Aj;uV1Ec*vo`J}~uPz6pR( literal 0 HcmV?d00001 diff --git a/public/android-chrome-384x384.png b/public/android-chrome-384x384.png new file mode 100644 index 0000000000000000000000000000000000000000..feb8a5ab0c293f774c8bd88402bc7bfc7074d62d GIT binary patch literal 4610 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 literal 0 HcmV?d00001 diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0299810d57dddd24d448028490fe2331bff53f10 GIT binary patch literal 1672 zcma)+dpHw%7{`B->s*eBLTPe{v^9p9OXk|hFqb2$8Fr!5A)9NgwQ{LWqoiE7&}~QN z=(6G@B{gNNMPdt)TS~etROIaZd7kr}=jo64{XXyKeZJ58y#IWU2IKs+HH|d^0NU8? z-gt#x|EJUy4XnAi^PNIgQZRuS02&J+i$oR042#>24+J2~5&-5A0KO^^a|(b|BmmPf z0H8|&Se;zi9O9~2tcVTp^9IZLg`!r)q(;XE`lwARLsXr#(P!@}kO~~@jS0(;&d4N5 zq2X)Q-VSvKRKJ^_H|e+e=P0F%o6?iJTP8d1E#3)oqfE-PKSrm^ zhG-MkZTDBt9#(}#jl+y31re|UU;7#Z^%}hsR23H0+dS&fkKpAx(Wvq61vh7FCA}*< zJHlNN^toD&2>yXAek&{=%05C_A=K#DD?9Mu_-uR*#razdhtO%3NnZG>E{xHUx9`s+ zTQQ2yvbxV()R>i=WZkhINlHeCZasg_i)1JHUbITi+8AHM%?{H<->MGd3@k@^Xc`+6 zxbUvUJ~Uh6nuJJhnWVC28YIfE4jyi3J5Z5uJ?V9xYU^hEyJPKvXNW^@FSV$y?E8&T ziJjRpX-2CxDo%6`SqU=uwA|k>on_&ETOR4I9skBX`F_#PJt(N6`rsQe)UYV{buW81 zu-;(3J3L$ELkZ5Oi##RE+Oq&{v#C19IiJN@dTD)cZvme!jm^6zQ|&ZQoys0J-y!$?gn}aExJr~C9W+qTZsW0 zb@J_Umm0S>+EbhjS@NX-mHP0f2;r`)7e424#!hF;?Ql%z^XrDZga_k3T~kaog!@QZx!|c@;lKH(&41Cp-LEd2XP7xrXFPNtA(sBi*gnc&$ovnMWjop-0 z%l~+(>=`XGk=eZUJCiT~@fMEL+jFHV(ucd8d-|C;-j=2i7r#mAop?tXuVIS)j4f#r z)UG9)d}h*agwpvlkWu(62Dv&hpDNWd8LqoMT*>5^HJGuVbwByS7C&NN)X8g^VW#CS z;@*YLs8`K8dGMG3CF?G)I|rXg zwe>}L1P7f;ha#LpKGmL>*DapN>t8W9fN{$#n{wJ_IwG@3VL8U;ThTTO_tse(r@ z!p+;Xf_q5#YlKhz4W=iSIkHHL#|rX!aWKErq>R!?xHJiOc2NZ{Gi?#?!-!uVj}QTf zyqdpsOJD3h>M>vFoD_cFa$?qcM^oCZ`9e?9Zj?}IEx$|LmN68qHtt>}=Z^r>tM%v~JsnCECjiz5=gs$wVf_u~0rdU= literal 0 HcmV?d00001 diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000..d416bc5 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #ffffff + + + diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..5a020750b5ee44b5cda3291d8a17a8015f4477d2 GIT binary patch literal 622 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 HuuFdd!stgN literal 0 HcmV?d00001 diff --git a/public/og.png b/public/og.png index a2fdf0c35ffb9260cd224b5f520d5766f1f37dae..fd23b4330d3032bf3ddcffe9953a9fb9b166cc25 100644 GIT binary patch literal 15381 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 BI8Oio literal 32348 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 diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index 1f53798..0000000 --- a/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg new file mode 100644 index 0000000..0772c63 --- /dev/null +++ b/public/safari-pinned-tab.svg @@ -0,0 +1,21 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..c5d00d4 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Foldaway", + "short_name": "Foldaway", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/src/assets/images/computer-guy.svg b/src/assets/images/computer-guy.svg deleted file mode 100644 index 44b6eef..0000000 --- a/src/assets/images/computer-guy.svg +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/images/ie9.svg b/src/assets/images/ie9.svg deleted file mode 100644 index c41684a..0000000 --- a/src/assets/images/ie9.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg deleted file mode 100644 index e786e24..0000000 --- a/src/assets/images/logo.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/images/triangle.svg b/src/assets/images/triangle.svg deleted file mode 100644 index 385962e..0000000 --- a/src/assets/images/triangle.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/buildCache.ts b/src/buildCache.ts deleted file mode 100644 index 27fbf53..0000000 --- a/src/buildCache.ts +++ /dev/null @@ -1,41 +0,0 @@ -import fs from 'fs'; -import lodashGet from 'lodash/get'; -import lodashSet from 'lodash/set'; -import path from 'path'; -import lockfile from 'proper-lockfile'; - -const FILE_CACHE = path.join(process.cwd(), 'buildCache.json'); - -function readCache() { - try { - const rawText = fs.readFileSync(FILE_CACHE, { encoding: 'utf8' }); - - return JSON.parse(rawText) as Record; - } catch (e) { - return {}; - } -} - -export async function get(keyPath: string | string[]): Promise { - if (fs.existsSync(FILE_CACHE) === false) { - fs.writeFileSync(FILE_CACHE, ''); - } - const release = await lockfile.lock(FILE_CACHE, { retries: 10 }); - const cache = readCache(); - await release(); - - return lodashGet(cache, keyPath) ?? null; -} - -export async function set(keyPath: string | string[], value: string) { - if (fs.existsSync(FILE_CACHE) === false) { - fs.writeFileSync(FILE_CACHE, ''); - } - const release = await lockfile.lock(FILE_CACHE, { retries: 10 }); - const cache = readCache(); - - lodashSet(cache, keyPath, value); - await release(); - - fs.writeFileSync(FILE_CACHE, JSON.stringify(cache, null, 2)); -} diff --git a/src/cms/CMSContextWrapper.tsx b/src/cms/CMSContextWrapper.tsx deleted file mode 100644 index 638147a..0000000 --- a/src/cms/CMSContextWrapper.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -import SiteConfigurationContext from '../contexts/SiteConfigurationContext'; - -export interface CMSContextWrapperProps { - siteConfiguration: CMS.SiteConfiguration; -} - -const CMSContextWrapper: React.FC = function(props) { - const { children, siteConfiguration } = props; - - return ( - - {children} - - ); -}; - -export default CMSContextWrapper; diff --git a/src/cms/ErrorFallback.tsx b/src/cms/ErrorFallback.tsx deleted file mode 100644 index ee9919a..0000000 --- a/src/cms/ErrorFallback.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { FallbackProps } from 'react-error-boundary'; - -const ErrorFallback: React.FC = function(props) { - const { error, resetErrorBoundary } = props; - - return ( -

-

Something went wrong:

-
{error.message}
- -
- ); -}; - -export default ErrorFallback; diff --git a/src/cms/MDX.tsx b/src/cms/MDX.tsx deleted file mode 100644 index b4d0842..0000000 --- a/src/cms/MDX.tsx +++ /dev/null @@ -1,93 +0,0 @@ -// Modified from https://github.com/mdx-js/mdx/blob/main/packages/runtime/src/index.js -// -// The MIT License (MIT) -// -// Copyright (c) 2017-2018 Compositor and Vercel, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// @ts-ignore -import mdx from '@mdx-js/mdx'; -import { mdx as createElement, MDXProvider } from '@mdx-js/react'; -// @ts-ignore -import { transform } from 'buble-jsx-only'; -import React from 'react'; -import styled from 'styled-components'; - -const suffix = `return React.createElement( - MDXProvider, - {components}, - React.createElement(MDXContent, props) -)`; - -const Error = styled.pre` - color: #e22424; - display: block; -`; - -interface Props { - scope?: any; - components?: { [name: string]: any }; - remarkPlugins?: any[]; - rehypePlugins?: any[]; -} - -const MDX: React.FC = function({ - scope = {}, - components = {}, - remarkPlugins = [], - rehypePlugins = [], - children, - ...props -}) { - const fullScope = { - mdx: createElement, - MDXProvider, - components, - props, - ...scope, - }; - - let jsx; - - try { - jsx = mdx - .sync(children, { - remarkPlugins, - rehypePlugins, - skipExport: true, - commonmark: true, - }) - .trim(); - } catch (e) { - return An error occurred: {e.message}; - } - - const code = transform(jsx, { objectAssign: 'Object.assign' }).code; - - const keys = Object.keys(fullScope); - const values = Object.values(fullScope); - - // eslint-disable-next-line no-new-func - const fn = new Function('React', ...keys, `${code}\n\n${suffix}`); - - return fn(React, ...values); -}; - -export default MDX; diff --git a/src/cms/config.yml b/src/cms/config.yml deleted file mode 100644 index 2036597..0000000 --- a/src/cms/config.yml +++ /dev/null @@ -1,73 +0,0 @@ -backend: - name: github - branch: main - repo: fourthclasshonours/landing - auth_endpoint: api/cms-auth - use_graphql: true - -media_folder: public/images -public_folder: /images - -local_backend: true - -collections: - - name: 'site_configuration' - label: 'Site Configuration' - folder: 'content/site_configuration' - create: false - extension: 'mdx' - format: 'frontmatter' - fields: - - label: 'Title' - name: 'title' - widget: 'string' - - label: 'Menu Items' - name: 'menu_items' - widget: 'list' - fields: - - label: 'name' - name: 'name' - widget: 'string' - - label: 'link' - name: 'link' - widget: 'string' - - label: 'Children' - name: 'children' - widget: 'list' - fields: - - label: 'name' - name: 'name' - widget: 'string' - - label: 'link' - name: 'link' - widget: 'string' - - label: 'Children' - name: 'children' - widget: 'list' - fields: - - label: 'name' - name: 'name' - widget: 'string' - - label: 'link' - name: 'link' - widget: 'string' - - name: 'post' - label: 'Post' - folder: 'content/post' - create: true - extension: 'mdx' - format: 'frontmatter' - slug: '{{year}}-{{month}}-{{day}}-{{slug}}' - fields: - - label: 'title' - name: 'title' - widget: 'string' - - label: 'Content' - name: 'content' - widget: 'markdown' - - label: 'Published Date' - name: 'pub_date' - widget: 'datetime' - - label: 'Author' - name: 'author' - widget: 'string' diff --git a/src/cms/oauth/provider.ts b/src/cms/oauth/provider.ts deleted file mode 100644 index 0a4042c..0000000 --- a/src/cms/oauth/provider.ts +++ /dev/null @@ -1,23 +0,0 @@ -import ClientOAuth2 from 'client-oauth2'; - -const { - OAUTH_CLIENT_ID, - OAUTH_CLIENT_SECRET, - URL = 'http://localhost:3000', - SCOPES, -} = process.env; - -if (!OAUTH_CLIENT_ID || !OAUTH_CLIENT_SECRET) { - throw new Error('Missing GitHub OAuth'); -} - -const provider = new ClientOAuth2({ - clientId: OAUTH_CLIENT_ID, - clientSecret: OAUTH_CLIENT_SECRET, - accessTokenUri: 'https://github.com/login/oauth/access_token', - authorizationUri: 'https://github.com/login/oauth/authorize', - redirectUri: `${URL}/api/cms-auth/callback`, - scopes: SCOPES?.split(',') ?? ['repo', 'user'], -}); - -export default provider; diff --git a/src/cms/types.d.ts b/src/cms/types.d.ts deleted file mode 100644 index 81e03f9..0000000 --- a/src/cms/types.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare namespace CMS { - interface MenuItem { - name: string; - link: string; - children: MenuItem[]; - } - - interface SiteConfiguration { - title: string; - menu_items: MenuItem[]; - } - - interface Post { - title: string; - content: string; - pub_date: string; - author: string; - } -} diff --git a/src/cms/util.ts b/src/cms/util.ts deleted file mode 100644 index 43027e4..0000000 --- a/src/cms/util.ts +++ /dev/null @@ -1,53 +0,0 @@ -import fs from 'fs'; -import matter from 'gray-matter'; -import yaml from 'js-yaml'; -import path from 'path'; - -import { CMSContextWrapperProps } from './CMSContextWrapper'; - -export function readMDXFile(filePath: string) { - if (fs.existsSync(filePath) === false) { - throw new Error(`File path does not exist: ${filePath}`); - } - - const fileData = fs.readFileSync(filePath, { encoding: 'utf8' }); - const parsedData = matter(fileData, { - engines: { - //@ts-ignore - yaml: s => yaml.safeLoad(s, { schema: yaml.JSON_SCHEMA }), - }, - }); - - const { data } = parsedData; - - return data; -} - -export function readCMSContextWrapperProps(): CMSContextWrapperProps { - return { - siteConfiguration: readSiteConfig(), - }; -} - -export function readSiteConfig() { - const siteConfigDir = path.join(process.cwd(), 'content/site_configuration'); - const configData = readMDXFile( - path.join(siteConfigDir, 'site-configuration.mdx') - ); - - return configData as CMS.SiteConfiguration; -} - -export function readPosts() { - const dir = path.join(process.cwd(), 'content/post'); - - const files = fs.readdirSync(dir).filter(file => file.endsWith('.mdx')); - - const categories = files.map(file => { - const data = readMDXFile(path.join(dir, file)); - - return data; - }); - - return categories as CMS.Post[]; -} diff --git a/src/components/ComponentWithSVG.tsx b/src/components/ComponentWithSVG.tsx deleted file mode 100644 index e7e69c0..0000000 --- a/src/components/ComponentWithSVG.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import computerGuyUrl from '../assets/images/computer-guy.svg'; -import { ReactComponent as Logo } from '../assets/images/ie9.svg'; - -const StyledContainer = styled.div` - position: relative; - height: 200px; - background: url(${computerGuyUrl}) no-repeat; - background-size: contain; -`; - -const StyledLogo = styled(Logo)` - height: 30px; - width: 30px; - margin-top: 120px; - margin-left: 50px; -`; - -const ComponentWithSVG: React.FC = function() { - return ( - - - - ); -}; - -export default ComponentWithSVG; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx deleted file mode 100644 index 96cd583..0000000 --- a/src/components/Footer.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import config from '../config'; - -const Wrapper = styled.footer` - border-top: 1px solid ${props => props.theme.colors.primary}; - text-align: center; - padding: 2rem 0; - display: flex; - justify-content: space-between; - font-size: 14px; -`; - -const Footnote = styled.span` - &:hover { - font-family: 'Comic Sans MS'; - } -`; - -const Copyright = styled.span` - opacity: 0.7; -`; - -const Footer: React.FC = function() { - return ( - - Learning is fun. - - © {new Date().getFullYear()} {config.siteMetadata.title} - - - ); -}; - -export default Footer; diff --git a/src/components/Header.tsx b/src/components/Header.tsx deleted file mode 100644 index 0499869..0000000 --- a/src/components/Header.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { ReactComponent as Logo } from '../assets/images/logo.svg'; -import Link from './Link'; - -const Wrapper = styled.header` - display: grid; - grid-template-columns: 1fr 1fr; - align-items: center; - width: 100%; - margin-bottom: 50px; - padding: 30px 0 20px; - border-bottom: 1px solid ${props => props.theme.colors.primary}; - font-family: ${props => props.theme.secondary}; - font-style: italic; - - @media (max-width: ${props => props.theme.breakMedium}) { - display: block; - text-align: center; - } -`; - -const StyledLink = styled(Link)` - font-size: 28px; - text-decoration: none; - color: ${props => props.theme.colors.primary}; - - &:visited { - color: ${props => props.theme.colors.primary}; - } - - &:hover { - text-decoration: underline; - } -`; - -const StyledLogo = styled(Logo)` - width: 200px; -`; - -const Nav = styled.nav` - display: flex; - justify-content: flex-end; - gap: 5rem; - - @media (max-width: ${props => props.theme.breakMedium}) { - justify-content: center; - gap: 2rem; - margin-top: 1rem; - } -`; - -const Header: React.FC = function() { - return ( - - - - - - - ); -}; - -export default Header; diff --git a/src/components/Link.tsx b/src/components/Link.tsx deleted file mode 100644 index a908466..0000000 --- a/src/components/Link.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import NextLink from 'next/link'; -import React from 'react'; - -interface Props { - className?: string; - href: string; -} - -const Link: React.FC = function(props) { - const { href, children, className } = props; - - return ( - - {children} - - ); -}; - -export default Link; diff --git a/src/components/Member.tsx b/src/components/Member.tsx deleted file mode 100644 index 010d15c..0000000 --- a/src/components/Member.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -const Wrapper = styled.a` - display: inline-block; - font-weight: 500; - font-size: 48px; - line-height: 1; - letter-spacing: -0.04em; - text-decoration: none; - color: ${props => props.theme.colors.primary}; - - &:visited { - color: ${props => props.theme.colors.primary}; - } - - &:hover { - text-decoration: underline; - } - - &:not(:last-child) { - margin-right: 20px; - } -`; - -const Avatar = styled.img` - height: 40px; - width: 40px; - border-radius: 100%; - margin-right: 10px; - vertical-align: middle; -`; - -const Name = styled.span` - vertical-align: middle; -`; - -interface Props { - member: GraphQL.Member; -} - -const Member: React.FC = function(props) { - const { member } = props; - - if (member.name == null) { - return null; - } - - return ( - - - {member.name} - - ); -}; - -export default Member; diff --git a/src/components/Project.tsx b/src/components/Project.tsx deleted file mode 100644 index 07ba584..0000000 --- a/src/components/Project.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -const Arrow = styled.span` - position: absolute; - top: 0; - right: 0; -`; - -const Title = styled.span` - position: relative; - grid-area: title; - padding-right: 44px; - font-weight: 500; - font-size: 48px; - line-height: 1; - letter-spacing: -0.04em; - white-space: nowrap; - - @media (max-width: ${props => props.theme.breakMedium}) { - white-space: initial; - } -`; - -const Wrapper = styled.a` - display: flex; - align-items: center; - gap: 10px; - padding: 10px 0; - border-bottom: 1px solid ${props => props.theme.colors.primary}; - text-decoration: none; - color: ${props => props.theme.colors.primary}; - - &:visited { - color: ${props => props.theme.colors.primary}; - } - - &:hover { - ${Arrow} { - top: -5px; - right: -5px; - } - - ${Title} { - text-decoration: underline; - } - } - - @media (max-width: ${props => props.theme.breakMedium}) { - display: grid; - grid-template: - 'index title' - 'description description' - / auto 1fr; - justify-items: start; - } -`; - -const Index = styled.span` - grid-area: index; - opacity: 0.5; - font-style: italic; - font-size: 14px; -`; - -const Description = styled.span` - grid-area: description; - flex-grow: 1; - font-family: ${props => props.theme.secondary}; - font-style: italic; - font-size: 18px; - text-align: right; - - @media (max-width: ${props => props.theme.breakMedium}) { - text-align: left; - } -`; - -interface Props { - index: number; - project: GraphQL.Project; -} - -const Project: React.FC = function(props) { - const { index, project } = props; - return ( - - {('0' + index).slice(-2)} - - {project.name || ''} - <Arrow>↗</Arrow> - - {project.description} - - ); -}; - -export default Project; diff --git a/src/components/SEO.tsx b/src/components/SEO.tsx deleted file mode 100644 index ef4a123..0000000 --- a/src/components/SEO.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import Head from 'next/head'; -import React from 'react'; -import { resolve } from 'url'; - -import config from '../config'; - -interface Props { - lang?: string; - description?: string; - title: string; -} - -const SEO: React.FC = function(props) { - const { description, title } = props; - const { siteMetadata } = config; - - const metaDescription = description ?? ''; - - const jsonLDSchema = { - '@context': 'https://schema.org', - '@type': 'Organization', - name: 'Fourth Class Honours', - description: metaDescription, - url: siteMetadata.siteUrl, - logo: resolve(siteMetadata.siteUrl, 'og.png'), - }; - - return ( - - - {title} | {siteMetadata.title} - - - - - - - - - - - - - - - ); -}; - -export default SEO; diff --git a/src/components/StyleInjector.tsx b/src/components/StyleInjector.tsx deleted file mode 100644 index 5ecec2c..0000000 --- a/src/components/StyleInjector.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { StyleSheetManager, ThemeProvider } from 'styled-components'; - -import theme from '../styles/theme'; - -const StyleInjector: React.FC = function({ children }) { - const [iframeRef, setIframeRef] = useState(null); - - useEffect(() => { - const iframe = document.getElementsByTagName('iframe')[0]; - const iframeHeadElem = iframe?.contentDocument?.head; - //@ts-ignore - setIframeRef(iframeHeadElem); - }, []); - - return ( - iframeRef && ( - //@ts-ignore - - {children} - - ) - ); -}; - -export default StyleInjector; diff --git a/src/components/styled.tsx b/src/components/styled.tsx deleted file mode 100644 index 7985ffb..0000000 --- a/src/components/styled.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import styled from 'styled-components'; - -import Link from './Link'; - -export const Section = styled.div` - margin-bottom: 100px; -`; - -export const SectionHeading = styled.h1` - font-family: ${props => props.theme.secondary}; - font-style: italic; - font-size: 36px; - font-weight: 400; - line-height: 1; - margin: 0 0 8px; -`; - -export const SectionBody = styled.p` - margin-top: 0; - font-weight: 500; - font-size: 48px; - line-height: 1; - letter-spacing: -0.04em; -`; - -export const SeeMore = styled(Link)` - display: block; - width: 100%; - padding: 10px 0; - font-weight: 500; - font-size: 48px; - line-height: 1; - letter-spacing: -0.04em; - text-decoration: none; - color: ${props => props.theme.colors.primary}; - - &:visited { - color: ${props => props.theme.colors.primary}; - } - - &:hover { - text-decoration: underline; - } -`; diff --git a/src/config.tsx b/src/config.tsx deleted file mode 100644 index 77f9578..0000000 --- a/src/config.tsx +++ /dev/null @@ -1,9 +0,0 @@ -const config = { - siteMetadata: { - title: 'Fourth Class Honours', - author: `@fourthclasshonours`, - siteUrl: 'https://fourthclasshonours.com', - }, -}; - -export default config; diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 15b645d..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -const size = { - mobileS: '320px', - mobileM: '375px', - mobileL: '425px', - tablet: '768px', - laptop: '1024px', - laptopL: '1440px', - desktop: '2560px', -}; - -export const device = { - mobileS: `(min-width: ${size.mobileS})`, - mobileM: `(min-width: ${size.mobileM})`, - mobileL: `(min-width: ${size.mobileL})`, - tablet: `(min-width: ${size.tablet})`, - laptop: `(min-width: ${size.laptop})`, - laptopL: `(min-width: ${size.laptopL})`, - desktop: `(min-width: ${size.desktop})`, - desktopL: `(min-width: ${size.desktop})`, -}; diff --git a/src/contexts/SiteConfigurationContext.ts b/src/contexts/SiteConfigurationContext.ts deleted file mode 100644 index 1cd39ea..0000000 --- a/src/contexts/SiteConfigurationContext.ts +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const SiteConfigurationContext = React.createContext( - null -); - -export default SiteConfigurationContext; diff --git a/src/layouts/Layout.tsx b/src/layouts/Layout.tsx deleted file mode 100644 index b8a655c..0000000 --- a/src/layouts/Layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -import Footer from '../components/Footer'; -import Header from '../components/Header'; - -const Layout: React.FC = function(props) { - const { children } = props; - - return ( - <> -
-
{children}
-