Move syntax highlighting to web client

Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
Sebastian Martinez
2022-12-16 11:00:17 +01:00
parent 795ab5253d
commit 569b660134
17 changed files with 848 additions and 90 deletions
+1
View File
@@ -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" />
+333
View File
@@ -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",
+3
View File
@@ -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",
+190
View File
@@ -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
View File
@@ -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;
+70 -61
View File
@@ -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>
+2 -11
View File
@@ -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) => {
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 });
}
}
});
+159
View File
@@ -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,
},
],
},
],
};
}
+27 -3
View File
@@ -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",
);
});
+2 -2
View File
@@ -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 }) => {
+7
View File
@@ -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.
+16
View File
@@ -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"],
},
},