diff --git a/package-lock.json b/package-lock.json index a8a5f288..9428c822 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@auth/sveltekit": "^1.7.4", "@iconify/svelte": "^4.0.2", "@iktakahiro/markdown-it-katex": "^4.0.1", + "@shikijs/markdown-it": "^1.24.1", "@skeletonlabs/skeleton": "^3.0.0-next.9", "@skeletonlabs/skeleton-svelte": "^1.0.0-next.14", "@supabase/supabase-js": "^2.46.1", @@ -45,6 +46,7 @@ "prettier": "^3.4.0", "prettier-plugin-svelte": "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.9", + "shiki": "^1.24.1", "svelte": "^5.2.8", "svelte-check": "^4.1.0", "tailwindcss": "^3.4.15", @@ -1179,6 +1181,73 @@ "win32" ] }, + "node_modules/@shikijs/core": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.24.1.tgz", + "integrity": "sha512-3q/9oarMVcLqJ+NQOdKL40dJVq/UKCsiWXz3QRQPBglHqa8dDJ0p6TuMuk2gHphy5FZcvFtg4UHBgpW0JtZ8+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "1.24.1", + "@shikijs/engine-oniguruma": "1.24.1", + "@shikijs/types": "1.24.1", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.3" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.24.1.tgz", + "integrity": "sha512-lNgUSHYDYaQ6daj4lJJqcY2Ru9LgHwpFoposJkRVRPh21Yg4kaPFRhzaWoSg3PliwcDOpDuMy3xsmQaJp201Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.24.1", + "@shikijs/vscode-textmate": "^9.3.0", + "oniguruma-to-es": "0.7.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.24.1.tgz", + "integrity": "sha512-KdrTIBIONWd+Xs61eh8HdIpfigtrseat9dpARvaOe2x0g/FNTbwbkGr3y92VSOVD1XotzEskh3v/nCzyWjkf7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.24.1", + "@shikijs/vscode-textmate": "^9.3.0" + } + }, + "node_modules/@shikijs/markdown-it": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@shikijs/markdown-it/-/markdown-it-1.24.1.tgz", + "integrity": "sha512-on33IGJwwmKNQOdhRKP0fBq2jymiCBGRA4tJf5bR708+fzUAW7W0qA+kUiVyU/FYUHv+fttQpx7gTjsh9L10wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-it": "^14.1.0", + "shiki": "1.24.1" + } + }, + "node_modules/@shikijs/types": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.24.1.tgz", + "integrity": "sha512-ZwZFbShFY/APfKNt3s9Gv8rhTm29GodSKsOW66X6N+HGsZuaHalE1VUEX4fv93UXHTZTLjb3uxn63F96RhGfXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.0.tgz", + "integrity": "sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==", + "dev": true, + "license": "MIT" + }, "node_modules/@skeletonlabs/skeleton": { "version": "3.0.0-next.9", "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-3.0.0-next.9.tgz", @@ -1470,6 +1539,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1497,6 +1576,16 @@ "@types/mdurl": "^2" } }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", @@ -1522,6 +1611,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -1756,6 +1852,13 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true, + "license": "ISC" + }, "node_modules/@zag-js/accordion": { "version": "0.75.0", "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-0.75.0.tgz", @@ -2641,6 +2744,17 @@ "node": "^18.12.0 || >= 20.9.0" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2658,6 +2772,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", @@ -2702,6 +2838,17 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2824,6 +2971,16 @@ "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", @@ -2842,6 +2999,20 @@ "dev": true, "license": "MIT" }, + "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, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2877,6 +3048,13 @@ "dev": true, "license": "MIT" }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -3583,6 +3761,44 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/highlight.js": { "version": "11.10.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", @@ -3593,6 +3809,17 @@ "node": ">=12.0.0" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4085,6 +4312,28 @@ "node": ">6.4.0" } }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -4102,6 +4351,100 @@ "node": ">= 8" } }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -4358,6 +4701,18 @@ "wrappy": "1" } }, + "node_modules/oniguruma-to-es": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-0.7.0.tgz", + "integrity": "sha512-HRaRh09cE0gRS3+wi2zxekB+I5L8C/gN60S+vb11eADHUaB/q4u8wGGOX3GvwvitG8ixaeycZfeoyruKQzUgNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^5.0.2", + "regex-recursion": "^4.3.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4974,6 +5329,17 @@ } } }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-compare": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.0.tgz", @@ -5102,6 +5468,33 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/regex": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-5.0.2.tgz", + "integrity": "sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-4.3.0.tgz", + "integrity": "sha512-5LcLnizwjcQ2ALfOj95MjcatxyqF5RPySx9yT+PaXu3Gox2vyAtLDjHB8NTJLtMGkvyau6nI3CfpwFCjPUIs/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -5281,6 +5674,21 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.24.1.tgz", + "integrity": "sha512-/qByWMg05+POb63c/OvnrU17FcCUa34WU4F6FCrd/mjDPEDPl8YUNRkRMbo8l3iYMLydfCgxi1r37JFoSw8A4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "1.24.1", + "@shikijs/engine-javascript": "1.24.1", + "@shikijs/engine-oniguruma": "1.24.1", + "@shikijs/types": "1.24.1", + "@shikijs/vscode-textmate": "^9.3.0", + "@types/hast": "^3.0.4" + } + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -5354,6 +5762,17 @@ "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, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5429,6 +5848,21 @@ "node": ">=8" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -5937,6 +6371,17 @@ "dev": true, "license": "MIT" }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.2.tgz", @@ -6046,6 +6491,79 @@ "dev": true, "license": "MIT" }, + "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, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -6094,6 +6612,36 @@ "dev": true, "license": "MIT" }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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, + "license": "MIT", + "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": "5.4.11", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", @@ -6371,6 +6919,17 @@ "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", "dev": true, "license": "MIT" + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index c2b9dcc7..6af1cdeb 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@auth/sveltekit": "^1.7.4", "@iconify/svelte": "^4.0.2", "@iktakahiro/markdown-it-katex": "^4.0.1", + "@shikijs/markdown-it": "^1.24.1", "@skeletonlabs/skeleton": "^3.0.0-next.9", "@skeletonlabs/skeleton-svelte": "^1.0.0-next.14", "@supabase/supabase-js": "^2.46.1", @@ -49,6 +50,7 @@ "prettier": "^3.4.0", "prettier-plugin-svelte": "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.9", + "shiki": "^1.24.1", "svelte": "^5.2.8", "svelte-check": "^4.1.0", "tailwindcss": "^3.4.15", diff --git a/src/app.postcss b/src/app.postcss index f3fef833..f0c5b67f 100644 --- a/src/app.postcss +++ b/src/app.postcss @@ -7,3 +7,8 @@ html, body { @apply h-full overflow-hidden; } + +code, +pre { + @apply rounded-md border dark:border-primary-500; +} diff --git a/src/lib/runes.ts b/src/lib/runes.ts index a72555f6..592a568e 100644 --- a/src/lib/runes.ts +++ b/src/lib/runes.ts @@ -6,6 +6,7 @@ export const transitionKey = rune(""); export const layout = rune("expanded"); export const lightMode = rune("light"); export const currentTheme = rune("tutors"); +export const currentCodeTheme = rune("monokai"); export const currentLo = rune(null); export const currentCourse = rune(null); diff --git a/src/lib/services/course.svelte.ts b/src/lib/services/course.svelte.ts index 275667b1..110b0233 100644 --- a/src/lib/services/course.svelte.ts +++ b/src/lib/services/course.svelte.ts @@ -1,12 +1,15 @@ -import { courseUrl, currentCourse, currentLo } from "$lib/runes"; -import type { Lo, Course, Lab } from "$lib/services/models/lo-types"; +import { courseUrl, currentCodeTheme, currentCourse, currentLo } from "$lib/runes"; +import type { Lo, Course, Lab, Note } from "$lib/services/models/lo-types"; import { decorateCourseTree } from "./models/lo-tree"; import { LiveLab } from "./models/live-lab"; import type { CourseService } from "./types.svelte"; +import { themeService } from "$lib/ui/themes/theme-controller.svelte"; +import { markdownService } from "./markdown"; export const courseService: CourseService = { courses: new Map(), labs: new Map(), + notes: new Map(), courseUrl: "", async getOrLoadCourse(courseId: string, fetchFunction: typeof fetch): Promise { @@ -14,7 +17,8 @@ export const courseService: CourseService = { let courseUrl = courseId; function isValidURL(url: string) { - const urlPattern = /^(https?:\/\/)?([A-Za-z0-9.-]+\.[A-Za-z]{2,})(:[0-9]+)?(\/[A-Za-z0-9_.-]+)*(\/[A-Za-z0-9_.-]+\?[A-Za-z0-9_=-]+)?(#.*)?$/; + const urlPattern = + /^(https?:\/\/)?([A-Za-z0-9.-]+\.[A-Za-z]{2,})(:[0-9]+)?(\/[A-Za-z0-9_.-]+)*(\/[A-Za-z0-9_.-]+\?[A-Za-z0-9_=-]+)?(#.*)?$/; return urlPattern.test(url); } @@ -75,6 +79,8 @@ export const courseService: CourseService = { let liveLab = this.labs.get(labId); if (!liveLab) { const lab = course.loIndex.get(labId) as Lab; + themeService.initCodeTheme(); + markdownService.convertLabToHtml(course, lab, currentCodeTheme.value); liveLab = new LiveLab(course, lab, labId); this.labs.set(labId, liveLab); } @@ -93,6 +99,21 @@ export const courseService: CourseService = { const course = await this.readCourse(courseId, fetchFunction); const lo = course.loIndex.get(loId); if (lo) currentLo.value = lo; + if (lo?.type === "note") { + markdownService.convertNoteToHtml(lo as Note, currentCodeTheme.value); + this.notes.set(loId, lo as Note); + } return lo!; + }, + + refreshAllLabs(codeTheme: string) { + for (const liveLab of this.labs.values()) { + markdownService.convertLabToHtml(liveLab.course, liveLab.lab, codeTheme); + liveLab.convertMdToHtml(); + liveLab.refreshStep(); + } + for (const note of this.notes.values()) { + markdownService.convertNoteToHtml(note, codeTheme); + } } }; diff --git a/src/lib/services/markdown.ts b/src/lib/services/markdown.ts new file mode 100644 index 00000000..3b873dda --- /dev/null +++ b/src/lib/services/markdown.ts @@ -0,0 +1,56 @@ +import type { Course, Lab, Note, Lo } from "./models/lo-types"; +import { convertMdToHtml } from "./models/markdown-utils"; + +export const markdownService = { + convertLabToHtml(course: Course, lab: Lab, theme: string) { + lab.summary = convertMdToHtml(lab.summary, theme); + const url = lab.route.replace(`/lab/${course.courseId}`, course.courseUrl); + lab?.los?.forEach((step) => { + if (course.courseUrl) { + step.contentMd = this.filter(step.contentMd, url); + } + step.contentHtml = convertMdToHtml(step.contentMd, theme); + step.parentLo = lab; + step.type = "step"; + }); + }, + + convertNoteToHtml(note: Note, theme: string) { + note.summary = convertMdToHtml(note.summary, theme); + note.contentHtml = convertMdToHtml(note.contentMd, theme); + }, + + convertLoToHtml(course: Course, lo: Lo, theme: string = "monokai") { + if (lo.type === "lab" || lo.type == "note") { + // convertLabToHtml(course, lo as Lab); + } else { + if (lo.summary) lo.summary = convertMdToHtml(lo.summary, theme); + let md = lo.contentMd; + if (md) { + if (course.courseUrl) { + const url = lo.route.replace(`/${lo.type}/${course.courseId}`, course.courseUrl); + md = this.filter(md, url); + } + lo.contentHtml = convertMdToHtml(md, theme); + } + } + }, + + replaceAll(str: string, find: string, replace: string) { + return str.replace(new RegExp(find, "g"), replace); + }, + + filter(src: string, url: string): string { + let filtered = this.replaceAll(src, "./img\\/", `img/`); + filtered = this.replaceAll(filtered, "img\\/", `https://${url}/img/`); + filtered = this.replaceAll(filtered, "./archives\\/", `archives/`); + + //filtered = replaceAll(filtered, "archives\\/", `https://${url}/archives/`); + filtered = this.replaceAll(filtered, "(?). breaks: false, // Convert '\n' in paragraphs into
@@ -32,16 +106,11 @@ const markdownIt: any = new MarkdownIt({ typographer: true, quotes: "“”‘’", highlight: function (str: string, lang: string) { - if (lang && hljs.getLanguage(lang)) { - try { - return ( - '
' +
-          hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
-          "
" - ); - } catch (__) {} + try { + return shiki?.codeToHtml(str, { lang, theme: currentTheme }); + } catch (e) { + return shiki?.codeToHtml(str, { lang: "yaml", theme: currentTheme }); } - return '
' + markdownIt.utils.escapeHtml(str) + "
"; } }); @@ -85,53 +154,7 @@ markdownIt.renderer.rules.link_open = function (tokens: any, idx: any, options: return defaultRender(tokens, idx, options, env, self); }; -function replaceAll(str: string, find: string, replace: string) { - return str.replace(new RegExp(find, "g"), replace); -} - -function filter(src: string, url: string): string { - let filtered = replaceAll(src, "./img\\/", `img/`); - filtered = replaceAll(filtered, "img\\/", `https://${url}/img/`); - filtered = replaceAll(filtered, "./archives\\/", `archives/`); - - //filtered = replaceAll(filtered, "archives\\/", `https://${url}/archives/`); - filtered = replaceAll(filtered, "(? { - if (course.courseUrl) { - step.contentMd = filter(step.contentMd, url); - } - step.contentHtml = markdownIt.render(step.contentMd); - step.parentLo = lab; - step.type = "step"; - }); -} - -export function convertLoToHtml(course: Course, lo: Lo) { - if (lo.type === "lab") { - convertLabToHtml(course, lo as Lab); - } else { - if (lo.summary) lo.summary = markdownIt.render(lo.summary); - let md = lo.contentMd; - if (md) { - if (course.courseUrl) { - const url = lo.route.replace(`/${lo.type}/${course.courseId}`, course.courseUrl); - md = filter(md, url); - } - lo.contentHtml = markdownIt.render(md); - } - } -} - -export function convertMdToHtml(md: string): string { +export function convertMdToHtml(md: string, codeTheme: string): string { + currentTheme = codeTheme; return markdownIt.render(md); } diff --git a/src/lib/services/types.svelte.ts b/src/lib/services/types.svelte.ts index befacca3..c8e582dc 100644 --- a/src/lib/services/types.svelte.ts +++ b/src/lib/services/types.svelte.ts @@ -1,5 +1,5 @@ import type { LiveLab } from "./models/live-lab"; -import type { Course, IconType, Lo } from "./models/lo-types"; +import type { Course, IconType, Lo, Note } from "./models/lo-types"; export type TutorsId = { name: string; @@ -60,6 +60,7 @@ export interface CardDetails { export interface CourseService { courses: Map; labs: Map; + notes: Map; courseUrl: ""; getOrLoadCourse(courseId: string, fetchFunction: typeof fetch): Promise; @@ -68,6 +69,7 @@ export interface CourseService { readLab(courseId: string, labId: string, fetchFunction: typeof fetch): Promise; readWall(courseId: string, type: string, fetchFunction: typeof fetch): Promise; readLo(courseId: string, loId: string, fetchFunction: typeof fetch): Promise; + refreshAllLabs(codeTheme: string): void; } export interface ProfileStore { diff --git a/src/lib/ui/learning-objects/content/Lab.svelte b/src/lib/ui/learning-objects/content/Lab.svelte index e6304b26..91448ef2 100644 --- a/src/lib/ui/learning-objects/content/Lab.svelte +++ b/src/lib/ui/learning-objects/content/Lab.svelte @@ -6,6 +6,7 @@ import type { LiveLab } from "$lib/services/models/live-lab"; import { fly } from "svelte/transition"; import { slideFromLeft } from "$lib/ui/themes/animations"; + import { currentCodeTheme } from "$lib/runes"; interface Props { lab: LiveLab; @@ -80,7 +81,9 @@
- {@html lab.content} + {#key currentCodeTheme.value} + {@html lab.content} + {/key}
diff --git a/src/lib/ui/learning-objects/content/Note.svelte b/src/lib/ui/learning-objects/content/Note.svelte index 19b6bcd2..0efecc7b 100644 --- a/src/lib/ui/learning-objects/content/Note.svelte +++ b/src/lib/ui/learning-objects/content/Note.svelte @@ -1,4 +1,5 @@ -
- {@html lo.contentHtml} +
+ {#key currentCodeTheme.value} + {@html lo.contentHtml} + {/key}
diff --git a/src/lib/ui/navigators/footers/TutorsMessage.svelte b/src/lib/ui/navigators/footers/TutorsMessage.svelte index 34c7d2af..e334944e 100644 --- a/src/lib/ui/navigators/footers/TutorsMessage.svelte +++ b/src/lib/ui/navigators/footers/TutorsMessage.svelte @@ -1,15 +1,13 @@ -
+