Skip to content

Instantly share code, notes, and snippets.

@OmerFarukOruc
Last active March 17, 2026 22:41
Show Gist options
  • Select an option

  • Save OmerFarukOruc/03441ea352c98a4eeba2586e7d126998 to your computer and use it in GitHub Desktop.

Select an option

Save OmerFarukOruc/03441ea352c98a4eeba2586e7d126998 to your computer and use it in GitHub Desktop.
πŸ“– Pandoc Markdown Viewer β€” Render .md files as styled HTML with a Typewriter dark theme

πŸ“– Pandoc Markdown Viewer

Render markdown files as beautifully styled HTML in your browser β€” using pandoc with a custom Typewriter dark theme (inspired by the Obsidian Typewriter theme).

Warm sepia palette Β· Clean typography Β· JetBrains Mono code Β· No animations

Preview

Feature Details
Background Warm dark #1e1e1e
Text Sepia rgb(197, 184, 161)
Code font JetBrains Mono
Max width 40rem (readable column)
Line height 1.5
Heading style Uniform color, no flashy colors

Installation

1. Install pandoc

# Fedora / RHEL
sudo dnf install pandoc

# Ubuntu / Debian
sudo apt install pandoc

# macOS
brew install pandoc

# Or download from https://github.com/jgm/pandoc/releases/latest

2. Install the CSS theme

mkdir -p ~/.local/share/pandoc
curl -sL https://gist.githubusercontent.com/oruc/03441ea352c98a4eeba2586e7d126998/raw/pandoc-md.css \
  -o ~/.local/share/pandoc/pandoc-md.css

3. Install the viewer script

mkdir -p ~/.local/bin
curl -sL https://gist.githubusercontent.com/oruc/03441ea352c98a4eeba2586e7d126998/raw/pandoc-md-viewer \
  -o ~/.local/bin/pandoc-md-viewer
chmod +x ~/.local/bin/pandoc-md-viewer

Note: Edit pandoc-md-viewer to change the browser command if you don't use Brave (default is brave-browser). Replace with firefox, chromium, or xdg-open.

4. Add shell function (optional)

Add to your ~/.bashrc or ~/.zshrc:

md() {
  local file="${1:?Usage: md <file.md>}"
  local name="$(basename "$file")"
  local out="/tmp/pandoc-${name}.html"
  pandoc "$file" -s --embed-resources \
    --metadata title="$name" \
    -c ~/.local/share/pandoc/pandoc-md.css \
    -o "$out" && brave-browser "$out"
}

5. Set as default .md handler (optional, Linux)

mkdir -p ~/.local/share/applications
curl -sL https://gist.githubusercontent.com/oruc/03441ea352c98a4eeba2586e7d126998/raw/pandoc-md-viewer.desktop \
  -o ~/.local/share/applications/pandoc-md-viewer.desktop
xdg-mime default pandoc-md-viewer.desktop text/markdown
update-desktop-database ~/.local/share/applications/

Now double-clicking any .md file in your file manager will render it in the browser.

Usage

# From terminal
md README.md
md ~/notes/todo.md

# Or directly
pandoc-md-viewer README.md

Files

File Description
pandoc-md.css Typewriter dark theme stylesheet
pandoc-md-viewer Shell script that converts & opens in browser
pandoc-md-viewer.desktop Linux desktop entry for file manager integration

Customization

Edit ~/.local/share/pandoc/pandoc-md.css to change colors. Key variables at the top:

:root {
  --bg:           #1e1e1e;    /* Background */
  --fg:           rgb(197, 184, 161); /* Text */
  --yellow:       #e5b567;    /* Strings */
  --green:        #b4d273;    /* Commands */
  --orange:       #e87d3e;    /* Numbers */
  --purple:       #9e86c8;    /* Keywords */
  --blue:         #6c99bb;    /* Functions, links */
}

License

MIT

