mirror of
https://github.com/ApfelTeeSaft/LiveSplitOne.git
synced 2026-08-26 19:23:40 +00:00
This replaces the context menu with our own. By doing that we no longer need to force install our npm packages, as there are no longer any conflicts. In fact, as part of this change, I updated us to the latest React 19 and even enabled the React compiler. I also explored CSS modules for the first time, which are going to allow us to reduce conflicts between CSS rules and possibly even allow us to fully remove SASS, as the need for it is going to be reduced. I also found out that the latest Rust nightly is broken due to their update to LLVM 20. So I pinned the version to the last working nightly version.
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
import * as React from "react";
|
|
import markdownit from "markdown-it";
|
|
import { emoteList } from "../api/EmoteList";
|
|
|
|
const UNSAFE = markdownit({ html: true, breaks: false, linkify: true });
|
|
const SAFE = markdownit({ html: false, breaks: true, linkify: true });
|
|
|
|
const unsafeDefault = UNSAFE.renderer.rules.link_open || function (tokens, idx, options, _env, self) {
|
|
return self.renderToken(tokens, idx, options);
|
|
};
|
|
UNSAFE.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
|
tokens[idx].attrSet('target', '_blank');
|
|
return unsafeDefault(tokens, idx, options, env, self);
|
|
};
|
|
|
|
const safeDefault = SAFE.renderer.rules.link_open || function (tokens, idx, options, _env, self) {
|
|
return self.renderToken(tokens, idx, options);
|
|
};
|
|
SAFE.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
|
tokens[idx].attrSet('target', '_blank');
|
|
return safeDefault(tokens, idx, options, env, self);
|
|
};
|
|
|
|
function replaceTwitchEmotes(text: string): string {
|
|
return text.replace(/[A-Za-z0-9<):(\\;_>#/\]|]+/g, (matched) => {
|
|
const emoteId = emoteList[matched];
|
|
if (emoteId === undefined) {
|
|
return matched;
|
|
}
|
|
|
|
const url = `https://static-cdn.jtvnw.net/emoticons/v1/${emoteId}/1.0`;
|
|
return ``;
|
|
});
|
|
}
|
|
|
|
export function replaceFlag(countryCode: string): React.JSX.Element {
|
|
const url = `https://www.speedrun.com/images/flags/${countryCode}.png`;
|
|
|
|
return <img className="flag" src={url} alt={countryCode} />;
|
|
}
|
|
|
|
export const Markdown = React.memo(renderMarkdown);
|
|
|
|
export function renderMarkdown({ markdown, unsafe }: { markdown: string,
|
|
unsafe?: boolean,
|
|
}): React.JSX.Element {
|
|
const markdownWithEmotes = replaceTwitchEmotes(markdown);
|
|
const html = (unsafe ? UNSAFE : SAFE).render(markdownWithEmotes);
|
|
|
|
return <div dangerouslySetInnerHTML={{ __html: html }} />;
|
|
}
|