mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-06-10 09:10:03 +00:00
Resolve https://projekte.kosit.org/kosit/validator/-/issues/97 "Replace docsify from UI"
This commit is contained in:
parent
a10cc14d06
commit
219aeaa1b7
100 changed files with 27369 additions and 1072 deletions
89
server/ui/src/components/Codeblock/Codeblock.module.css
Normal file
89
server/ui/src/components/Codeblock/Codeblock.module.css
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
.codeblock {
|
||||
box-shadow: inset var(--ifm-global-shadow-lw);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:where(.buttonWrapper) {
|
||||
--codeblock-button-text-color: var(--text-main);
|
||||
--codeblock-button-background-color: var(--surface-2);
|
||||
--codeblock-button-background-color-hover: var(--surface-accent-1);
|
||||
--codeblock-button-separator-color: var(--surface-4);
|
||||
--codeblock-button-border-color: var(--codeblock-button-separator-color);
|
||||
--codeblock-button-icon-size: 1.5rem;
|
||||
--codeblock-button-size: 2rem;
|
||||
--codeblock-button-shadow: var(--ifm-global-shadow-tl);
|
||||
}
|
||||
|
||||
:where([data-theme="dark"] .buttonWrapper) {
|
||||
--codeblock-button-text-color: var(--text-0);
|
||||
--codeblock-button-background-color: var(--surface-6);
|
||||
--codeblock-button-background-color-hover: var(--surface-5);
|
||||
--codeblock-button-separator-color: var(--codeblock-button-text-color);
|
||||
--codeblock-button-shadow: var(--ifm-global-shadow-tl);
|
||||
--codeblock-button-shadow: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
width: var(--codeblock-button-size);
|
||||
height: var(--codeblock-button-size);
|
||||
background: var(--codeblock-button-background-color);
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
color: var(--codeblock-button-text-color);
|
||||
font-weight: var(--ifm-font-weight-semibold);
|
||||
border: none;
|
||||
padding: 0;
|
||||
height: 2.25em;
|
||||
line-height: 1;
|
||||
border-radius: var(--border-radius-small);
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
transition: color 200ms ease, background-color 200ms ease;
|
||||
}
|
||||
|
||||
.button:not(:first-child) {
|
||||
border-left: 1px solid var(--codeblock-button-separator-color);
|
||||
}
|
||||
.button:first-child {
|
||||
border-top-left-radius: var(--border-radius-small);
|
||||
border-bottom-left-radius: var(--border-radius-small);
|
||||
}
|
||||
.button:last-child {
|
||||
border-top-right-radius: var(--border-radius-small);
|
||||
border-bottom-right-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
.button:focus {
|
||||
background: var(--codeblock-button-background-color-hover);
|
||||
}
|
||||
|
||||
.button svg {
|
||||
width: var(--codeblock-button-icon-size);
|
||||
height: var(--codeblock-button-icon-size);
|
||||
}
|
||||
|
||||
.buttonWrapper {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 1;
|
||||
box-shadow: var(--codeblock-button-shadow);
|
||||
border: 1px solid var(--codeblock-button-border-color);
|
||||
border-radius: var(--border-radius-small);
|
||||
opacity: 0.75;
|
||||
transition: opacity 300ms ease;
|
||||
}
|
||||
|
||||
.buttonWrapper:hover,
|
||||
.buttonWrapper:focus-within {
|
||||
opacity: 1;
|
||||
}
|
||||
119
server/ui/src/components/Codeblock/Codeblock.tsx
Normal file
119
server/ui/src/components/Codeblock/Codeblock.tsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import type { PrismTheme, Language } from "prism-react-renderer";
|
||||
import Highlight, { defaultProps } from "prism-react-renderer";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import clsx from "clsx";
|
||||
import downloadFile from "js-file-download";
|
||||
import styles from "./Codeblock.module.css";
|
||||
|
||||
type ThemeValue = "light" | "dark";
|
||||
|
||||
const getTheme = () =>
|
||||
(document.documentElement.dataset.theme || "light") as ThemeValue;
|
||||
|
||||
function useGlobalTheme() {
|
||||
const [theme, setTheme] = useState<ThemeValue>(getTheme);
|
||||
useEffect(() => {
|
||||
const mo = new MutationObserver(() => {
|
||||
setTheme(getTheme());
|
||||
});
|
||||
mo.observe(document.documentElement, {
|
||||
subtree: false,
|
||||
attributeFilter: ["data-theme"],
|
||||
});
|
||||
return () => mo.disconnect();
|
||||
});
|
||||
return theme;
|
||||
}
|
||||
|
||||
function Codeblock({
|
||||
children,
|
||||
language = "markup",
|
||||
enableCopy = false,
|
||||
download,
|
||||
}: {
|
||||
children: string;
|
||||
language?: Language;
|
||||
enableCopy?: boolean;
|
||||
download?: { fileName: string; mime: string };
|
||||
}): JSX.Element {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
const theme = useGlobalTheme();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const codeThemeLight = (siteConfig.themeConfig.prism as any)
|
||||
.theme as PrismTheme;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const codeThemeDark = (siteConfig.themeConfig.prism as any)
|
||||
.darkTheme as PrismTheme;
|
||||
const codeTheme = theme === "light" ? codeThemeLight : codeThemeDark;
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
navigator.clipboard.writeText(children);
|
||||
} catch {
|
||||
// Copying did unfortunately not work, but we'll not crash the app
|
||||
// beacause of that...
|
||||
}
|
||||
};
|
||||
const handleDownload = () => {
|
||||
if (!download || !download.fileName || !download.mime) return;
|
||||
downloadFile(children, download.fileName, download.mime);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Highlight
|
||||
{...defaultProps}
|
||||
code={children}
|
||||
language={language}
|
||||
theme={codeTheme}
|
||||
>
|
||||
{({ className, style, tokens, getLineProps, getTokenProps }) => (
|
||||
<pre className={clsx(className, styles.codeblock)} style={style}>
|
||||
{tokens.map((line, i) => (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<div {...getLineProps({ line, key: i })}>
|
||||
{line.map((token, key) => (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<span {...getTokenProps({ token, key })} />
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</pre>
|
||||
)}
|
||||
</Highlight>
|
||||
{(enableCopy || download) && (
|
||||
<div className={styles.buttonWrapper}>
|
||||
{enableCopy && (
|
||||
<button
|
||||
className={styles.button}
|
||||
type="button"
|
||||
aria-label="Copy content"
|
||||
title="Copy content"
|
||||
onClick={handleCopy}
|
||||
>
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
{download && (
|
||||
<button
|
||||
className={styles.button}
|
||||
type="button"
|
||||
aria-label="Download content as file"
|
||||
title="Download content as file"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M5 20h14v-2H5v2zM19 9h-4V3H9v6H5l7 7 7-7z" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Codeblock;
|
||||
3
server/ui/src/components/Codeblock/index.ts
Normal file
3
server/ui/src/components/Codeblock/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import Codeblock from "./Codeblock";
|
||||
|
||||
export default Codeblock;
|
||||
Loading…
Add table
Add a link
Reference in a new issue