├── .dependabot └── config.yml ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .prettierrc ├── .releaserc ├── LICENSE ├── README.md ├── docs └── CHANGELOG.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-ssr.js ├── index.js ├── jest-preprocess.js ├── package.json ├── setup-jest.js ├── src ├── @types │ ├── gatsby-plugin-google-analytics.d.ts │ ├── mdx.d.ts │ └── react-anchor-link-smooth-scroll.d.ts ├── components │ ├── Button │ │ ├── Button.tsx │ │ ├── CommandCenterButton.tsx │ │ ├── CopyToClipboardButton.tsx │ │ ├── LightDarkSwitcher.tsx │ │ ├── LinkButton.tsx │ │ ├── __tests__ │ │ │ ├── Button.spec.tsx │ │ │ └── __snapshots__ │ │ │ │ └── Button.spec.tsx.snap │ │ └── index.tsx │ ├── Callout │ │ ├── Callout.tsx │ │ ├── __tests__ │ │ │ ├── Callout.test.tsx │ │ │ └── __snapshots__ │ │ │ │ └── Callout.test.tsx.snap │ │ └── index.tsx │ ├── Flex │ │ ├── Flex.tsx │ │ ├── __tests__ │ │ │ ├── Flex.spec.tsx │ │ │ └── __snapshots__ │ │ │ │ └── Flex.spec.tsx.snap │ │ └── index.tsx │ ├── Footer │ │ ├── Footer.tsx │ │ ├── __tests__ │ │ │ └── Footer.spec.tsx │ │ └── index.tsx │ ├── GlobalStyles │ │ ├── GlobalStyles.tsx │ │ └── index.tsx │ ├── Header │ │ ├── Context.tsx │ │ ├── Logo.tsx │ │ ├── Navigation.tsx │ │ ├── Title.tsx │ │ ├── Wrapper.tsx │ │ ├── __tests__ │ │ │ └── Header.spec.tsx │ │ └── index.tsx │ ├── Hero │ │ ├── Hero.tsx │ │ ├── __tests__ │ │ │ └── Hero.spec.tsx │ │ └── index.tsx │ ├── Logo │ │ └── index.tsx │ ├── MDX │ │ ├── Blockquote │ │ │ ├── __tests__ │ │ │ │ ├── Blockquote.test.tsx │ │ │ │ └── __snapshots__ │ │ │ │ │ └── Blockquote.test.tsx.snap │ │ │ └── index.tsx │ │ ├── Code │ │ │ ├── __tests__ │ │ │ │ ├── Code.spec.tsx │ │ │ │ └── __snapshots__ │ │ │ │ │ └── Code.spec.tsx.snap │ │ │ └── index.tsx │ │ ├── MDX.tsx │ │ ├── Pill │ │ │ └── index.tsx │ │ ├── __tests__ │ │ │ ├── MDX.spec.tsx │ │ │ └── __snapshots__ │ │ │ │ └── MDX.spec.tsx.snap │ │ └── index.tsx │ ├── Pill │ │ ├── Pill.tsx │ │ ├── __tests__ │ │ │ ├── Pill.spec.tsx │ │ │ └── __snapshots__ │ │ │ │ └── Pill.spec.tsx.snap │ │ └── index.tsx │ ├── ProgressBar │ │ └── index.tsx │ ├── SearchBox │ │ ├── __tests__ │ │ │ └── SearchBox.spec.tsx │ │ └── index.tsx │ ├── Seo │ │ ├── SchemaOrg.tsx │ │ └── index.tsx │ ├── Signature │ │ ├── Signature.tsx │ │ └── index.tsx │ ├── VisuallyHidden │ │ ├── VisuallyHidden.tsx │ │ └── index.tsx │ └── Webmentions │ │ ├── WebmentionCount.tsx │ │ ├── WebmentionReplies.tsx │ │ ├── __tests__ │ │ ├── WebmentionCount.spec.tsx │ │ └── WebmentionReplies.spec.tsx │ │ └── index.tsx ├── constants │ ├── constants.tsx │ └── index.tsx ├── context │ ├── ThemeContext.tsx │ └── ThemeProvider.tsx ├── hooks │ ├── useDebouncedValue.ts │ └── useScrollCounter.ts ├── layouts │ ├── MainLayout.tsx │ └── index.tsx ├── pages │ └── 404.tsx ├── templates │ ├── BlogPost.tsx │ ├── PortfolioProject.tsx │ └── Snippet.tsx └── utils │ └── sectionize.ts ├── tsconfig.json └── yarn.lock /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | update_configs: 3 | - package_manager: 'javascript' 4 | directory: '/' 5 | update_schedule: 'weekly' 6 | default_labels: 7 | - 'dependencies' 8 | target_branch: 'main' 9 | version_requirement_updates: 'increase_versions' 10 | automerged_updates: 11 | - match: 12 | dependency_type: 'development' 13 | update_type: 'semver:patch' 14 | commit_message: 15 | prefix: 'chore' 16 | include_scope: true 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | }, 6 | extends: [ 7 | 'plugin:react/recommended', 8 | 'plugin:prettier/recommended', 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | ], 11 | globals: { 12 | Atomics: 'readonly', 13 | SharedArrayBuffer: 'readonly', 14 | }, 15 | parser: '@typescript-eslint/parser', 16 | parserOptions: { 17 | ecmaFeatures: { 18 | jsx: true, 19 | }, 20 | ecmaVersion: 2018, 21 | sourceType: 'module', 22 | }, 23 | plugins: ['@typescript-eslint', 'react', 'react-hooks'], 24 | rules: { 25 | 'react-hooks/rules-of-hooks': 'error', 26 | 'react-hooks/exhaustive-deps': 'warn', 27 | 'react/prop-types': 0, 28 | 'no-console': 'error', 29 | }, 30 | settings: { react: { version: 'detect' } }, 31 | }; 32 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - publish 8 | 9 | jobs: 10 | lint-format-test-type-check: 11 | runs-on: ubuntu-20.04 12 | strategy: 13 | matrix: 14 | node: [12.x] 15 | steps: 16 | - name: Checkout Commit 17 | uses: actions/checkout@v1 18 | - name: Use Node.js ${{ matrix.node }} 19 | uses: actions/setup-node@v1 20 | with: 21 | node: ${{ matrix.node }} 22 | - name: Install Dependencies 23 | if: steps.cache-dependencies.outputs.cache-hit != 'true' 24 | run: | 25 | yarn install --force --non-interactive 26 | - name: Run Prettier 27 | run: | 28 | yarn format 29 | - name: Run Lint 30 | run: | 31 | yarn lint 32 | - name: Run Unit Tests 33 | run: | 34 | yarn test:coverage 35 | - name: Run Type Checking 36 | run: | 37 | yarn type-check 38 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - publish 7 | jobs: 8 | release: 9 | name: Release 10 | runs-on: ubuntu-18.04 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v1 14 | - name: Setup Node.js 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 12 18 | - name: Install dependencies 19 | run: yarn 20 | - name: Release 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 23 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 24 | run: npx semantic-release 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | cypress/screenshots 72 | cypress/videos -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branches": ["publish"], 3 | "plugins": [ 4 | ["@semantic-release/commit-analyzer", { 5 | "preset": "angular", 6 | "parserOpts": { 7 | "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"] 8 | }, 9 | "releaseRules": [ 10 | { 11 | "type": "style", 12 | "release": "patch" 13 | } 14 | ] 15 | }], 16 | ["@semantic-release/release-notes-generator", { 17 | "preset": "angular", 18 | "parserOpts": { 19 | "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"] 20 | }, 21 | "releaseRules": [ 22 | { 23 | "type": "style", 24 | "release": "patch" 25 | } 26 | ], 27 | "writerOpts": { 28 | "commitsSort": ["subject", "scope"] 29 | } 30 | }], 31 | ["@semantic-release/changelog", { 32 | "changelogFile": "docs/CHANGELOG.md", 33 | "changelogTitle": "# Gatsby-theme-maximeheckel" 34 | }], 35 | ["@semantic-release/npm", { 36 | "npmPublish": true, 37 | }], 38 | ["@semantic-release/git", { 39 | "assets": ["docs/CHANGELOG.md", "package.json"], 40 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 41 | }], 42 | ["@semantic-release/github", { 43 | "assets": "dist/*.tgz" 44 | }], 45 | ] 46 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Maxime Heckel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gatsby-theme-maximeheckel 2 | 3 | This is my gatsby theme that contains the main config / components / branding of my personal websites: 4 | 5 | - [Blog](https://blog.maximeheckel.com) 6 | - [Portfolio](https://maximeheckel.com) 7 | 8 | This theme is built for my own requirements. For any questions / inquiry about it you can reach me on Twitter at [@MaximeHeckel](https://twitter.com/MaximeHeckel). 9 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Gatsby-theme-maximeheckel 2 | 3 | ## [1.2.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.2.1...v1.2.2) (2021-04-16) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * Add missing components for new blog post ([dcbbe6a](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/dcbbe6a198600429a606383132d85e28ca4c6eba)) 9 | 10 | ## [1.2.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.2.0...v1.2.1) (2021-01-31) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * **theme:** Ensure arrow svg used in li responds to theme changes ([b99e799](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/b99e799f543f1d802cdfdc76cf6d62c29c1c0b7b)) 16 | 17 | # [1.2.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.1.1...v1.2.0) (2021-01-04) 18 | 19 | 20 | ### Features 21 | 22 | * Update portfolio project template ([16a96d6](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/16a96d640f7d1bf6da6be9eeb6c1b692d8b6542d)) 23 | 24 | ## [1.1.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.1.0...v1.1.1) (2020-12-30) 25 | 26 | 27 | ### Bug Fixes 28 | 29 | * **a11y:** Fix wrong aria-label references in lightdarkswitcher button ([cc6768f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/cc6768fa7fdcd8498076e53f85bb7d5dde8c6a2e)) 30 | 31 | # [1.1.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.0.1...v1.1.0) (2020-12-30) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * Fix header not collapsing properly and hidding tooltips ([6f1bb42](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6f1bb42037fc9fd6641fb8344dda007205281dc6)) 37 | 38 | 39 | ### Features 40 | 41 | * Introduce first version of tooltip component ([a846cf0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/a846cf0e6b0786442e49c5bc8db67c3cb0e5fc27)) 42 | 43 | ## [1.0.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v1.0.0...v1.0.1) (2020-12-28) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * revert framer motion to 2.6.13 ([b4ef14c](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/b4ef14cbba8a78f916762662cb3aaa31586eaf87)) 49 | 50 | # [1.0.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.15.0...v1.0.0) (2020-12-28) 51 | 52 | 53 | * Merge pull request #427 from MaximeHeckel/main ([6d3e7b3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6d3e7b347b343118a938a469b6ec22bb48a7c8bb)), closes [#427](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/issues/427) 54 | 55 | 56 | ### BREAKING CHANGES 57 | 58 | * new color palette, new font scale, js based theme deprecation 59 | 60 | # [0.15.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.7...v0.15.0) (2020-12-27) 61 | 62 | 63 | ### Features 64 | 65 | * Add VisuallyHidden component ([44f4eb4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/44f4eb4373ecb68491a8d4b62f740a299cf2229d)) 66 | 67 | ## [0.14.7](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.6...v0.14.7) (2020-12-15) 68 | 69 | 70 | ### Bug Fixes 71 | 72 | * **component:** Fix overflow style in searchbox ([3b40f3c](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/3b40f3cc1c922e0a6a6e47e1c6d36857842afbb2)) 73 | 74 | ## [0.14.6](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.5...v0.14.6) (2020-12-15) 75 | 76 | 77 | ### Bug Fixes 78 | 79 | * **component:** Fix scrollbar artifacts showing up in code snippet component when macOS scrollbar is always enabled ([201223b](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/201223ba78721ec391a8d2144fdbb51d4f830ef9)) 80 | 81 | ## [0.14.5](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.4...v0.14.5) (2020-12-10) 82 | 83 | ## [0.14.4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.3...v0.14.4) (2020-11-22) 84 | 85 | 86 | ### Bug Fixes 87 | 88 | * **webmention:** Improve animation and dedup webmentions replies ([c59de3b](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/c59de3b7aa7dc319b82597a84ca5800212c38dd8)) 89 | 90 | ## [0.14.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.2...v0.14.3) (2020-11-21) 91 | 92 | 93 | ### Bug Fixes 94 | 95 | * **a11y:** Fix missing aria label in RSS Feed button ([d8776bb](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/d8776bb1acec43d0100658499423e7b40b987512)) 96 | 97 | ## [0.14.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.1...v0.14.2) (2020-10-22) 98 | 99 | 100 | ### Bug Fixes 101 | 102 | * **header:** fix icons overflowing to the left because of title size ([ae62294](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/ae62294efe8eda8b2fef0bc25895fe8b5ff8ef9b)) 103 | 104 | ## [0.14.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.14.0...v0.14.1) (2020-10-22) 105 | 106 | 107 | ### Bug Fixes 108 | 109 | * trigger release ([8acf63c](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8acf63c55f9a4da5150afd31e639d1cbe635b077)) 110 | 111 | # [0.14.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.5...v0.14.0) (2020-10-14) 112 | 113 | 114 | ### Features 115 | 116 | * **logo:** Add new logo ([64d5909](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/64d5909f57fed1d48c64ff4334b1525dd1fda936)) 117 | 118 | ## [0.13.5](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.4...v0.13.5) (2020-10-13) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * **shortcut:** Fix esc key toggling lock scroll ([00ea294](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/00ea294a3337abd78c85f43dda5599cd085a95e3)) 124 | 125 | ## [0.13.4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.3...v0.13.4) (2020-10-02) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * **hero:** Let gatsby pages override hero style ([19f79d4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/19f79d4b91d45dc0f26911945b89b185ab1513d6)) 131 | 132 | ## [0.13.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.2...v0.13.3) (2020-10-02) 133 | 134 | 135 | ### Bug Fixes 136 | 137 | * **button:** Fix padding shrinking icons on safari mobile ([9bcc899](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/9bcc899665003e2bbb8530e82c747e3f580f5909)) 138 | 139 | ## [0.13.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.1...v0.13.2) (2020-10-02) 140 | 141 | ## [0.13.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.13.0...v0.13.1) (2020-09-26) 142 | 143 | 144 | ### Bug Fixes 145 | 146 | * **component:** Fix undefined theme issue ([ec71590](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/ec71590a7069b9e6a23a4faca846b5d692e1e15a)) 147 | 148 | # [0.13.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.12.1...v0.13.0) (2020-09-26) 149 | 150 | 151 | ### Features 152 | 153 | * **theme:** Add dark/light mode code snippet colors ([8ce53b3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8ce53b33c9bf5d4c89860af94077a2b2db7361ab)) 154 | * **components:** Update code snippet component, copy to clipboard button and theme ([3123cec](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/3123cec124e0d91998c39a2d878b74fc610a1611)) 155 | 156 | ## [0.12.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.12.0...v0.12.1) (2020-09-17) 157 | 158 | 159 | ### Bug Fixes 160 | 161 | * **webmention:** Fix invalid webmention ([ac2f0e9](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/ac2f0e96931886be265d5bb64a624bc9ba7a2b77)) 162 | 163 | # [0.12.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.11.1...v0.12.0) (2020-09-11) 164 | 165 | 166 | ### Features 167 | 168 | * **layout:** Add suport for Plyr ([dbc7c2f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/dbc7c2ff21e19f7dd05dec208142233da802ede7)) 169 | 170 | ## [0.11.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.11.0...v0.11.1) (2020-08-23) 171 | 172 | 173 | ### Bug Fixes 174 | 175 | * **component:** Add support for Swift language for Code component ([c203f0d](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/c203f0db57c4e23211ec4a15cdd350f9216146af)) 176 | 177 | # [0.11.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.10.1...v0.11.0) (2020-08-03) 178 | 179 | 180 | ### Features 181 | 182 | * **seo:** Add canonical url tag in SEO component ([a8ba107](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/a8ba107b35bcb795eae97d7ca4451932e1550bcd)) 183 | 184 | ## [0.10.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.10.0...v0.10.1) (2020-08-03) 185 | 186 | 187 | ### Bug Fixes 188 | 189 | * **ssr:** Revert changes made in ssr and browser files in 0.9.9 ([a790eb2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/a790eb259999ca32cbb6ef1cc23f0799e1e55d5e)) 190 | 191 | # [0.10.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.9...v0.10.0) (2020-08-02) 192 | 193 | 194 | ### Features 195 | 196 | * Consistent code snippet theme and dark mode readability improvements ([414c9a3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/414c9a328f9d859f7b2b59b0a3620d2601272301)) 197 | 198 | ## [0.9.9](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.8...v0.9.9) (2020-06-29) 199 | 200 | 201 | ### Bug Fixes 202 | 203 | * Gatsby Plugin Feed wants names export wrapRootElement in ThemeProvider ([4f5ff7f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/4f5ff7fc06640b700dc06e336ce89d08a674f00d)) 204 | 205 | ## [0.9.8](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.7...v0.9.8) (2020-06-28) 206 | 207 | 208 | ### Bug Fixes 209 | 210 | * **a11y:** Fix blue and gray color in light mode to bring accessibility score to a 100% ([a5244fb](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/a5244fbe1bcc22c5d616e1a498b7e845de1521bd)) 211 | 212 | ## [0.9.7](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.6...v0.9.7) (2020-06-23) 213 | 214 | 215 | ### Bug Fixes 216 | 217 | * **webmentions:** Restrict height of reply avatar to avoid oval pictures ([f959378](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/f9593787633ae656ee5767a8160cd2dfe9b58887)) 218 | 219 | ## [0.9.6](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.5...v0.9.6) (2020-06-19) 220 | 221 | 222 | ### Bug Fixes 223 | 224 | * **types:** Fix new type checking issues ([43f63cd](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/43f63cdaaa3398ba5e1054b93ee97ca49cbaf498)) 225 | 226 | ## [0.9.5](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.4...v0.9.5) (2020-06-15) 227 | 228 | 229 | ### Bug Fixes 230 | 231 | * **live-scope:** Add missing Recharts dependency to allow drawing charts in react-live ([e756187](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/e75618765bd23cc5e70f9238065d2cf66a389b7e)) 232 | 233 | ## [0.9.4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.3...v0.9.4) (2020-05-30) 234 | 235 | 236 | ### Bug Fixes 237 | 238 | * **layout:** Ensure consistent initial visual paddingbetween h1 progressbar and header ([64d2df9](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/64d2df90a642a047a7fc1f5c6bc46baa52734a3e)) 239 | * **header:** Fix header title ellipsis not rendering ([6eccec8](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6eccec8859bd68b9a24ebd4ce29043e5c2c5230e)) 240 | * **progress-bar:** Fix table of content item showing up on hover when progress bar was completely hidden ([803afc0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/803afc02326bfcabeade05ffa06040eb4c5cb7cf)) 241 | * **search:** Make sure to not call navigate on change to keep current scroll position ([7545e5d](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/7545e5d074bcb74d7fdc629a68e5c29539db99b8)) 242 | 243 | ## [0.9.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.2...v0.9.3) (2020-05-29) 244 | 245 | 246 | ### Bug Fixes 247 | 248 | * **theme:** Update light background color to #FFFFFF ([8f5cead](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8f5cead9b2af4a884a671b816c55d0aeba08bf36)) 249 | 250 | ## [0.9.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.1...v0.9.2) (2020-05-29) 251 | 252 | 253 | ### Bug Fixes 254 | 255 | * **button:** Fix animation time and type for button + add Vercel deploy style button ([93c4d0b](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/93c4d0b40cdeb34d143637456cd6e26762cf4674)) 256 | 257 | ## [0.9.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.9.0...v0.9.1) (2020-05-21) 258 | 259 | 260 | ### Bug Fixes 261 | 262 | * **components:** Improve framer motion animation ([53c34a7](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/53c34a7295d0734733bd38399aedbb02770858a6)) 263 | * **layout:** Make layout for blog posts wider and remove description in post view ([5b26fa8](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/5b26fa84055b3d768798c0ea7ffa97dc9737e842)) 264 | 265 | # [0.9.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.8.1...v0.9.0) (2020-05-20) 266 | 267 | 268 | ### Features 269 | 270 | * **layout:** Add snippet layout ([835afc1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/835afc1a0acd37fbbcbb2382132e365c6dbcf7a5)) 271 | 272 | ## [0.8.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.8.0...v0.8.1) (2020-05-12) 273 | 274 | 275 | ### Bug Fixes 276 | 277 | * **component:** Fix floating title bar in Code component ([2df8c94](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/2df8c94fd981a3d7ed525abc3699d991b4fc079f)) 278 | * **components:** Use motion.[component] in emotion styled function ([207faac](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/207faacf437e72b768ceb8629f4c969863aedf75)) 279 | 280 | # [0.8.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.7.3...v0.8.0) (2020-05-09) 281 | 282 | 283 | ### Features 284 | 285 | * **component:** Add live code editor ([#141](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/issues/141)) ([6a2486f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6a2486f8b34a8827ba8641c7a631f7c3a639c2ea)) 286 | 287 | ## [0.7.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.7.2...v0.7.3) (2020-05-03) 288 | 289 | 290 | ### Performance Improvements 291 | 292 | * Refactor templates and components ([e44a72b](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/e44a72b8bcea70cb52a7b291e17afa0bb9aff43d)) 293 | 294 | ## [0.7.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.7.1...v0.7.2) (2020-04-23) 295 | 296 | 297 | ### Bug Fixes 298 | 299 | * **webmentions:** Add missing replies ([836c3dd](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/836c3dd52c086eaed9121db344e0bcd119ab93e2)) 300 | 301 | ## [0.7.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.7.0...v0.7.1) (2020-04-22) 302 | 303 | 304 | ### Bug Fixes 305 | 306 | * **webmentions:** Fix InfoRow responsiveness ([0a3f41a](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/0a3f41ad5d5fa554f687b85c899e86bd94293f41)) 307 | 308 | # [0.7.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.6.0...v0.7.0) (2020-04-22) 309 | 310 | 311 | ### Features 312 | 313 | * **webmentions:** Add webmention counter in blog layout ([6d44e58](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6d44e585e2d1daac65512ffcdc757b0ecd8dfbab)) 314 | 315 | # [0.6.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.6...v0.6.0) (2020-04-21) 316 | 317 | 318 | ### Features 319 | 320 | * **layout:** Add microformats2 support ([0ba2e4f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/0ba2e4ff13307816e1d75a0d04119cf0fd7c2447)) 321 | 322 | ## [0.5.6](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.5...v0.5.6) (2020-04-21) 323 | 324 | 325 | ### Bug Fixes 326 | 327 | * **release:** Fix release pipeline not including style commits in changelog ([dde34d8](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/dde34d83932d5c961881542b0209442abe6715b2)) 328 | * **webmentions:** Fix twitter link for webmentions login ([3ff7680](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/3ff7680f488696fb2122a60071dca4decd5d43c7)) 329 | 330 | ## [0.5.5](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.4...v0.5.5) (2020-04-18) 331 | 332 | ## [0.5.4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.3...v0.5.4) (2020-04-18) 333 | 334 | ## [0.5.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.2...v0.5.3) (2020-04-18) 335 | 336 | 337 | ### Bug Fixes 338 | 339 | * Replace unsafe first-child with first-of-type ([419692e](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/419692eff8e60d11e26e62525601f256f90fd33c)) 340 | 341 | ## [0.5.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.1...v0.5.2) (2020-04-16) 342 | 343 | 344 | ### Bug Fixes 345 | 346 | * **dark mode:** Use css variables for main theme color to avoid dark mode flash (removes previous css hack) ([323cf51](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/323cf51611969027a38c8ef5d85ff80ddd2a3d56)) 347 | 348 | ## [0.5.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.5.0...v0.5.1) (2020-04-14) 349 | 350 | 351 | ### Bug Fixes 352 | 353 | * **layout:** Fix missing body background color from theme ([5e50786](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/5e5078697f163e43d16be7989d7b14ea1a1e875f)) 354 | 355 | # [0.5.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.4.0...v0.5.0) (2020-04-14) 356 | 357 | 358 | ### Features 359 | 360 | * **layout:** Add spy scroll to table of content ([0998923](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/0998923c94e4935e302da3cffe673eced99de1b7)) 361 | 362 | # [0.4.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.3.0...v0.4.0) (2020-04-05) 363 | 364 | 365 | ### Features 366 | 367 | * **seo:** Improve SEO component with schema.org script ([67af9f7](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/67af9f7940d9fb59377562e6f4415a55dee00b0e)) 368 | 369 | # [0.3.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.2.4...v0.3.0) (2020-04-04) 370 | 371 | 372 | ### Features 373 | 374 | * Add Fira Code font for MDX component ([2b22170](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/2b2217012a3581562aab19d84804d647a30b3d4e)) 375 | 376 | ## [0.2.4](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.2.3...v0.2.4) (2020-04-04) 377 | 378 | 379 | ### Bug Fixes 380 | 381 | * **a11y:** Fix keydown handler on light/dark switch ([9d225a7](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/9d225a78bb1d8f1e7b807c641a108f60df021bcd)) 382 | * **theme:** Tweak theme colors and ensure style consistency ([8e465a9](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8e465a920bb5a33516fce690dc04943e68d1520a)) 383 | 384 | ## [0.2.3](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.2.2...v0.2.3) (2020-03-29) 385 | 386 | 387 | ### Bug Fixes 388 | 389 | * **deps:** Fix sharp dependency conflict ([c81cffd](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/c81cffdb5aaec7218bb5a24115abd97b8baeae26)) 390 | 391 | ## [0.2.2](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.2.1...v0.2.2) (2020-03-29) 392 | 393 | 394 | ### Bug Fixes 395 | 396 | * **layout:** Change date format to MM/DD/YYYY in main layout ([5137de6](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/5137de62af55da043e2108100290e262fef8014b)) 397 | * **a11y:** Make light/dark switcher accessible via tab ([bac9e4f](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/bac9e4f1397ec5d4391f2720571340d9f9c9cbfa)) 398 | 399 | ## [0.2.1](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.2.0...v0.2.1) (2020-03-08) 400 | 401 | 402 | ### Bug Fixes 403 | 404 | * Fix default color of ToC links in ProgressBar ([6661d84](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/6661d84cd7daf27570bd46f14fafd2f62eb4da8b)) 405 | 406 | # [0.2.0](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/compare/v0.1.55...v0.2.0) (2020-03-08) 407 | 408 | 409 | ### Bug Fixes 410 | 411 | * Improve box shadow header in dark mode ([fdefe43](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/fdefe430993d2e039a6b48a46bd3db0ed192810f)) 412 | * Release GH workflow ([8273b7d](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8273b7d61c8f92a998740692bf261ab740bd7472)) 413 | * Update footer ([a27c59e](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/a27c59e29f40cd1a1c54559320547849526b7f82)) 414 | 415 | 416 | ### Features 417 | 418 | * Branding adjustments ([#27](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/issues/27)) ([0b1ff19](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/0b1ff19f14bc33392c1c70ddb5e381f7d6c49bda)) 419 | * Introduce new foreground color ([06dd8ba](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/06dd8baa366ea739963d8c4822f4a6ea632197fd)) 420 | * New appearance for links, blockquotes and signature ([8392415](https://github.com/MaximeHeckel/gatsby-theme-maximeheckel/commit/8392415a5470f7c5fcf6cb9063dcf460a4c27c8d)) 421 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Import fonts to expose them globaly 3 | */ 4 | import 'typeface-fira-code'; 5 | 6 | import React from 'react'; 7 | import RootWrapper from './src/context/ThemeProvider'; 8 | 9 | export const wrapRootElement = ({ element }) => { 10 | return {element}; 11 | }; 12 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | plugins: [ 6 | { 7 | resolve: 'gatsby-plugin-mdx', 8 | options: { 9 | extensions: ['.mdx', '.md'], 10 | defaultLayouts: { 11 | default: require.resolve('./src/templates/BlogPost.tsx'), 12 | posts: require.resolve('./src/templates/BlogPost.tsx'), 13 | projects: require.resolve('./src/templates/PortfolioProject.tsx'), 14 | snippets: require.resolve('./src/templates/Snippet.tsx'), 15 | }, 16 | remarkPlugins: [require('remark-toc')], 17 | gatsbyRemarkPlugins: [ 18 | { 19 | resolve: 'gatsby-remark-images', 20 | options: { 21 | maxWidth: 900, 22 | backgroundColor: 'transparent', 23 | showCaptions: true, 24 | }, 25 | }, 26 | 'gatsby-remark-copy-linked-files', 27 | 'gatsby-remark-sectionize', 28 | { 29 | resolve: 'gatsby-remark-autolink-headers', 30 | options: { 31 | icon: ``, 32 | }, 33 | }, 34 | ], 35 | }, 36 | }, 37 | 'gatsby-transformer-sharp', 38 | 'gatsby-plugin-sharp', 39 | { 40 | resolve: 'gatsby-plugin-typography', 41 | options: { 42 | pathToConfigModule: './src/utils/typography', 43 | }, 44 | }, 45 | { 46 | resolve: `gatsby-plugin-page-creator`, 47 | options: { 48 | path: path.resolve(__dirname, `src/pages`), 49 | }, 50 | }, 51 | 'gatsby-plugin-emotion', 52 | 'gatsby-plugin-react-helmet', 53 | 'gatsby-plugin-twitter', 54 | ], 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RootWrapper from './src/context/ThemeProvider'; 3 | 4 | export const wrapRootElement = ({ element }) => ( 5 | {element} 6 | ); 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | export { default as Button } from './src/components/Button'; 2 | export { Code, CodeBlock } from './src/components/Code'; 3 | export { default as Footer } from './src/components/Footer'; 4 | export { default as Header } from './src/components/Header'; 5 | export { default as GlobalStyles } from './src/components/GlobalStyles'; 6 | export { default as Logo } from './src/components/Logo'; 7 | export { default as Seo } from './src/components/Seo'; 8 | export { default as styled } from './src/utils/styled'; 9 | -------------------------------------------------------------------------------- /jest-preprocess.js: -------------------------------------------------------------------------------- 1 | const babelOptions = { 2 | presets: ['babel-preset-gatsby', '@babel/preset-typescript'], 3 | }; 4 | module.exports = require('babel-jest').createTransformer(babelOptions); 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-theme-maximeheckel", 3 | "description": "Gatsby theme for maximeheckel.com and other consumer gatsby projects", 4 | "version": "1.2.2", 5 | "main": "index.js", 6 | "types": "dist/index.d.ts", 7 | "author": "Maxime Heckel ", 8 | "license": "MIT", 9 | "scripts": { 10 | "format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx}\"", 11 | "lint": "eslint --ext=jsx,ts,tsx src", 12 | "semantic-release": "semantic-release", 13 | "test": "is-ci \"test:coverage\" \"test:watch\"", 14 | "test:coverage": "jest --coverage", 15 | "test:watch": "jest --watch", 16 | "type-check": "tsc --noEmit" 17 | }, 18 | "dependencies": { 19 | "@emotion/core": "^10.0.6", 20 | "@emotion/styled": "^10.0.6", 21 | "@sindresorhus/slugify": "^0.11.0", 22 | "focus-trap-react": "^6.0.0", 23 | "framer-motion": "3.1.1", 24 | "gatsby": "2.23.4", 25 | "gatsby-image": "2.4.7", 26 | "gatsby-plugin-emotion": "4.1.22", 27 | "gatsby-plugin-google-analytics": "^2.3.4", 28 | "gatsby-plugin-mdx": "^1.2.6", 29 | "gatsby-plugin-page-creator": "^2.1.5", 30 | "gatsby-plugin-react-helmet": "3.3.4", 31 | "gatsby-plugin-sharp": "2.6.11", 32 | "gatsby-plugin-twitter": "^2.3.1", 33 | "gatsby-plugin-typography": "^2.5.4", 34 | "gatsby-remark-autolink-headers": "^2.2.1", 35 | "gatsby-remark-copy-linked-files": "^2.2.1", 36 | "gatsby-remark-embed-gist": "^1.1.9", 37 | "gatsby-remark-embedder": "^2.0.1", 38 | "gatsby-remark-images": "^3.3.10", 39 | "gatsby-remark-sectionize": "^1.0.0", 40 | "gatsby-transformer-sharp": "2.4.3", 41 | "mousetrap": "^1.6.5", 42 | "plyr": "3.6.2", 43 | "prism-react-renderer": "^1.1.1", 44 | "prismjs": "^1.20.0", 45 | "react-anchor-link-smooth-scroll": "^1.0.11", 46 | "react-error-boundary": "^1.2.5", 47 | "react-helmet": "5.2.1", 48 | "react-intersection-observer": "^8.30.3", 49 | "react-live": "^2.2.2", 50 | "react-scrollspy": "^3.4.2", 51 | "react-simple-code-editor": "^0.11.0", 52 | "react-tooltip": "^4.2.5", 53 | "recharts": "^1.8.5", 54 | "remark-toc": "^7.0.0", 55 | "typeface-fira-code": "^1.1.4" 56 | }, 57 | "devDependencies": { 58 | "@babel/preset-typescript": "7.9.0", 59 | "@semantic-release/changelog": "^5.0.1", 60 | "@semantic-release/git": "^9.0.0", 61 | "@semantic-release/npm": "^7.0.5", 62 | "@testing-library/react": "^10.0.1", 63 | "@types/mousetrap": "^1.6.3", 64 | "@types/reach__router": "^1.3.5", 65 | "@types/react-helmet": "^5.0.15", 66 | "@types/react-scrollspy": "^3.3.2", 67 | "@types/recharts": "^1.8.12", 68 | "@typescript-eslint/eslint-plugin": "^3.3.0", 69 | "@typescript-eslint/parser": "^2.31.0", 70 | "babel-jest": "^26.0.1", 71 | "eslint": "^6.8.0", 72 | "eslint-config-prettier": "^6.11.0", 73 | "eslint-plugin-prettier": "^3.1.4", 74 | "eslint-plugin-react-hooks": "^4.0.0", 75 | "identity-obj-proxy": "^3.0.0", 76 | "is-ci-cli": "^2.0.0", 77 | "jest": "26.0.0", 78 | "jest-dom": "^3.0.2", 79 | "jest-emotion": "^10.0.32", 80 | "jest-fetch-mock": "^3.0.3", 81 | "prettier": "^2.0.2", 82 | "react": "16.13.1", 83 | "react-dom": "16.13.1", 84 | "semantic-release": "^17.0.7", 85 | "typescript": "^3.8.2" 86 | }, 87 | "peerDependencies": { 88 | "@mdx-js/mdx": "^1.6.1", 89 | "@mdx-js/react": "^1.1.6", 90 | "react": "16.13.1", 91 | "react-dom": "16.13.1" 92 | }, 93 | "jest": { 94 | "snapshotSerializers": [ 95 | "jest-emotion" 96 | ], 97 | "setupFilesAfterEnv": [ 98 | "./setup-jest.js" 99 | ], 100 | "globals": { 101 | "__PATH_PREFIX__": "" 102 | }, 103 | "testURL": "http://localhost", 104 | "transform": { 105 | "^.+\\.[jt]sx?$": "/jest-preprocess.js" 106 | }, 107 | "transformIgnorePatterns": [ 108 | "node_modules/(?!(gatsby)/)" 109 | ], 110 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx)$", 111 | "testPathIgnorePatterns": [ 112 | "node_modules", 113 | ".cache" 114 | ], 115 | "moduleNameMapper": { 116 | "typeface-*": "identity-obj-proxy", 117 | ".+\\.(css|styl|less|sass|scss)$": "identity-obj-proxy", 118 | ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/file.js" 119 | }, 120 | "collectCoverage": false, 121 | "coverageReporters": [ 122 | "lcov", 123 | "text", 124 | "html" 125 | ] 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /setup-jest.js: -------------------------------------------------------------------------------- 1 | import 'jest-dom/extend-expect'; 2 | 3 | global.___loader = { 4 | enqueue: jest.fn(), 5 | }; 6 | global.__BASE_PATH__ = ``; 7 | 8 | if (!SVGElement.prototype.getTotalLength) { 9 | SVGElement.prototype.getTotalLength = () => 1; 10 | } 11 | -------------------------------------------------------------------------------- /src/@types/gatsby-plugin-google-analytics.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'gatsby-plugin-google-analytics' { 2 | let OutboundLink: (props: any) => JSX.Element; 3 | export { OutboundLink }; 4 | } 5 | -------------------------------------------------------------------------------- /src/@types/mdx.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@mdx-js/react' { 2 | let MDXProvider: (props: any) => JSX.Element; 3 | export { MDXProvider }; 4 | } 5 | -------------------------------------------------------------------------------- /src/@types/react-anchor-link-smooth-scroll.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-anchor-link-smooth-scroll' { 2 | let AnchorLink: (props: any) => JSX.Element; 3 | export default AnchorLink; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { motion } from 'framer-motion'; 3 | import styled from '@emotion/styled'; 4 | import React from 'react'; 5 | interface ButtonProps { 6 | primary?: boolean; 7 | secondary?: boolean; 8 | tertiary?: boolean; 9 | white?: boolean; 10 | danger?: boolean; 11 | vercel?: boolean; 12 | disabled?: boolean; 13 | children: ReactNode; 14 | onClick?: () => any; 15 | } 16 | 17 | const StyledButton = styled(motion.button)` 18 | height: 48px; 19 | margin: 0; 20 | border: none; 21 | cursor: pointer; 22 | display: inline-flex; 23 | justify-content: center; 24 | align-items: center; 25 | position: relative; 26 | font-weight: 600; 27 | font-size: 18px; 28 | padding: 0 30px; 29 | border-radius: var(--border-radius-1); 30 | 31 | &:focus:not(:focus-visible) { 32 | outline: 0; 33 | } 34 | 35 | &:focus-visible { 36 | outline: 2px solid var(--maximeheckel-colors-brand); 37 | background-color: var(--maximeheckel-colors-foreground); 38 | } 39 | 40 | ${(p) => 41 | p.primary 42 | ? ` 43 | background-color: var(--maximeheckel-colors-brand); 44 | color: hsla(var(--palette-gray-00), 100%); 45 | min-width: 150px; 46 | 47 | ${ 48 | p.danger 49 | ? ` 50 | background-color: var(--maximeheckel-colors-danger); 51 | ` 52 | : '' 53 | } 54 | 55 | ${ 56 | p.vercel 57 | ? ` 58 | display: flex; 59 | align-item: center; 60 | color: var(--maximeheckel-colors-body); 61 | background-color: var(--maximeheckel-colors-typeface-0); 62 | ` 63 | : '' 64 | } 65 | 66 | ${ 67 | p.disabled 68 | ? ` 69 | cursor: not-allowed; 70 | opacity: 0.5; 71 | background-color: var(--maximeheckel-colors-typeface-1); 72 | color: #000000; 73 | &:hover { 74 | transform: none; 75 | } 76 | ` 77 | : '' 78 | } 79 | 80 | ` 81 | : ''}; 82 | 83 | ${(p) => 84 | p.secondary 85 | ? ` 86 | background-color: transparent; 87 | color: var(--maximeheckel-colors-brand); 88 | border: 2px solid var(--maximeheckel-colors-brand); 89 | min-width: 150px; 90 | 91 | ${ 92 | p.danger 93 | ? ` 94 | color: var(--maximeheckel-colors-danger); 95 | border-color: var(--maximeheckel-colors-danger); 96 | ` 97 | : '' 98 | } 99 | 100 | ${ 101 | p.disabled 102 | ? ` 103 | cursor: not-allowed; 104 | opacity: 0.5; 105 | color: var(--maximeheckel-colors-typeface-1); 106 | border-color: var(--maximeheckel-colors-typeface-1); 107 | &:hover { 108 | transform: none; 109 | } 110 | ` 111 | : '' 112 | } 113 | 114 | ` 115 | : ''}; 116 | 117 | ${(p) => 118 | p.tertiary 119 | ? ` 120 | background-color: transparent; 121 | color: var(--maximeheckel-colors-brand); 122 | min-width: inherited; 123 | padding: 0px; 124 | 125 | ::after { 126 | content: ''; 127 | display: block; 128 | position: absolute; 129 | top: 96%; 130 | left: 0; 131 | right: 0; 132 | height: 2px; 133 | background-color: var(--maximeheckel-colors-brand); 134 | transform: scaleX(0); 135 | transition: transform 0.25s ease-in; 136 | transform-origin: right center; 137 | text-decoration: none; 138 | } 139 | 140 | &:hover::after { 141 | transform: scale(1); 142 | transform-origin: left center; 143 | } 144 | 145 | ${ 146 | p.danger 147 | ? ` 148 | color: var(--maximeheckel-colors-danger); 149 | ::after { 150 | background-color: var(--maximeheckel-colors-danger); 151 | } 152 | ` 153 | : '' 154 | } 155 | 156 | ${ 157 | p.disabled 158 | ? ` 159 | opacity: 0.5; 160 | cursor: not-allowed; 161 | color: var(--maximeheckel-colors-typeface-1); 162 | ::after { 163 | background-color: var(--maximeheckel-colors-typeface-1); 164 | } 165 | ` 166 | : '' 167 | } 168 | ` 169 | : ''}; 170 | `; 171 | 172 | const Button = React.forwardRef( 173 | ({ children, ...props }: ButtonProps, ref: React.Ref) => { 174 | return ( 175 | 181 | {props.vercel ? ( 182 | Vercel logo 191 | ) : null} 192 | {children} 193 | 194 | ); 195 | } 196 | ); 197 | 198 | Button.displayName = 'Button'; 199 | 200 | export { Button }; 201 | -------------------------------------------------------------------------------- /src/components/Button/CommandCenterButton.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/core'; 2 | import { motion, useAnimation, useMotionValue } from 'framer-motion'; 3 | import React from 'react'; 4 | import VisuallyHidden from '../VisuallyHidden'; 5 | import { LinkButton } from './LinkButton'; 6 | 7 | interface Props { 8 | onClick: () => void; 9 | isSearchShown: boolean; 10 | } 11 | 12 | export const CommandCenterButton = (props: Props) => { 13 | const { isSearchShown, onClick } = props; 14 | const duration = 0.7; 15 | 16 | const commandCenterVariants = { 17 | pressed: { pathLength: 0.05 }, 18 | checked: { pathLength: 0 }, 19 | unchecked: { pathLength: 1 }, 20 | }; 21 | 22 | const pathLength = useMotionValue(1); 23 | 24 | const controls = useAnimation(); 25 | 26 | const tooltipRef = React.useRef(null); 27 | 28 | function showTooltip() { 29 | if (tooltipRef.current) { 30 | tooltipRef.current.setAttribute('aria-hidden', 'false'); 31 | controls.start('hover'); 32 | } 33 | } 34 | 35 | function hideTooltip() { 36 | if (tooltipRef.current) { 37 | tooltipRef.current.setAttribute('aria-hidden', 'true'); 38 | controls.start('idle'); 39 | } 40 | } 41 | 42 | const tipVariants = { 43 | hover: { 44 | rotate: 0, 45 | scale: 1, 46 | y: 6, 47 | opacity: 1, 48 | }, 49 | idle: { 50 | rotate: -8, 51 | scale: 0.97, 52 | y: 10, 53 | opacity: 0, 54 | }, 55 | }; 56 | 57 | return ( 58 | { 69 | if (event.which === 27) { 70 | event.preventDefault(); 71 | hideTooltip(); 72 | return false; 73 | } 74 | }} 75 | > 76 | { 81 | onClick(); 82 | }} 83 | initial={false} 84 | animate={isSearchShown ? 'checked' : 'unchecked'} 85 | whileHover="hover" 86 | whileTap="pressed" 87 | transition={{ duration }} 88 | > 89 | 96 | 106 | 107 | 108 | Opens a modal to allow you to quickly search for the content of this 109 | blog and access links to my portfolio, Twitter account, and email. 110 | 111 | 112 | 139 | Show command center 140 | 141 | 142 | ); 143 | }; 144 | -------------------------------------------------------------------------------- /src/components/Button/CopyToClipboardButton.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/core'; 2 | import { motion, useMotionValue, useTransform } from 'framer-motion'; 3 | import React from 'react'; 4 | 5 | export const CopyToClipboardButton = (props: { text: string }) => { 6 | const duration = 0.4; 7 | const svgVariants = { 8 | hover: (isChecked: boolean) => ({ 9 | scale: isChecked ? 1 : 1.05, 10 | strokeWidth: isChecked ? 2 : 3, 11 | }), 12 | pressed: (isChecked: boolean) => ({ 13 | scale: isChecked ? 1 : 0.95, 14 | strokeWidth: isChecked ? 2 : 1, 15 | }), 16 | idle: { 17 | scale: 1, 18 | strokeWidth: 2, 19 | }, 20 | }; 21 | 22 | const boxVariants = { 23 | checked: { opacity: 0 }, 24 | unchecked: { opacity: 1 }, 25 | }; 26 | 27 | const tickVariants = { 28 | pressed: (isChecked: boolean) => ({ pathLength: isChecked ? 0.85 : 0.05 }), 29 | checked: { strokeWidth: 2, pathLength: 1 }, 30 | unchecked: { strokeWidth: 2, pathLength: 0 }, 31 | }; 32 | 33 | const [isChecked, setIsChecked] = React.useState(false); 34 | const pathLength = useMotionValue(0); 35 | const opacity = useTransform(pathLength, [0.05, 0.15], [0, 1]); 36 | 37 | const copyToClipboard = (content: string) => { 38 | const el = document.createElement(`textarea`); 39 | el.value = content; 40 | el.setAttribute(`readonly`, ``); 41 | el.style.position = `absolute`; 42 | el.style.left = `-9999px`; 43 | document.body.appendChild(el); 44 | el.select(); 45 | document.execCommand(`copy`); 46 | document.body.removeChild(el); 47 | }; 48 | 49 | React.useEffect(() => { 50 | if (isChecked) { 51 | setTimeout(() => setIsChecked(false), 3000); 52 | } 53 | }, [isChecked]); 54 | 55 | return ( 56 | 128 | ); 129 | }; 130 | -------------------------------------------------------------------------------- /src/components/Button/LightDarkSwitcher.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/core'; 2 | import { 3 | motion, 4 | useMotionValue, 5 | useTransform, 6 | useAnimation, 7 | } from 'framer-motion'; 8 | import React from 'react'; 9 | import { useTheme } from '../../context/ThemeContext'; 10 | import VisuallyHidden from '../VisuallyHidden'; 11 | import { LinkButton } from './LinkButton'; 12 | 13 | const LightDarkSwitcher = () => { 14 | const theme = useTheme(); 15 | const duration = 0.7; 16 | 17 | const moonVariants = { 18 | checked: { 19 | scale: 1, 20 | }, 21 | unchecked: { 22 | scale: 0, 23 | }, 24 | }; 25 | 26 | const sunVariants = { 27 | checked: { 28 | scale: 0, 29 | }, 30 | unchecked: { 31 | scale: 1, 32 | }, 33 | }; 34 | 35 | const isChecked = theme.dark; 36 | 37 | const scaleMoon = useMotionValue(isChecked ? 1 : 0); 38 | const scaleSun = useMotionValue(isChecked ? 0 : 1); 39 | const pathLengthMoon = useTransform(scaleMoon, [0.6, 1], [0, 1]); 40 | const pathLengthSun = useTransform(scaleSun, [0.6, 1], [0, 1]); 41 | 42 | const tooltipRef = React.useRef(null); 43 | 44 | const controls = useAnimation(); 45 | 46 | function showTooltip() { 47 | if (tooltipRef.current) { 48 | tooltipRef.current.setAttribute('aria-hidden', 'false'); 49 | controls.start('hover'); 50 | } 51 | } 52 | 53 | function hideTooltip() { 54 | if (tooltipRef.current) { 55 | tooltipRef.current.setAttribute('aria-hidden', 'true'); 56 | controls.start('idle'); 57 | } 58 | } 59 | 60 | const tipVariants = { 61 | hover: { 62 | rotate: 0, 63 | scale: 1, 64 | y: 6, 65 | opacity: 1, 66 | }, 67 | idle: { 68 | rotate: -8, 69 | scale: 0.97, 70 | y: 10, 71 | opacity: 0, 72 | }, 73 | }; 74 | 75 | return ( 76 | { 87 | if (event.which === 27) { 88 | event.preventDefault(); 89 | hideTooltip(); 90 | return false; 91 | } 92 | }} 93 | > 94 | { 99 | theme.toggleDark(); 100 | }} 101 | // aria-label={theme.dark ? 'Activate light mode' : 'Activate dark mode'} 102 | // title={theme.dark ? 'Activate light mode' : 'Activate dark mode'} 103 | initial={false} 104 | animate={isChecked ? 'checked' : 'unchecked'} 105 | transition={{ duration }} 106 | > 107 | 114 | 128 | 142 | 156 | 170 | 184 | 198 | 212 | 226 | 240 | 254 | 255 | 256 | Toggles between light and dark mode. 257 | 258 | 259 | 286 | {theme.dark ? 'Activate light mode' : 'Activate dark mode'} 287 | 288 | 289 | ); 290 | }; 291 | 292 | export { LightDarkSwitcher }; 293 | -------------------------------------------------------------------------------- /src/components/Button/LinkButton.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from 'framer-motion'; 2 | import styled from '@emotion/styled'; 3 | 4 | const LinkButton = styled(motion.button)` 5 | border-radius: var(--border-radius-1); 6 | width: 44px; 7 | height: 40px; 8 | cursor: pointer; 9 | border: none; 10 | background-color: transparent; 11 | transition: 0.4s; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | padding: 0px; 16 | color: var(--maximeheckel-colors-typeface-2); 17 | 18 | > * { 19 | margin-left: auto; 20 | margin-right: auto; 21 | } 22 | 23 | &:focus:not(:focus-visible) { 24 | outline: 0; 25 | } 26 | 27 | &:focus-visible { 28 | outline: 2px solid var(--maximeheckel-colors-brand); 29 | background-color: var(--maximeheckel-colors-foreground); 30 | } 31 | 32 | &:hover { 33 | background-color: var(--maximeheckel-colors-foreground); 34 | } 35 | `; 36 | 37 | export { LinkButton }; 38 | -------------------------------------------------------------------------------- /src/components/Button/__tests__/Button.spec.tsx: -------------------------------------------------------------------------------- 1 | import { cleanup, render } from '@testing-library/react'; 2 | import 'jest-dom/extend-expect'; 3 | import React from 'react'; 4 | import Button from '../'; 5 | 6 | describe('Button', () => { 7 | beforeEach(cleanup); 8 | 9 | it('renders the primary button', () => { 10 | const component = render(); 11 | expect(component.baseElement).toMatchSnapshot(); 12 | }); 13 | 14 | it('renders the secondary button', () => { 15 | const component = render(); 16 | expect(component.baseElement).toMatchSnapshot(); 17 | }); 18 | 19 | it('renders the tertiary button', () => { 20 | const component = render(); 21 | expect(component.baseElement).toMatchSnapshot(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/Button/__tests__/__snapshots__/Button.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Button renders the primary button 1`] = ` 4 | .emotion-0 { 5 | height: 48px; 6 | margin: 0; 7 | border: none; 8 | cursor: pointer; 9 | display: -webkit-inline-box; 10 | display: -webkit-inline-flex; 11 | display: -ms-inline-flexbox; 12 | display: inline-flex; 13 | -webkit-box-pack: center; 14 | -webkit-justify-content: center; 15 | -ms-flex-pack: center; 16 | justify-content: center; 17 | -webkit-align-items: center; 18 | -webkit-box-align: center; 19 | -ms-flex-align: center; 20 | align-items: center; 21 | position: relative; 22 | font-weight: 600; 23 | font-size: 18px; 24 | padding: 0 30px; 25 | border-radius: var(--border-radius-1); 26 | background-color: var(--maximeheckel-colors-brand); 27 | color: hsla(var(--palette-gray-00),100%); 28 | min-width: 150px; 29 | } 30 | 31 | .emotion-0:focus:not(:focus-visible) { 32 | outline: 0; 33 | } 34 | 35 | .emotion-0:focus-visible { 36 | outline: 2px solid var(--maximeheckel-colors-brand); 37 | background-color: var(--maximeheckel-colors-foreground); 38 | } 39 | 40 | 41 |
42 | 47 |
48 | 49 | `; 50 | 51 | exports[`Button renders the secondary button 1`] = ` 52 | .emotion-0 { 53 | height: 48px; 54 | margin: 0; 55 | border: none; 56 | cursor: pointer; 57 | display: -webkit-inline-box; 58 | display: -webkit-inline-flex; 59 | display: -ms-inline-flexbox; 60 | display: inline-flex; 61 | -webkit-box-pack: center; 62 | -webkit-justify-content: center; 63 | -ms-flex-pack: center; 64 | justify-content: center; 65 | -webkit-align-items: center; 66 | -webkit-box-align: center; 67 | -ms-flex-align: center; 68 | align-items: center; 69 | position: relative; 70 | font-weight: 600; 71 | font-size: 18px; 72 | padding: 0 30px; 73 | border-radius: var(--border-radius-1); 74 | background-color: transparent; 75 | color: var(--maximeheckel-colors-brand); 76 | border: 2px solid var(--maximeheckel-colors-brand); 77 | min-width: 150px; 78 | } 79 | 80 | .emotion-0:focus:not(:focus-visible) { 81 | outline: 0; 82 | } 83 | 84 | .emotion-0:focus-visible { 85 | outline: 2px solid var(--maximeheckel-colors-brand); 86 | background-color: var(--maximeheckel-colors-foreground); 87 | } 88 | 89 | 90 |
91 | 96 |
97 | 98 | `; 99 | 100 | exports[`Button renders the tertiary button 1`] = ` 101 | .emotion-0 { 102 | height: 48px; 103 | margin: 0; 104 | border: none; 105 | cursor: pointer; 106 | display: -webkit-inline-box; 107 | display: -webkit-inline-flex; 108 | display: -ms-inline-flexbox; 109 | display: inline-flex; 110 | -webkit-box-pack: center; 111 | -webkit-justify-content: center; 112 | -ms-flex-pack: center; 113 | justify-content: center; 114 | -webkit-align-items: center; 115 | -webkit-box-align: center; 116 | -ms-flex-align: center; 117 | align-items: center; 118 | position: relative; 119 | font-weight: 600; 120 | font-size: 18px; 121 | padding: 0 30px; 122 | border-radius: var(--border-radius-1); 123 | background-color: transparent; 124 | color: var(--maximeheckel-colors-brand); 125 | min-width: inherited; 126 | padding: 0px; 127 | } 128 | 129 | .emotion-0:focus:not(:focus-visible) { 130 | outline: 0; 131 | } 132 | 133 | .emotion-0:focus-visible { 134 | outline: 2px solid var(--maximeheckel-colors-brand); 135 | background-color: var(--maximeheckel-colors-foreground); 136 | } 137 | 138 | .emotion-0::after { 139 | content: ''; 140 | display: block; 141 | position: absolute; 142 | top: 96%; 143 | left: 0; 144 | right: 0; 145 | height: 2px; 146 | background-color: var(--maximeheckel-colors-brand); 147 | -webkit-transform: scaleX(0); 148 | -ms-transform: scaleX(0); 149 | transform: scaleX(0); 150 | -webkit-transition: -webkit-transform 0.25s ease-in; 151 | -webkit-transition: transform 0.25s ease-in; 152 | transition: transform 0.25s ease-in; 153 | -webkit-transform-origin: right center; 154 | -ms-transform-origin: right center; 155 | transform-origin: right center; 156 | -webkit-text-decoration: none; 157 | text-decoration: none; 158 | } 159 | 160 | .emotion-0:hover::after { 161 | -webkit-transform: scale(1); 162 | -ms-transform: scale(1); 163 | transform: scale(1); 164 | -webkit-transform-origin: left center; 165 | -ms-transform-origin: left center; 166 | transform-origin: left center; 167 | } 168 | 169 | 170 |
171 | 176 |
177 | 178 | `; 179 | -------------------------------------------------------------------------------- /src/components/Button/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from './Button'; 2 | export { CopyToClipboardButton } from './CopyToClipboardButton'; 3 | export { CommandCenterButton } from './CommandCenterButton'; 4 | export { LightDarkSwitcher } from './LightDarkSwitcher'; 5 | export default Button; 6 | -------------------------------------------------------------------------------- /src/components/Callout/Callout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from '@emotion/styled'; 3 | 4 | export enum VARIANT { 5 | DANGER = 'danger', 6 | INFO = 'info', 7 | } 8 | 9 | interface Props { 10 | variant: VARIANT; 11 | } 12 | 13 | const Callout: React.FC = (props) => ( 14 | {props.children} 15 | ); 16 | 17 | const variantColors = { 18 | [VARIANT.DANGER]: ` 19 | background-color: var(--maximeheckel-colors-danger-emphasis); 20 | border-color: var(--maximeheckel-colors-danger); 21 | color: var(--maximeheckel-colors-typeface-0); 22 | `, 23 | [VARIANT.INFO]: ` 24 | background-color: var(--maximeheckel-colors-emphasis); 25 | border-color: var(--maximeheckel-colors-brand); 26 | color: var(--maximeheckel-colors-typeface-0); 27 | `, 28 | }; 29 | 30 | const StyledCallout = styled('div')<{ variant: VARIANT }>` 31 | @media (max-width: 600px) { 32 | position: relative; 33 | width: 100vw; 34 | left: calc(-50vw + 50%); 35 | border-radius: 0px; 36 | } 37 | 38 | border-radius: 4px var(--border-radius-2) var(--border-radius-2) 4px; 39 | border-left: 3px solid; 40 | padding: 30px 30px; 41 | margin-bottom: 25px; 42 | 43 | *:last-child { 44 | margin-bottom: 0px; 45 | } 46 | 47 | ${(p) => variantColors[p.variant]} 48 | `; 49 | 50 | export { Callout }; 51 | -------------------------------------------------------------------------------- /src/components/Callout/__tests__/Callout.test.tsx: -------------------------------------------------------------------------------- 1 | import { cleanup, render } from '@testing-library/react'; 2 | import React from 'react'; 3 | import Callout from '../'; 4 | import { VARIANT } from '../Callout'; 5 | 6 | describe('Callout', () => { 7 | afterEach(cleanup); 8 | it('can render a Callout with variant info', () => { 9 | const component = render(Test); 10 | expect(component.baseElement).toMatchSnapshot(); 11 | }); 12 | 13 | it('can render a Callout with variant danger', () => { 14 | const component = render(Test); 15 | expect(component.baseElement).toMatchSnapshot(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Callout/__tests__/__snapshots__/Callout.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Callout can render a Callout with variant danger 1`] = ` 4 | .emotion-0 { 5 | border-radius: 4px var(--border-radius-2) var(--border-radius-2) 4px; 6 | border-left: 3px solid; 7 | padding: 30px 30px; 8 | margin-bottom: 25px; 9 | background-color: var(--maximeheckel-colors-danger-emphasis); 10 | border-color: var(--maximeheckel-colors-danger); 11 | color: var(--maximeheckel-colors-typeface-0); 12 | } 13 | 14 | @media (max-width:600px) { 15 | .emotion-0 { 16 | position: relative; 17 | width: 100vw; 18 | left: calc(-50vw + 50%); 19 | border-radius: 0px; 20 | } 21 | } 22 | 23 | .emotion-0 *:last-child { 24 | margin-bottom: 0px; 25 | } 26 | 27 | 28 |
29 |
32 | Test 33 |
34 |
35 | 36 | `; 37 | 38 | exports[`Callout can render a Callout with variant info 1`] = ` 39 | .emotion-0 { 40 | border-radius: 4px var(--border-radius-2) var(--border-radius-2) 4px; 41 | border-left: 3px solid; 42 | padding: 30px 30px; 43 | margin-bottom: 25px; 44 | background-color: var(--maximeheckel-colors-emphasis); 45 | border-color: var(--maximeheckel-colors-brand); 46 | color: var(--maximeheckel-colors-typeface-0); 47 | } 48 | 49 | @media (max-width:600px) { 50 | .emotion-0 { 51 | position: relative; 52 | width: 100vw; 53 | left: calc(-50vw + 50%); 54 | border-radius: 0px; 55 | } 56 | } 57 | 58 | .emotion-0 *:last-child { 59 | margin-bottom: 0px; 60 | } 61 | 62 | 63 |
64 |
67 | Test 68 |
69 |
70 | 71 | `; 72 | -------------------------------------------------------------------------------- /src/components/Callout/index.tsx: -------------------------------------------------------------------------------- 1 | import { Callout } from './Callout'; 2 | export default Callout; 3 | -------------------------------------------------------------------------------- /src/components/Flex/Flex.tsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | 3 | const Flex = styled.div<{ 4 | justifyContent?: string; 5 | direction?: string; 6 | wrap?: string; 7 | }>` 8 | display: flex; 9 | flex-wrap: wrap; 10 | align-items: center; 11 | flex-wrap: ${(p) => p.wrap || 'nowrap'}; 12 | flex-direction: ${(p) => p.direction || 'row'}; 13 | justify-content: ${(p) => p.justifyContent || 'flex-start'}; 14 | 15 | > * { 16 | margin-right: 5px; 17 | margin-bottom: 0px; 18 | } 19 | `; 20 | 21 | export { Flex }; 22 | -------------------------------------------------------------------------------- /src/components/Flex/__tests__/Flex.spec.tsx: -------------------------------------------------------------------------------- 1 | import { cleanup, render } from '@testing-library/react'; 2 | import 'jest-dom/extend-expect'; 3 | import React from 'react'; 4 | import Flex from '../'; 5 | 6 | describe('Flex', () => { 7 | beforeEach(cleanup); 8 | 9 | it('renders Flex with justifyContent prop', () => { 10 | const component = render(Test); 11 | expect(component.baseElement).toMatchSnapshot(); 12 | }); 13 | 14 | it('renders Flex with direction prop', () => { 15 | const component = render(Test); 16 | expect(component.baseElement).toMatchSnapshot(); 17 | }); 18 | 19 | it('renders Flex with wrap prop', () => { 20 | const component = render(Test); 21 | expect(component.baseElement).toMatchSnapshot(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/Flex/__tests__/__snapshots__/Flex.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Flex renders Flex with direction prop 1`] = ` 4 | .emotion-0 { 5 | display: -webkit-box; 6 | display: -webkit-flex; 7 | display: -ms-flexbox; 8 | display: flex; 9 | -webkit-flex-wrap: wrap; 10 | -ms-flex-wrap: wrap; 11 | flex-wrap: wrap; 12 | -webkit-align-items: center; 13 | -webkit-box-align: center; 14 | -ms-flex-align: center; 15 | align-items: center; 16 | -webkit-flex-wrap: nowrap; 17 | -ms-flex-wrap: nowrap; 18 | flex-wrap: nowrap; 19 | -webkit-flex-direction: column; 20 | -ms-flex-direction: column; 21 | flex-direction: column; 22 | -webkit-box-pack: start; 23 | -webkit-justify-content: flex-start; 24 | -ms-flex-pack: start; 25 | justify-content: flex-start; 26 | } 27 | 28 | .emotion-0 > * { 29 | margin-right: 5px; 30 | margin-bottom: 0px; 31 | } 32 | 33 | 34 |
35 |
39 | Test 40 |
41 |
42 | 43 | `; 44 | 45 | exports[`Flex renders Flex with justifyContent prop 1`] = ` 46 | .emotion-0 { 47 | display: -webkit-box; 48 | display: -webkit-flex; 49 | display: -ms-flexbox; 50 | display: flex; 51 | -webkit-flex-wrap: wrap; 52 | -ms-flex-wrap: wrap; 53 | flex-wrap: wrap; 54 | -webkit-align-items: center; 55 | -webkit-box-align: center; 56 | -ms-flex-align: center; 57 | align-items: center; 58 | -webkit-flex-wrap: nowrap; 59 | -ms-flex-wrap: nowrap; 60 | flex-wrap: nowrap; 61 | -webkit-flex-direction: row; 62 | -ms-flex-direction: row; 63 | flex-direction: row; 64 | -webkit-box-pack: center; 65 | -webkit-justify-content: center; 66 | -ms-flex-pack: center; 67 | justify-content: center; 68 | } 69 | 70 | .emotion-0 > * { 71 | margin-right: 5px; 72 | margin-bottom: 0px; 73 | } 74 | 75 | 76 |
77 |
80 | Test 81 |
82 |
83 | 84 | `; 85 | 86 | exports[`Flex renders Flex with wrap prop 1`] = ` 87 | .emotion-0 { 88 | display: -webkit-box; 89 | display: -webkit-flex; 90 | display: -ms-flexbox; 91 | display: flex; 92 | -webkit-flex-wrap: wrap; 93 | -ms-flex-wrap: wrap; 94 | flex-wrap: wrap; 95 | -webkit-align-items: center; 96 | -webkit-box-align: center; 97 | -ms-flex-align: center; 98 | align-items: center; 99 | -webkit-flex-wrap: wrap; 100 | -ms-flex-wrap: wrap; 101 | flex-wrap: wrap; 102 | -webkit-flex-direction: row; 103 | -ms-flex-direction: row; 104 | flex-direction: row; 105 | -webkit-box-pack: start; 106 | -webkit-justify-content: flex-start; 107 | -ms-flex-pack: start; 108 | justify-content: flex-start; 109 | } 110 | 111 | .emotion-0 > * { 112 | margin-right: 5px; 113 | margin-bottom: 0px; 114 | } 115 | 116 | 117 |
118 |
122 | Test 123 |
124 |
125 | 126 | `; 127 | -------------------------------------------------------------------------------- /src/components/Flex/index.tsx: -------------------------------------------------------------------------------- 1 | import { Flex } from './Flex'; 2 | export default Flex; 3 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Logo from '../Logo'; 3 | import styled from '@emotion/styled'; 4 | 5 | const HR = styled.hr` 6 | height: 2px; 7 | background: var(--maximeheckel-colors-typeface-0); 8 | `; 9 | 10 | const FooterBlock = styled.div` 11 | background: var(--maximeheckel-colors-body); 12 | transition: 0.5s; 13 | height: 130px; 14 | width: 100%; 15 | `; 16 | 17 | const FooterWrapper = styled.div` 18 | @media (max-width: 700px) { 19 | padding-left: 20px; 20 | padding-right: 20px; 21 | } 22 | 23 | padding-top: 30px; 24 | padding-left: 70px; 25 | padding-right: 70px; 26 | max-width: 1020px; 27 | margin-top: 30px; 28 | color: var(--maximeheckel-colors-typeface-0); 29 | font-size: 14px; 30 | margin: 0 auto; 31 | a { 32 | color: inherit; 33 | } 34 | `; 35 | 36 | const FooterContent = styled.div` 37 | display: flex; 38 | justify-content: space-between; 39 | align-items: center; 40 | `; 41 | 42 | const Footer: React.FC<{}> = () => ( 43 | 44 | 45 |
46 | 47 |
© {new Date().getFullYear()} Maxime Heckel —— SF/NY
48 | 49 |
50 |
51 |
52 | ); 53 | 54 | export { Footer }; 55 | -------------------------------------------------------------------------------- /src/components/Footer/__tests__/Footer.spec.tsx: -------------------------------------------------------------------------------- 1 | import { cleanup, render } from '@testing-library/react'; 2 | import 'jest-dom/extend-expect'; 3 | import React from 'react'; 4 | import Footer from '..'; 5 | 6 | describe('Footer', () => { 7 | beforeEach(cleanup); 8 | 9 | it('renders the Footer without the table of contents', () => { 10 | const { getByTestId } = render(