diff --git a/.gitignore b/.gitignore index 9fdeef4f..7f23391f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,7 @@ src/@types/Gatsby.d.ts # build output dist/ +src/images/icons/ + # generated types .astro/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..25bf17fc --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 662926d2..3b04a1e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@astrojs/rss": "^3.0.0", "@astrojs/sitemap": "^3.0.0", "@rainbow-me/rainbowkit": "^1.0.9", - "astro": "^3.0.3", + "astro": "^3.0.7", "classnames": "^2.3.2", "date-fns": "^2.30.0", "dms2dec": "^1.1.0", @@ -28,7 +28,6 @@ "react": "^18.2.0", "react-clipboard.js": "^2.0.16", "react-dom": "^18.2.0", - "react-feather": "^2.0.10", "slugify": "^1.6.6", "use-debounce": "^9.0.4", "viem": "^1.9.0", @@ -64,12 +63,13 @@ "stylelint-config-css-modules": "^4.3.0", "stylelint-config-standard": "^34.0.0", "stylelint-prettier": "^4.0.2", + "svgo": "^3.0.2", "ts-node": "^10.9.1", "typescript": "^5.2.2", "typescript-plugin-css-modules": "^5.0.1" }, "engines": { - "node": ">=16" + "node": "18" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -232,9 +232,9 @@ } }, "node_modules/@astrojs/telemetry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.0.tgz", - "integrity": "sha512-RhFlEXTiT0gbWX1osMuPS9IWm1SwhQmCZVAdAixrPyZ0xiLlHfw3Nkw3z6IYuzX3hqbx24G4XmkT/akBMBqxPg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.1.tgz", + "integrity": "sha512-7zJMuikRDQ0LLLivteu0+y4pqdgznrChFiRrY3qmKlOEkLWD1T3u1a5M970lvpErP7Vgh4P298JBPjv8LTj+sw==", "dependencies": { "ci-info": "^3.8.0", "debug": "^4.3.4", @@ -4505,15 +4505,6 @@ "@svgr/core": "*" } }, - "node_modules/@svgr/plugin-svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@svgr/plugin-svgo/node_modules/cosmiconfig": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", @@ -4532,82 +4523,6 @@ "url": "https://github.com/sponsors/d-fischer" } }, - "node_modules/@svgr/plugin-svgo/node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/@svgr/plugin-svgo/node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@svgr/plugin-svgo/node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@svgr/plugin-svgo/node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - }, - "node_modules/@svgr/plugin-svgo/node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/@svgr/plugin-svgo/node_modules/svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, "node_modules/@svgr/webpack": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", @@ -6689,14 +6604,14 @@ } }, "node_modules/astro": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-3.0.3.tgz", - "integrity": "sha512-bugdGn9wIniVFbfyAHYtF9bc9pZpPaEs3gJAnK/XWROxCBAI2UQjR6lQuWM20iCc3snqu7GDgoW2MdzO7WFZZw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/astro/-/astro-3.0.7.tgz", + "integrity": "sha512-slUnDBXfxMzq5abE4svcKbaeYC/tHZsJYOrzwDNU9lLye3/4cqYP7OuHMTXiRlx7LSpHQlUhwbMe2HqCv2GKag==", "dependencies": { "@astrojs/compiler": "^2.0.1", "@astrojs/internal-helpers": "0.2.0", "@astrojs/markdown-remark": "3.0.0", - "@astrojs/telemetry": "3.0.0", + "@astrojs/telemetry": "3.0.1", "@babel/core": "^7.22.10", "@babel/generator": "^7.22.10", "@babel/parser": "^7.22.10", @@ -8375,6 +8290,19 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", @@ -8403,6 +8331,39 @@ "node": ">=4" } }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -14978,6 +14939,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -17308,17 +17275,6 @@ "react": "^18.2.0" } }, - "node_modules/react-feather": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz", - "integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==", - "dependencies": { - "prop-types": "^15.7.2" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -19508,25 +19464,6 @@ "url": "https://github.com/sponsors/d-fischer" } }, - "node_modules/stylelint/node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/stylelint/node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, "node_modules/stylelint/node_modules/signal-exit": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", @@ -19656,6 +19593,39 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "node_modules/svgo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -21970,9 +21940,9 @@ } }, "@astrojs/telemetry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.0.tgz", - "integrity": "sha512-RhFlEXTiT0gbWX1osMuPS9IWm1SwhQmCZVAdAixrPyZ0xiLlHfw3Nkw3z6IYuzX3hqbx24G4XmkT/akBMBqxPg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.1.tgz", + "integrity": "sha512-7zJMuikRDQ0LLLivteu0+y4pqdgznrChFiRrY3qmKlOEkLWD1T3u1a5M970lvpErP7Vgh4P298JBPjv8LTj+sw==", "requires": { "ci-info": "^3.8.0", "debug": "^4.3.4", @@ -24922,12 +24892,6 @@ "svgo": "^3.0.2" }, "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - }, "cosmiconfig": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", @@ -24939,63 +24903,6 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0" } - }, - "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "requires": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - } - }, - "csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "requires": { - "css-tree": "~2.2.0" - }, - "dependencies": { - "css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "requires": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - } - }, - "mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - } - } - }, - "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - } } } }, @@ -26660,14 +26567,14 @@ "dev": true }, "astro": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-3.0.3.tgz", - "integrity": "sha512-bugdGn9wIniVFbfyAHYtF9bc9pZpPaEs3gJAnK/XWROxCBAI2UQjR6lQuWM20iCc3snqu7GDgoW2MdzO7WFZZw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/astro/-/astro-3.0.7.tgz", + "integrity": "sha512-slUnDBXfxMzq5abE4svcKbaeYC/tHZsJYOrzwDNU9lLye3/4cqYP7OuHMTXiRlx7LSpHQlUhwbMe2HqCv2GKag==", "requires": { "@astrojs/compiler": "^2.0.1", "@astrojs/internal-helpers": "0.2.0", "@astrojs/markdown-remark": "3.0.0", - "@astrojs/telemetry": "3.0.0", + "@astrojs/telemetry": "3.0.1", "@babel/core": "^7.22.10", "@babel/generator": "^7.22.10", "@babel/parser": "^7.22.10", @@ -27835,6 +27742,16 @@ } } }, + "css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "requires": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + } + }, "css-what": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", @@ -27851,6 +27768,33 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, + "csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "requires": { + "css-tree": "~2.2.0" + }, + "dependencies": { + "css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "requires": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + } + }, + "mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + } + } + }, "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -32675,6 +32619,12 @@ "@types/mdast": "^3.0.0" } }, + "mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -34241,14 +34191,6 @@ "scheduler": "^0.23.0" } }, - "react-feather": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz", - "integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==", - "requires": { - "prop-types": "^15.7.2" - } - }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -35814,22 +35756,6 @@ "path-type": "^4.0.0" } }, - "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "requires": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - } - }, - "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, "signal-exit": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", @@ -35974,6 +35900,28 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "svgo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index 6608525f..6702e38b 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "description": "Blog of Designer & Developer Matthias Kretschmann", "homepage": "https://kremalicious.com", "license": "MIT", + "type": "module", "scripts": { - "dev": "astro dev --config .config/astro.config.mjs", - "start": "astro dev --config .config/astro.config.mjs", - "build": "astro build --config .config/astro.config.mjs", + "start": "npm run create:icons && astro dev --config .config/astro.config.mjs", + "build": "npm run create:icons && astro build --config .config/astro.config.mjs", "preview": "astro preview", "astro": "astro", "test": "astro check && tsc --noEmit && npm run lint && npm run type-check && npm run jest", @@ -20,14 +20,15 @@ "format": "prettier --ignore-path .gitignore --write '**/*.{js,jsx,ts,tsx,md,json,css}'", "type-check": "tsc --noEmit", "deploy:s3": "./scripts/deploy-s3.sh", - "new": "ts-node scripts/new.ts" + "new": "ts-node --esm scripts/new.ts", + "create:icons": "ts-node --esm scripts/create-icons/index.ts" }, "dependencies": { "@astrojs/react": "^3.0.0", "@astrojs/rss": "^3.0.0", "@astrojs/sitemap": "^3.0.0", "@rainbow-me/rainbowkit": "^1.0.9", - "astro": "^3.0.3", + "astro": "^3.0.7", "classnames": "^2.3.2", "date-fns": "^2.30.0", "dms2dec": "^1.1.0", @@ -42,7 +43,6 @@ "react": "^18.2.0", "react-clipboard.js": "^2.0.16", "react-dom": "^18.2.0", - "react-feather": "^2.0.10", "slugify": "^1.6.6", "use-debounce": "^9.0.4", "viem": "^1.9.0", @@ -78,12 +78,13 @@ "stylelint-config-css-modules": "^4.3.0", "stylelint-config-standard": "^34.0.0", "stylelint-prettier": "^4.0.2", + "svgo": "^3.0.2", "ts-node": "^10.9.1", "typescript": "^5.2.2", "typescript-plugin-css-modules": "^5.0.1" }, "engines": { - "node": ">=16" + "node": "18" }, "repository": { "type": "git", diff --git a/scripts/createExif.ts b/scripts/create-exif/index.ts similarity index 100% rename from scripts/createExif.ts rename to scripts/create-exif/index.ts diff --git a/scripts/create-icons/Props.ts b/scripts/create-icons/Props.ts new file mode 100644 index 00000000..b81e6a53 --- /dev/null +++ b/scripts/create-icons/Props.ts @@ -0,0 +1,320 @@ +// All the WAI-ARIA 1.1 attributes from https://www.w3.org/TR/wai-aria-1.1/ +export interface AriaAttributes { + /** Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. */ + 'aria-activedescendant'?: string + /** Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. */ + 'aria-atomic'?: 'true' | 'false' | boolean + /** + * Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be + * presented if they are made. + */ + 'aria-autocomplete'?: 'none' | 'inline' | 'list' | 'both' + /** Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. */ + 'aria-busy'?: 'true' | 'false' | boolean + /** + * Indicates the current 'checked' state of checkboxes, radio buttons, and other widgets. + * @see aria-pressed @see aria-selected. + */ + 'aria-checked'?: 'false' | 'mixed' | 'true' | boolean + /** + * Defines the total number of columns in a table, grid, or treegrid. + * @see aria-colindex. + */ + 'aria-colcount'?: number + /** + * Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. + * @see aria-colcount @see aria-colspan. + */ + 'aria-colindex'?: number + /** + * Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. + * @see aria-colindex @see aria-rowspan. + */ + 'aria-colspan'?: number + /** + * Identifies the element (or elements) whose contents or presence are controlled by the current element. + * @see aria-owns. + */ + 'aria-controls'?: string + /** Indicates the element that represents the current item within a container or set of related elements. */ + 'aria-current'?: + | 'false' + | 'true' + | 'page' + | 'step' + | 'location' + | 'date' + | 'time' + | boolean + /** + * Identifies the element (or elements) that describes the object. + * @see aria-labelledby + */ + 'aria-describedby'?: string + /** + * Identifies the element that provides a detailed, extended description for the object. + * @see aria-describedby. + */ + 'aria-details'?: string + /** + * Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. + * @see aria-hidden @see aria-readonly. + */ + 'aria-disabled'?: 'true' | 'false' | boolean + /** + * Identifies the element that provides an error message for the object. + * @see aria-invalid @see aria-describedby. + */ + 'aria-errormessage'?: string + /** Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. */ + 'aria-expanded'?: 'true' | 'false' | boolean + /** + * Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, + * allows assistive technology to override the general default of reading in document source order. + */ + 'aria-flowto'?: string + /** Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. */ + 'aria-haspopup'?: + | 'false' + | 'true' + | 'menu' + | 'listbox' + | 'tree' + | 'grid' + | 'dialog' + | boolean + /** + * Indicates whether the element is exposed to an accessibility API. + * @see aria-disabled. + */ + 'aria-hidden'?: 'true' | 'false' | boolean + /** + * Indicates the entered value does not conform to the format expected by the application. + * @see aria-errormessage. + */ + 'aria-invalid'?: 'false' | 'true' | 'grammar' | 'spelling' | boolean + /** Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. */ + 'aria-keyshortcuts'?: string + /** + * Defines a string value that labels the current element. + * @see aria-labelledby. + */ + 'aria-label'?: string + /** + * Identifies the element (or elements) that labels the current element. + * @see aria-describedby. + */ + 'aria-labelledby'?: string + /** Defines the hierarchical level of an element within a structure. */ + 'aria-level'?: number + /** Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. */ + 'aria-live'?: 'off' | 'assertive' | 'polite' + /** Indicates whether an element is modal when displayed. */ + 'aria-modal'?: 'true' | 'false' | boolean + /** Indicates whether a text box accepts multiple lines of input or only a single line. */ + 'aria-multiline'?: 'true' | 'false' | boolean + /** Indicates that the user may select more than one item from the current selectable descendants. */ + 'aria-multiselectable'?: 'true' | 'false' | boolean + /** Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. */ + 'aria-orientation'?: 'horizontal' | 'vertical' + /** + * Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship + * between DOM elements where the DOM hierarchy cannot be used to represent the relationship. + * @see aria-controls. + */ + 'aria-owns'?: string + /** + * Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. + * A hint could be a sample value or a brief description of the expected format. + */ + 'aria-placeholder'?: string + /** + * Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. + * @see aria-setsize. + */ + 'aria-posinset'?: number + /** + * Indicates the current 'pressed' state of toggle buttons. + * @see aria-checked @see aria-selected. + */ + 'aria-pressed'?: 'false' | 'mixed' | 'true' | boolean + /** + * Indicates that the element is not editable, but is otherwise operable. + * @see aria-disabled. + */ + 'aria-readonly'?: 'true' | 'false' | boolean + /** + * Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. + * @see aria-atomic. + */ + 'aria-relevant'?: + | 'additions' + | 'additions removals' + | 'additions text' + | 'all' + | 'removals' + | 'removals additions' + | 'removals text' + | 'text' + | 'text additions' + | 'text removals' + /** Indicates that user input is required on the element before a form may be submitted. */ + 'aria-required'?: 'true' | 'false' | boolean + /** Defines a human-readable, author-localized description for the role of an element. */ + 'aria-roledescription'?: string + /** + * Defines the total number of rows in a table, grid, or treegrid. + * @see aria-rowindex. + */ + 'aria-rowcount'?: number + /** + * Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. + * @see aria-rowcount @see aria-rowspan. + */ + 'aria-rowindex'?: number + /** + * Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. + * @see aria-rowindex @see aria-colspan. + */ + 'aria-rowspan'?: number + /** + * Indicates the current 'selected' state of various widgets. + * @see aria-checked @see aria-pressed. + */ + 'aria-selected'?: 'true' | 'false' | boolean + /** + * Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. + * @see aria-posinset. + */ + 'aria-setsize'?: number + /** Indicates if items in a table or grid are sorted in ascending or descending order. */ + 'aria-sort'?: 'none' | 'ascending' | 'descending' | 'other' + /** Defines the maximum allowed value for a range widget. */ + 'aria-valuemax'?: number + /** Defines the minimum allowed value for a range widget. */ + 'aria-valuemin'?: number + /** + * Defines the current value for a range widget. + * @see aria-valuetext. + */ + 'aria-valuenow'?: number + /** Defines the human readable text alternative of aria-valuenow for a range widget. */ + 'aria-valuetext'?: string +} + +// All the WAI-ARIA 1.1 role attribute values from https://www.w3.org/TR/wai-aria-1.1/#role_definitions +export type AriaRole = + | 'alert' + | 'alertdialog' + | 'application' + | 'article' + | 'banner' + | 'button' + | 'cell' + | 'checkbox' + | 'columnheader' + | 'combobox' + | 'complementary' + | 'contentinfo' + | 'definition' + | 'dialog' + | 'directory' + | 'document' + | 'feed' + | 'figure' + | 'form' + | 'grid' + | 'gridcell' + | 'group' + | 'heading' + | 'img' + | 'link' + | 'list' + | 'listbox' + | 'listitem' + | 'log' + | 'main' + | 'marquee' + | 'math' + | 'menu' + | 'menubar' + | 'menuitem' + | 'menuitemcheckbox' + | 'menuitemradio' + | 'navigation' + | 'none' + | 'note' + | 'option' + | 'presentation' + | 'progressbar' + | 'radio' + | 'radiogroup' + | 'region' + | 'row' + | 'rowgroup' + | 'rowheader' + | 'scrollbar' + | 'search' + | 'searchbox' + | 'separator' + | 'slider' + | 'spinbutton' + | 'status' + | 'switch' + | 'tab' + | 'table' + | 'tablist' + | 'tabpanel' + | 'term' + | 'textbox' + | 'timer' + | 'toolbar' + | 'tooltip' + | 'tree' + | 'treegrid' + | 'treeitem' + | (string & object) + +export interface HTMLAttributes extends AriaAttributes { + accesskey?: string + autocapitalize?: string + autofocus?: string + class?: string + contenteditable?: 'true' | 'false' | 'inherit' | boolean + contextMenu?: string + dir?: 'ltr' | 'rtl' | 'auto' + draggable?: 'true' | 'false' | boolean + enterkeyhint?: string + exportparts?: string + hidden?: string + id?: string + inputmode?: string + is?: string + lang?: string + placeholder?: string + role?: AriaRole + slot?: string + spellcheck?: 'true' | 'false' | boolean + style?: string + tabindex?: number + title?: string + translate?: 'yes' | 'no' +} + +export interface Props extends HTMLAttributes { + fill?: string + 'fill-opacity'?: number | string + 'fill-rule'?: 'nonzero' | 'evenodd' | 'inherit' + height?: number | string + size?: number | string + stroke?: string + 'stroke-dasharray'?: string | number + 'stroke-dashoffset'?: string | number + 'stroke-linecap'?: 'butt' | 'round' | 'square' | 'inherit' + 'stroke-linejoin'?: 'miter' | 'round' | 'bevel' | 'inherit' + 'stroke-miterlimit'?: number | string + 'stroke-opacity'?: number | string + 'stroke-width'?: number | string + viewBox?: string + width?: number | string +} diff --git a/scripts/create-icons/index.ts b/scripts/create-icons/index.ts new file mode 100644 index 00000000..4dbac437 --- /dev/null +++ b/scripts/create-icons/index.ts @@ -0,0 +1,89 @@ +// +// Generate Astro components from SVG files. +// adapted from https://github.com/astro-community/icons +// +import fs from 'node:fs/promises' +import ps from 'node:path/posix' +import { toAstroComponent, toInnerSvg } from './svg.ts' + +// Current directory. +const currentDir = ps.resolve('.') + +// // Source directories +const srcDirs = [ + ps.resolve(currentDir, 'node_modules/feather-icons/dist/icons'), + ps.resolve(currentDir, 'src/images') +] + +// Distribution directory. +const distDir = ps.resolve(currentDir, 'src/images/icons') + +// Data related to each icon exported by this package. +const icons = [] + +// clean the distribution directory +await fs.rm(distDir, { force: true, recursive: true }) +await fs.mkdir(distDir, { recursive: true }) + +// copy the attribute typings file +await fs.copyFile( + ps.resolve(currentDir, 'scripts/create-icons/Props.ts'), + ps.resolve(distDir, 'Props.ts') +) + +// convert the SVG files into Astro components +let contentOfIndexJS = '' + +for (const src of srcDirs) { + for (let filepath of await fs.readdir(src, { encoding: 'utf8' })) { + // ignore non-svg files + if (!filepath.endsWith('.svg')) continue + + // Base name of the SVG. + const name = filepath.replace(/\.svg$/, '') + + // get filepath as a full path + filepath = ps.resolve(src, filepath) + + // Inner contents of the SVG file. + const innerSVG = toInnerSvg(await fs.readFile(filepath, 'utf8')) + + // Formatted title. + const title = name + .replace( + // uppercase alphabetic characters after the start or a dash + /(?<=^|-)([a-z])/g, + (_0, $1) => $1.toUpperCase() + ) + .replace( + // replace non-alphanumeric characters with space + /[^A-Za-z0-9]+/g, + ' ' + ) + .replace( + // respect 'GitHub' brand casing + 'Github Logo', + 'GitHub Logo' + ) + + // Base name, which is the formatted title without spaces (PascalCase) + const baseName = title.replace(/ /g, '') + + // write the astro component to a file + await fs.writeFile( + ps.resolve(distDir, `${baseName}.astro`), + toAstroComponent(innerSVG, title), + 'utf8' + ) + + // add the astro component export to the main entry `index.ts` file + contentOfIndexJS += `\nexport { default as ${baseName} } from './${baseName}.astro'` + + icons.push({ name, baseName, title }) + } +} + +// write the main entry `index.ts` file +await fs.writeFile(ps.resolve(distDir, 'index.ts'), contentOfIndexJS, 'utf8') + +console.log(`✔️ Generated ${icons.length} icons into @images/icons.`) diff --git a/scripts/create-icons/svg.ts b/scripts/create-icons/svg.ts new file mode 100644 index 00000000..625b3c1c --- /dev/null +++ b/scripts/create-icons/svg.ts @@ -0,0 +1,85 @@ +import { optimize as optimizeSVGNative } from 'svgo' + +export const toAstroComponent = (innerSVG: string, title: string) => `--- +export { Props } from './Props.ts'; + +let { + size = '24px', + title, + width = size, + height = size, + ...props +} = { + 'fill': 'none', + 'title': '${title}', + 'viewBox': '0 0 24 24', + ...Astro.props +} + +const toAttributeSize = (size: number) => String(size).replace(/(?<=[0-9])x$/, 'em') + +size = toAttributeSize(size) +width = toAttributeSize(width) +height = toAttributeSize(height) +--- + +{title ? ({title}) : ''}${innerSVG}` + +export const toInnerSvg = (input: string) => + optimizeSVGNative(input, { + plugins: [ + 'removeDoctype', + 'removeXMLProcInst', + 'removeComments', + 'removeMetadata', + 'removeXMLNS', + 'removeEditorsNSData', + 'cleanupAttrs', + 'minifyStyles', + 'convertStyleToAttrs', + 'cleanupIds', + 'removeRasterImages', + 'removeUselessDefs', + 'cleanupNumericValues', + 'cleanupListOfValues', + 'convertColors', + 'removeUnknownsAndDefaults', + 'removeNonInheritableGroupAttrs', + 'removeUselessStrokeAndFill', + 'removeViewBox', + 'cleanupEnableBackground', + 'removeHiddenElems', + 'removeEmptyText', + 'convertShapeToPath', + 'moveElemsAttrsToGroup', + 'moveGroupAttrsToElems', + 'collapseGroups', + 'convertPathData', + 'convertTransform', + 'removeEmptyAttrs', + 'removeEmptyContainers', + 'mergePaths', + 'removeUnusedNS', + 'sortAttrs', + 'removeTitle', + 'removeDesc', + 'removeDimensions', + 'removeStyleElement', + 'removeScriptElement' + ] + }) + .data.replace(/^]*>|<\/svg>$/g, '') + .replace(/ fill="currentColor"/g, '') + .replace(/ (clip|fill)-rule="evenodd"/g, '') + .replace(/\/>/g, ' />') diff --git a/scripts/new.ts b/scripts/new.ts index bc4f8877..e7de49b9 100644 --- a/scripts/new.ts +++ b/scripts/new.ts @@ -1,5 +1,5 @@ import fastExif from 'fast-exif' -import fs from 'fs-extra' +import fs from 'fs' import iptc from 'node-iptc' import ora from 'ora' import path from 'path' diff --git a/src/components/Footer/Networks.astro b/src/components/Footer/Networks.astro new file mode 100644 index 00000000..9c228111 --- /dev/null +++ b/src/components/Footer/Networks.astro @@ -0,0 +1,30 @@ +--- +import styles from './Networks.module.css' +import { Twitter, Rss, Mastodon, Github, Jsonfeed } from '@images/icons' + +type Props = { + links: string[] +} + +const { links } = Astro.props +--- + +

