diff --git a/package-lock.json b/package-lock.json index 31082da..89c8a31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,21 +7,35 @@ "": { "name": "website", "version": "0.0.1", + "dependencies": { + "@fontsource/comfortaa": "^5.0.17" + }, "devDependencies": { - "@fontsource/comfortaa": "^5.0.16", "@neoconfetti/svelte": "^1.0.0", "@sveltejs/adapter-static": "^2.0.3", "@sveltejs/kit": "^1.20.4", "@types/cookie": "^0.5.1", + "@types/dateformat": "^5.0.1", + "@types/prismjs": "^1.26.2", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "dateformat": "^5.0.3", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.30.0", + "image-transmutation": "^0.1.3", + "mdsvex": "^0.11.0", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.10.1", + "reading-time": "^1.5.0", + "rehype-autolink-headings": "^7.0.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "sass": "^1.69.4", + "striptags": "^3.2.0", "svelte": "^4.0.5", "svelte-check": "^3.4.3", + "svelte-sitemap": "^2.6.0", "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^4.4.2", @@ -468,10 +482,9 @@ } }, "node_modules/@fontsource/comfortaa": { - "version": "5.0.16", - "resolved": "https://registry.npmjs.org/@fontsource/comfortaa/-/comfortaa-5.0.16.tgz", - "integrity": "sha512-cMLfF68WhM2SRxrjvg/Ixeq53xk9LaLv1A/yWz3VuXoOMPx04NYhUlJnKDDqk1rMsjxEFyK3/MWGWlqynb0vpA==", - "dev": true + "version": "5.0.17", + "resolved": "https://registry.npmjs.org/@fontsource/comfortaa/-/comfortaa-5.0.17.tgz", + "integrity": "sha512-k4YVmoMoTva1bD3VzRH60oJTMMnbqH8AL0mJO+D6rOeO/Y6jFMOQvvwkR4Mi6zqTMzQSIzb5J/uiq5RgSp/ISw==" }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", @@ -607,6 +620,54 @@ "node": ">= 8" } }, + "node_modules/@oozcitak/dom": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.10.tgz", + "integrity": "sha512-0JT29/LaxVgRcGKvHmSrUTEvZ8BXvZhGl2LASRUgHqDTC1M5g1pLmVv56IYNyt3bG2CUjDkc67wnyZC14pbQrQ==", + "dev": true, + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/url": "1.0.4", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/infra": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.8.tgz", + "integrity": "sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==", + "dev": true, + "dependencies": { + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@oozcitak/url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.4.tgz", + "integrity": "sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==", + "dev": true, + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/util": { + "version": "8.3.8", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.8.tgz", + "integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.23", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", @@ -720,12 +781,27 @@ "integrity": "sha512-SLg07AS9z1Ab2LU+QxzU8RCmzsja80ywjf/t5oqw+4NSH20gIGlhLOrBDm1L3PBWzPa4+wkgFQVZAjE6Ioj2ug==", "dev": true }, + "node_modules/@types/dateformat": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-5.0.1.tgz", + "integrity": "sha512-mdFQYNj44kRls3iZTgW0vkMOyko70KRsxkjD6qjSdfkVZLXlIFU6w9mYd62zv2uZBYyKbYkr9Mh0EVulIvyZ3g==", + "dev": true + }, "node_modules/@types/estree": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", "dev": true }, + "node_modules/@types/hast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.2.tgz", + "integrity": "sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", @@ -741,6 +817,12 @@ "undici-types": "~5.25.1" } }, + "node_modules/@types/prismjs": { + "version": "1.26.2", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.2.tgz", + "integrity": "sha512-/r7Cp7iUIk7gts26mHXD66geUC+2Fo26TZYjQK6Nr4LDfi6lmdRmMqM0oPwfiMhUwoBAOFe8GstKi2pf6hZvwA==", + "dev": true + }, "node_modules/@types/pug": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.8.tgz", @@ -753,6 +835,12 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "node_modules/@types/unist": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.9.tgz", + "integrity": "sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", @@ -942,6 +1030,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@vitest/expect": { "version": "0.32.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.4.tgz", @@ -1162,12 +1256,48 @@ "dequal": "^2.0.3" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1177,6 +1307,17 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1199,6 +1340,30 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -1311,6 +1476,12 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "node_modules/code-red": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", @@ -1324,6 +1495,19 @@ "periscopic": "^3.1.0" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1342,6 +1526,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1396,6 +1590,15 @@ "node": ">=4" } }, + "node_modules/dateformat": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-5.0.3.tgz", + "integrity": "sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1413,6 +1616,21 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -1425,6 +1643,15 @@ "node": ">=6" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1458,12 +1685,34 @@ "node": ">=8" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/devalue": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", "dev": true }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -1497,6 +1746,15 @@ "node": ">=6.0.0" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", @@ -1680,6 +1938,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/esm-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", @@ -1703,6 +1970,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -1754,12 +2034,33 @@ "node": ">=0.10.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -1869,6 +2170,12 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1898,6 +2205,18 @@ "node": "*" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1998,6 +2317,65 @@ "node": ">=8" } }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", + "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2007,6 +2385,27 @@ "node": ">= 4" } }, + "node_modules/image-transmutation": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/image-transmutation/-/image-transmutation-0.1.3.tgz", + "integrity": "sha512-eGO1T2ed0iS2v75atisKR+hmuCFvslssUW6P0+B6mqYIJ44Ey3+LRzRQyF1ezhPZyU17jRCYEwERqSeJp1W8+A==", + "dev": true, + "dependencies": { + "esm": "^3.2.25", + "glob": "^7.1.6", + "minimist": "^1.2.5", + "sharp": "^0.32.1" + }, + "bin": { + "image-transmutation": "bin/image-transmutation" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2048,6 +2447,30 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2099,6 +2522,18 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-reference": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", @@ -2274,6 +2709,21 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, + "node_modules/mdsvex": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.11.0.tgz", + "integrity": "sha512-gJF1s0N2nCmdxcKn8HDn0LKrN8poStqAicp6bBcsKFd/zkUBGLP5e7vnxu+g0pjBbDFOscUyI1mtHz+YK2TCDw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.3", + "prism-svelte": "^0.4.7", + "prismjs": "^1.17.1", + "vfile-message": "^2.0.4" + }, + "peerDependencies": { + "svelte": ">=3 <5" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2296,10 +2746,22 @@ "node": ">=8.6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "engines": { "node": ">=4" @@ -2338,6 +2800,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/mlly": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", @@ -2392,12 +2860,36 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-abi": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -2712,6 +3204,60 @@ "node": ">=4" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2772,6 +3318,31 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prism-svelte": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", + "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==", + "dev": true + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -2801,12 +3372,56 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -2819,6 +3434,65 @@ "node": ">=8.10.0" } }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "dev": true + }, + "node_modules/rehype-autolink-headings": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.0.0.tgz", + "integrity": "sha512-DLskejGYHQP9v7vUW85BeYIclgfMQ1IwAMx+0lm8Sr3cME2NThgy2OdTfosmuBA68fqP5o4FK+dknpUMFvlxYQ==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2904,6 +3578,26 @@ "node": ">=6" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/sander": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", @@ -2928,6 +3622,23 @@ "rimraf": "bin.js" } }, + "node_modules/sass": { + "version": "1.69.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.4.tgz", + "integrity": "sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -2949,6 +3660,29 @@ "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", "dev": true }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2976,6 +3710,60 @@ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/sirv": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", @@ -3023,6 +3811,22 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -3035,6 +3839,25 @@ "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==", "dev": true }, + "node_modules/streamx": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", + "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3083,6 +3906,12 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/striptags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", + "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==", + "dev": true + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3254,6 +4083,45 @@ "node": ">=12" } }, + "node_modules/svelte-sitemap": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/svelte-sitemap/-/svelte-sitemap-2.6.0.tgz", + "integrity": "sha512-WcwsuIeo8iJFG9a5cgvXwXEGoyjk6Zowb6JmL5BbwfnFXMzakGa1+mQjthw5Ni3UV/gGbE0PgJvc7Ygir3LmFg==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.12", + "minimist": "^1.2.8", + "xmlbuilder2": "^3.0.2" + }, + "bin": { + "svelte-sitemap": "index.js" + }, + "engines": { + "node": ">= 14.17.0" + } + }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3315,6 +4183,16 @@ "node": ">=6" } }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -3333,6 +4211,18 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3403,6 +4293,104 @@ "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", "dev": true }, + "node_modules/unified": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.3.tgz", + "integrity": "sha512-jlCV402P+YDcFcB2VcN/n8JasOddqIiaxv118wNBoZXEhOn+lYG7BR4Bfg2BwxvlK58dwbuH2w7GX2esAjL6Mg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/@types/unist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.1.tgz", + "integrity": "sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==", + "dev": true + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is/node_modules/@types/unist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.1.tgz", + "integrity": "sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==", + "dev": true + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents/node_modules/@types/unist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.1.tgz", + "integrity": "sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==", + "dev": true + }, + "node_modules/unist-util-visit/node_modules/@types/unist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.1.tgz", + "integrity": "sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==", + "dev": true + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3418,6 +4406,68 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/@types/unist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.1.tgz", + "integrity": "sha512-ue/hDUpPjC85m+PM9OQDMZr3LywT+CT6mPsQq8OJtCLiERkGRcQUFvu9XASF5XWqyZFXbf15lvb3JFJ4dRLWPg==", + "dev": true + }, + "node_modules/vfile/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -3624,6 +4674,43 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xmlbuilder2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-3.1.1.tgz", + "integrity": "sha512-WCSfbfZnQDdLQLiMdGUQpMxxckeQ4oZNMNhLVkcekTu7xhD4tuUDyAPoY8CwXvBYE6LwBHd6QW2WZXlOWr1vCw==", + "dev": true, + "dependencies": { + "@oozcitak/dom": "1.15.10", + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8", + "js-yaml": "3.14.1" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/xmlbuilder2/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/xmlbuilder2/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 318493d..b6b4b89 100644 --- a/package.json +++ b/package.json @@ -9,27 +9,43 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." + "format": "prettier --plugin-search-dir . --write .", + "optimize-images": "image-transmutation --run --sourceFolder './build/images' --targetFolder './build/images' --inputFormats 'jpg' --inputFormats 'jpeg' --inputFormats 'png' --outputFormats 'png' --outputFormats 'webp' --outputFormats 'avif'", + "postbuild": "npm run optimize-images && svelte-sitemap --domain https://languagexchange.net/" }, "devDependencies": { - "@fontsource/comfortaa": "^5.0.16", "@neoconfetti/svelte": "^1.0.0", "@sveltejs/adapter-static": "^2.0.3", "@sveltejs/kit": "^1.20.4", "@types/cookie": "^0.5.1", + "@types/dateformat": "^5.0.1", + "@types/prismjs": "^1.26.2", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "dateformat": "^5.0.3", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.30.0", + "image-transmutation": "^0.1.3", + "mdsvex": "^0.11.0", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.10.1", + "reading-time": "^1.5.0", + "rehype-autolink-headings": "^7.0.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "sass": "^1.69.4", + "striptags": "^3.2.0", "svelte": "^4.0.5", "svelte-check": "^3.4.3", + "svelte-sitemap": "^2.6.0", "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^4.4.2", "vitest": "^0.32.2" }, - "type": "module" + "type": "module", + "dependencies": { + "@fontsource/comfortaa": "^5.0.17" + } } diff --git a/src/app.html b/src/app.html index 6769ed5..99366b9 100644 --- a/src/app.html +++ b/src/app.html @@ -2,11 +2,53 @@ - + + + + + + + + + + + + + %sveltekit.head% -
%sveltekit.body%
+
%sveltekit.body%
diff --git a/src/lib/components/atoms/Button.svelte b/src/lib/components/atoms/Button.svelte new file mode 100644 index 0000000..f0bb660 --- /dev/null +++ b/src/lib/components/atoms/Button.svelte @@ -0,0 +1,132 @@ + + + + {#if $$slots['icon']} +
+ +
+ {/if} + +
+ + diff --git a/src/lib/components/atoms/Card.svelte b/src/lib/components/atoms/Card.svelte new file mode 100644 index 0000000..ce347af --- /dev/null +++ b/src/lib/components/atoms/Card.svelte @@ -0,0 +1,99 @@ + + + + {#if $$slots.image} +
+ +
+ {/if} +
+
+ +
+ {#if $$slots.footer} + + {/if} +
+
+ + diff --git a/src/lib/components/atoms/Image.svelte b/src/lib/components/atoms/Image.svelte new file mode 100644 index 0000000..08e773c --- /dev/null +++ b/src/lib/components/atoms/Image.svelte @@ -0,0 +1,59 @@ + + + + + + + diff --git a/src/lib/components/atoms/Logo.svelte b/src/lib/components/atoms/Logo.svelte new file mode 100644 index 0000000..c392b36 --- /dev/null +++ b/src/lib/components/atoms/Logo.svelte @@ -0,0 +1,82 @@ + + + + + diff --git a/src/lib/components/atoms/SingleSparkle.svelte b/src/lib/components/atoms/SingleSparkle.svelte new file mode 100644 index 0000000..6f1fe2f --- /dev/null +++ b/src/lib/components/atoms/SingleSparkle.svelte @@ -0,0 +1,55 @@ + + +
+ + + +
+ + diff --git a/src/lib/components/atoms/Sparkles.svelte b/src/lib/components/atoms/Sparkles.svelte new file mode 100644 index 0000000..d0ad4bc --- /dev/null +++ b/src/lib/components/atoms/Sparkles.svelte @@ -0,0 +1,71 @@ + + +
+ {#each sparkles as sparkle (sparkle.id)} + + {/each} + + + +
+ + diff --git a/src/lib/components/atoms/Tag.svelte b/src/lib/components/atoms/Tag.svelte new file mode 100644 index 0000000..024b9cf --- /dev/null +++ b/src/lib/components/atoms/Tag.svelte @@ -0,0 +1,31 @@ + + +
+ +
+ + diff --git a/src/lib/components/molecules/BlogPostCard.svelte b/src/lib/components/molecules/BlogPostCard.svelte new file mode 100644 index 0000000..e79d505 --- /dev/null +++ b/src/lib/components/molecules/BlogPostCard.svelte @@ -0,0 +1,97 @@ + + + +
+ {#if coverImage} + Cover image of this blog post + {/if} +
+
+

+ {title} +

+ {#if readingTime} +
{readingTime}
+ {/if} + {#if excerpt} +

+ {excerpt} +

+ {/if} +
+ +
+ + diff --git a/src/lib/components/molecules/Callout.svelte b/src/lib/components/molecules/Callout.svelte new file mode 100644 index 0000000..e5e451b --- /dev/null +++ b/src/lib/components/molecules/Callout.svelte @@ -0,0 +1,71 @@ + + +
+ {#if type} +
+ {#if type == 'info'} + + {:else if type == 'warning' || type == 'error'} + + {:else if type == 'success'} + + {/if} +
+ {/if} + +
+ + diff --git a/src/lib/components/molecules/CodeBlock.svelte b/src/lib/components/molecules/CodeBlock.svelte new file mode 100644 index 0000000..d63c118 --- /dev/null +++ b/src/lib/components/molecules/CodeBlock.svelte @@ -0,0 +1,72 @@ + + +
+ {#if filename} +
{filename}
+ {/if} + {#if lang} +
{lang}
+ {/if} + +
+ + diff --git a/src/lib/components/molecules/FeatureCard.svelte b/src/lib/components/molecules/FeatureCard.svelte new file mode 100644 index 0000000..45c8b69 --- /dev/null +++ b/src/lib/components/molecules/FeatureCard.svelte @@ -0,0 +1,67 @@ + + + +
+ Picture describing the {name} feature +
+
+
+ {name} +
+

{description}

+
+ +
+ + diff --git a/src/lib/components/molecules/MarkerHighlight.svelte b/src/lib/components/molecules/MarkerHighlight.svelte new file mode 100644 index 0000000..d5e55d2 --- /dev/null +++ b/src/lib/components/molecules/MarkerHighlight.svelte @@ -0,0 +1,34 @@ + + + + + + + diff --git a/src/lib/components/molecules/Socials.svelte b/src/lib/components/molecules/Socials.svelte new file mode 100644 index 0000000..625ae85 --- /dev/null +++ b/src/lib/components/molecules/Socials.svelte @@ -0,0 +1,63 @@ + + +
+ + + + + + + + + + + + +
+ + diff --git a/src/lib/components/molecules/SparklingHighlight.svelte b/src/lib/components/molecules/SparklingHighlight.svelte new file mode 100644 index 0000000..088d23a --- /dev/null +++ b/src/lib/components/molecules/SparklingHighlight.svelte @@ -0,0 +1,19 @@ + + + + + diff --git a/src/lib/components/molecules/ThemeToggle.svelte b/src/lib/components/molecules/ThemeToggle.svelte new file mode 100644 index 0000000..375f44a --- /dev/null +++ b/src/lib/components/molecules/ThemeToggle.svelte @@ -0,0 +1,167 @@ + + + + + + + diff --git a/src/lib/components/molecules/TintHighlight.svelte b/src/lib/components/molecules/TintHighlight.svelte new file mode 100644 index 0000000..5bc35c8 --- /dev/null +++ b/src/lib/components/molecules/TintHighlight.svelte @@ -0,0 +1,21 @@ + + + + + + + diff --git a/src/lib/components/organisms/About.svelte b/src/lib/components/organisms/About.svelte new file mode 100644 index 0000000..ace6770 --- /dev/null +++ b/src/lib/components/organisms/About.svelte @@ -0,0 +1,94 @@ + + +
+
+

+ Language learning can be a challenging but + rewarding process! +

+

+ At languageXchange, we believe that the best way to learn a language is through practice and + immersion. That's why we've created a platform that connects language learners from around the + world, +

+

+ So you can practice speaking with native speakers and improve your skills in a fun and + engaging way. Connect with native speakers to dive into immersive experiences. Start your + adventure soon! +

+
+ Socials: + +
+
+
+ Sample for the static template +
+
+ + diff --git a/src/lib/components/organisms/ContentSection.svelte b/src/lib/components/organisms/ContentSection.svelte new file mode 100644 index 0000000..898a878 --- /dev/null +++ b/src/lib/components/organisms/ContentSection.svelte @@ -0,0 +1,104 @@ + + +
+
+ {#if title || description} +
+ {#if title} +

+ {title} +

+ {/if} + {#if description} +

+ {description} +

+ {/if} +
+ {/if} + {#if $$slots['button']} +
+ +
+ {/if} +
+
+ +
+
+ + diff --git a/src/lib/components/organisms/Features.svelte b/src/lib/components/organisms/Features.svelte new file mode 100644 index 0000000..4db5cf3 --- /dev/null +++ b/src/lib/components/organisms/Features.svelte @@ -0,0 +1,73 @@ + + + +
+
+ {#each features as feature} + + {/each} +
+
+
+ + diff --git a/src/lib/components/organisms/Footer.svelte b/src/lib/components/organisms/Footer.svelte new file mode 100644 index 0000000..9c80b90 --- /dev/null +++ b/src/lib/components/organisms/Footer.svelte @@ -0,0 +1,69 @@ + + + + + diff --git a/src/lib/components/organisms/Header.svelte b/src/lib/components/organisms/Header.svelte new file mode 100644 index 0000000..9d3d997 --- /dev/null +++ b/src/lib/components/organisms/Header.svelte @@ -0,0 +1,78 @@ + + +
+ +
+ + diff --git a/src/lib/components/organisms/Hero.svelte b/src/lib/components/organisms/Hero.svelte new file mode 100644 index 0000000..4a10546 --- /dev/null +++ b/src/lib/components/organisms/Hero.svelte @@ -0,0 +1,77 @@ + + +
+

Practice, Learn, Succeed!

+

+ Words are the keys that unlock + a world of connections. +

+
+ + + + +
+
+ + diff --git a/src/lib/components/organisms/RecentPosts.svelte b/src/lib/components/organisms/RecentPosts.svelte new file mode 100644 index 0000000..0f8f350 --- /dev/null +++ b/src/lib/components/organisms/RecentPosts.svelte @@ -0,0 +1,46 @@ + + + +
+ +
+
+ {#each posts as post} + + {/each} +
+
+ + diff --git a/src/lib/components/organisms/RelatedPosts.svelte b/src/lib/components/organisms/RelatedPosts.svelte new file mode 100644 index 0000000..fb1cfc5 --- /dev/null +++ b/src/lib/components/organisms/RelatedPosts.svelte @@ -0,0 +1,41 @@ + + + +
+ {#each posts as post} + + {/each} +
+
+ + diff --git a/src/lib/components/organisms/Waves.svelte b/src/lib/components/organisms/Waves.svelte new file mode 100644 index 0000000..1cb2edd --- /dev/null +++ b/src/lib/components/organisms/Waves.svelte @@ -0,0 +1,93 @@ +
+ + + + + + + + + + + +
+ + diff --git a/src/lib/data/blog-posts/index.ts b/src/lib/data/blog-posts/index.ts new file mode 100644 index 0000000..586ec55 --- /dev/null +++ b/src/lib/data/blog-posts/index.ts @@ -0,0 +1,4 @@ +import { filterPosts, importPosts } from './utils'; + +export const allPosts = importPosts(true); +export const filteredPosts = filterPosts(allPosts); diff --git a/src/lib/data/blog-posts/utils.ts b/src/lib/data/blog-posts/utils.ts new file mode 100644 index 0000000..9f2bd96 --- /dev/null +++ b/src/lib/data/blog-posts/utils.ts @@ -0,0 +1,73 @@ +// Disabling eslint because importing Prism is needed +// even if not directly used in this file +// eslint-disable-next-line no-unused-vars +import Prism from 'prismjs'; +// Here we assign it to a variable so the import above +// is not removed automatically on build +const ifYouRemoveMeTheBuildFails = Prism; +import 'prism-svelte'; +import readingTime from 'reading-time'; +import striptags from 'striptags'; +import type { BlogPost } from '$lib/utils/types'; + +export const importPosts = (render = false) => { + const blogImports = import.meta.glob('$routes/*/*/*.md', { eager: true }); + const innerImports = import.meta.glob('$routes/*/*/*/*.md', { eager: true }); + + const imports = { ...blogImports, ...innerImports }; + + const posts: BlogPost[] = []; + for (const path in imports) { + const post = imports[path] as any; + if (post) { + posts.push({ + ...post.metadata, + html: render && post.default.render ? post.default.render()?.html : undefined + }); + } + } + + return posts; +}; + +export const filterPosts = (posts: BlogPost[]) => { + return posts + .filter((post) => !post.hidden) + .sort((a, b) => + new Date(a.date).getTime() > new Date(b.date).getTime() + ? -1 + : new Date(a.date).getTime() < new Date(b.date).getTime() + ? 1 + : 0 + ) + .map((post) => { + const readingTimeResult = post.html ? readingTime(striptags(post.html) || '') : undefined; + const relatedPosts = getRelatedPosts(posts, post); + + return { + ...post, + readingTime: readingTimeResult ? readingTimeResult.text : '', + relatedPosts: relatedPosts + } as BlogPost; + }); +}; + +// #region Unexported Functions + +const getRelatedPosts = (posts: BlogPost[], post: BlogPost) => { + // Get the first 3 posts that have the highest number of tags in common + const relatedPosts = posts + .filter((p) => p.slug !== post.slug) + .sort((a, b) => { + const aTags = a.tags?.filter((t) => post.tags?.includes(t)); + const bTags = b.tags?.filter((t) => post.tags?.includes(t)); + return aTags?.length > bTags?.length ? -1 : aTags?.length < bTags?.length ? 1 : 0; + }); + + return relatedPosts.slice(0, 3).map((p) => ({ + ...p, + readingTime: p.html ? readingTime(striptags(p.html) || '').text : '' + })); +}; + +// #endregion diff --git a/src/lib/data/features.ts b/src/lib/data/features.ts new file mode 100644 index 0000000..60974d1 --- /dev/null +++ b/src/lib/data/features.ts @@ -0,0 +1,25 @@ +import type { Feature } from '$lib/utils/types'; + +export default [ + { + name: 'Markdown Support', + description: + 'Blog posts are written in Markdown, a simple and nearly-universal format. This means you can bring over your posts from other platforms, and easily export to another if you want to.', + image: 'images/features/markdown.jpg', + tags: [{ label: 'Powered by MDsveX' }] + }, + { + name: 'Themeable', + description: + 'You can easily theme the entire website by changing just a few colors in the _themes.scss file.', + image: 'images/features/themeable.jpg', + tags: [{ label: 'Primary Color' }, { label: 'Secondary Color', color: 'secondary' }] + }, + { + name: 'Well Optimized', + description: + 'Images are automatically optimized and lazy loaded, to ensure the website loads as fast as possible regardless of connection speed.', + image: 'images/features/optimized.jpg', + tags: [{ label: 'Powered by Image Transmutation' }] + } +] as Feature[]; diff --git a/src/lib/data/meta.ts b/src/lib/data/meta.ts new file mode 100644 index 0000000..869a8dd --- /dev/null +++ b/src/lib/data/meta.ts @@ -0,0 +1,206 @@ +// Base values for meta tags +// So they can be added as suffixes on different pages +// Via + +export const siteBaseUrl = 'https://languageXchange.net/'; + +export const description = + "At languageXchange, we believe that the best way to learn a language is through practice and immersion. That's why we've created a platform that connects language learners from around the world."; + +export const title = 'Practice, Learn, Succeed!'; + +export const image = `${siteBaseUrl}/images/site-preview.png`; + +export const keywords = [ + 'language exchange', + 'language learning', + 'language practice', + 'conversation partner', + 'language skills', + 'speaking partner', + 'language exchange platform', + 'language exchange app', + 'tandem language exchange', + 'hello talk', + 'speaky', + 'learn a language', + 'foreign language practice', + 'language exchange community', + 'speak with natives', + 'language learning partner', + 'improve language skills', + 'language exchange website', + 'language learners', + 'find a language partner', + 'online language exchange', + 'language conversation', + 'language exchange service', + 'practice speaking', + 'language fluency', + 'language tandem', + 'language exchange program', + 'exchange language skills', + 'meet language partners', + 'language learning community', + 'connect with native speakers', + 'language exchange network', + 'improve speaking skills', + 'speak a foreign language', + 'language exchange community', + 'practice with a native speaker', + 'tandem language learning', + 'speak in a foreign language', + 'language exchange partner', + 'foreign language conversation', + 'language learning app', + 'speaking practice', + 'language exchange website', + 'online language learning', + 'language exchange chat', + 'conversation in another language', + 'language exchange opportunities', + 'language exchange program', + 'foreign language partner', + 'language exchange app', + 'conversation exchange', + 'language exchange platform', + 'speak with native speakers', + 'improve language fluency', + 'meet language learners', + 'language exchange app', + 'find conversation partners', + 'exchange language skills', + 'language learning platform', + 'connect with language learners', + 'practice language speaking', + 'speak a new language', + 'language exchange practice', + 'language exchange network', + 'speaking with native speakers', + 'learn a second language', + 'foreign language conversation partner', + 'language exchange service', + 'online language exchange', + 'find a language exchange partner', + 'language learning opportunities', + 'language exchange program', + 'language learning community', + 'practice with native speakers', + 'tandem language exchange', + 'language exchange website', + 'improve language skills', + 'conversation in a foreign language', + 'foreign language fluency', + 'speak with language partners', + 'language exchange chat', + 'online language tandem', + 'conversation exchange platform', + 'language exchange community', + 'language partner search', + 'practice speaking skills', + 'speak a foreign language fluently', + 'language exchange network', + 'learn a language online', + 'foreign language conversation practice', + 'language exchange app', + 'find language exchange partners', + 'improve speaking fluency', + 'speak with language learners', + 'language exchange forum', + 'language tandem program', + 'conversation partner app', + 'language exchange website', + 'language exchange community', + 'practice with language speakers', + 'foreign language learning partner', + 'speak with language exchange partners', + 'language exchange platform', + 'language exchange service', + 'learn a language online', + 'find language tandem partners', + 'improve language conversation skills', + 'foreign language exchange program', + 'language exchange app', + 'conversation exchange website', + 'speak with language natives', + 'online language learning community', + 'language exchange network', + 'foreign language speaking practice', + 'language exchange chat', + 'practice with language partners', + 'find language exchange opportunities', + 'language exchange program', + 'tandem language learning app', + 'speak with language experts', + 'improve language speaking fluency', + 'speak with language tutors', + 'language exchange website', + 'foreign language conversation exchange', + 'language practice with natives', + 'connect with language learners', + 'learn a language online', + 'foreign language exchange service', + 'language exchange forum', + 'language learning partners', + 'practice with language natives', + 'language exchange network', + 'conversation in another language', + 'language exchange chat', + 'language exchange platform', + 'speak with language exchange partners', + 'learn a new language', + 'foreign language conversation practice', + 'find conversation exchange partners', + 'improve language skills with native speakers', + 'language exchange app', + 'language learning community', + 'practice speaking with language learners', + 'speak with language exchange tutors', + 'foreign language fluency exchange', + 'language exchange website', + 'language tandem practice', + 'connect with language exchange community', + 'language partner search platform', + 'speak with language experts', + 'improve speaking skills with natives', + 'language exchange network', + 'learn a foreign language', + 'conversation exchange chat', + 'language exchange service', + 'language exchange program', + 'practice speaking a foreign language', + 'speak with language tandem partners', + 'improve language fluency with native speakers', + 'language exchange website', + 'foreign language conversation partner search', + 'language learning app', + 'connect with language partners', + 'language exchange opportunities', + 'language exchange program', + 'language exchange community', + 'find conversation exchange partners', + 'improve speaking skills with language natives', + 'speak with language exchange tutors', + 'foreign language fluency exchange', + 'language exchange network', + 'learn a foreign language online', + 'conversation exchange chat', + 'language exchange service', + 'language exchange program', + 'practice speaking a foreign language', + 'speak with language tandem partners', + 'improve language fluency with native speakers', + 'language exchange website', + 'foreign language conversation partner search', + 'language learning app', + 'connect with language partners', + 'language exchange opportunities', + 'language exchange program', + 'language exchange community', + 'find conversation exchange partners', + 'improve speaking skills with language natives', + 'speak with language exchange tutors', + 'foreign language fluency exchange', + 'language exchange network', + 'learn a foreign language online' +]; diff --git a/src/lib/icons/alert.svelte b/src/lib/icons/alert.svelte new file mode 100644 index 0000000..29e7367 --- /dev/null +++ b/src/lib/icons/alert.svelte @@ -0,0 +1,22 @@ + + + + + diff --git a/src/lib/icons/blog.svelte b/src/lib/icons/blog.svelte new file mode 100644 index 0000000..cde82f2 --- /dev/null +++ b/src/lib/icons/blog.svelte @@ -0,0 +1,16 @@ + + + + diff --git a/src/lib/icons/chat.svelte b/src/lib/icons/chat.svelte new file mode 100644 index 0000000..f7455bd --- /dev/null +++ b/src/lib/icons/chat.svelte @@ -0,0 +1,36 @@ + + + + + + diff --git a/src/lib/icons/check.svelte b/src/lib/icons/check.svelte new file mode 100644 index 0000000..fec37d4 --- /dev/null +++ b/src/lib/icons/check.svelte @@ -0,0 +1,21 @@ + + + + diff --git a/src/lib/icons/circle.svelte b/src/lib/icons/circle.svelte new file mode 100644 index 0000000..fb96e6a --- /dev/null +++ b/src/lib/icons/circle.svelte @@ -0,0 +1,15 @@ + + + diff --git a/src/lib/icons/download.svelte b/src/lib/icons/download.svelte new file mode 100644 index 0000000..2f2d468 --- /dev/null +++ b/src/lib/icons/download.svelte @@ -0,0 +1,16 @@ + + + + diff --git a/src/lib/icons/error.svelte b/src/lib/icons/error.svelte new file mode 100644 index 0000000..717b297 --- /dev/null +++ b/src/lib/icons/error.svelte @@ -0,0 +1,138 @@ + diff --git a/src/lib/icons/experience.svelte b/src/lib/icons/experience.svelte new file mode 100644 index 0000000..977a1ac --- /dev/null +++ b/src/lib/icons/experience.svelte @@ -0,0 +1,14 @@ + + + diff --git a/src/lib/icons/external-link.svelte b/src/lib/icons/external-link.svelte new file mode 100644 index 0000000..74fb130 --- /dev/null +++ b/src/lib/icons/external-link.svelte @@ -0,0 +1,21 @@ + + + + diff --git a/src/lib/icons/features.svelte b/src/lib/icons/features.svelte new file mode 100644 index 0000000..c423f51 --- /dev/null +++ b/src/lib/icons/features.svelte @@ -0,0 +1,16 @@ + + + diff --git a/src/lib/icons/footer-wave.svelte b/src/lib/icons/footer-wave.svelte new file mode 100644 index 0000000..93114c6 --- /dev/null +++ b/src/lib/icons/footer-wave.svelte @@ -0,0 +1,15 @@ + + + diff --git a/src/lib/icons/info.svelte b/src/lib/icons/info.svelte new file mode 100644 index 0000000..afcfaae --- /dev/null +++ b/src/lib/icons/info.svelte @@ -0,0 +1,22 @@ + + + + + diff --git a/src/lib/icons/internet.svelte b/src/lib/icons/internet.svelte new file mode 100644 index 0000000..facdf20 --- /dev/null +++ b/src/lib/icons/internet.svelte @@ -0,0 +1,63 @@ + + + + + + + + + + + diff --git a/src/lib/icons/pin.svelte b/src/lib/icons/pin.svelte new file mode 100644 index 0000000..1aa2467 --- /dev/null +++ b/src/lib/icons/pin.svelte @@ -0,0 +1,21 @@ + + + + diff --git a/src/lib/icons/rss.svelte b/src/lib/icons/rss.svelte new file mode 100644 index 0000000..b0fdbbf --- /dev/null +++ b/src/lib/icons/rss.svelte @@ -0,0 +1,27 @@ + + + + + diff --git a/src/lib/icons/socials/email.svelte b/src/lib/icons/socials/email.svelte new file mode 100644 index 0000000..b2f014e --- /dev/null +++ b/src/lib/icons/socials/email.svelte @@ -0,0 +1,20 @@ + + + + diff --git a/src/lib/icons/socials/github.svelte b/src/lib/icons/socials/github.svelte new file mode 100644 index 0000000..f49f238 --- /dev/null +++ b/src/lib/icons/socials/github.svelte @@ -0,0 +1,21 @@ + + + + diff --git a/src/lib/icons/socials/instagram.svelte b/src/lib/icons/socials/instagram.svelte new file mode 100644 index 0000000..c0eab06 --- /dev/null +++ b/src/lib/icons/socials/instagram.svelte @@ -0,0 +1,28 @@ + + + + + diff --git a/src/lib/icons/socials/x.svelte b/src/lib/icons/socials/x.svelte new file mode 100644 index 0000000..fc9d66e --- /dev/null +++ b/src/lib/icons/socials/x.svelte @@ -0,0 +1,15 @@ + + + diff --git a/src/lib/icons/star.svelte b/src/lib/icons/star.svelte new file mode 100644 index 0000000..394d743 --- /dev/null +++ b/src/lib/icons/star.svelte @@ -0,0 +1,15 @@ + + + diff --git a/src/lib/scss/_animations.scss b/src/lib/scss/_animations.scss new file mode 100644 index 0000000..828dfe2 --- /dev/null +++ b/src/lib/scss/_animations.scss @@ -0,0 +1,34 @@ +@keyframes svg-text-stroke { + 0% { + fill: transparent; + stroke: var(--text-color); + stroke-dashoffset: 25%; + stroke-dasharray: 0 50%; + stroke-width: 2; + } + 70% { + fill: transparent; + stroke: var(--text-color); + } + 80% { + fill: transparent; + stroke: var(--text-color); + stroke-width: 3; + } + 100% { + fill: var(--text-color); + stroke: transparent; + stroke-dashoffset: -25%; + stroke-dasharray: 50% 0; + stroke-width: 0; + } +} + +@keyframes spin { + from { + transform: rotate(0turn); + } + to { + transform: rotate(1turn); + } +} diff --git a/src/lib/scss/_base.scss b/src/lib/scss/_base.scss new file mode 100644 index 0000000..8b80de6 --- /dev/null +++ b/src/lib/scss/_base.scss @@ -0,0 +1,22 @@ +// Styles that are used everywhere + +.container { + @include padded-container; +} + +ul, +ol { + margin: 10px 0 10px 40px; + padding: 0; + + li { + margin: 6px 0; + + &::marker { + color: var(--color--primary); + } + } +} +ul { + list-style: outside; +} diff --git a/src/lib/scss/_breakpoints.scss b/src/lib/scss/_breakpoints.scss new file mode 100644 index 0000000..c14577f --- /dev/null +++ b/src/lib/scss/_breakpoints.scss @@ -0,0 +1,43 @@ +$breakpoint-iphone-se-max: 320px; +$breakpoint-phone-max: 767px; +$breakpoint-tablet-portrait-min: 768px; +$breakpoint-tablet-portrait-max: 900px; +$breakpoint-tablet-landscape-min: 901px; +$breakpoint-tablet-landscape-max: 1200px; +$breakpoint-desktop-min: 1201px; + +@mixin for-iphone-se { + @media (max-width: $breakpoint-iphone-se-max) { + @content; + } +} +@mixin for-phone-only { + @media (max-width: $breakpoint-phone-max) { + @content; + } +} +@mixin for-tablet-portrait-up { + @media (min-width: $breakpoint-tablet-portrait-min) { + @content; + } +} +@mixin for-tablet-portrait-down { + @media (max-width: $breakpoint-tablet-portrait-max) { + @content; + } +} +@mixin for-tablet-landscape-up { + @media (min-width: $breakpoint-tablet-landscape-min) { + @content; + } +} +@mixin for-tablet-landscape-down { + @media (max-width: $breakpoint-tablet-landscape-max) { + @content; + } +} +@mixin for-desktop-up { + @media (min-width: $breakpoint-desktop-min) { + @content; + } +} diff --git a/src/lib/scss/_code-highlights.scss b/src/lib/scss/_code-highlights.scss new file mode 100644 index 0000000..a815547 --- /dev/null +++ b/src/lib/scss/_code-highlights.scss @@ -0,0 +1,151 @@ +// pre[class*="language-"] { +// display: block; +// background-color: var(--code-background-color); +// color: var(--code-text-color); +// font-family: var(--mono-font); +// font-size: 0.85em; +// line-height: 1.33em; +// border-radius: 0.25em; +// box-shadow: var(--card-shadow); + +// padding: 30px 15px; + +// overflow-x: auto; +// scrollbar-color: var(--primary-color) var(--scrollbar-track-color); +// scrollbar-width: thin; + +// &::-webkit-scrollbar { +// height: 5px; +// } +// &::-webkit-scrollbar-thumb { +// background: var(--primary-color); +// } +// } + +code[class*='language-'], +pre[class*='language-'] { + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: rgba(29, 59, 83, 0.99); +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: rgba(29, 59, 83, 0.99); +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +.token.comment, +.token.prolog, +.token.cdata { + color: rgb(99, 119, 119); + font-style: italic; +} + +.token.punctuation { + color: rgb(199, 146, 234); +} + +.namespace { + color: rgb(178, 204, 214); +} + +.token.deleted { + color: rgba(239, 83, 80, 0.56); + font-style: italic; +} + +.token.symbol, +.token.property { + color: rgb(128, 203, 196); +} + +.token.tag, +.token.operator, +.token.keyword { + color: rgb(127, 219, 202); +} + +.token.boolean { + color: rgb(255, 88, 116); +} + +.token.number { + color: rgb(247, 140, 108); +} + +.token.constant, +.token.function, +.token.builtin, +.token.char { + color: rgb(130, 170, 255); +} + +.token.selector, +.token.doctype { + color: rgb(199, 146, 234); + font-style: italic; +} + +.token.attr-name, +.token.inserted { + color: rgb(173, 219, 103); + font-style: italic; +} + +.token.string, +.token.url, +.token.entity, +.language-css .token.string, +.style .token.string { + color: rgb(173, 219, 103); +} + +.token.class-name, +.token.atrule, +.token.attr-value { + color: rgb(255, 203, 139); +} + +.token.regex, +.token.important, +.token.variable { + color: rgb(214, 222, 235); +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} diff --git a/src/lib/scss/_functions.scss b/src/lib/scss/_functions.scss new file mode 100644 index 0000000..bdd9d0b --- /dev/null +++ b/src/lib/scss/_functions.scss @@ -0,0 +1,6 @@ +// Calculate brightness of a given color. +@function brightness($color) { + // @return ((red($color) * 0.299) + (green($color) * 0.587) + (blue($color) * 0.114)) / 255 * 100%; + // @return math.div((red($color) * 0.299) + (green($color) * 0.587) + (blue($color) * 0.114), 255); + @return calc(((red($color) * 0.299) + (green($color) * 0.587) + (blue($color) * 0.114)) / 255); +} diff --git a/src/lib/scss/_markdown.scss b/src/lib/scss/_markdown.scss new file mode 100644 index 0000000..6265b2b --- /dev/null +++ b/src/lib/scss/_markdown.scss @@ -0,0 +1,85 @@ +#article-content { + .content { + a:not(.button) { + &:hover { + filter: drop-shadow(0px 0px 3px var(--color--primary)); + } + } + + p { + margin: 0.75rem 0; + line-height: 1.55em; + } + + h2 { + margin: 3rem 0 0.5rem; + } + + h3 { + font-size: 1.2rem; + margin: 2rem 0 0.3rem; + } + + h4 { + font-size: 1.3rem; + margin: 2rem 0 0.3rem; + } + + picture { + display: inline; + } + + img { + display: block; + margin-left: auto; + margin-right: auto; + margin-top: 2rem; + margin-bottom: 2rem; + + max-width: 100%; + height: auto; + width: auto; + + box-shadow: var(--image-shadow); + } + + figcaption { + font-size: 0.85rem; + text-align: center; + margin-bottom: 2rem; + color: rgba(var(--color--text-rgb), 0.8); + } + + img + figcaption { + margin-top: -1rem; + } + + blockquote { + padding: 25px 25px 15px; + border-radius: 20px; + font-size: 1.1rem; + border-left: 4px solid var(--color--primary); + background: var(--color--callout-background); + } + + code:not([class^='language-']) { + background: var(--color--code-inline-background); + padding: 5px 10px; + border-radius: 5px; + } + + code { + font-family: var(--font--mono); + } + } + + .heading-link { + color: var(--color--primary); + text-decoration: none; + margin-right: 10px; + } + + img { + border-radius: 6px; + } +} diff --git a/src/lib/scss/_mixins.scss b/src/lib/scss/_mixins.scss new file mode 100644 index 0000000..221d102 --- /dev/null +++ b/src/lib/scss/_mixins.scss @@ -0,0 +1,49 @@ +@import './_breakpoints.scss'; +@import './_functions.scss'; + +@mixin padded-container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; + + @include for-iphone-se { + padding-left: 0; + padding-right: 0; + } + + @include for-tablet-portrait-up { + padding-right: 20px; + padding-left: 20px; + } + + @include for-tablet-landscape-up { + padding-right: 30px; + padding-left: 30px; + } + + @include for-desktop-up { + max-width: 1080px; + } +} + +// Defines a bunch of CSS variables for a given color +// In HEX, HSL and RGB formats +// Plus a contrast option for text +@mixin define-color($title, $color) { + --color--#{$title}: #{$color}; + + --color--#{$title}-h: #{hue($color)}; + --color--#{$title}-l: #{lightness($color)}; + --color--#{$title}-s: #{saturation($color)}; + --color--#{$title}-a: #{alpha($color)}; + + --color--#{$title}-rgb: #{red($color)}, #{green($color)}, #{blue($color)}; + + --color--#{$title}-contrast: #{if( + brightness($color) > 186, + var(--color--text), + var(--color--text-inverse) + )}; +} diff --git a/src/lib/scss/_reset.scss b/src/lib/scss/_reset.scss new file mode 100644 index 0000000..58fde3d --- /dev/null +++ b/src/lib/scss/_reset.scss @@ -0,0 +1,47 @@ +/* + Josh's Custom CSS Reset + https://www.joshwcomeau.com/css/custom-css-reset/ +*/ +*, +*::before, +*::after { + box-sizing: border-box; +} +* { + margin: 0; +} +html, +body { + height: 100%; +} +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} +input, +button, +textarea, +select { + font: inherit; +} +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; +} +#root, +#__next { + isolation: isolate; +} diff --git a/src/lib/scss/_themes.scss b/src/lib/scss/_themes.scss new file mode 100644 index 0000000..9813a79 --- /dev/null +++ b/src/lib/scss/_themes.scss @@ -0,0 +1,93 @@ +@import '$lib/scss/_mixins.scss'; + +@mixin base-theme { + @include define-color('primary', #ffc409); + @include define-color('primary-shade', #e0ac08); + @include define-color('primary-tint', #f9f6fe); + + @include define-color('secondary', #ff571a); + @include define-color('secondary-shade', #ffa280); + @include define-color('secondary-tint', #fff8f5); + + @include define-color('yellow', #ffd400); + + @include define-color('text', #1c1e26); + @include define-color('text-shade', #5d5f65); + @include define-color('text-inverse', #ffffff); + @include define-color('text-inverse-shade', #9eb4b5); + + @include define-color('page-background', #f4f8fb); + @include define-color('post-page-background', #f3fbfc); + @include define-color('card-background', #ffffff); + + // Used for Callout component + @include define-color('callout-background', #f4f8fb); + @include define-color('callout-background--info', #dfeffd); + @include define-color('callout-accent--info', #2883f4); + @include define-color('callout-background--warning', #fff6b6); + @include define-color('callout-accent--warning', #c87820); + @include define-color('callout-background--error', #ffe8e8); + @include define-color('callout-accent--error', #f95256); + @include define-color('callout-background--success', #dcf7ec); + @include define-color('callout-accent--success', #009f70); + + // Used for Code Block component + @include define-color('code-background', #1c1e26); + @include define-color('code-text', #ffffff); + @include define-color('code-inline-background', #e3e3e3); + + --color--waves-start: rgba(var(--color--primary-rgb), 0.3); + --color--waves-end: rgba(var(--color--primary-rgb), 0.1); + + --card-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1); + --card-shadow-hover: 0px 4px 10px 8px rgb(0 0 0 / 10%); + --image-shadow: 8px 14px 38px rgba(39, 44, 49, 0.06), 1px 3px 8px rgba(39, 44, 49, 0.03); +} + +@mixin dark-theme { + @include define-color('primary', #ffc409); + @include define-color('primary-shade', #e0ac08); + @include define-color('primary-tint', #231934); + + @include define-color('secondary', #ff723f); + @include define-color('secondary-shade', #ab3307); + @include define-color('secondary-tint', #1b1918); + + @include define-color('yellow', #ffd400); + + @include define-color('text', #ffffff); + @include define-color('text-shade', #9eb4b5); + @include define-color('text-inverse', #1c1e26); + @include define-color('text-inverse-shade', #5d5f65); + + @include define-color('page-background', #1c1e26); + @include define-color('post-page-background', #141519); + @include define-color('card-background', #32343e); + + // Used for Callout component + @include define-color('callout-background', #1c1e26); + @include define-color('callout-background--info', #1d3874); + @include define-color('callout-accent--info', #6ca9f7); + @include define-color('callout-background--warning', #724413); + @include define-color('callout-accent--warning', #ffca39); + @include define-color('callout-background--error', #7c1d20); + @include define-color('callout-accent--error', #ff8082); + @include define-color('callout-background--success', #004737); + @include define-color('callout-accent--success', #00c48f); + + @include define-color('code-inline-background', #2b3131); +} + +:root { + @include base-theme; + + &[data-theme='dark'] { + @include dark-theme; + } + + &[data-theme='auto'] { + @media (prefers-color-scheme: dark) { + @include dark-theme; + } + } +} diff --git a/src/lib/scss/_typography.scss b/src/lib/scss/_typography.scss new file mode 100644 index 0000000..52c7b90 --- /dev/null +++ b/src/lib/scss/_typography.scss @@ -0,0 +1,63 @@ +a { + color: var(--color--text); + text-decoration-color: var(--color--primary); + text-underline-offset: 0.1em; + text-decoration-thickness: 2px; + transition: all 0.2s ease-in-out; + + &:hover { + text-underline-offset: 0.3em; + } +} + +::selection { + background-color: rgba(var(--color--primary-rgb), 0.3); + color: var(--color--text); + text-shadow: none; +} + +strong, +b { + font-weight: 600; +} +em, +i { + font-style: italic; +} + +// #region Titles +h1 { + font-size: 2.5rem; + font-weight: 700; + + @include for-phone-only { + font-size: 2rem; + } +} + +h2 { + font-size: 1.8rem; + font-weight: 600; +} + +h3 { + font-size: 1.5rem; + font-weight: 600; +} + +h4 { + font-size: 1.2rem; +} + +h5 { + font-size: 1rem; +} + +h1, +h2, +h3, +h4, +h5 { + font-family: var(--font--title); +} +// #endregion diff --git a/src/lib/scss/_variables.scss b/src/lib/scss/_variables.scss new file mode 100644 index 0000000..52ca8cd --- /dev/null +++ b/src/lib/scss/_variables.scss @@ -0,0 +1,13 @@ +:root { + // Fonts + --font--default: Comfortaa, sans-serif; + --font--title: Comfortaa, serif; + --font--mono: Comfortaa, monospace; + + // Grabbed from open-props.style + --ease-3: cubic-bezier(0.25, 0, 0.3, 1); + --ease-4: cubic-bezier(0.25, 0, 0.2, 1); + --ease-out-1: cubic-bezier(0, 0, 0.75, 1); + --ease-out-3: cubic-bezier(0, 0, 0.3, 1); + --ease-elastic-4: cubic-bezier(0.5, 1.5, 0.75, 1.25); +} diff --git a/src/lib/scss/global.scss b/src/lib/scss/global.scss new file mode 100644 index 0000000..c0cff4a --- /dev/null +++ b/src/lib/scss/global.scss @@ -0,0 +1,45 @@ +@import '$lib/scss/_reset.scss'; +@import '$lib/scss/_variables.scss'; +@import '$lib/scss/_themes.scss'; +@import '$lib/scss/_breakpoints.scss'; +@import '$lib/scss/_functions.scss'; +@import '$lib/scss/_mixins.scss'; +@import '$lib/scss/_base.scss'; +@import '$lib/scss/_typography.scss'; +@import '$lib/scss/_markdown.scss'; +@import '$lib/scss/_code-highlights.scss'; +@import '$lib/scss/animations.scss'; + +@import '@fontsource/comfortaa'; +@import '@fontsource/comfortaa/600.css'; +@import '@fontsource/comfortaa/700.css'; + +body { + --body-background-color: var(--color--page-background); + background-color: var(--body-background-color); + color: var(--color--text); + fill: var(--color--text); + transition: all 0.4s ease; + font-family: var(--font--default); + line-height: 1.3; + scroll-behavior: smooth; + + height: 100%; + min-height: 100vh; + /* safari viewport bug fix */ + min-height: -webkit-fill-available; + + width: 100%; + overflow-x: hidden; +} + +html { + scroll-behavior: smooth; + font-size: 18px; + width: 100%; +} + +#svelte-root { + height: 100%; + position: relative; +} diff --git a/src/lib/stores/theme.ts b/src/lib/stores/theme.ts new file mode 100644 index 0000000..ed79d1e --- /dev/null +++ b/src/lib/stores/theme.ts @@ -0,0 +1,24 @@ +import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; + +function createTheme() { + let currentTheme; + if (browser) { + currentTheme = localStorage.getItem('theme-preference') || 'auto'; + } + + const { subscribe, set } = writable(currentTheme); + + return { + subscribe, + set: (value: string) => { + if (browser) { + localStorage.setItem('theme-preference', value); + document.firstElementChild?.setAttribute('data-theme', value); + } + set(value); + } + }; +} + +export const theme = createTheme(); diff --git a/src/lib/utils/regex.ts b/src/lib/utils/regex.ts new file mode 100644 index 0000000..8397cd0 --- /dev/null +++ b/src/lib/utils/regex.ts @@ -0,0 +1 @@ +export const HttpRegex = /^((http|https):\/\/)/; diff --git a/src/lib/utils/types.ts b/src/lib/utils/types.ts new file mode 100644 index 0000000..cdcc12b --- /dev/null +++ b/src/lib/utils/types.ts @@ -0,0 +1,38 @@ +export type NoUndefinedField = { [P in keyof T]-?: NoUndefinedField> }; + +export type SparkleType = { + id: string; + createdAt: number; + color: string; + size: number; + style: any; +}; + +export type TagType = { + label: string; + color?: 'primary' | 'secondary'; +}; + +export type SocialLink = {}; + +export type Feature = { + name: string; + description: string; + image: string; + tags: TagType[]; +}; + +export type BlogPost = { + tags: string[]; + keywords: string[]; + hidden: boolean; + slug: string; + title: string; + date: string; + updated: string; + excerpt: string; + html: string | undefined; + readingTime: string; + relatedPosts: BlogPost[]; + coverImage: string | undefined; +}; diff --git a/src/routes/(blog-article)/+layout.server.ts b/src/routes/(blog-article)/+layout.server.ts new file mode 100644 index 0000000..2ac7449 --- /dev/null +++ b/src/routes/(blog-article)/+layout.server.ts @@ -0,0 +1,11 @@ +import { filteredPosts } from '$lib/data/blog-posts'; + +export async function load({ url }: { url: { pathname: string } }) { + const { pathname } = url; + const slug = pathname.replace('/', ''); + const post = filteredPosts.find((post) => post.slug === slug); + + return { + post + }; +} diff --git a/src/routes/(blog-article)/+layout.svelte b/src/routes/(blog-article)/+layout.svelte new file mode 100644 index 0000000..460ba07 --- /dev/null +++ b/src/routes/(blog-article)/+layout.svelte @@ -0,0 +1,190 @@ + + + + {#if post} + + + + + + + + {post.title} - {title} + + + + {#if post.coverImage} + + + {/if} + {/if} + + +
+
+ +
+
+
+ {#if post} +

{post.title}

+
Published on {dateformat(post.date, 'UTC:dd mmmm yyyy')}
+ {#if post.updated} +
Updated on {dateformat(post.updated, 'UTC:dd mmmm yyyy')}
+ {/if} + {#if post.readingTime} +
{post.readingTime}
+ {/if} + {#if post.tags?.length} +
+ {#each post.tags as tag} + {tag} + {/each} +
+ {/if} + {/if} +
+ {#if post && post.coverImage} +
+ {post.title} +
+ {/if} +
+ +
+
+ + {#if post.relatedPosts && post.relatedPosts.length > 0} +
+ +
+ {/if} +
+ +
+
+ + diff --git a/src/routes/(blog-article)/blog-posts/+page.md b/src/routes/(blog-article)/blog-posts/+page.md new file mode 100644 index 0000000..1005097 --- /dev/null +++ b/src/routes/(blog-article)/blog-posts/+page.md @@ -0,0 +1,63 @@ +--- +title: How Blog Posts Work +slug: blog-posts +coverImage: /images/posts/blog-posts.jpg +date: 2023-04-22T21:55:15.361Z +excerpt: How to manage existing blog posts and create new ones +tags: + - Documentation +--- + + + +All blog posts are located inside the `src/routes/(blog-article)` folder. Each folder inside it represents a blog post, and each folder has a `+page.md` file, which is the file that contains the post's content. + +This way, the URL for each blog post is generated with the folder's name. For example, the folder `src/routes/(blog-article)/how-blog-posts-work` will generate the URL `https://mysite.com/how-blog-posts-work`. + +All posts are Markdown files, which means you can use the [Markdown syntax](https://www.markdownguide.org/basic-syntax) in them, and it will work out of the box. However, since this projects uses [MDsveX](https://mdsvex.pngwn.io/) to parse Markdown, you can also use Svelte components inside them! This means that the components used in other pages can also be used in blog posts. + + + This is a Svelte component inside a Markdown file! + + +## Processing + +Besides the blog post page itself, the blog posts can be displayed in other places, such as the `/blog` page, which lists all blog posts, and the `` component, used in the home page. + +To be able to do that, posts are processed in the `src/lib/data/blog-posts/index.ts` file. That file imports the blog post files and processes them, so we're able to use some of the post's metadata to list them. For example, we get the post's title, cover image, and calculate the reading time based on its content, so that information is displayed in the blog post cards in the `/blog` page. + +There is also some basic logic to get related posts based on a post's tags. The logic should be straightforward enough to modify it to your needs. + +## Creating a new post + +To create a new post, create a new folder inside the `src/routes/(blog-article)` folder, and inside it, create a `+page.md` file. The folder name will be used as the post's URL slug, so make sure it's a valid URL slug. + +Inside the `+page.md` file, you must start with the front matter, which is a YAML-like syntax that is used to define metadata for the post. The front matter must be the first thing in the file, and must be separated from the rest of the content by three dashes (`---`). An example of a front matter is: + + + +```md +--- +slug: my-new-blog-post +title: My New Blog Post +date: 2023-04-22T20:45:25.350Z +excerpt: A short description of the post +coverImage: /images/posts/cover-image.jpg +tags: + - Example +--- +``` + + + +## Managing blog posts + +I highly recommend the [Front Matter VS Code extension](https://frontmatter.codes/) to manage blog posts. It gives you a nice CMS-like UI to manage the front matter of all blog posts, as well as a preview of their content. It is, of course, optional, and you can manage everything directly in the Markdown files if you prefer. + +Screenshot of the Front Matter VS Code extension, showing the dashboard with all posts + +Screenshot of the Front Matter VS Code extension, showing the post editing UI diff --git a/src/routes/(blog-article)/customization/+page.md b/src/routes/(blog-article)/customization/+page.md new file mode 100644 index 0000000..1f9ee79 --- /dev/null +++ b/src/routes/(blog-article)/customization/+page.md @@ -0,0 +1,60 @@ +--- +slug: customization +title: How to Customize this Template +date: 2023-04-22T21:55:27.154Z +excerpt: How to customize what you're seeing here and make it your own. +coverImage: /images/posts/customization.jpg +tags: + - Documentation +--- + +In general, content can be modified by editing the **organisms** and the pages themselves. Below is a list of the most common changes that you may want to make. + +## Domain/site URL + +The first thing you might want to do is replace the domain of of the site with your own. There are two places where you need to do that: + +- In the `package.json` file, check the `postbuild` script. Change the domain there to your own, so it ends up like this: `svelte-sitemap --domain https://your-domain.com`. This is used to generate the sitemap of your website, which is used by search engines to index your site. +- In the `src/lib/data/meta.ts` file, change the `siteBaseUrl` property to your own domain. This is used in multiple parts of the app wherever the site needs to link to itself. + +## Header/site logo + +To replace the logo that appears in the header, modify or replace the contents of the `Logo.svelte` atom. + +The links that appear on the header can be modified directly in the `Header.svelte` organism. + +## Hero section + +The hero section is the first section of the site's home page. It is composed of a Heading, the _intro_ text, and a list of buttons/CTAs. The contents of this section can be modified directly in the `Hero.svelte` organism. + +## About section + +The about section contains another headline, a paragraph of text, some social media links, and optionally an image. The contents of this section can be modified directly in the `About.svelte` organism. + +## Social Links + +The social links are contained in the `Socials.svelte` molecule and can be used in any page. This template shows them on the About section and in the Footer. + +## Footer + +The footer contains some credits, a list of social links, and the Theme toggle. The contents of this section can be modified directly in the `Footer.svelte` organism. + +## Colors + +You can change the color palette of the website just by tweaking the `_themes.scss` file. The file uses the `define-color` scss function to automatically set the color variables in Hex, RGB and HSL formats, so you can choose whichever format you need. + +The main theme colors (primary and secondary) have two variants: shade and tint. The shade is a lighter version of the color (darker in dark mode), and the tint should almost match the page's background, so that in light mode, it's really bright, and in dark mode, it's really dark. + +## Fonts + +This template uses the Inter, Merriweather and Ubuntu Mono font families. You can change the font family by editing the `_variables.scss` file, and the code is already set up to accept a default font, a heading font, and a monospace font. + +I recommend using [Fontsource](https://fontsource.org/) to import the fonts you need, or self-hosting them. In case you're using Fontsource, you can import the fonts in `global.scss` file to make sure they're available in the entire site. + +## Favicon + +Favicons are located in the `static/favicons` folder. I like to use [Real Favicon Generator](https://realfavicongenerator.net) to generate mine, but you can use any other tool you like. I wrote [a blog post about Favicons](https://fantinel.dev/fixing-favicons) in case you want to learn more about them. + +## Social Media Link Preview + +You probably want to customize how links to your website look when posted on social media/messaging apps. To do that, you can edit the info in `src/lib/data/meta.ts`. There, you can edit the site's title, description, tags (used by search engines) and the image that appears when sharing a link. diff --git a/src/routes/(blog-article)/project-structure/+page.md b/src/routes/(blog-article)/project-structure/+page.md new file mode 100644 index 0000000..eae0fab --- /dev/null +++ b/src/routes/(blog-article)/project-structure/+page.md @@ -0,0 +1,53 @@ +--- +slug: project-structure +title: Project Structure +date: 2023-04-22T21:55:21.800Z +excerpt: How code and structure are organized. +coverImage: /images/posts/project-structure.jpg +tags: + - Documentation +--- + + + +This project follows the basic [SvelteKit structure](https://kit.svelte.dev/docs/project-structure), with some added conventions to make customization a post-management easier. + +## Components + +The components are organized following the [Atomic Design](https://medium.com/@WeAreMobile1st/atomic-design-getting-started-916bc81bad0e) principles, albeit somewhat simplified. Components are in the `src/lib/components` folder, and are organized in the following way: + +### Atoms + +Atoms are the most basic components, which can be seen as building blocks for other components. They're small and self-contained, and do only one thing. Examples of atoms are buttons, inputs, and tags. + +### Molecules + +Molecules are groups of atoms that work together to form a more complex component. Examples of molecules are cards, groups of links, or an alert callout. + +### Organisms + +Organisms, in this project, are code blocks that represent a section of a page, such as the header, footer and hero section. They can be used directly in a page as a sort of building block, so the page's code can be as simple as this: + + + +```html +
+ + +