code layout
This commit is contained in:
@ -479,29 +479,63 @@ body {
|
|||||||
color: #656d76;
|
color: #656d76;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Molokai-inspired code blocks */
|
||||||
.article-body pre {
|
.article-body pre {
|
||||||
background: #f6f8fa;
|
background: #1B1D1E;
|
||||||
border: 1px solid #d1d9e0;
|
border: 1px solid #3E3D32;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 0;
|
||||||
overflow-x: auto;
|
overflow: hidden;
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body code {
|
/* Code filename header */
|
||||||
background: #f6f8fa;
|
.article-body pre[data-filename]::before {
|
||||||
padding: 2px 4px;
|
content: attr(data-filename);
|
||||||
border-radius: 4px;
|
display: block;
|
||||||
|
background: #272822;
|
||||||
|
color: #A6E22E;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-bottom: 1px solid #3E3D32;
|
||||||
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
|
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body pre code {
|
.article-body pre code {
|
||||||
|
display: block;
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 16px;
|
||||||
|
color: #F8F8F2;
|
||||||
|
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
|
||||||
|
overflow-x: auto;
|
||||||
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
.article-body code {
|
||||||
|
background: #2F3129;
|
||||||
|
color: #A6E22E;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid #3E3D32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Molokai color scheme for syntax highlighting */
|
||||||
|
.article-body pre code .hljs-keyword { color: #F92672; }
|
||||||
|
.article-body pre code .hljs-string { color: #E6DB74; }
|
||||||
|
.article-body pre code .hljs-comment { color: #75715E; font-style: italic; }
|
||||||
|
.article-body pre code .hljs-number { color: #AE81FF; }
|
||||||
|
.article-body pre code .hljs-variable { color: #FD971F; }
|
||||||
|
.article-body pre code .hljs-function { color: #A6E22E; }
|
||||||
|
.article-body pre code .hljs-tag { color: #F92672; }
|
||||||
|
.article-body pre code .hljs-attr { color: #A6E22E; }
|
||||||
|
.article-body pre code .hljs-value { color: #E6DB74; }
|
||||||
|
|
||||||
/* Sidebar styles */
|
/* Sidebar styles */
|
||||||
.article-sidebar {
|
.article-sidebar {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
@ -92,8 +92,8 @@ impl MarkdownProcessor {
|
|||||||
for event in parser {
|
for event in parser {
|
||||||
match event {
|
match event {
|
||||||
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(kind)) => {
|
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(kind)) => {
|
||||||
if let CodeBlockKind::Fenced(lang) = &kind {
|
if let CodeBlockKind::Fenced(lang_info) = &kind {
|
||||||
code_block = Some((String::new(), lang.to_string()));
|
code_block = Some((String::new(), lang_info.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::Text(text) => {
|
pulldown_cmark::Event::Text(text) => {
|
||||||
@ -104,8 +104,8 @@ impl MarkdownProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::End(pulldown_cmark::TagEnd::CodeBlock) => {
|
pulldown_cmark::Event::End(pulldown_cmark::TagEnd::CodeBlock) => {
|
||||||
if let Some((code, lang)) = code_block.take() {
|
if let Some((code, lang_info)) = code_block.take() {
|
||||||
let highlighted = self.highlight_code_block(&code, &lang, theme);
|
let highlighted = self.highlight_code_block(&code, &lang_info, theme);
|
||||||
events.push(pulldown_cmark::Event::Html(highlighted.into()));
|
events.push(pulldown_cmark::Event::Html(highlighted.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,13 +117,29 @@ impl MarkdownProcessor {
|
|||||||
Ok(html_output)
|
Ok(html_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_code_block(&self, code: &str, lang: &str, theme: &syntect::highlighting::Theme) -> String {
|
fn highlight_code_block(&self, code: &str, lang_info: &str, theme: &syntect::highlighting::Theme) -> String {
|
||||||
|
// Parse language and filename from lang_info (e.g., "sh:/path/to/file" or "rust:main.rs")
|
||||||
|
let (lang, filename) = if lang_info.contains(':') {
|
||||||
|
let parts: Vec<&str> = lang_info.splitn(2, ':').collect();
|
||||||
|
(parts[0], Some(parts[1]))
|
||||||
|
} else {
|
||||||
|
(lang_info, None)
|
||||||
|
};
|
||||||
|
|
||||||
let syntax = self.syntax_set
|
let syntax = self.syntax_set
|
||||||
.find_syntax_by_token(lang)
|
.find_syntax_by_token(lang)
|
||||||
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
|
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
|
||||||
|
|
||||||
let mut highlighter = syntect::easy::HighlightLines::new(syntax, theme);
|
let mut highlighter = syntect::easy::HighlightLines::new(syntax, theme);
|
||||||
let mut output = String::from("<pre><code>");
|
|
||||||
|
// Create pre tag with optional filename attribute
|
||||||
|
let pre_tag = if let Some(filename) = filename {
|
||||||
|
format!("<pre data-filename=\"{}\">", filename)
|
||||||
|
} else {
|
||||||
|
"<pre>".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output = format!("{}<code>", pre_tag);
|
||||||
|
|
||||||
for line in code.lines() {
|
for line in code.lines() {
|
||||||
let ranges = highlighter.highlight_line(line, &self.syntax_set).unwrap();
|
let ranges = highlighter.highlight_line(line, &self.syntax_set).unwrap();
|
||||||
|
Reference in New Issue
Block a user