#!/bin/bash
# Pandoc Markdown Viewer β€” renders .md as styled HTML and opens in Brave
file="$1"
[ -z "$file" ] && exit 1
name="$(basename "$file")"
out="/tmp/pandoc-${name}.html"
# Preprocess: inject blank line before pipe tables that lack one
# Ensures pandoc recognizes pipe tables even when they follow text without gap
python3 -c "
import sys, re
lines = open(sys.argv[1]).readlines()
out = []
for i, line in enumerate(lines):
if i > 0 and re.match(r'\s*\|', line) and not re.match(r'\s*\|', lines[i-1]) and lines[i-1].strip():
out.append('\n')
out.append(line)
sys.stdout.write(''.join(out))
" "$file" \
| pandoc -s --embed-resources \
--metadata title="$name" \
-c "$HOME/.local/share/pandoc/pandoc-md.css" \
-o "$out" && brave-browser "$out"
[Desktop Entry]
Type=Application
Name=Markdown Viewer (Pandoc)
Comment=Render Markdown files as styled HTML in the browser
Exec=$HOME/.local/bin/pandoc-md-viewer %f
MimeType=text/markdown;text/x-markdown;
Terminal=false
NoDisplay=true
Categories=Utility;TextEditor;
/* ═══════════════════════════════════════════════════════════════
Typewriter β€” Pandoc Markdown Viewer
Based on Obsidian Typewriter theme by crashmoney
Warm sepia dark palette, clean typographic aesthetic
═══════════════════════════════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
@font-face {
font-family: "iA Writer Quattro S";
src: local("iA Writer Quattro S"),
local("iAWriterQuattroS-Regular"),
local("Inter");
font-weight: normal;
}
@font-face {
font-family: "iA Writer Quattro S";
src: local("iA Writer Quattro S Bold"),
local("iAWriterQuattroS-Bold"),
local("Inter");
font-weight: bold;
}
:root {
--bg: #1e1e1e;
--bg-secondary: #171717;
--bg-code: #151515;
--border: #333;
--border-hover: #5e5e5e;
--fg: rgb(197, 184, 161);
--fg-muted: #7d7567;
--fg-faint: #5c5549;
--yellow: #e5b567;
--green: #b4d273;
--orange: #e87d3e;
--purple: #9e86c8;
--pink: #b05279;
--blue: #6c99bb;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
}
body {
font-family: 'iA Writer Quattro S', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg);
color: var(--fg);
line-height: 1.65;
font-weight: 500;
font-feature-settings: "kern" 1, "liga" 1;
padding: 3rem 2rem 5rem;
max-width: 54rem;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
}
/* ── Headings ─────────────────────────────────────────────────── */
h1, h2, h3, h4, h5, h6 {
color: var(--fg);
line-height: 1.3;
margin-top: 2.5rem;
margin-bottom: 0.75rem;
letter-spacing: -0.01em;
}
h1 {
font-size: 1.8em;
font-weight: 600;
padding-bottom: 0.4rem;
border-bottom: 1px solid var(--border);
margin-top: 0;
}
h2 {
font-size: 1.55em;
font-weight: 600;
}
h3 {
font-size: 1.35em;
font-weight: 550;
}
h4 {
font-size: 1.15em;
font-weight: 550;
}
h5 {
font-size: 1em;
font-weight: 550;
}
h6 {
font-size: 0.95em;
font-weight: 550;
color: var(--fg-muted);
}
/* ── Paragraphs & Text ────────────────────────────────────────── */
p {
margin-bottom: 1.25rem;
}
strong {
font-weight: 620;
}
em {
font-style: italic;
}
a {
color: var(--blue);
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: var(--border-hover);
}
a:hover {
text-decoration-color: var(--blue);
}
mark {
background: rgba(229, 181, 103, 0.3);
color: var(--fg);
padding: 0.1em 0.3em;
border-radius: 2px;
}
hr {
border: none;
height: 1px;
background: var(--border);
margin: 2rem 0;
}
/* ── Lists ────────────────────────────────────────────────────── */
ul, ol {
padding-left: 1.5rem;
margin-bottom: 1.25rem;
}
li {
margin-bottom: 0.35rem;
}
li::marker {
color: var(--fg-muted);
}
li > ul, li > ol {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
/* Task lists */
ul li input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
width: 1em;
height: 1em;
border: 1px solid var(--border-hover);
border-radius: 2px;
background: transparent;
vertical-align: middle;
margin-right: 0.4em;
position: relative;
top: -1px;
}
ul li input[type="checkbox"]:checked {
background: var(--green);
border-color: var(--green);
}
ul li input[type="checkbox"]:checked::after {
content: "βœ“";
color: var(--bg);
font-size: 0.7em;
font-weight: 700;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* ── Blockquotes ──────────────────────────────────────────────── */
blockquote {
border-left: 3px solid var(--fg-muted);
padding: 0.75rem 1.25rem;
margin: 1.25rem 0;
color: var(--fg-muted);
font-style: italic;
}
blockquote p:last-child {
margin-bottom: 0;
}
blockquote blockquote {
margin-top: 0.5rem;
}
/* ── Code ─────────────────────────────────────────────────────── */
code {
font-family: 'JetBrains Mono', 'Fira Code', monospace;
font-size: 0.9em;
}
:not(pre) > code {
background: var(--bg-secondary);
color: var(--blue);
padding: 0.15em 0.4em;
border-radius: 2px;
border: 1px solid var(--border);
}
pre {
background: var(--bg-code) !important;
border: 1px solid var(--border);
border-radius: 5px;
padding: 1rem 1.25rem !important;
margin: 1.25rem 0 !important;
overflow-x: auto !important;
overflow-y: visible;
line-height: 1.5;
}
pre code {
background: none;
border: none;
padding: 0;
color: var(--fg);
font-size: 0.85rem;
}
/* Override pandoc's sourceCode inline styles that clip code */
.sourceCode { overflow: auto !important; }
div.sourceCode { overflow: auto !important; margin: 1.25rem 0 !important; }
pre.sourceCode { margin: 0 !important; }
pre > code.sourceCode { white-space: pre !important; }
pre > code.sourceCode > span {
text-indent: 0 !important;
padding-left: 0 !important;
display: inline-block;
line-height: 1.5;
}
pre::-webkit-scrollbar {
height: 4px;
}
pre::-webkit-scrollbar-track {
background: transparent;
}
pre::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 2px;
}
/* ── Tables ───────────────────────────────────────────────────── */
/* Horizontal scroll wrapper for wide tables */
table {
width: 100%;
border-collapse: collapse;
margin: 1.25rem 0;
font-size: 0.9rem;
display: block;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
th {
color: var(--fg);
font-weight: 600;
text-align: left;
padding: 0.75rem 1rem;
border-bottom: 2px solid var(--border-hover);
background: var(--bg-secondary);
white-space: nowrap;
}
td {
padding: 0.65rem 1rem;
border-bottom: 1px solid var(--border);
vertical-align: top;
line-height: 1.5;
}
td code {
font-size: 0.85em;
}
tr:last-child td {
border-bottom: none;
}
tbody tr:nth-child(even) {
background: rgba(255, 255, 255, 0.02);
}
tbody tr:hover {
background: rgba(255, 255, 255, 0.04);
}
/* ── Images ───────────────────────────────────────────────────── */
img {
max-width: 100%;
height: auto;
border-radius: 5px;
margin: 1.25rem 0;
display: block;
}
figure {
margin: 1.25rem 0;
text-align: center;
}
figcaption {
color: var(--fg-faint);
font-size: 0.85rem;
margin-top: 0.5rem;
font-style: italic;
}
/* ── Definition Lists ─────────────────────────────────────────── */
dl { margin: 1.25rem 0; }
dt {
font-weight: 600;
margin-top: 0.75rem;
}
dd {
margin-left: 1.5rem;
margin-bottom: 0.5rem;
color: var(--fg-muted);
}
/* ── Footnotes ────────────────────────────────────────────────── */
.footnotes {
margin-top: 2.5rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
font-size: 0.9rem;
color: var(--fg-muted);
}
sup a { color: var(--purple); }
/* ── TOC ──────────────────────────────────────────────────────── */
nav#TOC {
border: 1px solid var(--border);
border-radius: 5px;
padding: 1rem 1.25rem;
margin-bottom: 2rem;
}
nav#TOC > ul { margin-bottom: 0; }
nav#TOC a { color: var(--fg-muted); text-decoration: none; }
nav#TOC a:hover { color: var(--fg); }
/* ── Keyboard ─────────────────────────────────────────────────── */
kbd {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-bottom-width: 2px;
border-radius: 3px;
padding: 0.1em 0.4em;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85em;
}
/* ── Syntax Highlighting (pandoc classes) ─────────────────────── */
code span.kw { color: var(--purple); } /* Keyword */
code span.bu { color: var(--purple); } /* BuiltIn */
code span.ex { color: var(--green); } /* Extension (git, sudo, cat) */
code span.fu { color: var(--blue); } /* Function */
code span.co { color: var(--fg-muted); font-style: italic; } /* Comment */
code span.st { color: var(--yellow); } /* String */
code span.dv { color: var(--orange); } /* DecVal (numbers) */
code span.bn { color: var(--orange); } /* BaseN */
code span.fl { color: var(--orange); } /* Float */
code span.ch { color: var(--yellow); } /* Char */
code span.sc { color: var(--yellow); } /* SpecialChar */
code span.vs { color: var(--yellow); } /* VerbatimString */
code span.ss { color: var(--yellow); } /* SpecialString */
code span.va { color: var(--fg); } /* Variable */
code span.cf { color: var(--purple); } /* ControlFlow */
code span.op { color: var(--fg); } /* Operator */
code span.dt { color: var(--blue); } /* DataType */
code span.at { color: var(--green); } /* Attribute */
code span.pp { color: var(--orange); } /* Preprocessor */
code span.do { color: var(--fg-muted); font-style: italic; } /* Documentation */
code span.an { color: var(--fg-muted); font-style: italic; } /* Annotation */
code span.in { color: var(--fg-muted); font-style: italic; } /* Information */
code span.wa { color: var(--orange); } /* Warning */
code span.er { color: #e06c75; } /* Error */
code span.al { color: #e06c75; } /* Alert */
/* ── Selection ────────────────────────────────────────────────── */
::selection {
background: rgba(23, 48, 77, 0.99);
}
/* ── Print ────────────────────────────────────────────────────── */
@media print {
body { background: white; color: #222; max-width: none; padding: 1cm; }
h1, h2, h3 { color: #222; }
pre, blockquote { background: #f5f5f5; border-color: #ddd; }
a { color: #0066cc; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment