This commit is contained in:
parent
0025e453e8
commit
b03d27cc3a
20 changed files with 1052 additions and 330 deletions
|
|
@ -279,7 +279,8 @@ authorName: "Neeldhara"
|
|||
- Standard Markdown headings, lists, links, tables, code fences, footnotes, and raw HTML are preserved.
|
||||
- Use colocated relative assets: \`\`.
|
||||
- Quarto image attributes such as \`{width=70%}\` are removed during import. Use normal Markdown now; layout should be handled by Astro CSS.
|
||||
- Quarto callouts are converted to simple blockquotes:
|
||||
- Quarto callouts are converted to simple blockquotes. The callout type controls
|
||||
styling only; it does not create a visible heading by default:
|
||||
|
||||
\`\`\`markdown
|
||||
> **Note**
|
||||
|
|
@ -287,14 +288,22 @@ authorName: "Neeldhara"
|
|||
> Text of the callout.
|
||||
\`\`\`
|
||||
|
||||
- For new notes, use the same blockquote convention for portable callouts:
|
||||
- For new notes, the bracket form is also supported:
|
||||
|
||||
\`\`\`markdown
|
||||
> **Warning**
|
||||
> [!warning]
|
||||
>
|
||||
> This point needs attention.
|
||||
\`\`\`
|
||||
|
||||
- To show a heading, put it explicitly inside the bracket after \`:\` or \`|\`:
|
||||
|
||||
\`\`\`markdown
|
||||
> [!tip: Useful observation]
|
||||
>
|
||||
> Text of the callout.
|
||||
\`\`\`
|
||||
|
||||
- Quarto margin notes such as \`[text]{.aside}\` are converted to:
|
||||
|
||||
\`\`\`markdown
|
||||
|
|
|
|||
|
|
@ -101,6 +101,13 @@ local function first_inline_text(block)
|
|||
return inline_text(block.content[1])
|
||||
end
|
||||
|
||||
local function paragraph_text(block)
|
||||
if not block or block.t ~= "Para" then
|
||||
return ""
|
||||
end
|
||||
return pandoc.utils.stringify(block)
|
||||
end
|
||||
|
||||
local function latex_escape(value)
|
||||
value = tostring(value or "")
|
||||
value = value:gsub("\\", "\\textbackslash{}")
|
||||
|
|
@ -356,6 +363,70 @@ local function strip_text_prefix(block, pattern)
|
|||
end
|
||||
end
|
||||
|
||||
local function cleanup_inline_start(block)
|
||||
if not block or block.t ~= "Para" or not block.content then
|
||||
return
|
||||
end
|
||||
|
||||
while #block.content > 0 do
|
||||
local first = block.content[1]
|
||||
if first.t == "Space" or first.t == "SoftBreak" or first.t == "LineBreak" then
|
||||
table.remove(block.content, 1)
|
||||
elseif first.t == "Str" then
|
||||
first.text = first.text:gsub("^%s+", "")
|
||||
if first.text == "" then
|
||||
table.remove(block.content, 1)
|
||||
else
|
||||
return
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function strip_bracket_callout(block)
|
||||
if not block or block.t ~= "Para" or not block.content then
|
||||
return
|
||||
end
|
||||
|
||||
while #block.content > 0 do
|
||||
local first = block.content[1]
|
||||
local text = inline_text(first)
|
||||
local close_index = text:find("%]")
|
||||
|
||||
if close_index then
|
||||
local remaining = text:sub(close_index + 1):gsub("^%s+", "")
|
||||
if first.t == "Str" and remaining ~= "" then
|
||||
first.text = remaining
|
||||
elseif remaining ~= "" then
|
||||
block.content[1] = pandoc.Str(remaining)
|
||||
else
|
||||
table.remove(block.content, 1)
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
table.remove(block.content, 1)
|
||||
end
|
||||
|
||||
cleanup_inline_start(block)
|
||||
end
|
||||
|
||||
local function parse_bracket_callout(text)
|
||||
local key, title = text:match("^%s*%[!([%a-]+)%s*[:|]%s*([^%]]+)%]")
|
||||
if key then
|
||||
return normalize_label(key), title:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
key = text:match("^%s*%[!([%a-]+)%]")
|
||||
if key then
|
||||
return normalize_label(key), ""
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local function detect_callout(block)
|
||||
local text = first_inline_text(block)
|
||||
if text == "" then
|
||||
|
|
@ -365,21 +436,18 @@ local function detect_callout(block)
|
|||
if block.content[1].t == "Strong" then
|
||||
local key = normalize_label(text)
|
||||
if callout_labels[key] then
|
||||
return { key = key, label = callout_labels[key], remover = "strong" }
|
||||
return { key = key, title = "", remover = "strong" }
|
||||
end
|
||||
end
|
||||
|
||||
local bracket = text:match("^%[!([%a-]+)%]")
|
||||
if bracket then
|
||||
local key = normalize_label(bracket)
|
||||
if callout_labels[key] then
|
||||
return { key = key, label = callout_labels[key], remover = "bracket" }
|
||||
end
|
||||
local key, title = parse_bracket_callout(paragraph_text(block))
|
||||
if key and callout_labels[key] then
|
||||
return { key = key, title = title or "", remover = "bracket" }
|
||||
end
|
||||
|
||||
for _, item in ipairs(callout_markers) do
|
||||
if text:sub(1, #item.marker) == item.marker then
|
||||
return { key = item.key, label = callout_labels[item.key], remover = "marker", marker = item.marker }
|
||||
return { key = item.key, title = "", remover = "marker", marker = item.marker }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -400,7 +468,7 @@ local function callout_to_latex(el)
|
|||
if callout.remover == "strong" then
|
||||
remove_first_inline(blocks[1])
|
||||
elseif callout.remover == "bracket" then
|
||||
strip_text_prefix(blocks[1], "^%[![%a-]+%]%s*")
|
||||
strip_bracket_callout(blocks[1])
|
||||
elseif callout.remover == "marker" then
|
||||
strip_text_prefix(blocks[1], "^" .. callout.marker .. "%s*")
|
||||
end
|
||||
|
|
@ -412,7 +480,7 @@ local function callout_to_latex(el)
|
|||
local env = callout_envs[callout.key] or "blognotebox"
|
||||
return pandoc.RawBlock(
|
||||
"latex",
|
||||
"\\begin{" .. env .. "}{}\n"
|
||||
"\\begin{" .. env .. "}{" .. latex_escape(callout.title or "") .. "}\n"
|
||||
.. blocks_to_latex(blocks)
|
||||
.. "\n\\end{" .. env .. "}"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -46,49 +46,119 @@
|
|||
}
|
||||
}
|
||||
|
||||
\newtcolorbox{blognotebox}[2][]{
|
||||
blog callout,
|
||||
title={NOTE\if\relax\detokenize{#2}\relax\else: #2\fi},
|
||||
colback=BlogCalloutNoteBack,
|
||||
colframe=BlogCalloutNoteFrame,
|
||||
boxed title style={colback=BlogCalloutNoteBack},
|
||||
#1
|
||||
\NewDocumentEnvironment{blognotebox}{O{} m}{%
|
||||
\if\relax\detokenize{#2}\relax
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
colback=BlogCalloutNoteBack,
|
||||
colframe=BlogCalloutNoteFrame,
|
||||
boxed title style={colback=BlogCalloutNoteBack},
|
||||
#1
|
||||
]%
|
||||
\else
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
title={#2},
|
||||
colback=BlogCalloutNoteBack,
|
||||
colframe=BlogCalloutNoteFrame,
|
||||
boxed title style={colback=BlogCalloutNoteBack},
|
||||
#1
|
||||
]%
|
||||
\fi
|
||||
}{%
|
||||
\end{tcolorbox}%
|
||||
}
|
||||
|
||||
\newtcolorbox{blogtipbox}[2][]{
|
||||
blog callout,
|
||||
title={TIP\if\relax\detokenize{#2}\relax\else: #2\fi},
|
||||
colback=BlogCalloutTipBack,
|
||||
colframe=BlogCalloutTipFrame,
|
||||
boxed title style={colback=BlogCalloutTipBack},
|
||||
#1
|
||||
\NewDocumentEnvironment{blogtipbox}{O{} m}{%
|
||||
\if\relax\detokenize{#2}\relax
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
colback=BlogCalloutTipBack,
|
||||
colframe=BlogCalloutTipFrame,
|
||||
boxed title style={colback=BlogCalloutTipBack},
|
||||
#1
|
||||
]%
|
||||
\else
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
title={#2},
|
||||
colback=BlogCalloutTipBack,
|
||||
colframe=BlogCalloutTipFrame,
|
||||
boxed title style={colback=BlogCalloutTipBack},
|
||||
#1
|
||||
]%
|
||||
\fi
|
||||
}{%
|
||||
\end{tcolorbox}%
|
||||
}
|
||||
|
||||
\newtcolorbox{blogwarningbox}[2][]{
|
||||
blog callout,
|
||||
title={WARNING\if\relax\detokenize{#2}\relax\else: #2\fi},
|
||||
colback=BlogCalloutWarningBack,
|
||||
colframe=BlogCalloutWarningFrame,
|
||||
boxed title style={colback=BlogCalloutWarningBack},
|
||||
#1
|
||||
\NewDocumentEnvironment{blogwarningbox}{O{} m}{%
|
||||
\if\relax\detokenize{#2}\relax
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
colback=BlogCalloutWarningBack,
|
||||
colframe=BlogCalloutWarningFrame,
|
||||
boxed title style={colback=BlogCalloutWarningBack},
|
||||
#1
|
||||
]%
|
||||
\else
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
title={#2},
|
||||
colback=BlogCalloutWarningBack,
|
||||
colframe=BlogCalloutWarningFrame,
|
||||
boxed title style={colback=BlogCalloutWarningBack},
|
||||
#1
|
||||
]%
|
||||
\fi
|
||||
}{%
|
||||
\end{tcolorbox}%
|
||||
}
|
||||
|
||||
\newtcolorbox{blogcautionbox}[2][]{
|
||||
blog callout,
|
||||
title={CAUTION\if\relax\detokenize{#2}\relax\else: #2\fi},
|
||||
colback=BlogCalloutCautionBack,
|
||||
colframe=BlogCalloutCautionFrame,
|
||||
boxed title style={colback=BlogCalloutCautionBack},
|
||||
#1
|
||||
\NewDocumentEnvironment{blogcautionbox}{O{} m}{%
|
||||
\if\relax\detokenize{#2}\relax
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
colback=BlogCalloutCautionBack,
|
||||
colframe=BlogCalloutCautionFrame,
|
||||
boxed title style={colback=BlogCalloutCautionBack},
|
||||
#1
|
||||
]%
|
||||
\else
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
title={#2},
|
||||
colback=BlogCalloutCautionBack,
|
||||
colframe=BlogCalloutCautionFrame,
|
||||
boxed title style={colback=BlogCalloutCautionBack},
|
||||
#1
|
||||
]%
|
||||
\fi
|
||||
}{%
|
||||
\end{tcolorbox}%
|
||||
}
|
||||
|
||||
\newtcolorbox{blogasidebox}[2][]{
|
||||
blog callout,
|
||||
title={ASIDE\if\relax\detokenize{#2}\relax\else: #2\fi},
|
||||
colback=BlogCalloutAsideBack,
|
||||
colframe=BlogCalloutAsideFrame,
|
||||
boxed title style={colback=BlogCalloutAsideBack},
|
||||
#1
|
||||
\NewDocumentEnvironment{blogasidebox}{O{} m}{%
|
||||
\if\relax\detokenize{#2}\relax
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
colback=BlogCalloutAsideBack,
|
||||
colframe=BlogCalloutAsideFrame,
|
||||
boxed title style={colback=BlogCalloutAsideBack},
|
||||
#1
|
||||
]%
|
||||
\else
|
||||
\begin{tcolorbox}[
|
||||
blog callout,
|
||||
title={#2},
|
||||
colback=BlogCalloutAsideBack,
|
||||
colframe=BlogCalloutAsideFrame,
|
||||
boxed title style={colback=BlogCalloutAsideBack},
|
||||
#1
|
||||
]%
|
||||
\fi
|
||||
}{%
|
||||
\end{tcolorbox}%
|
||||
}
|
||||
|
||||
\ExplSyntaxOn
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue