mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-02 02:00:31 +08:00
Move syntax highlighting to web client
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="/colors.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/elevations.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/layout.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/prettylights.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/index.css" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
|
||||
Generated
+333
@@ -12,10 +12,13 @@
|
||||
"@radicle/gray-matter": "4.1.0",
|
||||
"@stardazed/streams": "^3.1.0",
|
||||
"@walletconnect/client": "^1.8.0",
|
||||
"@wooorm/starry-night": "^1.4.2",
|
||||
"buffer": "^6.0.3",
|
||||
"dompurify": "^2.4.1",
|
||||
"ethers": "^5.7.2",
|
||||
"events": "^3.3.0",
|
||||
"hast-util-to-dom": "^3.1.0",
|
||||
"hast-util-to-html": "^8.0.3",
|
||||
"katex": "^0.16.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^7.14.1",
|
||||
@@ -1343,6 +1346,14 @@
|
||||
"@types/trusted-types": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
|
||||
"integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
|
||||
"dependencies": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
@@ -1430,6 +1441,11 @@
|
||||
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz",
|
||||
@@ -1804,6 +1820,21 @@
|
||||
"@walletconnect/window-getters": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@wooorm/starry-night": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@wooorm/starry-night/-/starry-night-1.4.2.tgz",
|
||||
"integrity": "sha512-SkhIweiThgUK+KmvZPR2VCSnA1m0awTi/jPHey71MtR+jZG6phmcc9F9b0xpvxmHFFiKqxkgD/UKSVWVua+xrw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"import-meta-resolve": "^2.0.0",
|
||||
"vscode-oniguruma": "^1.0.0",
|
||||
"vscode-textmate": "^7.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
|
||||
@@ -2105,6 +2136,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/ccount": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
|
||||
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
|
||||
@@ -2135,6 +2175,24 @@
|
||||
"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==",
|
||||
"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==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
@@ -2219,6 +2277,15 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||
@@ -3226,6 +3293,62 @@
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-is-element": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz",
|
||||
"integrity": "sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"@types/unist": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-dom": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-dom/-/hast-util-to-dom-3.1.0.tgz",
|
||||
"integrity": "sha512-ZGrDF2qJDSWIHqos/YWbzeehVI4AYPz1RGWklNrKf2mJPCVe+cLnnsSzheSpHeIrJ/KFfz9tOzMwyphy+EIUUg==",
|
||||
"dependencies": {
|
||||
"property-information": "^6.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-html": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz",
|
||||
"integrity": "sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"hast-util-is-element": "^2.0.0",
|
||||
"hast-util-whitespace": "^2.0.0",
|
||||
"html-void-elements": "^2.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"stringify-entities": "^4.0.2",
|
||||
"unist-util-is": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-whitespace": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz",
|
||||
"integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
@@ -3245,6 +3368,15 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/html-void-elements": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz",
|
||||
"integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -3301,6 +3433,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/import-meta-resolve": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.0.tgz",
|
||||
"integrity": "sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@@ -4083,6 +4224,15 @@
|
||||
"svelte": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/property-information": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.2.0.tgz",
|
||||
"integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
@@ -4500,6 +4650,15 @@
|
||||
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
@@ -4525,6 +4684,19 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stringify-entities": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz",
|
||||
"integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==",
|
||||
"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": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
@@ -4892,6 +5064,15 @@
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-is": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz",
|
||||
"integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
@@ -5045,6 +5226,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-oniguruma": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA=="
|
||||
},
|
||||
"node_modules/vscode-textmate": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-7.0.4.tgz",
|
||||
"integrity": "sha512-9hJp0xL7HW1Q5OgGe03NACo7yiCTMEk3WU/rtKXUbncLtdg6rVVNJnHwD88UhbIYU2KoxY0Dih0x+kIsmUKn2A=="
|
||||
},
|
||||
"node_modules/web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
|
||||
"integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
@@ -5914,6 +6114,14 @@
|
||||
"@types/trusted-types": "*"
|
||||
}
|
||||
},
|
||||
"@types/hast": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
|
||||
"integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
|
||||
"requires": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
@@ -6001,6 +6209,11 @@
|
||||
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/unist": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz",
|
||||
@@ -6300,6 +6513,17 @@
|
||||
"@walletconnect/window-getters": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@wooorm/starry-night": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@wooorm/starry-night/-/starry-night-1.4.2.tgz",
|
||||
"integrity": "sha512-SkhIweiThgUK+KmvZPR2VCSnA1m0awTi/jPHey71MtR+jZG6phmcc9F9b0xpvxmHFFiKqxkgD/UKSVWVua+xrw==",
|
||||
"requires": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"import-meta-resolve": "^2.0.0",
|
||||
"vscode-oniguruma": "^1.0.0",
|
||||
"vscode-textmate": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
|
||||
@@ -6519,6 +6743,11 @@
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ccount": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
|
||||
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
|
||||
@@ -6540,6 +6769,16 @@
|
||||
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
|
||||
"dev": true
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
@@ -6603,6 +6842,11 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||
@@ -7411,6 +7655,46 @@
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hast-util-is-element": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz",
|
||||
"integrity": "sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA==",
|
||||
"requires": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"@types/unist": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-dom": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-dom/-/hast-util-to-dom-3.1.0.tgz",
|
||||
"integrity": "sha512-ZGrDF2qJDSWIHqos/YWbzeehVI4AYPz1RGWklNrKf2mJPCVe+cLnnsSzheSpHeIrJ/KFfz9tOzMwyphy+EIUUg==",
|
||||
"requires": {
|
||||
"property-information": "^6.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-html": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz",
|
||||
"integrity": "sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==",
|
||||
"requires": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"hast-util-is-element": "^2.0.0",
|
||||
"hast-util-whitespace": "^2.0.0",
|
||||
"html-void-elements": "^2.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"stringify-entities": "^4.0.2",
|
||||
"unist-util-is": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-whitespace": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz",
|
||||
"integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg=="
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
@@ -7427,6 +7711,11 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"html-void-elements": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz",
|
||||
"integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A=="
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -7457,6 +7746,11 @@
|
||||
"resolve-from": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"import-meta-resolve": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.0.tgz",
|
||||
"integrity": "sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw=="
|
||||
},
|
||||
"imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@@ -8009,6 +8303,11 @@
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"property-information": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.2.0.tgz",
|
||||
"integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
@@ -8294,6 +8593,11 @@
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
@@ -8313,6 +8617,15 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"stringify-entities": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz",
|
||||
"integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==",
|
||||
"requires": {
|
||||
"character-entities-html4": "^2.0.0",
|
||||
"character-entities-legacy": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
@@ -8553,6 +8866,11 @@
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true
|
||||
},
|
||||
"unist-util-is": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz",
|
||||
"integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ=="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
@@ -8627,6 +8945,21 @@
|
||||
"vite": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"vscode-oniguruma": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA=="
|
||||
},
|
||||
"vscode-textmate": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-7.0.4.tgz",
|
||||
"integrity": "sha512-9hJp0xL7HW1Q5OgGe03NACo7yiCTMEk3WU/rtKXUbncLtdg6rVVNJnHwD88UhbIYU2KoxY0Dih0x+kIsmUKn2A=="
|
||||
},
|
||||
"web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
|
||||
"integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
|
||||
@@ -47,10 +47,13 @@
|
||||
"@radicle/gray-matter": "4.1.0",
|
||||
"@stardazed/streams": "^3.1.0",
|
||||
"@walletconnect/client": "^1.8.0",
|
||||
"@wooorm/starry-night": "^1.4.2",
|
||||
"buffer": "^6.0.3",
|
||||
"dompurify": "^2.4.1",
|
||||
"ethers": "^5.7.2",
|
||||
"events": "^3.3.0",
|
||||
"hast-util-to-dom": "^3.1.0",
|
||||
"hast-util-to-html": "^8.0.3",
|
||||
"katex": "^0.16.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^7.14.1",
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/* This is a theme distributed by `starry-night`.
|
||||
* It’s based on what GitHub uses on their site.
|
||||
* See <https://github.com/wooorm/starry-night> for more info. */
|
||||
:root {
|
||||
--color-prettylights-syntax-comment: #6e7781;
|
||||
--color-prettylights-syntax-constant: #0550ae;
|
||||
--color-prettylights-syntax-entity: #8250df;
|
||||
--color-prettylights-syntax-storage-modifier-import: #24292f;
|
||||
--color-prettylights-syntax-entity-tag: #116329;
|
||||
--color-prettylights-syntax-keyword: #cf222e;
|
||||
--color-prettylights-syntax-string: #0a3069;
|
||||
--color-prettylights-syntax-variable: #953800;
|
||||
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
|
||||
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
|
||||
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
|
||||
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
|
||||
--color-prettylights-syntax-carriage-return-bg: #cf222e;
|
||||
--color-prettylights-syntax-string-regexp: #116329;
|
||||
--color-prettylights-syntax-markup-list: #3b2300;
|
||||
--color-prettylights-syntax-markup-heading: #0550ae;
|
||||
--color-prettylights-syntax-markup-italic: #24292f;
|
||||
--color-prettylights-syntax-markup-bold: #24292f;
|
||||
--color-prettylights-syntax-markup-deleted-text: #82071e;
|
||||
--color-prettylights-syntax-markup-deleted-bg: #ffebe9;
|
||||
--color-prettylights-syntax-markup-inserted-text: #116329;
|
||||
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
|
||||
--color-prettylights-syntax-markup-changed-text: #953800;
|
||||
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
|
||||
--color-prettylights-syntax-markup-ignored-text: #eaeef2;
|
||||
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
|
||||
--color-prettylights-syntax-meta-diff-range: #8250df;
|
||||
--color-prettylights-syntax-brackethighlighter-angle: #57606a;
|
||||
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
|
||||
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-prettylights-syntax-comment: #8b949e;
|
||||
--color-prettylights-syntax-constant: #79c0ff;
|
||||
--color-prettylights-syntax-entity: #d2a8ff;
|
||||
--color-prettylights-syntax-storage-modifier-import: #c9d1d9;
|
||||
--color-prettylights-syntax-entity-tag: #7ee787;
|
||||
--color-prettylights-syntax-keyword: #ff7b72;
|
||||
--color-prettylights-syntax-string: #a5d6ff;
|
||||
--color-prettylights-syntax-variable: #ffa657;
|
||||
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
|
||||
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
|
||||
--color-prettylights-syntax-invalid-illegal-bg: #8e1519;
|
||||
--color-prettylights-syntax-carriage-return-text: #f0f6fc;
|
||||
--color-prettylights-syntax-carriage-return-bg: #b62324;
|
||||
--color-prettylights-syntax-string-regexp: #7ee787;
|
||||
--color-prettylights-syntax-markup-list: #f2cc60;
|
||||
--color-prettylights-syntax-markup-heading: #1f6feb;
|
||||
--color-prettylights-syntax-markup-italic: #c9d1d9;
|
||||
--color-prettylights-syntax-markup-bold: #c9d1d9;
|
||||
--color-prettylights-syntax-markup-deleted-text: #ffdcd7;
|
||||
--color-prettylights-syntax-markup-deleted-bg: #67060c;
|
||||
--color-prettylights-syntax-markup-inserted-text: #aff5b4;
|
||||
--color-prettylights-syntax-markup-inserted-bg: #033a16;
|
||||
--color-prettylights-syntax-markup-changed-text: #ffdfb6;
|
||||
--color-prettylights-syntax-markup-changed-bg: #5a1e02;
|
||||
--color-prettylights-syntax-markup-ignored-text: #c9d1d9;
|
||||
--color-prettylights-syntax-markup-ignored-bg: #1158c7;
|
||||
--color-prettylights-syntax-meta-diff-range: #d2a8ff;
|
||||
--color-prettylights-syntax-brackethighlighter-angle: #8b949e;
|
||||
--color-prettylights-syntax-sublimelinter-gutter-mark: #484f58;
|
||||
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
|
||||
}
|
||||
}
|
||||
|
||||
.pl-c {
|
||||
color: var(--color-prettylights-syntax-comment);
|
||||
}
|
||||
|
||||
.pl-c1,
|
||||
.pl-s .pl-v {
|
||||
color: var(--color-prettylights-syntax-constant);
|
||||
}
|
||||
|
||||
.pl-e,
|
||||
.pl-en {
|
||||
color: var(--color-prettylights-syntax-entity);
|
||||
}
|
||||
|
||||
.pl-smi,
|
||||
.pl-s .pl-s1 {
|
||||
color: var(--color-prettylights-syntax-storage-modifier-import);
|
||||
}
|
||||
|
||||
.pl-ent {
|
||||
color: var(--color-prettylights-syntax-entity-tag);
|
||||
}
|
||||
|
||||
.pl-k {
|
||||
color: var(--color-prettylights-syntax-keyword);
|
||||
}
|
||||
|
||||
.pl-s,
|
||||
.pl-pds,
|
||||
.pl-s .pl-pse .pl-s1,
|
||||
.pl-sr,
|
||||
.pl-sr .pl-cce,
|
||||
.pl-sr .pl-sre,
|
||||
.pl-sr .pl-sra {
|
||||
color: var(--color-prettylights-syntax-string);
|
||||
}
|
||||
|
||||
.pl-v,
|
||||
.pl-smw {
|
||||
color: var(--color-prettylights-syntax-variable);
|
||||
}
|
||||
|
||||
.pl-bu {
|
||||
color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
|
||||
}
|
||||
|
||||
.pl-ii {
|
||||
color: var(--color-prettylights-syntax-invalid-illegal-text);
|
||||
background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
|
||||
}
|
||||
|
||||
.pl-c2 {
|
||||
color: var(--color-prettylights-syntax-carriage-return-text);
|
||||
background-color: var(--color-prettylights-syntax-carriage-return-bg);
|
||||
}
|
||||
|
||||
.pl-sr .pl-cce {
|
||||
font-weight: bold;
|
||||
color: var(--color-prettylights-syntax-string-regexp);
|
||||
}
|
||||
|
||||
.pl-ml {
|
||||
color: var(--color-prettylights-syntax-markup-list);
|
||||
}
|
||||
|
||||
.pl-mh,
|
||||
.pl-mh .pl-en,
|
||||
.pl-ms {
|
||||
font-weight: bold;
|
||||
color: var(--color-prettylights-syntax-markup-heading);
|
||||
}
|
||||
|
||||
.pl-mi {
|
||||
font-style: italic;
|
||||
color: var(--color-prettylights-syntax-markup-italic);
|
||||
}
|
||||
|
||||
.pl-mb {
|
||||
font-weight: bold;
|
||||
color: var(--color-prettylights-syntax-markup-bold);
|
||||
}
|
||||
|
||||
.pl-md {
|
||||
color: var(--color-prettylights-syntax-markup-deleted-text);
|
||||
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
|
||||
}
|
||||
|
||||
.pl-mi1 {
|
||||
color: var(--color-prettylights-syntax-markup-inserted-text);
|
||||
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
|
||||
}
|
||||
|
||||
.pl-mc {
|
||||
color: var(--color-prettylights-syntax-markup-changed-text);
|
||||
background-color: var(--color-prettylights-syntax-markup-changed-bg);
|
||||
}
|
||||
|
||||
.pl-mi2 {
|
||||
color: var(--color-prettylights-syntax-markup-ignored-text);
|
||||
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
|
||||
}
|
||||
|
||||
.pl-mdr {
|
||||
font-weight: bold;
|
||||
color: var(--color-prettylights-syntax-meta-diff-range);
|
||||
}
|
||||
|
||||
.pl-ba {
|
||||
color: var(--color-prettylights-syntax-brackethighlighter-angle);
|
||||
}
|
||||
|
||||
.pl-sg {
|
||||
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
|
||||
}
|
||||
|
||||
.pl-corl {
|
||||
text-decoration: underline;
|
||||
color: var(--color-prettylights-syntax-constant-other-reference-link);
|
||||
}
|
||||
+29
-2
@@ -4,6 +4,7 @@
|
||||
import dompurify from "dompurify";
|
||||
import matter from "@radicle/gray-matter";
|
||||
import { base } from "@app/router";
|
||||
import { highlight } from "@app/syntax";
|
||||
import {
|
||||
markdownExtensions as extensions,
|
||||
renderer,
|
||||
@@ -14,6 +15,7 @@
|
||||
} from "@app/utils";
|
||||
import { marked } from "marked";
|
||||
import { onMount } from "svelte";
|
||||
import { toDom } from "hast-util-to-dom";
|
||||
|
||||
export let content: string;
|
||||
export let doc = matter(content);
|
||||
@@ -29,7 +31,7 @@
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
dompurify.sanitize(marked.parse(content), { SANITIZE_DOM: false });
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
// Don't underline <a> tags that contain images.
|
||||
const elems = container.querySelectorAll("a");
|
||||
|
||||
@@ -59,6 +61,31 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces code blocks in the background with highlighted code.
|
||||
const prefix = "language-";
|
||||
const nodes = Array.from(document.body.querySelectorAll("pre code"));
|
||||
|
||||
const treeChanges: Promise<void>[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
const className = Array.from(node.classList).find(name =>
|
||||
name.startsWith(prefix),
|
||||
);
|
||||
if (!className) continue;
|
||||
|
||||
treeChanges.push(
|
||||
highlight(node.textContent ?? "", className.slice(prefix.length))
|
||||
.then(tree => {
|
||||
if (tree) {
|
||||
node.replaceChildren(toDom(tree, { fragment: true }));
|
||||
}
|
||||
})
|
||||
.catch(e => console.warn("Not able to highlight code block", e)),
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.allSettled(treeChanges);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -160,7 +187,7 @@
|
||||
.markdown :global(code) {
|
||||
font-family: var(--font-family-monospace);
|
||||
font-size: var(--font-size-regular);
|
||||
color: var(--color-secondary-6);
|
||||
color: var(--color-foreground);
|
||||
background-color: var(--color-foreground-2);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.125rem 0.25rem;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<script lang="ts">
|
||||
import type { Blob } from "@app/project";
|
||||
import type { MaybeHighlighted } from "@app/syntax";
|
||||
import type { ProjectRoute } from "@app/router/definitions";
|
||||
|
||||
import HeaderToggleLabel from "@app/base/projects/HeaderToggleLabel.svelte";
|
||||
import ProjectLink from "@app/router/ProjectLink.svelte";
|
||||
import Readme from "@app/base/projects/Readme.svelte";
|
||||
import { afterUpdate, beforeUpdate, onMount } from "svelte";
|
||||
import { highlight } from "@app/syntax";
|
||||
import { isMarkdownPath, scrollIntoView, twemoji } from "@app/utils";
|
||||
import { onMount } from "svelte";
|
||||
import { lineNumbersGutter } from "@app/syntax";
|
||||
import { toHtml } from "hast-util-to-html";
|
||||
import { updateProjectRoute } from "@app/router";
|
||||
|
||||
export let activeRoute: ProjectRoute;
|
||||
@@ -14,25 +17,42 @@
|
||||
export let getImage: (path: string) => Promise<Blob>;
|
||||
export let line: string | undefined = undefined;
|
||||
|
||||
$: lineNumber = line ? parseInt(line.substring(1)) : undefined;
|
||||
|
||||
const fileExtension = blob.path.split(".").pop() ?? "";
|
||||
const lastCommit = blob.info.lastCommit;
|
||||
const lines = blob.binary ? 0 : (blob.content.match(/\n/g) || []).length;
|
||||
const hasFinalNewline = blob.content.endsWith("\n");
|
||||
const lineNumbers = Array(hasFinalNewline ? lines : lines + 1)
|
||||
.fill(0)
|
||||
.map((_, index) => (index + 1).toString());
|
||||
const parentDir = blob.path
|
||||
.match(/^.*\/|/)
|
||||
?.values()
|
||||
.next().value;
|
||||
let content: MaybeHighlighted = undefined;
|
||||
|
||||
// Waiting onMount, due to the line numbers still loading.
|
||||
onMount(() => {
|
||||
if (line) {
|
||||
scrollIntoView(line);
|
||||
// Any time a user clicks on a line number, the `line` prop gets updated,
|
||||
// and the line is highlighted, but the previous line is not unhighlighted.
|
||||
// So we have to make sure here that any previous highlighting gets removed,
|
||||
// before updating the component.
|
||||
beforeUpdate(() => {
|
||||
for (const item of document.getElementsByClassName("highlight")) {
|
||||
item.classList.remove("highlight");
|
||||
}
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
const output = await highlight(blob.content, fileExtension);
|
||||
if (output) {
|
||||
content = lineNumbersGutter(output);
|
||||
}
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
if (line) {
|
||||
scrollIntoView(line);
|
||||
|
||||
const element = document.getElementById(line);
|
||||
if (element) {
|
||||
element.classList.add("highlight");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const isMarkdown = isMarkdownPath(blob.path);
|
||||
// If we have a line number we should show the raw output.
|
||||
let showMarkdown = line ? false : isMarkdown;
|
||||
@@ -40,10 +60,6 @@
|
||||
updateProjectRoute({ line: undefined });
|
||||
showMarkdown = !showMarkdown;
|
||||
};
|
||||
|
||||
$: if (line) {
|
||||
scrollIntoView(line);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -100,29 +116,51 @@
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.line-numbers {
|
||||
.code :global(.line-number) {
|
||||
color: var(--color-foreground-4);
|
||||
font-family: var(--font-family-sans-serif);
|
||||
text-align: right;
|
||||
user-select: none;
|
||||
padding: 1rem 1rem 0.5rem 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.line-number {
|
||||
display: block;
|
||||
.code :global(.line-number:hover) {
|
||||
cursor: pointer;
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
.line-number:hover,
|
||||
.line-number.highlighted {
|
||||
color: var(--color-foreground-6);
|
||||
|
||||
.code :global(.content) {
|
||||
display: inline;
|
||||
font-family: var(--font-family-monospace);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.code :global(.line) {
|
||||
line-height: 22px; /* This seems to be the line-height of a pre code block */
|
||||
}
|
||||
.code :global(.highlight) {
|
||||
background-color: var(--color-caution-3);
|
||||
}
|
||||
.code :global(.highlight td a) {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
|
||||
.code :global(.line-content) {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.code {
|
||||
padding-bottom: 0.5rem;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
overflow-x: auto;
|
||||
font-size: 1rem;
|
||||
padding-top: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--color-foreground-3);
|
||||
border-top-style: dashed;
|
||||
border-bottom-left-radius: var(--border-radius-small);
|
||||
@@ -144,14 +182,6 @@
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1.5rem;
|
||||
top: 1rem;
|
||||
background-color: var(--color-caution-3);
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
@@ -165,13 +195,9 @@
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.code,
|
||||
.line-numbers {
|
||||
.code {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
.highlight {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
@@ -215,27 +241,10 @@
|
||||
</div>
|
||||
{:else if showMarkdown}
|
||||
<Readme content={blob.content} {getImage} {activeRoute} />
|
||||
{:else}
|
||||
{#if lineNumber}
|
||||
<div
|
||||
class="highlight"
|
||||
style="top: {lineNumber === 1 ? 1 : 1.5 * lineNumber - 0.5}rem" />
|
||||
{/if}
|
||||
<div class="line-numbers">
|
||||
{#each lineNumbers as lineNumber}
|
||||
<ProjectLink
|
||||
projectParams={{ line: `L${lineNumber}` }}
|
||||
id="L{lineNumber}">
|
||||
<span class="line-number" class:highlighted={lineNumber === line} />
|
||||
{lineNumber}
|
||||
</ProjectLink>
|
||||
{/each}
|
||||
</div>
|
||||
{#if blob.html}
|
||||
<pre class="code no-scrollbar">{@html blob.content}</pre>
|
||||
{:else}
|
||||
<pre class="code txt-monospace no-scrollbar">{blob.content}</pre>
|
||||
{/if}
|
||||
{:else if content}
|
||||
<table class="code no-scrollbar">
|
||||
{@html toHtml(content)}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,17 +47,8 @@
|
||||
return state.blob;
|
||||
}
|
||||
|
||||
const isMarkdownPath = utils.isMarkdownPath(path);
|
||||
const promise =
|
||||
path === "/"
|
||||
? project.getReadme(commit)
|
||||
: project.getBlob(
|
||||
commit,
|
||||
path,
|
||||
isMarkdownPath
|
||||
? { highlight: false }
|
||||
: { highlight: true, theme: `base16-ocean.${theme}` },
|
||||
);
|
||||
path === "/" ? project.getReadme(commit) : project.getBlob(commit, path);
|
||||
|
||||
state = { status: Status.Loading, path };
|
||||
try {
|
||||
@@ -71,7 +62,7 @@
|
||||
// Get an image blob based on a relative path.
|
||||
const getImage = async (imagePath: string): Promise<proj.Blob> => {
|
||||
const finalPath = utils.canonicalize(imagePath, path);
|
||||
return project.getBlob(commit, finalPath, { highlight: false });
|
||||
return project.getBlob(commit, finalPath);
|
||||
};
|
||||
|
||||
const onSelect = async (newPath: string, theme: Theme) => {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
const getImage = async (imagePath: string): Promise<Blob> => {
|
||||
const finalPath = canonicalize(imagePath, "/"); // We only use the root path in issues.
|
||||
const commit = project.branches[project.defaultBranch]; // We suppose that all issues are only looked at on HEAD of the default branch.
|
||||
return project.getBlob(commit, finalPath, { highlight: false });
|
||||
return project.getBlob(commit, finalPath);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
const getImage = async (imagePath: string): Promise<Blob> => {
|
||||
const finalPath = canonicalize(imagePath, "/"); // We only use the root path in issues.
|
||||
const commit = project.branches[project.defaultBranch]; // We suppose that all issues are only looked at on HEAD of the default branch.
|
||||
return project.getBlob(commit, finalPath, { highlight: false });
|
||||
return project.getBlob(commit, finalPath);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
+2
-8
@@ -278,17 +278,11 @@ export class Project implements ProjectInfo {
|
||||
).get();
|
||||
}
|
||||
|
||||
async getBlob(
|
||||
commit: string,
|
||||
path: string,
|
||||
options:
|
||||
| { highlight: false }
|
||||
| { highlight: true; theme: "base16-ocean.dark" | "base16-ocean.light" },
|
||||
): Promise<Blob> {
|
||||
async getBlob(commit: string, path: string): Promise<Blob> {
|
||||
return new Request(
|
||||
`projects/${this.urn}/blob/${commit}/${path}`,
|
||||
this.seed.api,
|
||||
).get(options);
|
||||
).get();
|
||||
}
|
||||
|
||||
async getReadme(commit: string): Promise<Blob> {
|
||||
|
||||
+5
-1
@@ -23,7 +23,11 @@ export const base = window.HASH_ROUTING ? "./" : "/";
|
||||
window.addEventListener("hashchange", e => {
|
||||
const route = pathToRoute(e.newURL);
|
||||
if (route?.resource === "projects" && route.params.hash) {
|
||||
updateProjectRoute({ hash: route.params.hash });
|
||||
if (route.params.hash.match(/^L\d+$/)) {
|
||||
updateProjectRoute({ line: route.params.hash });
|
||||
} else {
|
||||
updateProjectRoute({ hash: route.params.hash });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import type { Root } from "@wooorm/starry-night";
|
||||
import type { ElementContent } from "hast";
|
||||
|
||||
import { createStarryNight, common } from "@wooorm/starry-night";
|
||||
import sourceTsx from "@wooorm/starry-night/lang/source.tsx";
|
||||
import sourceSvelte from "@wooorm/starry-night/lang/source.svelte.js";
|
||||
import sourceSolidity from "@wooorm/starry-night/lang/source.solidity.js";
|
||||
import sourceToml from "@wooorm/starry-night/lang/source.toml";
|
||||
import sourceErlang from "@wooorm/starry-night/lang/source.erlang.js";
|
||||
import sourceDockerfile from "@wooorm/starry-night/lang/source.dockerfile";
|
||||
import sourceAsciiDoc from "@wooorm/starry-night/lang/text.html.asciidoc";
|
||||
|
||||
export type MaybeHighlighted = Root | undefined;
|
||||
|
||||
export const grammars = [
|
||||
...common,
|
||||
sourceSvelte,
|
||||
sourceSolidity,
|
||||
sourceTsx,
|
||||
sourceErlang,
|
||||
sourceDockerfile,
|
||||
sourceAsciiDoc,
|
||||
sourceToml,
|
||||
// A grammar that doesn't do any parsing, but needed for files without a known filetype.
|
||||
{
|
||||
extensions: [""],
|
||||
names: ["raw-format"],
|
||||
patterns: [],
|
||||
scopeName: "text.raw",
|
||||
},
|
||||
];
|
||||
|
||||
let starryNight: Awaited<ReturnType<typeof createStarryNight>>;
|
||||
|
||||
export async function highlight(
|
||||
content: string,
|
||||
grammar: string,
|
||||
): Promise<MaybeHighlighted> {
|
||||
if (starryNight === undefined) {
|
||||
starryNight = await createStarryNight(grammars);
|
||||
}
|
||||
const scope = starryNight.flagToScope(grammar);
|
||||
return starryNight.highlight(content, scope ?? "text.raw");
|
||||
}
|
||||
|
||||
export function lineNumbersGutter(tree: Root) {
|
||||
const replacement: ElementContent[] = [];
|
||||
const search = /\r?\n|\r/g;
|
||||
let index = -1;
|
||||
let start = 0;
|
||||
let startTextRemainder = "";
|
||||
let lineNumber = 0;
|
||||
|
||||
while (++index < tree.children.length) {
|
||||
const child = tree.children[index];
|
||||
|
||||
if (child.type === "text") {
|
||||
let textStart = 0;
|
||||
let match = search.exec(child.value);
|
||||
|
||||
while (match) {
|
||||
// Nodes in this line.
|
||||
const line = tree.children.slice(start, index) as ElementContent[];
|
||||
|
||||
// Prepend text from a partial matched earlier text.
|
||||
if (startTextRemainder) {
|
||||
line.unshift({ type: "text", value: startTextRemainder });
|
||||
startTextRemainder = "";
|
||||
}
|
||||
|
||||
// Append text from this text.
|
||||
if (match.index > textStart) {
|
||||
line.push({
|
||||
type: "text",
|
||||
value: child.value.slice(textStart, match.index),
|
||||
});
|
||||
}
|
||||
|
||||
// Add a line, and the eol.
|
||||
lineNumber += 1;
|
||||
replacement.push(createLine(line, lineNumber), {
|
||||
type: "text",
|
||||
value: match[0],
|
||||
});
|
||||
|
||||
start = index + 1;
|
||||
textStart = match.index + match[0].length;
|
||||
match = search.exec(child.value);
|
||||
}
|
||||
|
||||
// If we matched, make sure to not drop the text after the last line ending.
|
||||
if (start === index + 1) {
|
||||
startTextRemainder = child.value.slice(textStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const line = tree.children.slice(start) as ElementContent[];
|
||||
// Prepend text from a partial matched earlier text.
|
||||
if (startTextRemainder) {
|
||||
line.unshift({ type: "text", value: startTextRemainder });
|
||||
startTextRemainder = "";
|
||||
}
|
||||
|
||||
if (line.length > 0) {
|
||||
lineNumber += 1;
|
||||
replacement.push(createLine(line, lineNumber));
|
||||
}
|
||||
|
||||
// Replace children with new array.
|
||||
tree.children = replacement;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
function createLine(children: ElementContent[], line: number): ElementContent {
|
||||
return {
|
||||
type: "element",
|
||||
tagName: "tr",
|
||||
properties: {
|
||||
class: "line",
|
||||
id: "L" + line,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "td",
|
||||
properties: {
|
||||
className: "line-number",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "a",
|
||||
properties: { href: "#L" + line },
|
||||
children: [{ type: "text", value: line.toString() }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "element",
|
||||
tagName: "td",
|
||||
properties: {
|
||||
className: "line-content",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "pre",
|
||||
properties: {
|
||||
className: "content",
|
||||
},
|
||||
children,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import { test, expect } from "@tests/support/fixtures.js";
|
||||
import { expectUrlPersistsReload } from "@tests/support/router";
|
||||
|
||||
const sourceBrowsingFixture =
|
||||
"/seeds/0.0.0.0/rad:git:hnrkgd7sjt79k4j59ddh11ooxg18rk7soej8o";
|
||||
@@ -74,9 +75,32 @@ test("source file highlighting", async ({ page }) => {
|
||||
await page.getByText("src/").click();
|
||||
await page.getByText("true.c").click();
|
||||
|
||||
await expect(page.getByText("return")).toHaveCSS(
|
||||
"color",
|
||||
"rgb(180, 142, 173)",
|
||||
await expect(page.getByText("return")).toHaveCSS("color", "rgb(207, 34, 46)");
|
||||
});
|
||||
|
||||
test("navigate line numbers", async ({ page }) => {
|
||||
await page.goto(`${sourceBrowsingFixture}/tree/main/markdown/cheatsheet.md`);
|
||||
await page.locator('role=button[name="Raw"]').click();
|
||||
|
||||
await page.locator('[href="#L5"]').click();
|
||||
await expect(page.locator("#L5")).toHaveClass("line highlight");
|
||||
await expect(page).toHaveURL(
|
||||
"/seeds/0.0.0.0/rad:git:hnrkgd7sjt79k4j59ddh11ooxg18rk7soej8o/tree/main/markdown/cheatsheet.md#L5",
|
||||
);
|
||||
|
||||
await expectUrlPersistsReload(page);
|
||||
await expect(page.locator("#L5")).toHaveClass("line highlight");
|
||||
|
||||
await page.locator('[href="#L30"]').click();
|
||||
await expect(page.locator("#L5")).not.toHaveClass("line highlight");
|
||||
await expect(page.locator("#L30")).toHaveClass("line highlight");
|
||||
await expect(page).toHaveURL(
|
||||
"/seeds/0.0.0.0/rad:git:hnrkgd7sjt79k4j59ddh11ooxg18rk7soej8o/tree/main/markdown/cheatsheet.md#L30",
|
||||
);
|
||||
|
||||
await page.getByText(".hidden").click();
|
||||
await expect(page).toHaveURL(
|
||||
"/seeds/0.0.0.0/rad:git:hnrkgd7sjt79k4j59ddh11ooxg18rk7soej8o/tree/main/.hidden",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ test("change theme", async ({ page }) => {
|
||||
"rgb(243, 246, 253)",
|
||||
);
|
||||
// Source highlighting reacts to theme change.
|
||||
await expect(page.getByText("() {")).toHaveCSS("color", "rgb(79, 91, 102)");
|
||||
await expect(page.getByText("() {")).toHaveCSS("color", "rgb(26, 26, 44)");
|
||||
|
||||
await page.locator(".theme .toggle").click();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
@@ -53,7 +53,7 @@ test("change theme", async ({ page }) => {
|
||||
"rgb(11, 19, 26)",
|
||||
);
|
||||
// Source highlighting reacts to theme change.
|
||||
await expect(page.getByText("() {")).toHaveCSS("color", "rgb(192, 197, 206)");
|
||||
await expect(page.getByText("() {")).toHaveCSS("color", "rgb(255, 255, 255)");
|
||||
});
|
||||
|
||||
test("change code font", async ({ page }) => {
|
||||
|
||||
@@ -83,6 +83,13 @@ export const test = base.extend<{
|
||||
status: 200,
|
||||
path: "./public/favicon.ico",
|
||||
});
|
||||
} else if (
|
||||
route.request().url().startsWith("https://esm.sh/vscode-oniguruma@1")
|
||||
) {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
path: "./tests/support/onig.wasm",
|
||||
});
|
||||
} else {
|
||||
log(
|
||||
`Aborted remote request: ${route.request().url()}`,
|
||||
|
||||
Binary file not shown.
@@ -70,6 +70,22 @@ export default defineConfig({
|
||||
],
|
||||
cache: ["lru-cache", "@stardazed/streams"],
|
||||
markdown: ["katex", "dompurify", "marked", "@radicle/gray-matter"],
|
||||
syntax: ["@wooorm/starry-night"],
|
||||
grammarsTsx: [
|
||||
"@wooorm/starry-night/lang/source.ts.js",
|
||||
"@wooorm/starry-night/lang/source.tsx.js",
|
||||
],
|
||||
grammars: [
|
||||
"@wooorm/starry-night/lang/source.python.js",
|
||||
"@wooorm/starry-night/lang/source.js.js",
|
||||
"@wooorm/starry-night/lang/source.perl.js",
|
||||
"@wooorm/starry-night/lang/source.haskell.js",
|
||||
"@wooorm/starry-night/lang/source.ruby.js",
|
||||
"@wooorm/starry-night/lang/source.css.js",
|
||||
"@wooorm/starry-night/lang/source.solidity.js",
|
||||
"@wooorm/starry-night/lang/source.cs.js",
|
||||
"@wooorm/starry-night/lang/source.swift.js",
|
||||
],
|
||||
dom: ["svelte", "pure-svg-code", "twemoji"],
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user