diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 6c346778..00000000 --- a/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": "react-app", - "plugins": ["prettier"], - "rules": { - "prettier/prettier": "error", - "jsx-a11y/no-redundant-roles": "off" - } -} diff --git a/.github/workflows/deploy-beta.yml b/.github/workflows/deploy-beta.yml deleted file mode 100644 index 75378bb7..00000000 --- a/.github/workflows/deploy-beta.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: deploy-beta - -on: - push: - branches: - - main - -jobs: - deploy: - runs-on: ubuntu-latest - env: - CI: true - steps: - - name: Create GitHub deployment - uses: bobheadxi/deployments@v0.4.3 - id: deployment - with: - step: start - token: ${{ github.token }} - env: beta - - - uses: actions/checkout@v2 - - name: Use Node.js 14.x - uses: actions/setup-node@v1 - with: - node-version: '14' - - # From: https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#example-using-the-cache-action - - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Install Dependencies - run: npm ci - - - name: Build - run: npm run build-beta - - - uses: jakejarvis/s3-sync-action@v0.5.1 - name: Sync files to DigitalOcean Spaces - with: - args: --acl public-read --follow-symlinks --delete - env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_S3_ENDPOINT: https://sfo2.digitaloceanspaces.com - SOURCE_DIR: public - DEST_DIR: beta - - - name: Install doctl - uses: digitalocean/action-doctl@v2 - with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - - name: Flush DigitalOcean Spaces cache - run: doctl compute cdn flush ${{ secrets.DIGITALOCEAN_CDN_ID }} --files beta/* - - - name: Update deployment status - uses: bobheadxi/deployments@v0.4.3 - if: always() - with: - step: finish - token: ${{ github.token }} - status: ${{ job.status }} - deployment_id: ${{ steps.deployment.outputs.deployment_id }} - env_url: https://beta.unicorn-utterances.com diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml deleted file mode 100644 index f7dd6737..00000000 --- a/.github/workflows/deploy-dev.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: deploy-dev - -on: pull_request - -jobs: - deploy: - if: github.repository_owner == 'unicorn-utterances' - runs-on: ubuntu-latest - env: - CI: true - steps: - # see https://dev.to/bobheadxi/branch-previews-with-google-app-engine-and-github-actions-3pco - - name: Extract branch name - id: get_branch - shell: bash - env: - PR_HEAD: ${{ github.head_ref }} - run: echo "##[set-output name=branch;]$(echo ${PR_HEAD#refs/heads/} | tr / -)" - - - name: Create GitHub deployment - uses: bobheadxi/deployments@v0.4.3 - id: deployment - with: - step: start - token: ${{ github.token }} - env: ${{ steps.get_branch.outputs.branch }} - ref: ${{ github.head_ref }} - - - uses: actions/checkout@v2 - - name: Use Node.js 14.x - uses: actions/setup-node@v1 - with: - node-version: '14' - - # From: https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#example-using-the-cache-action - - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Install Dependencies - run: npm ci - - - name: Build - run: npm run build-beta - env: - SITE_URL: https://${{ steps.get_branch.outputs.branch }}.unicorn-utterances.com - - - uses: jakejarvis/s3-sync-action@v0.5.1 - name: Sync files to DigitalOcean Spaces - with: - args: --acl public-read --follow-symlinks --delete - env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_S3_ENDPOINT: https://sfo2.digitaloceanspaces.com - SOURCE_DIR: public - DEST_DIR: ${{ steps.get_branch.outputs.branch }} - - - name: Install doctl - uses: digitalocean/action-doctl@v2 - with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - - name: Flush DigitalOcean Spaces cache - run: doctl compute cdn flush ${{ secrets.DIGITALOCEAN_CDN_ID }} --files ${{ steps.get_branch.outputs.branch }}/* - - - name: Update deployment status - uses: bobheadxi/deployments@v0.4.3 - if: always() - with: - step: finish - token: ${{ github.token }} - status: ${{ job.status }} - deployment_id: ${{ steps.deployment.outputs.deployment_id }} - env_url: https://${{ steps.get_branch.outputs.branch }}.unicorn-utterances.com diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml deleted file mode 100644 index 7982f570..00000000 --- a/.github/workflows/deploy-prod.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: deploy-prod - -on: workflow_dispatch - -jobs: - deploy: - runs-on: ubuntu-latest - env: - CI: true - steps: - - name: Create GitHub deployment - uses: bobheadxi/deployments@v0.4.3 - id: deployment - with: - step: start - token: ${{ github.token }} - env: production - - - uses: actions/checkout@v2 - - name: Use Node.js 14.x - uses: actions/setup-node@v1 - with: - node-version: '14' - - # From: https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#example-using-the-cache-action - - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Install Dependencies - run: npm ci - - - name: Build - run: npm run build - - - uses: jakejarvis/s3-sync-action@v0.5.1 - name: Sync files to DigitalOcean Spaces - with: - args: --acl public-read --follow-symlinks --delete - env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_S3_ENDPOINT: https://sfo2.digitaloceanspaces.com - SOURCE_DIR: public - DEST_DIR: prod - - - name: Install doctl - uses: digitalocean/action-doctl@v2 - with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - - name: Flush DigitalOcean Spaces cache - run: doctl compute cdn flush ${{ secrets.DIGITALOCEAN_CDN_ID }} --files prod/* - - - name: Update deployment status - uses: bobheadxi/deployments@v0.4.3 - if: always() - with: - step: finish - token: ${{ github.token }} - status: ${{ job.status }} - deployment_id: ${{ steps.deployment.outputs.deployment_id }} - env_url: https://unicorn-utterances.com diff --git a/.github/workflows/destroy-dev.yml b/.github/workflows/destroy-dev.yml deleted file mode 100644 index d2dd8be3..00000000 --- a/.github/workflows/destroy-dev.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: destroy-dev - -on: - pull_request: - types: - - closed - -jobs: - destroy: - if: github.repository_owner == 'unicorn-utterances' - runs-on: ubuntu-latest - env: - CI: true - steps: - # see https://dev.to/bobheadxi/branch-previews-with-google-app-engine-and-github-actions-3pco - - name: Extract branch name - id: get_branch - shell: bash - env: - PR_HEAD: ${{ github.head_ref }} - run: echo "##[set-output name=branch;]$(echo ${PR_HEAD#refs/heads/} | tr / -)" - - - name: Remove files from DigitalOcean Spaces - uses: vitorsgomes/s3-rm-action@v1.0.1 - with: - args: --recursive - env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_S3_ENDPOINT: https://sfo2.digitaloceanspaces.com - PATH_TO_DELETE: "${{ steps.get_branch.outputs.branch }}" - - - name: Mark environment as deactivated - uses: bobheadxi/deployments@v0.4.3 - with: - step: deactivate-env - token: ${{ github.token }} - env: ${{ steps.get_branch.outputs.branch }} - desc: Deployment was pruned diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index c84003cc..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: test - -on: push - -jobs: - test-lint-build: - env: - CI: true - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Use Node.js 14.x - uses: actions/setup-node@v1 - with: - node-version: '14' - - # From: https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#example-using-the-cache-action - - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - name: Install Dependencies - run: npm ci - - - name: Test - run: npm test - - - name: Lint - run: npm run lint - - - name: Build - run: npm run build diff --git a/.gitignore b/.gitignore index 066a1ddf..1437c53f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,69 +1,34 @@ -# Logs -logs -*.log +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug npm-debug.log* yarn-debug.log* yarn-error.log* -.idea/ -# Runtime data -pids -*.pid -*.seed -*.pid.lock -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://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 - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# dotenv environment variables file -.env - -# gatsby files -.cache/ -public - -# Mac files -.DS_Store - -# Yarn -yarn-error.log -.pnp/ -.pnp.js -# Yarn Integrity file -.yarn-integrity +# vercel +.vercel diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100644 index d37daa07..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no-install lint-staged diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..b58b603f --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..42b77934 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/unicorn-utterances.iml b/.idea/unicorn-utterances.iml new file mode 100644 index 00000000..0c8867d7 --- /dev/null +++ b/.idea/unicorn-utterances.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index c34785c3..00000000 --- a/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "useTabs": true, - "endOfLine": "auto" -} diff --git a/.stylelintrc b/.stylelintrc deleted file mode 100644 index 24d4d996..00000000 --- a/.stylelintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["stylelint-prettier/recommended"] -} \ No newline at end of file diff --git a/@types/remark-html.d.ts b/@types/remark-html.d.ts new file mode 100644 index 00000000..e1b76b54 --- /dev/null +++ b/@types/remark-html.d.ts @@ -0,0 +1 @@ +declare module 'remark-html' diff --git a/__mocks__/data/mock-license.ts b/__mocks__/data/mock-license.ts deleted file mode 100644 index 4b1a2bd6..00000000 --- a/__mocks__/data/mock-license.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const MockLicense = { - licenceType: 'Mocked License', - footerImg: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - explainLink: "example.com/explainLink", - name: "The Mocking License", - displayName: "MockLicense with Attribution" -} \ No newline at end of file diff --git a/__mocks__/data/mock-post.ts b/__mocks__/data/mock-post.ts deleted file mode 100644 index 28cb94c2..00000000 --- a/__mocks__/data/mock-post.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MockUnicorn, MockUnicornTwo } from "./mock-unicorn"; -import { MockLicense } from "./mock-license"; - -export const MockPost = { - id: "123123", - excerpt: "This would be an auto generated excerpt of the post in particular", - html: "
Hey there
", - frontmatter: { - title: "Post title", - published: "10-10-2010", - tags: ["item1"], - description: - "This is a short description dunno why this would be this short", - authors: [MockUnicorn], - license: MockLicense - }, - fields: { - slug: "/this-post-name-here", - inlineCount: 0, - headingsWithId: [] - }, - wordCount: { - words: 10000 - } -}; - -export const MockMultiAuthorPost = { - id: "345345", - excerpt: - "This would be a second auto generated excerpt of the post in particular", - html: "
Hello, friends
", - frontmatter: { - title: "Another post title", - published: "10-20-2010", - tags: ["item1"], - description: - "This is another short description dunno why this would be this short", - authors: [MockUnicornTwo, MockUnicorn], - license: MockLicense - }, - fields: { - slug: "/this-other-post-name-here", - inlineCount: 0, - headingsWithId: [] - }, - wordCount: { - words: 100000 - } -}; diff --git a/__mocks__/data/mock-role.ts b/__mocks__/data/mock-role.ts deleted file mode 100644 index 01520947..00000000 --- a/__mocks__/data/mock-role.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const MockRole = { - id: "developer", - prettyname: "Developer" -} \ No newline at end of file diff --git a/__mocks__/data/mock-site-metadata.ts b/__mocks__/data/mock-site-metadata.ts deleted file mode 100644 index b4d302d1..00000000 --- a/__mocks__/data/mock-site-metadata.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const siteMetadata = { - title: 'siteTitle', - siteUrl: "https://example.com/siteUrl/", - disqusShortname: "disqus-example-shorthand", - repoPath: 'unicorn-example-repo-path', - relativeToPosts: 'relative/to/posts' -} diff --git a/__mocks__/data/mock-unicorn.ts b/__mocks__/data/mock-unicorn.ts deleted file mode 100644 index 817659f2..00000000 --- a/__mocks__/data/mock-unicorn.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { MockRole } from "./mock-role"; -import { UnicornInfo } from "../../src/types"; - -export const MockUnicorn: UnicornInfo = { - name: "Joe", - firstName: "Joe", - lastName: "Other", - id: "joe", - description: "Exists", - color: "red", - fields: { - isAuthor: true, - }, - roles: [MockRole as any], - socials: { - twitter: "twtrusrname", - github: "ghusrname", - website: "example.com", - }, - pronouns: { - they: "they", - them: "them", - their: "their", - theirs: "theirs", - themselves: "themselves", - }, - profileImg: { - childImageSharp: { - smallPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - mediumPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - bigPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - }, - }, -}; - -export const MockUnicornTwo: UnicornInfo = { - name: "Diane", - firstName: "Diane", - lastName: "", - id: "diane", - description: "Is a human", - color: "blue", - fields: { - isAuthor: true, - }, - roles: [MockRole] as any[], - socials: { - twitter: "twtrusrname2", - github: "ghusrname2", - website: "example.com/2", - }, - pronouns: { - they: "they", - them: "them", - their: "their", - theirs: "theirs", - themselves: "themselves", - }, - profileImg: { - childImageSharp: { - smallPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - mediumPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - bigPic: { - images: { - fallback: { - src: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - }, - sources: [ - { - srcSet: - "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", - type: "png", - }, - ], - }, - width: 272, - height: 92, - layout: "fixed", - }, - }, - }, -}; diff --git a/__mocks__/file-mock.ts b/__mocks__/file-mock.ts deleted file mode 100644 index ebf20155..00000000 --- a/__mocks__/file-mock.ts +++ /dev/null @@ -1 +0,0 @@ -module.exports = "test-file-stub" diff --git a/__mocks__/modules/disqus-react.tsx b/__mocks__/modules/disqus-react.tsx deleted file mode 100644 index 7d5d1974..00000000 --- a/__mocks__/modules/disqus-react.tsx +++ /dev/null @@ -1,8 +0,0 @@ -jest.mock("disqus-react", () => { - const React = require("react"); - return { - DiscussionEmbed: () => <> - }; -}); - -export default {}; diff --git a/__mocks__/modules/gatsby-image.tsx b/__mocks__/modules/gatsby-image.tsx deleted file mode 100644 index 40acff90..00000000 --- a/__mocks__/modules/gatsby-image.tsx +++ /dev/null @@ -1,16 +0,0 @@ -jest.mock("gatsby-image", () => { - const React = require("react"); - - return (props: any) => { - return ( - {props.alt} - ); - }; -}); - -export default {}; diff --git a/__mocks__/modules/gatsby-plugin-google-analytics.tsx b/__mocks__/modules/gatsby-plugin-google-analytics.tsx deleted file mode 100644 index a3d39fce..00000000 --- a/__mocks__/modules/gatsby-plugin-google-analytics.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { onLinkClick } from "gatsby-plugin-google-analytics"; - -afterEach(() => { - onLinkClick.mockReset(); -}); - -jest.mock("gatsby-plugin-google-analytics", () => { - const React = require("react"); - const onLinkClickFn = jest.fn(); - - return { - OutboundLink: (props: any) => ( -
{props.children}
- ), - onLinkClick: onLinkClickFn - }; -}); - -export default {}; diff --git a/__mocks__/modules/gatsby.tsx b/__mocks__/modules/gatsby.tsx deleted file mode 100644 index ef5e38f8..00000000 --- a/__mocks__/modules/gatsby.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { onLinkClick } from "gatsby"; - -afterEach(() => { - onLinkClick.mockReset(); -}); - -jest.mock("gatsby", () => { - const React = require("react"); - const gatsbyOGl = jest.requireActual("gatsby"); - const onLinkClickFn = jest.fn(); - - return { - ...gatsbyOGl, - Link: React.forwardRef((props: any, ref: any) => { - const { - // these props are invalid for an `a` tag - activeClassName, - activeStyle, - getProps, - innerRef, - partiallyActive, - replace, - to, - ...rest - } = props; - return ( - - {props.children} - - ); - }), - onLinkClick: onLinkClickFn, - graphql: jest.fn(), - StaticQuery: jest.fn(), - useStaticQuery: jest.fn() - }; -}); - -export default {}; diff --git a/__mocks__/modules/index.ts b/__mocks__/modules/index.ts deleted file mode 100644 index f8f0f929..00000000 --- a/__mocks__/modules/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "./gatsby"; -import "./gatsby-image"; -import "./disqus-react"; -import "./gatsby-plugin-google-analytics"; diff --git a/__mocks__/svg-comp-mock.ts b/__mocks__/svg-comp-mock.ts deleted file mode 100644 index 461f67a0..00000000 --- a/__mocks__/svg-comp-mock.ts +++ /dev/null @@ -1 +0,0 @@ -export default () => null; diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 2d5d73a4..00000000 --- a/babel.config.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - node: 'current', - }, - }, - ], - '@babel/preset-typescript' - ], - plugins: [ - '@babel/plugin-proposal-optional-chaining', - '@babel/plugin-transform-react-jsx', - '@babel/plugin-proposal-class-properties' - ], -}; diff --git a/components/PostRenderer.tsx b/components/PostRenderer.tsx new file mode 100644 index 00000000..670c0ac1 --- /dev/null +++ b/components/PostRenderer.tsx @@ -0,0 +1,19 @@ +import Image, {ImageProps} from "next/image"; +import { MDXRemote } from "next-mdx-remote"; + +// this object will contain all the replacements we want to make +const components = { + img: (props: ImageProps) => ( + // height and width are part of the props, so they get automatically passed here with {...props} + + ), +}; + +export function PostRenderer({ post }: { post: string }) { + return ( + <> + {/* MDXRemote uses the components prop to decide which html elements to switch for components */} + + + ); +} diff --git a/config/gatsby-config-consts.js b/config/gatsby-config-consts.js deleted file mode 100644 index 7c792620..00000000 --- a/config/gatsby-config-consts.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - googleAnalytics: "UA-143062623-1" -}; diff --git a/config/jest/setup-test-env.ts b/config/jest/setup-test-env.ts deleted file mode 100644 index e2672cdf..00000000 --- a/config/jest/setup-test-env.ts +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import "@testing-library/jest-dom/extend-expect"; -import "jest-axe/extend-expect"; -import "../../__mocks__/modules"; - -const originConsoleErr = console.error; -console.error = (message?: any, ...optionalParams: any[]) => { - if (/Not implemented: navigation/.exec(message)) return; - originConsoleErr(message, ...optionalParams); -}; - -(global as any).IntersectionObserver = class IntersectionObserver { - constructor() {} - - observe() { - return null; - } - - disconnect() { - return null; - } - - unobserve() { - return null; - } -}; diff --git a/config/redirects_unicorn-utterances.com b/config/redirects_unicorn-utterances.com deleted file mode 100644 index 0471918b..00000000 --- a/config/redirects_unicorn-utterances.com +++ /dev/null @@ -1,15 +0,0 @@ -# this is the config for our redirects for our NGINX server -# include this file with "include redirects_unicorn-utterances.com;" - -# url migration per PR #15 -location = /authors/crutchcorn/ { - return 301 /unicorns/crutchcorn; -} - -location = /unicorns/ { - return 302 /about; -} - -location = /posts/ { - return 301 /; -} diff --git a/content/blog/python-list-comprehension-guide/.idea/.gitignore b/content/blog/python-list-comprehension-guide/.idea/.gitignore new file mode 100644 index 00000000..b58b603f --- /dev/null +++ b/content/blog/python-list-comprehension-guide/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/content/blog/python-list-comprehension-guide/.idea/modules.xml b/content/blog/python-list-comprehension-guide/.idea/modules.xml new file mode 100644 index 00000000..2f79bfad --- /dev/null +++ b/content/blog/python-list-comprehension-guide/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/content/blog/python-list-comprehension-guide/.idea/python-list-comprehension-guide.iml b/content/blog/python-list-comprehension-guide/.idea/python-list-comprehension-guide.iml new file mode 100644 index 00000000..0c8867d7 --- /dev/null +++ b/content/blog/python-list-comprehension-guide/.idea/python-list-comprehension-guide.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/python-list-comprehension-guide/.idea/vcs.xml b/content/blog/python-list-comprehension-guide/.idea/vcs.xml new file mode 100644 index 00000000..c2365ab1 --- /dev/null +++ b/content/blog/python-list-comprehension-guide/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/gatsby-config.js b/gatsby-config.js deleted file mode 100644 index f87d2688..00000000 --- a/gatsby-config.js +++ /dev/null @@ -1,435 +0,0 @@ -const { SeriesToC } = require("./src/components/series-toc"); - -let CONSTS = require("./config/gatsby-config-consts"); -if (!CONSTS) CONSTS = {}; - -const buildMode = process.env.BUILD_ENV || "production"; - -let siteUrl = process.env.SITE_URL; - -if (!siteUrl) { - switch (buildMode) { - case "production": - siteUrl = "https://unicorn-utterances.com"; - break; - case "local": - siteUrl = "localhost:8000"; - break; - default: - siteUrl = "https://beta.unicorn-utterances.com"; - } -} - -// To set for Twitch -let parent; - -// Try & Catch to allow for hosts themselves to be passed -// `new URL('domain.com')` will fail/throw, but is a valid host -try { - const url = new URL(siteUrl); - // URLs like 'localhost:3000' might not give host. - // Throw in order to catch in wrapper handler - if (!url.host) throw new Error(); - parent = url.host; -} catch (_) { - const url = new URL("https://" + siteUrl); - parent = url.host; -} - -// Twitch embed throws error with strings like 'localhost:3000', but -// those persist with `new URL().host` -if (parent.startsWith("localhost")) { - parent = "localhost"; -} - -console.log(`Building for ${buildMode} at ${siteUrl} with the parent ${parent}`); - -module.exports = { - siteMetadata: { - title: `Unicorn Utterances`, - description: `Learning programming from magically majestic words. A place to learn about all sorts of programming topics from entry-level concepts to advanced abstractions`, - siteUrl, - disqusShortname: "unicorn-utterances", - repoPath: "unicorn-utterances/unicorn-utterances", - relativeToPosts: "/content/blog", - keywords: - "programming,development,mobile,web,game,utterances,software engineering,javascript,angular,react,computer science", - }, - plugins: [ - { - resolve: `gatsby-source-filesystem`, - options: { - path: `${__dirname}/content/blog`, - name: `blog`, - }, - }, - { - resolve: `gatsby-source-filesystem`, - options: { - path: `${__dirname}/src/assets`, - name: `assets`, - }, - }, - { - resolve: `gatsby-source-filesystem`, - options: { - path: `${__dirname}/content/site`, - name: `sitecontent`, - }, - }, - `gatsby-transformer-json`, - `gatsby-plugin-typescript`, - { - resolve: `gatsby-source-filesystem`, - options: { - path: `./content/data`, - }, - }, - { - resolve: "gatsby-plugin-web-font-loader", - options: { - google: { - families: [ - `Work Sans:400,500,600,700`, - `Archivo:400,500,600`, - `Roboto Mono:400`, - ], - }, - }, - }, - { - resolve: `gatsby-transformer-remark`, - options: { - plugins: [ - `gatsby-remark-behead`, - { - // TODO: NEXTJS: Replace with https://ironeko.com/posts/how-to-use-next-js-image-with-markdown-or-mdx - resolve: `gatsby-remark-images`, - options: { - maxWidth: 590, - linkImagesToOriginal: false, - backgroundColor: `transparent`, - }, - }, - { - // TODO: NEXTJS: Replace with https://ironeko.com/posts/how-to-use-next-js-image-with-markdown-or-mdx - // https://wangchujiang.com/rehype-video/ - resolve: "gatsby-remark-video", - options: { - width: "100%", - height: "auto", - preload: "auto", - muted: true, - autoplay: true, - controls: true, - loop: true, - }, - }, - { - // TODO: NEXTJS: Replace with https://github.com/francoischalifour/medium-zoom/blob/master/examples/react-markdown/src/Post.js - resolve: `gatsby-remark-images-medium-zoom`, - options: { - includedSelector: '[src$=".svg"]', - }, - }, - { - // TODO: NEXTJS: Replace with https://ironeko.com/posts/how-to-use-next-js-image-with-markdown-or-mdx - resolve: `gatsby-remark-responsive-iframe`, - options: { - wrapperStyle: `margin-bottom: 1.0725rem`, - }, - }, - { - // TODO: NEXTJS: Replace with https://github.com/rehypejs/rehype-autolink-headings - resolve: `gatsby-remark-autolink-headers`, - options: { - offsetY: `100`, - icon: ``, - maintainCase: true, - removeAccents: true, - enableCustomId: true, - }, - }, - { - // TODO: NEXTJS: Replace with https://github.com/rehypejs/rehype-highlight - resolve: `gatsby-remark-prismjs`, - options: { - aliases: { - gradle: "groovy", //prismjs doesn't support gradle yet, so aliasing it to groovy provides at least some highlighting - }, - }, - }, - // TODO: NEXTJS: Are we legit using this at all? - `gatsby-remark-copy-linked-files`, - { - resolve: "gatsby-remark-series", - options: { - render: { - // The location where the toc should be rendered. - placeholder: "top", - template: SeriesToC, - }, - resolvers: { - slug: (markdownNode) => `/posts${markdownNode.fields.slug}`, - date: (markdownNode) => markdownNode.frontmatter.published, - draft: () => false, - }, - }, - }, - { - resolve: `gatsby-remark-embedder`, - options: { - services: { - Twitch: { - parent, - }, - }, - }, - }, - `gatsby-remark-external-links`, - ], - }, - }, - `count-inline-code`, - `remarked-autolink-headers-and-add-id`, - `gatsby-plugin-image`, - `gatsby-plugin-sharp`, - `gatsby-transformer-sharp`, - { - resolve: `gatsby-plugin-google-analytics`, - options: { - trackingId: CONSTS.googleAnalytics || "", - head: false, - respectDNT: true, - }, - }, - { - resolve: `gatsby-plugin-feed`, - options: { - query: ` - { - site { - siteMetadata { - title - description - siteUrl - site_url: siteUrl - } - } - } - `, - feeds: [ - { - serialize: ({ query: { site, allMarkdownRemark } }) => { - const siteUrl = site.siteMetadata.siteUrl; - return allMarkdownRemark.edges.map((edge) => { - const slug = edge.node.fields.slug; - const { frontmatter } = edge.node; - const nodeUrl = `${siteUrl}/posts${slug}`; - return { - description: frontmatter.description || edge.node.excerpt, - date: frontmatter.published, - title: frontmatter.title, - url: nodeUrl, - guid: nodeUrl, - custom_elements: [ - /** - * We chose `dc:creator` in order to avoid having - * to list contact information from our contributors, - * as `dc:creator` - * - * FIXME: This does not have the functionality we'd expect - * it only lists the last author's name - * - * @see https://github.com/dylang/node-rss/issues/92 - */ - { - "dc:creator": frontmatter.authors.map( - (author) => author.name - ), - }, - { comments: `${nodeUrl}#disqus_thread` }, - ], - }; - }); - }, - query: ` - { - allMarkdownRemark( - sort: { order: DESC, fields: [frontmatter___published] }, - filter: {fileAbsolutePath: {regex: "/content/blog/"}} - ) { - edges { - node { - excerpt - html - fields { slug } - frontmatter { - title - description - published - authors { - name - } - } - } - } - } - } - `, - output: "/rss.xml", - title: "Unicorn Utterances's RSS Feed", - }, - ], - }, - }, - { - resolve: `gatsby-plugin-manifest`, - options: { - name: `Unicorn Utterances`, - short_name: `Unicorn Utterances`, - start_url: `/`, - background_color: `#ffffff`, - theme_color: `#127db3`, - display: `minimal-ui`, - icon: `src/assets/unicorn_utterances_logo_512.png`, - }, - }, - { - resolve: `gatsby-plugin-offline`, - options: { - workboxConfig: { - runtimeCaching: [ - // Some as-is options from default config, explictly stated to avoid regressions from issues with `_.merge`ing into the default - { - // DEFAULT - Use cacheFirst since these don't need to be revalidated (same RegExp - // and same reason as above) - urlPattern: /(\.js$|\.css$|static\/)/, - handler: `CacheFirst`, - }, - { - // MODIFIED - page-data.json files are not content hashed - urlPattern: /^https?:.*\/page-data\/.*\/page-data\.json/, - handler: `NetworkFirst`, - }, - { - // MODIFIED - app-data.json is not content hashed - urlPattern: /^https?:.*\/page-data\/app-data\.json/, - handler: `NetworkFirst`, - }, - { - // DEFAULT - Add runtime caching of various other page resources - urlPattern: /^https?:.*\.(png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, - handler: `StaleWhileRevalidate`, - }, - { - // DEFAULT - Google Fonts CSS (doesn't end in .css so we need to specify it) - urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/, - handler: `StaleWhileRevalidate`, - }, - ], - }, - }, - }, - `gatsby-plugin-react-helmet`, - { - resolve: "gatsby-plugin-react-svg", - options: { - rule: { - include: /(?:\/src\/assets\/icons\/|\\src\\assets\\icons\\).*\.svg$/, - }, - }, - }, - `gatsby-plugin-sass`, - { - resolve: `gatsby-plugin-lunr`, - options: { - languages: [ - { - name: "en", - // A function for filtering nodes. () => true by default - filterNodes: (node) => - !!node.frontmatter && !!node.frontmatter.authors, - }, - ], - // Fields to index. If store === true value will be stored in index file. - // Attributes for custom indexing logic. See https://lunrjs.com/docs/lunr.Builder.html for details - fields: [ - { - name: "title", - store: true, - attributes: { boost: 20 }, - }, - { name: "excerpt" }, - { name: "description" }, - { - name: "slug", - store: true, - }, - { name: "authors" }, - { name: "tags" }, - ], - // How to resolve each field's value for a supported node type - resolvers: { - // For any node of type MarkdownRemark, list how to resolve the fields' values - MarkdownRemark: { - title: (node) => node.frontmatter.title, - excerpt: (node) => node.excerpt, - description: (node) => node.frontmatter.description, - slug: (node) => node.fields.slug, - /** - * FIXME: This does not work the way we'd want. We want the name - * the author rather than the username, but the node is not - * populated - * - * @see https://github.com/humanseelabs/gatsby-plugin-lunr/issues/24 - */ - authors: (node) => node.frontmatter.authors.join(", "), - tags: (node) => node.frontmatter.tags, - }, - }, - //custom index file name, default is search_index.json - filename: "search_index.json", - //custom options on fetch api call for search_Δ±ndex.json - fetchOptions: { - credentials: "same-origin", - }, - }, - }, - `gatsby-plugin-sitemap`, - { - resolve: "gatsby-plugin-robots-txt", - options: { - resolveEnv: () => buildMode, - env: { - development: { - host: siteUrl, - sitemap: `${siteUrl}/sitemap.xml`, - policy: [ - { - userAgent: "*", - disallow: ["/"], - }, - ], - }, - production: { - host: siteUrl, - sitemap: `${siteUrl}/sitemap.xml`, - policy: [ - { - userAgent: "*", - allow: "/", - }, - ], - }, - }, - }, - }, - ], - mapping: { - "MarkdownRemark.frontmatter.authors": `UnicornsJson`, - "MarkdownRemark.frontmatter.license": `LicensesJson`, - "UnicornsJson.pronouns": `PronounsJson`, - "UnicornsJson.roles": `RolesJson`, - }, -}; diff --git a/gatsby-node.js b/gatsby-node.js deleted file mode 100644 index c778ea36..00000000 --- a/gatsby-node.js +++ /dev/null @@ -1,236 +0,0 @@ -const path = require(`path`); -const fs = require("fs"); -const { createFilePath } = require(`gatsby-source-filesystem`); -const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); - -/** - * Allow tsconfig.path usage - */ -exports.onCreateWebpackConfig = ({ actions }) => { - actions.setWebpackConfig({ - resolve: { - plugins: [new TsconfigPathsPlugin()] - } - }); -}; - -/** - * Add slugs to Markdown and Unicorns - */ -exports.onCreateNode = ({ node, actions, getNode }) => { - const { createNodeField } = actions; - - if (node.internal.type === `MarkdownRemark`) { - const value = createFilePath({ - node, - getNode - }); - createNodeField({ - name: `slug`, - node, - value - }); - } - - if (node.internal.type === `UnicornsJson`) { - const value = createFilePath({ - node, - getNode - }); - createNodeField({ - name: `slug`, - node, - value - }); - } -}; - -/** - * Add "isAuthor" field to Markdown pages - */ -exports.sourceNodes = async ({ - getNodesByType, - actions: { createNodeField } -}) => { - const postNodes = getNodesByType(`MarkdownRemark`); - const unicornNodes = getNodesByType(`UnicornsJson`); - - unicornNodes.forEach(unicornNode => { - const isAuthor = postNodes - // Ensure it's actually a post - .filter(post => !!post.frontmatter.authors) - .some(post => { - return post.frontmatter.authors.includes(unicornNode.id); - }); - - createNodeField({ - name: `isAuthor`, - node: unicornNode, - value: isAuthor - }); - }); -}; - -exports.createPages = ({ graphql, actions }) => { - const { createPage } = actions; - - const blogPost = path.resolve(`./src/templates/blog-post/blog-post.tsx`); - const blogProfile = path.resolve( - `./src/templates/blog-profile/blog-profile.tsx` - ); - const postList = path.resolve(`./src/templates/post-list/post-list.tsx`); - return graphql( - ` - { - allMarkdownRemark( - sort: { fields: [frontmatter___published], order: DESC } - filter: { fileAbsolutePath: { regex: "/content/blog/" } } - limit: 1000 - ) { - edges { - node { - fields { - slug - } - frontmatter { - title - authors { - id - } - } - } - } - } - allUnicornsJson(limit: 100) { - edges { - node { - id - } - } - } - } - ` - ).then(result => { - if (result.errors) { - throw result.errors; - } - - // Create blog posts pages. - const posts = result.data.allMarkdownRemark.edges; - const unicorns = result.data.allUnicornsJson.edges; - - posts.forEach((post, index, arr) => { - const previous = index === arr.length - 1 ? null : arr[index + 1].node; - const next = index === 0 ? null : arr[index - 1].node; - - const postInfo = post.node.frontmatter; - if (postInfo.attached && postInfo.attached.length > 0) { - postInfo.attached.forEach(({ file: fileStr }) => { - const postPath = post.node.fields.slug; - const relFilePath = path.join( - __dirname, - "static", - "posts", - postPath, - fileStr - ); - const fileExists = fs.existsSync(path.resolve(relFilePath)); - if (!fileExists) { - console.error( - `Could not find file to attach in the static folder: ${postPath}${fileStr}` - ); - console.error( - `To fix this problem, attach the file to the static folder's expected path above, or remove it from the post frontmatter definition` - ); - process.exit(1); - } - }); - } - - createPage({ - path: `/posts${post.node.fields.slug}`, - component: blogPost, - context: { - slug: post.node.fields.slug, - previous, - next - } - }); - }); - - const postsPerPage = 8; - const numberOfPages = Math.ceil(posts.length / postsPerPage); - - createPage({ - path: "/", - component: postList, - context: { - limitNumber: postsPerPage, - skipNumber: 0, - pageIndex: 1, - numberOfPages, - absolutePath: "/" - } - }); - - for (const i of Array(numberOfPages).keys()) { - if (i === 0) continue; - const pageNum = i + 1; - const skipNumber = postsPerPage * i; - createPage({ - path: `/page/${pageNum}/`, - component: postList, - context: { - limitNumber: postsPerPage, - skipNumber, - pageIndex: pageNum, - numberOfPages, - absolutePath: "/" - } - }); - } - - unicorns.forEach(unicorn => { - const uniId = unicorn.node.id; - - const uniPosts = posts.filter(({ node: { frontmatter } }) => - frontmatter.authors.find(uni => uni.id === uniId) - ); - - const numberOfUniPages = Math.ceil(uniPosts.length / postsPerPage); - - createPage({ - path: `/unicorns/${uniId}/`, - component: blogProfile, - context: { - slug: uniId, - limitNumber: postsPerPage, - skipNumber: 0, - pageIndex: 1, - numberOfPages: numberOfUniPages, - absolutePath: `/unicorns/${uniId}/` - } - }); - - for (const i of Array(numberOfUniPages).keys()) { - if (i === 0) continue; - const pageNum = i + 1; - const skipNumber = postsPerPage * i; - createPage({ - path: `/unicorns/${uniId}/page/${pageNum}/`, - component: blogProfile, - context: { - slug: uniId, - limitNumber: postsPerPage, - skipNumber, - pageIndex: pageNum, - numberOfPages: numberOfUniPages, - absolutePath: `/unicorns/${uniId}/` - } - }); - } - }); - - return null; - }); -}; diff --git a/gatsby-ssr.js b/gatsby-ssr.js deleted file mode 100644 index 188ba7d5..00000000 --- a/gatsby-ssr.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Much of this code deals with dark mode. It's ripped straight from: - * @see https://joshwcomeau.com/gatsby/dark-mode/ - * - * Huge thanks to Josh for outlining how to do this - */ -import React from "react"; -import Terser from "terser"; - -import { - COLOR_MODE_KEY, - COLORS, - INITIAL_COLOR_MODE_CSS_PROP -} from "./src/constants"; - -/** - * DARK MODE CODE - * - * Prevents the "flash" of light mode - */ -/** - * Trust me, I know that it looks like we're reading entries from an emoji - * but what's really happening is that this function is being converted to a - * string, then mutated by "MagicScriptTag" in order to add in dynamic code - * into that string. This way, we're able to avoid duplicating - */ -function setColorsByTheme() { - const colors = "🌈"; - const colorModeKey = "πŸ”‘"; - const colorModeCssProp = "⚑️"; - - const mql = window.matchMedia("(prefers-color-scheme: dark)"); - const prefersDarkFromMQ = mql.matches; - const prefersDarkFromLocalStorage = localStorage.getItem(colorModeKey); - - let colorMode = "light"; - - const hasUsedToggle = typeof prefersDarkFromLocalStorage === "string"; - - if (hasUsedToggle) { - colorMode = prefersDarkFromLocalStorage; - } else { - colorMode = prefersDarkFromMQ ? "dark" : "light"; - } - - let root = document.documentElement; - - root.style.setProperty(colorModeCssProp, colorMode); - - Object.entries(colors).forEach(([name, colorByTheme]) => { - const cssVarName = `--${name}`; - - root.style.setProperty(cssVarName, colorByTheme[colorMode]); - }); -} - -const MagicScriptTag = () => { - const boundFn = String(setColorsByTheme) - .replace('"🌈"', JSON.stringify(COLORS)) - .replace("πŸ”‘", COLOR_MODE_KEY) - .replace("⚑️", INITIAL_COLOR_MODE_CSS_PROP); - - let calledFunction = `(${boundFn})()`; - - calledFunction = Terser.minify(calledFunction).code; - - // eslint-disable-next-line react/no-danger - return