@@ -5,166 +5,174 @@ import { PythonEmbeddedTerminal } from "../terminal/python/embedded";
55import { Heading } from "./section" ;
66import { AceLang , EditorComponent } from "../terminal/editor" ;
77import { ExecFile , ExecLang } from "../terminal/exec" ;
8+ import { ChangeTheme } from "./themeToggle" ;
9+ import { vscDarkPlus , prism } from "react-syntax-highlighter/dist/esm/styles/prism" ;
10+
11+
812
913export function StyledMarkdown ( { content } : { content : string } ) {
10- return (
11- < Markdown remarkPlugins = { [ remarkGfm ] } components = { components } >
12- { content }
13- </ Markdown >
14- ) ;
15- }
14+ const syntaxtheme = ChangeTheme ( ) === "twilight" ? vscDarkPlus : prism ;
1615
17- // TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある
18- const components : Components = {
19- h1 : ( { children } ) => < Heading level = { 1 } > { children } </ Heading > ,
20- h2 : ( { children } ) => < Heading level = { 2 } > { children } </ Heading > ,
21- h3 : ( { children } ) => < Heading level = { 3 } > { children } </ Heading > ,
22- h4 : ( { children } ) => < Heading level = { 4 } > { children } </ Heading > ,
23- h5 : ( { children } ) => < Heading level = { 5 } > { children } </ Heading > ,
24- h6 : ( { children } ) => < Heading level = { 6 } > { children } </ Heading > ,
25- p : ( { node, ...props } ) => < p className = "mx-2 my-2" { ...props } /> ,
26- ul : ( { node, ...props } ) => (
27- < ul className = "list-disc list-outside ml-6 my-2" { ...props } />
28- ) ,
29- ol : ( { node, ...props } ) => (
30- < ol className = "list-decimal list-outside ml-6 my-2" { ...props } />
31- ) ,
32- li : ( { node, ...props } ) => < li className = "my-1" { ...props } /> ,
33- a : ( { node, ...props } ) => < a className = "link link-info" { ...props } /> ,
34- strong : ( { node, ...props } ) => (
35- < strong className = "text-primary" { ...props } />
36- ) ,
37- table : ( { node, ...props } ) => (
38- < div className = "w-max max-w-full overflow-x-auto mx-auto my-2 rounded-lg border border-base-content/5 shadow-sm" >
39- < table className = "table w-max" { ...props } />
40- </ div >
41- ) ,
42- hr : ( { node, ...props } ) => < hr className = "border-primary my-4" { ...props } /> ,
43- pre : ( { node, ...props } ) => props . children ,
44- code : ( { node, className, ref, style, ...props } ) => {
45- const match = / ^ l a n g u a g e - ( \w + ) ( - r e p l | - e x e c | - r e a d o n l y ) ? \: ? ( .+ ) ? $ / . exec (
46- className || ""
47- ) ;
48- if ( match ) {
49- if ( match [ 2 ] === "-exec" && match [ 3 ] ) {
50- /*
51- ```python-exec:main.py
52- hello, world!
53- ```
54- ↓
55- ---------------------------
56- [▶ 実行] `python main.py`
16+ // TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある
17+ const components : Components = {
18+ h1 : ( { children } ) => < Heading level = { 1 } > { children } </ Heading > ,
19+ h2 : ( { children } ) => < Heading level = { 2 } > { children } </ Heading > ,
20+ h3 : ( { children } ) => < Heading level = { 3 } > { children } </ Heading > ,
21+ h4 : ( { children } ) => < Heading level = { 4 } > { children } </ Heading > ,
22+ h5 : ( { children } ) => < Heading level = { 5 } > { children } </ Heading > ,
23+ h6 : ( { children } ) => < Heading level = { 6 } > { children } </ Heading > ,
24+ p : ( { node, ...props } ) => < p className = "mx-2 my-2" { ...props } /> ,
25+ ul : ( { node, ...props } ) => (
26+ < ul className = "list-disc list-outside ml-6 my-2" { ...props } />
27+ ) ,
28+ ol : ( { node, ...props } ) => (
29+ < ol className = "list-decimal list-outside ml-6 my-2" { ...props } />
30+ ) ,
31+ li : ( { node, ...props } ) => < li className = "my-1" { ...props } /> ,
32+ a : ( { node, ...props } ) => < a className = "link link-info" { ...props } /> ,
33+ strong : ( { node, ...props } ) => (
34+ < strong className = "text-primary" { ...props } />
35+ ) ,
36+ table : ( { node, ...props } ) => (
37+ < div className = "w-max max-w-full overflow-x-auto mx-auto my-2 rounded-lg border border-base-content/5 shadow-sm" >
38+ < table className = "table w-max" { ...props } />
39+ </ div >
40+ ) ,
41+ hr : ( { node, ...props } ) => < hr className = "border-primary my-4" { ...props } /> ,
42+ pre : ( { node, ...props } ) => props . children ,
43+ code : ( { node, className, ref, style, ...props } ) => {
44+ const match = / ^ l a n g u a g e - ( \w + ) ( - r e p l | - e x e c | - r e a d o n l y ) ? \: ? ( .+ ) ? $ / . exec (
45+ className || ""
46+ ) ;
47+ if ( match ) {
48+ if ( match [ 2 ] === "-exec" && match [ 3 ] ) {
49+ /*
50+ ```python-exec:main.py
5751 hello, world!
58- ---------------------------
59- */
60- let execLang : ExecLang | undefined = undefined ;
61- switch ( match [ 1 ] ) {
62- case "python" :
63- execLang = "python" ;
64- break ;
65- case "cpp" :
66- case "c++" :
67- execLang = "cpp" ;
68- break ;
69- default :
70- console . warn ( `Unsupported language for exec: ${ match [ 1 ] } ` ) ;
71- break ;
72- }
73- if ( execLang ) {
52+ ```
53+ ↓
54+ ---------------------------
55+ [▶ 実行] `python main.py`
56+ hello, world!
57+ ---------------------------
58+ */
59+ let execLang : ExecLang | undefined = undefined ;
60+ switch ( match [ 1 ] ) {
61+ case "python" :
62+ execLang = "python" ;
63+ break ;
64+ case "cpp" :
65+ case "c++" :
66+ execLang = "cpp" ;
67+ break ;
68+ default :
69+ console . warn ( `Unsupported language for exec: ${ match [ 1 ] } ` ) ;
70+ break ;
71+ }
72+ if ( execLang ) {
73+ return (
74+ < div className = "border border-primary border-2 shadow-md m-2 rounded-lg" >
75+ < ExecFile
76+ language = { execLang }
77+ filenames = { match [ 3 ] . split ( "," ) }
78+ content = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
79+ />
80+ </ div >
81+ ) ;
82+ }
83+ } else if ( match [ 3 ] ) {
84+ // ファイル名指定がある場合、ファイルエディター
85+ let aceLang : AceLang | undefined = undefined ;
86+ switch ( match [ 1 ] ) {
87+ case "python" :
88+ aceLang = "python" ;
89+ break ;
90+ case "cpp" :
91+ case "c++" :
92+ aceLang = "c_cpp" ;
93+ break ;
94+ case "json" :
95+ aceLang = "json" ;
96+ break ;
97+ case "csv" :
98+ aceLang = "csv" ;
99+ break ;
100+ case "text" :
101+ case "txt" :
102+ aceLang = "text" ;
103+ break ;
104+ default :
105+ console . warn ( `Unsupported language for editor: ${ match [ 1 ] } ` ) ;
106+ break ;
107+ }
74108 return (
75109 < div className = "border border-primary border-2 shadow-md m-2 rounded-lg" >
76- < ExecFile
77- language = { execLang }
78- filenames = { match [ 3 ] . split ( "," ) }
79- content = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
110+ < EditorComponent
111+ language = { aceLang }
112+ tabSize = { 4 }
113+ filename = { match [ 3 ] }
114+ readonly = { match [ 2 ] === "-readonly" }
115+ initContent = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
80116 />
81117 </ div >
82118 ) ;
83- }
84- } else if ( match [ 3 ] ) {
85- // ファイル名指定がある場合、ファイルエディター
86- let aceLang : AceLang | undefined = undefined ;
87- switch ( match [ 1 ] ) {
88- case "python" :
89- aceLang = "python" ;
90- break ;
91- case "cpp" :
92- case "c++" :
93- aceLang = "c_cpp" ;
94- break ;
95- case "json" :
96- aceLang = "json" ;
97- break ;
98- case "csv" :
99- aceLang = "csv" ;
100- break ;
101- case "text" :
102- case "txt" :
103- aceLang = "text" ;
104- break ;
105- default :
106- console . warn ( `Unsupported language for editor: ${ match [ 1 ] } ` ) ;
107- break ;
119+ } else if ( match [ 2 ] === "-repl" ) {
120+ // repl付きの言語指定
121+ // 現状はPythonのみ対応
122+ switch ( match [ 1 ] ) {
123+ case "python" :
124+ return (
125+ < div className = "bg-base-300 border border-primary border-2 shadow-md m-2 p-4 pr-1 rounded-lg" >
126+ < PythonEmbeddedTerminal
127+ content = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
128+ />
129+ </ div >
130+ ) ;
131+ default :
132+ console . warn ( `Unsupported language for repl: ${ match [ 1 ] } ` ) ;
133+ break ;
134+ }
108135 }
109136 return (
110- < div className = "border border-primary border-2 shadow-md m-2 rounded-lg" >
111- < EditorComponent
112- language = { aceLang }
113- tabSize = { 4 }
114- filename = { match [ 3 ] }
115- readonly = { match [ 2 ] === "-readonly" }
116- initContent = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
117- />
118- </ div >
137+ < SyntaxHighlighter
138+ language = { match [ 1 ] }
139+ PreTag = "div"
140+ className = "border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
141+ style = { syntaxtheme }
142+ { ...props }
143+ >
144+ { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
145+ </ SyntaxHighlighter >
146+ ) ;
147+ } else if ( String ( props . children ) . includes ( "\n" ) ) {
148+ // 言語指定なしコードブロック
149+ return (
150+ < SyntaxHighlighter
151+ PreTag = "div"
152+ className = "border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
153+ style = { syntaxtheme }
154+ { ...props }
155+ >
156+ { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
157+ </ SyntaxHighlighter >
158+ ) ;
159+ } else {
160+ // inline
161+ return (
162+ < code
163+ className = "bg-base-200/60 border border-base-300 px-1 py-0.5 rounded text-sm "
164+ { ...props }
165+ />
119166 ) ;
120- } else if ( match [ 2 ] === "-repl" ) {
121- // repl付きの言語指定
122- // 現状はPythonのみ対応
123- switch ( match [ 1 ] ) {
124- case "python" :
125- return (
126- < div className = "bg-base-300 border border-primary border-2 shadow-md m-2 p-4 pr-1 rounded-lg" >
127- < PythonEmbeddedTerminal
128- content = { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
129- />
130- </ div >
131- ) ;
132- default :
133- console . warn ( `Unsupported language for repl: ${ match [ 1 ] } ` ) ;
134- break ;
135- }
136167 }
137- return (
138- < SyntaxHighlighter
139- language = { match [ 1 ] }
140- PreTag = "div"
141- className = "border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
142- // style={todo dark theme?}
143- { ...props }
144- >
145- { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
146- </ SyntaxHighlighter >
147- ) ;
148- } else if ( String ( props . children ) . includes ( "\n" ) ) {
149- // 言語指定なしコードブロック
150- return (
151- < SyntaxHighlighter
152- PreTag = "div"
153- className = "border border-base-300 mx-2 my-2 rounded-lg text-sm! m-2! p-4!"
154- // style={todo dark theme?}
155- { ...props }
156- >
157- { String ( props . children || "" ) . replace ( / \n $ / , "" ) }
158- </ SyntaxHighlighter >
159- ) ;
160- } else {
161- // inline
162- return (
163- < code
164- className = "bg-base-200/60 border border-base-300 px-1 py-0.5 rounded text-sm "
165- { ...props }
166- />
167- ) ;
168- }
169- } ,
170- } ;
168+ } ,
169+ } ;
170+
171+ return (
172+ < Markdown remarkPlugins = { [ remarkGfm ] } components = { components } >
173+ { content }
174+ </ Markdown >
175+ ) ;
176+ }
177+
178+
0 commit comments