mirror of
https://github.com/usememos/memos.git
synced 2024-11-10 17:02:21 +08:00
feat: add code wrapping option on mobile devices (#3196)
* feat: add code wrapping option on mobile devices * Minor changes * oopsie
This commit is contained in:
parent
71c39ed554
commit
8ee56bd29f
3 changed files with 52 additions and 25 deletions
|
@ -1,7 +1,11 @@
|
||||||
|
import { Checkbox } from "@mui/joy";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import hljs from "highlight.js";
|
import hljs from "highlight.js";
|
||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
import MermaidBlock from "./MermaidBlock";
|
import MermaidBlock from "./MermaidBlock";
|
||||||
import { BaseProps } from "./types";
|
import { BaseProps } from "./types";
|
||||||
|
@ -18,7 +22,8 @@ interface Props extends BaseProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
|
const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
|
||||||
const formatedLanguage = (language || "").toLowerCase() || "text";
|
const formatedLanguage = useMemo(() => (language || "").toLowerCase() || "text", [language]);
|
||||||
|
|
||||||
// Users can set Markdown code blocks as `__html` to render HTML directly.
|
// Users can set Markdown code blocks as `__html` to render HTML directly.
|
||||||
if (formatedLanguage === SpecialLanguage.HTML) {
|
if (formatedLanguage === SpecialLanguage.HTML) {
|
||||||
return <div className="w-full overflow-auto !my-2" dangerouslySetInnerHTML={{ __html: content }} />;
|
return <div className="w-full overflow-auto !my-2" dangerouslySetInnerHTML={{ __html: content }} />;
|
||||||
|
@ -26,37 +31,57 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
|
||||||
return <MermaidBlock content={content} />;
|
return <MermaidBlock content={content} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
let highlightedCode = content;
|
const { md } = useResponsiveWidth();
|
||||||
try {
|
const t = useTranslate();
|
||||||
const lang = hljs.getLanguage(formatedLanguage);
|
|
||||||
if (lang) {
|
|
||||||
const temp = hljs.highlight(content, {
|
|
||||||
language: formatedLanguage,
|
|
||||||
}).value;
|
|
||||||
highlightedCode = temp;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Skip error and use default highlighted code.
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCopyButtonClick = () => {
|
const [wrap, setWrap] = useState(true);
|
||||||
|
const handleWrapChange = useCallback(() => setWrap(!wrap), [setWrap, wrap]);
|
||||||
|
|
||||||
|
const highlightedCode: string = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const lang = hljs.getLanguage(formatedLanguage);
|
||||||
|
if (lang) {
|
||||||
|
return hljs.highlight(content, {
|
||||||
|
language: formatedLanguage,
|
||||||
|
}).value;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Skip error and use default highlighted code.
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}, [formatedLanguage, content]);
|
||||||
|
|
||||||
|
const handleCopyButtonClick = useCallback(() => {
|
||||||
copy(content);
|
copy(content);
|
||||||
toast.success("Copied to clipboard!");
|
toast.success("Copied to clipboard!");
|
||||||
};
|
}, [content]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full my-1 bg-amber-100 border-l-4 border-amber-400 rounded overflow-clip hover:shadow dark:bg-zinc-600 dark:border-zinc-400">
|
<div className="w-full my-1 bg-amber-100 border-l-4 border-amber-400 rounded hover:shadow dark:bg-zinc-600 dark:border-zinc-400 relative">
|
||||||
<div className="w-full px-2 py-1 flex flex-row justify-between items-center text-amber-500 dark:text-zinc-400">
|
<div className="w-full px-2 py-1 flex flex-row justify-between items-center text-amber-500 dark:text-zinc-400">
|
||||||
<span className="text-sm font-mono">{formatedLanguage}</span>
|
<span className="text-sm font-mono">{formatedLanguage}</span>
|
||||||
<Icon.Copy className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />
|
{md && <Icon.Copy className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<pre className="w-full p-2 bg-amber-50 dark:bg-zinc-700 whitespace-pre-wrap relative">
|
<div className="overflow-auto">
|
||||||
<code
|
<pre
|
||||||
className={classNames(`language-${formatedLanguage}`, "block text-sm leading-5")}
|
className={classNames(wrap ? "whitespace-pre-wrap" : "no-wrap overflow-auto", "w-full p-2 bg-amber-50 dark:bg-zinc-700 relative")}
|
||||||
dangerouslySetInnerHTML={{ __html: highlightedCode }}
|
>
|
||||||
></code>
|
<code
|
||||||
</pre>
|
className={classNames(`language-${formatedLanguage}`, "block text-sm leading-5")}
|
||||||
|
dangerouslySetInnerHTML={{ __html: highlightedCode }}
|
||||||
|
></code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
{!md && (
|
||||||
|
<div className="sticky flex px-2 h-8 bottom-0 bg-amber-100 dark:bg-zinc-600 rounded items-center">
|
||||||
|
<div className="grow h-full">
|
||||||
|
<Checkbox className="h-full items-center" label={t("memo.wrapping")} size="sm" checked={wrap} onChange={handleWrapChange} />
|
||||||
|
</div>
|
||||||
|
<Icon.Copy className="w-4 h-full cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -105,7 +105,8 @@
|
||||||
"self": "Comments",
|
"self": "Comments",
|
||||||
"no-comment": "No comment"
|
"no-comment": "No comment"
|
||||||
},
|
},
|
||||||
"show-more": "Show more"
|
"show-more": "Show more",
|
||||||
|
"wrapping": "Wrapping"
|
||||||
},
|
},
|
||||||
"reference": {
|
"reference": {
|
||||||
"add-references": "Add references",
|
"add-references": "Add references",
|
||||||
|
|
|
@ -122,7 +122,8 @@
|
||||||
"private": "Видно только вам",
|
"private": "Видно только вам",
|
||||||
"protected": "Видно только пользователям",
|
"protected": "Видно только пользователям",
|
||||||
"public": "Видно всем"
|
"public": "Видно всем"
|
||||||
}
|
},
|
||||||
|
"wrapping": "Перенос"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"change-memo-created-time": "Изменить время создания записи",
|
"change-memo-created-time": "Изменить время создания записи",
|
||||||
|
|
Loading…
Reference in a new issue