+ { + links.map((link: string) => ( + + {link.includes('mas.to') ? ( + + ) : link.includes('twitter') ? ( + + ) : link.includes('github') ? ( + + ) : link.includes('feed.xml') ? ( + + ) : link.includes('feed.json') ? ( + + ) : null} + + )) + } +

diff --git a/src/components/Footer/Networks.tsx b/src/components/Footer/Networks.tsx deleted file mode 100644 index 2f310c11..00000000 --- a/src/components/Footer/Networks.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import type { ReactElement } from 'react' -import Icon from '../core/Icon' -import styles from './Networks.module.css' - -function NetworkIcon({ link }: { link: string }) { - let IconComp - - if (link.includes('mas.to')) { - IconComp = - } else if (link.includes('twitter')) { - IconComp = - } else if (link.includes('github')) { - IconComp = - } else if (link.includes('feed.xml')) { - IconComp = - } else if (link.includes('feed.json')) { - IconComp = - } else { - return null - } - - return IconComp -} - -export default function IconLinks({ - links -}: { - links: string[] -}): ReactElement { - return ( -

- {links.map((link: string) => ( - - - - ))} -

- ) -} diff --git a/src/components/Footer/Vcard.astro b/src/components/Footer/Vcard.astro index aac71f7f..be843439 100644 --- a/src/components/Footer/Vcard.astro +++ b/src/components/Footer/Vcard.astro @@ -1,8 +1,8 @@ --- import { Image } from 'astro:assets' -import Networks from './Networks' -import avatar from '../../images/avatar.jpg' -import config from '../../../.config/blog.config.mjs' +import Networks from './Networks.astro' +import avatar from '@images/avatar.jpg' +import config from '@config/blog.config.mjs' const { author, rss, jsonfeed } = config const { mastodon, twitter, github, name, uri } = author diff --git a/src/components/Footer/index.astro b/src/components/Footer/index.astro index b4493a30..2af1546b 100644 --- a/src/components/Footer/index.astro +++ b/src/components/Footer/index.astro @@ -1,5 +1,5 @@ --- -import Icon from '../core/Icon' +import { Github, Bitcoin } from '@images/icons' import Vcard from './Vcard.astro' import styles from './index.module.css' import config from '@config/blog.config.mjs' @@ -18,11 +18,11 @@ const { name, uri, github } = config.author {name} - + View source - + Say Thanks

