Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
308 changes: 158 additions & 150 deletions app/[docs_id]/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,166 +5,174 @@ import { PythonEmbeddedTerminal } from "../terminal/python/embedded";
import { Heading } from "./section";
import { AceLang, EditorComponent } from "../terminal/editor";
import { ExecFile, ExecLang } from "../terminal/exec";
import { ChangeTheme } from "./themeToggle";
import { vscDarkPlus, prism } from "react-syntax-highlighter/dist/esm/styles/prism";



export function StyledMarkdown({ content }: { content: string }) {
return (
<Markdown remarkPlugins={[remarkGfm]} components={components}>
{content}
</Markdown>
);
}
const syntaxtheme = ChangeTheme() === "twilight" ? vscDarkPlus : prism;

// TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある
const components: Components = {
h1: ({ children }) => <Heading level={1}>{children}</Heading>,
h2: ({ children }) => <Heading level={2}>{children}</Heading>,
h3: ({ children }) => <Heading level={3}>{children}</Heading>,
h4: ({ children }) => <Heading level={4}>{children}</Heading>,
h5: ({ children }) => <Heading level={5}>{children}</Heading>,
h6: ({ children }) => <Heading level={6}>{children}</Heading>,
p: ({ node, ...props }) => <p className="mx-2 my-2" {...props} />,
ul: ({ node, ...props }) => (
<ul className="list-disc list-outside ml-6 my-2" {...props} />
),
ol: ({ node, ...props }) => (
<ol className="list-decimal list-outside ml-6 my-2" {...props} />
),
li: ({ node, ...props }) => <li className="my-1" {...props} />,
a: ({ node, ...props }) => <a className="link link-info" {...props} />,
strong: ({ node, ...props }) => (
<strong className="text-primary" {...props} />
),
table: ({ node, ...props }) => (
<div className="w-max max-w-full overflow-x-auto mx-auto my-2 rounded-lg border border-base-content/5 shadow-sm">
<table className="table w-max" {...props} />
</div>
),
hr: ({ node, ...props }) => <hr className="border-primary my-4" {...props} />,
pre: ({ node, ...props }) => props.children,
code: ({ node, className, ref, style, ...props }) => {
const match = /^language-(\w+)(-repl|-exec|-readonly)?\:?(.+)?$/.exec(
className || ""
);
if (match) {
if (match[2] === "-exec" && match[3]) {
/*
```python-exec:main.py
hello, world!
```
---------------------------
[▶ 実行] `python main.py`
// TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある
const components: Components = {
h1: ({ children }) => <Heading level={1}>{children}</Heading>,
h2: ({ children }) => <Heading level={2}>{children}</Heading>,
h3: ({ children }) => <Heading level={3}>{children}</Heading>,
h4: ({ children }) => <Heading level={4}>{children}</Heading>,
h5: ({ children }) => <Heading level={5}>{children}</Heading>,
h6: ({ children }) => <Heading level={6}>{children}</Heading>,
p: ({ node, ...props }) => <p className="mx-2 my-2" {...props} />,
ul: ({ node, ...props }) => (
<ul className="list-disc list-outside ml-6 my-2" {...props} />
),
ol: ({ node, ...props }) => (
<ol className="list-decimal list-outside ml-6 my-2" {...props} />
),
li: ({ node, ...props }) => <li className="my-1" {...props} />,
a: ({ node, ...props }) => <a className="link link-info" {...props} />,
strong: ({ node, ...props }) => (
<strong className="text-primary" {...props} />
),
table: ({ node, ...props }) => (
<div className="w-max max-w-full overflow-x-auto mx-auto my-2 rounded-lg border border-base-content/5 shadow-sm">
<table className="table w-max" {...props} />
</div>
),
hr: ({ node, ...props }) => <hr className="border-primary my-4" {...props} />,
pre: ({ node, ...props }) => props.children,
code: ({ node, className, ref, style, ...props }) => {
const match = /^language-(\w+)(-repl|-exec|-readonly)?\:?(.+)?$/.exec(
className || ""
);
if (match) {
if (match[2] === "-exec" && match[3]) {
/*
```python-exec:main.py
hello, world!
---------------------------
*/
let execLang: ExecLang | undefined = undefined;
switch (match[1]) {
case "python":
execLang = "python";
break;
case "cpp":
case "c++":
execLang = "cpp";
break;
default:
console.warn(`Unsupported language for exec: ${match[1]}`);
break;
}
if (execLang) {
```
---------------------------
[▶ 実行] `python main.py`
hello, world!
---------------------------
*/
let execLang: ExecLang | undefined = undefined;
switch (match[1]) {
case "python":
execLang = "python";
break;
case "cpp":
case "c++":
execLang = "cpp";
break;
default:
console.warn(`Unsupported language for exec: ${match[1]}`);
break;
}
if (execLang) {
return (
<div className="border border-primary border-2 shadow-md m-2 rounded-lg">
<ExecFile
language={execLang}
filenames={match[3].split(",")}
content={String(props.children || "").replace(/\n$/, "")}
/>
</div>
);
}
} else if (match[3]) {
// ファイル名指定がある場合、ファイルエディター
let aceLang: AceLang | undefined = undefined;
switch (match[1]) {
case "python":
aceLang = "python";
break;
case "cpp":
case "c++":
aceLang = "c_cpp";
break;
case "json":
aceLang = "json";
break;
case "csv":
aceLang = "csv";
break;
case "text":
case "txt":
aceLang = "text";
break;
default:
console.warn(`Unsupported language for editor: ${match[1]}`);
break;
}
return (
<div className="border border-primary border-2 shadow-md m-2 rounded-lg">
<ExecFile
language={execLang}
filenames={match[3].split(",")}
content={String(props.children || "").replace(/\n$/, "")}
<EditorComponent
language={aceLang}
tabSize={4}
filename={match[3]}
readonly={match[2] === "-readonly"}
initContent={String(props.children || "").replace(/\n$/, "")}
/>
</div>
);
}
} else if (match[3]) {
// ファイル名指定がある場合、ファイルエディター
let aceLang: AceLang | undefined = undefined;
switch (match[1]) {
case "python":
aceLang = "python";
break;
case "cpp":
case "c++":
aceLang = "c_cpp";
break;
case "json":
aceLang = "json";
break;
case "csv":
aceLang = "csv";
break;
case "text":
case "txt":
aceLang = "text";
break;
default:
console.warn(`Unsupported language for editor: ${match[1]}`);
break;
} else if (match[2] === "-repl") {
// repl付きの言語指定
// 現状はPythonのみ対応
switch (match[1]) {
case "python":
return (
<div className="bg-base-300 border border-primary border-2 shadow-md m-2 p-4 pr-1 rounded-lg">
<PythonEmbeddedTerminal
content={String(props.children || "").replace(/\n$/, "")}
/>
</div>
);
default:
console.warn(`Unsupported language for repl: ${match[1]}`);
break;
}
}
return (
<div className="border border-primary border-2 shadow-md m-2 rounded-lg">
<EditorComponent
language={aceLang}
tabSize={4}
filename={match[3]}
readonly={match[2] === "-readonly"}
initContent={String(props.children || "").replace(/\n$/, "")}
/>
</div>
<SyntaxHighlighter
language={match[1]}
PreTag="div"
className="border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
style={syntaxtheme}
Comment thread
na-trium-144 marked this conversation as resolved.
Outdated
{...props}
>
{String(props.children || "").replace(/\n$/, "")}
</SyntaxHighlighter>
);
} else if (String(props.children).includes("\n")) {
// 言語指定なしコードブロック
return (
<SyntaxHighlighter
PreTag="div"
className="border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
style={syntaxtheme}
{...props}
>
{String(props.children || "").replace(/\n$/, "")}
</SyntaxHighlighter>
);
} else {
// inline
return (
<code
className="bg-base-200/60 border border-base-300 px-1 py-0.5 rounded text-sm "
{...props}
/>
);
} else if (match[2] === "-repl") {
// repl付きの言語指定
// 現状はPythonのみ対応
switch (match[1]) {
case "python":
return (
<div className="bg-base-300 border border-primary border-2 shadow-md m-2 p-4 pr-1 rounded-lg">
<PythonEmbeddedTerminal
content={String(props.children || "").replace(/\n$/, "")}
/>
</div>
);
default:
console.warn(`Unsupported language for repl: ${match[1]}`);
break;
}
}
return (
<SyntaxHighlighter
language={match[1]}
PreTag="div"
className="border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
// style={todo dark theme?}
{...props}
>
{String(props.children || "").replace(/\n$/, "")}
</SyntaxHighlighter>
);
} else if (String(props.children).includes("\n")) {
// 言語指定なしコードブロック
return (
<SyntaxHighlighter
PreTag="div"
className="border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
// style={todo dark theme?}
{...props}
>
{String(props.children || "").replace(/\n$/, "")}
</SyntaxHighlighter>
);
} else {
// inline
return (
<code
className="bg-base-200/60 border border-base-300 px-1 py-0.5 rounded text-sm "
{...props}
/>
);
}
},
};
},
};

return (
<Markdown remarkPlugins={[remarkGfm]} components={components}>
Comment thread
na-trium-144 marked this conversation as resolved.
{content}
</Markdown>
);
}


38 changes: 38 additions & 0 deletions app/[docs_id]/themeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";
import { useState, useEffect } from "react";

export function ChangeTheme(){
const [theme, setTheme] = useState("tomorrow");
useEffect(() => {
const updateTheme = () => {
const theme = document.documentElement.getAttribute("data-theme");
setTheme(theme === "dark" ? "twilight" : "tomorrow");
};

const observer = new MutationObserver(updateTheme);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});

updateTheme(); // 初回実行

return () => observer.disconnect();
}, []);
return theme;

};
Comment thread
na-trium-144 marked this conversation as resolved.
Outdated
export function ThemeToggle() {
return (
<input
type="checkbox"
className="toggle theme-controller"
style={{ marginLeft: "1em" }}
onChange={(e) => {
const isDark = e.target.checked;
const theme = isDark ? "dark" : "light";
document.documentElement.setAttribute("data-theme", theme);
}}
/>
);
Comment thread
na-trium-144 marked this conversation as resolved.
}
7 changes: 6 additions & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
@import "tailwindcss";
@plugin "daisyui";
@plugin "daisyui"
{
themes: light --default, dark --prefersdark;
};



/* inconsolata-latin-wght-normal */
@font-face {
Expand Down
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function RootLayout({
children,
}: Readonly<{ children: ReactNode }>) {
return (
<html lang="ja">
<html lang="ja" data-theme="light">
Comment thread
na-trium-144 marked this conversation as resolved.
Outdated
<body className="w-screen h-screen">
<div className="drawer lg:drawer-open">
<input id="drawer-toggle" type="checkbox" className="drawer-toggle" />
Expand Down
Loading