Add code highlighting (#2195)

* Add highlighting

* Adds it to mdNoImages as well

* Revert "Adds it to mdNoImages as well"

This reverts commit 2f8e3bb0cc.

* Revert "Add highlighting"

This reverts commit 80bcddd4df.

* Prevent yarn.lock from massively updating

* Add code themes locally

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
Benjamin Barbeau 2023-10-20 11:18:13 -04:00 committed by GitHub
parent ca456fdd1b
commit 2b5068187c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 83 additions and 1 deletions

View file

@ -1,5 +1,6 @@
src/shared/translations src/shared/translations
lemmy-translations lemmy-translations
src/assets/css/themes/*.css src/assets/css/themes/*.css
src/assets/css/code-themes/*.css
stats.json stats.json
dist dist

View file

@ -77,6 +77,7 @@
"markdown-it-container": "^3.0.0", "markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.2", "markdown-it-emoji": "^2.0.2",
"markdown-it-footnote": "^3.0.3", "markdown-it-footnote": "^3.0.3",
"markdown-it-highlightjs": "^4.0.1",
"markdown-it-html5-embed": "^1.0.0", "markdown-it-html5-embed": "^1.0.0",
"markdown-it-ruby": "^0.1.1", "markdown-it-ruby": "^0.1.1",
"markdown-it-sub": "^1.0.0", "markdown-it-sub": "^1.0.0",

View file

@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}

View file

@ -0,0 +1 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#383a42;background:#fafafa}.hljs-comment,.hljs-quote{color:#a0a1a7;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e45649}.hljs-literal{color:#0184bb}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#50a14f}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#4078f2}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#c18401}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}

View file

@ -0,0 +1,35 @@
import type { Request, Response } from "express";
import { existsSync } from "fs";
import path from "path";
const extraThemesFolder =
process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";
export default async (req: Request, res: Response) => {
res.contentType("text/css");
const theme = req.params.name;
if (!theme.endsWith(".css")) {
return res.status(400).send("Theme must be a css file");
}
const customTheme = path.resolve(extraThemesFolder, theme);
if (existsSync(customTheme)) {
return res.sendFile(customTheme);
} else {
const internalTheme = path.resolve(
`./dist/assets/css/code-themes/${theme}`,
);
// If the theme doesn't exist, just send atom-one-light
if (existsSync(internalTheme)) {
return res.sendFile(internalTheme);
} else {
return res.sendFile(
path.resolve("./dist/assets/css/code-themes/atom-one-light.css"),
);
}
}
};

View file

@ -11,6 +11,7 @@ import ServiceWorkerHandler from "./handlers/service-worker-handler";
import ThemeHandler from "./handlers/theme-handler"; import ThemeHandler from "./handlers/theme-handler";
import ThemesListHandler from "./handlers/themes-list-handler"; import ThemesListHandler from "./handlers/themes-list-handler";
import { setCacheControl, setDefaultCsp } from "./middleware"; import { setCacheControl, setDefaultCsp } from "./middleware";
import CodeThemeHandler from "./handlers/code-theme-handler";
const server = express(); const server = express();
@ -47,6 +48,7 @@ server.get("/robots.txt", RobotsHandler);
server.get("/service-worker.js", ServiceWorkerHandler); server.get("/service-worker.js", ServiceWorkerHandler);
server.get("/manifest.webmanifest", ManifestHandler); server.get("/manifest.webmanifest", ManifestHandler);
server.get("/css/themes/:name", ThemeHandler); server.get("/css/themes/:name", ThemeHandler);
server.get("/css/code-themes/:name", CodeThemeHandler);
server.get("/css/themelist", ThemesListHandler); server.get("/css/themelist", ThemesListHandler);
server.get("/*", CatchAllHandler); server.get("/*", CatchAllHandler);

View file

@ -15,6 +15,7 @@ import { Navbar } from "./navbar";
import "./styles.scss"; import "./styles.scss";
import { Theme } from "./theme"; import { Theme } from "./theme";
import AnonymousGuard from "../common/anonymous-guard"; import AnonymousGuard from "../common/anonymous-guard";
import { CodeTheme } from "./code-theme";
interface AppProps { interface AppProps {
user?: MyUserInfo; user?: MyUserInfo;
@ -55,7 +56,10 @@ export class App extends Component<AppProps, any> {
{I18NextService.i18n.t("jump_to_content", "Jump to content")} {I18NextService.i18n.t("jump_to_content", "Jump to content")}
</button> </button>
{siteView && ( {siteView && (
<Theme defaultTheme={siteView.local_site.default_theme} /> <>
<Theme defaultTheme={siteView.local_site.default_theme} />
<CodeTheme />
</>
)} )}
<Navbar siteRes={siteRes} /> <Navbar siteRes={siteRes} />
<div className="mt-4 p-0 fl-1"> <div className="mt-4 p-0 fl-1">

View file

@ -0,0 +1,22 @@
import { Component } from "inferno";
export class CodeTheme extends Component {
render() {
return (
<>
<link
rel="stylesheet"
type="text/css"
href={`/css/code-themes/atom-one-light.css`}
media="(prefers-color-scheme: light)"
/>
<link
rel="stylesheet"
type="text/css"
href={`/css/code-themes/atom-one-dark.css`}
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
/>
</>
);
}
}

View file

@ -14,6 +14,7 @@ import markdown_it_html5_embed from "markdown-it-html5-embed";
import markdown_it_ruby from "markdown-it-ruby"; import markdown_it_ruby from "markdown-it-ruby";
import markdown_it_sub from "markdown-it-sub"; import markdown_it_sub from "markdown-it-sub";
import markdown_it_sup from "markdown-it-sup"; import markdown_it_sup from "markdown-it-sup";
import markdown_it_highlightjs from "markdown-it-highlightjs";
import Renderer from "markdown-it/lib/renderer"; import Renderer from "markdown-it/lib/renderer";
import Token from "markdown-it/lib/token"; import Token from "markdown-it/lib/token";
import { instanceLinkRegex, relTags } from "./config"; import { instanceLinkRegex, relTags } from "./config";
@ -170,6 +171,7 @@ export function setupMarkdown() {
.use(markdown_it_footnote) .use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig) .use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig) .use(markdown_it_container, "spoiler", spoilerConfig)
.use(markdown_it_highlightjs, { inline: true })
.use(markdown_it_ruby) .use(markdown_it_ruby)
.use(localInstanceLinkParser) .use(localInstanceLinkParser)
.use(markdown_it_bidi); .use(markdown_it_bidi);
@ -183,6 +185,7 @@ export function setupMarkdown() {
.use(markdown_it_footnote) .use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig) .use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig) .use(markdown_it_container, "spoiler", spoilerConfig)
.use(markdown_it_highlightjs, { inline: true })
.use(localInstanceLinkParser) .use(localInstanceLinkParser)
.use(markdown_it_bidi) .use(markdown_it_bidi)
// .use(markdown_it_emoji, { // .use(markdown_it_emoji, {

View file

@ -5020,6 +5020,11 @@ has@^1.0.3:
dependencies: dependencies:
function-bind "^1.1.1" function-bind "^1.1.1"
highlight.js@^11.5.1:
version "11.9.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
history@^5.3.0: history@^5.3.0:
version "5.3.0" version "5.3.0"
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b" resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
@ -6422,6 +6427,13 @@ markdown-it-footnote@^3.0.3:
resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8" resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8"
integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w== integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==
markdown-it-highlightjs@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/markdown-it-highlightjs/-/markdown-it-highlightjs-4.0.1.tgz#6b8eb6a3b971ed592db1ff160cfa5ce9f2e44232"
integrity sha512-EPXwFEN6P5nqR3G4KjT20r20xbGYKMMA/360hhSYFmeoGXTE6hsLtJAiB/8ID8slVH4CWHHEL7GX0YenyIstVQ==
dependencies:
highlight.js "^11.5.1"
markdown-it-html5-embed@^1.0.0: markdown-it-html5-embed@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/markdown-it-html5-embed/-/markdown-it-html5-embed-1.0.0.tgz#f36bedca1eb12ce4df2d53b5ec72f62ba5e094b3" resolved "https://registry.yarnpkg.com/markdown-it-html5-embed/-/markdown-it-html5-embed-1.0.0.tgz#f36bedca1eb12ce4df2d53b5ec72f62ba5e094b3"