diff --git a/src/components/Header/Search/SearchButton.tsx b/src/components/Header/Search/SearchButton.tsx index 8f5395f7..e4509e2d 100644 --- a/src/components/Header/Search/SearchButton.tsx +++ b/src/components/Header/Search/SearchButton.tsx @@ -1,6 +1,6 @@ import React, { ReactElement } from 'react' -import Icon from '../../core/Icon' import styles from './SearchButton.module.css' +import { Search } from '@images/icons' const SearchButton = ({ onClick }: { onClick: () => void }): ReactElement => ( ) diff --git a/src/components/Header/Search/SearchInput.tsx b/src/components/Header/Search/SearchInput.tsx index 810c0498..217b5c2a 100644 --- a/src/components/Header/Search/SearchInput.tsx +++ b/src/components/Header/Search/SearchInput.tsx @@ -1,7 +1,7 @@ import React, { ChangeEvent, ReactElement } from 'react' -import Icon from '../../core/Icon' import Input from '../../core/Input' import styles from './SearchInput.module.css' +import { X } from '@images/icons' export default function SearchInput({ value, @@ -27,7 +27,7 @@ export default function SearchInput({ onClick={onToggle} title="Close search" > - + ) diff --git a/src/components/Header/ThemeSwitch.test.tsx b/src/components/Header/ThemeSwitch.test.tsx deleted file mode 100644 index a4add5d5..00000000 --- a/src/components/Header/ThemeSwitch.test.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react' -import { fireEvent, render, screen } from '@testing-library/react' -import ThemeSwitch from './ThemeSwitch' - -describe('ThemeSwitch', () => { - it('renders correctly', async () => { - render() - const element = await screen.findByTitle('Toggle Dark Mode') - expect(element).toBeInTheDocument() - }) - - it('checkbox can be changed', () => { - const { container } = render() - - const toggle = container.querySelector('input') - const label = container.querySelector('label') - fireEvent.click(label) - fireEvent.change(toggle, { target: { checked: true } }) - }) -}) diff --git a/src/components/Header/ThemeSwitch.tsx b/src/components/Header/ThemeSwitch.tsx deleted file mode 100644 index 1ff659f5..00000000 --- a/src/components/Header/ThemeSwitch.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { ReactElement } from 'react' -import useDarkMode from '../../hooks/useDarkMode' -import Icon from '../core/Icon' -import styles from './ThemeSwitch.module.css' - -export default function ThemeSwitch(): ReactElement { - const { isDarkMode, setIsDarkMode } = useDarkMode() - - return ( -
- -
- ) -} diff --git a/src/components/Header/index.astro b/src/components/Header/index.astro index 2ee86a6b..f4c19997 100644 --- a/src/components/Header/index.astro +++ b/src/components/Header/index.astro @@ -1,20 +1,20 @@ --- -import logo from '@images/logo.svg' import Menu from './Menu' -import Search from './Search' -import ThemeSwitch from './ThemeSwitch' +// import Search from './Search' +import ThemeSwitch from '../ThemeSwitch/index.astro' +import { Logo } from '@images/icons' import styles from './index.module.css' ---