samhuri.net/lib/pressa/utils/markdown_renderer.rb
Sami Samhuri 007b1058b6
Migrate from Swift to Ruby (#33)
Replace the Swift site generator with a Ruby and Phlex implementation.
Loads site and projects from TOML, derive site metadata from posts.

Migrate from make to bake and add standardrb and code coverage tasks.

Update CI and docs to match the new workflow, and remove unused
assets/dependencies plus obsolete tooling.
2026-02-07 21:19:03 -08:00

148 lines
3.9 KiB
Ruby

require "kramdown"
require "yaml"
require "pressa/utils/file_writer"
require "pressa/site"
require "pressa/views/layout"
require "pressa/views/icons"
module Pressa
module Utils
class MarkdownRenderer
EXCERPT_LENGTH = 300
def can_render_file?(filename:, extension:)
extension == "md"
end
def render(site:, file_path:, target_dir:)
content = File.read(file_path)
metadata, body_markdown = parse_content(content)
html_body = render_markdown(body_markdown)
page_title = presence(metadata["Title"]) || File.basename(file_path, ".md").capitalize
page_type = presence(metadata["Page type"]) || "website"
page_description = presence(metadata["Description"]) || generate_excerpt(body_markdown)
show_extension = ["true", "yes", true].include?(metadata["Show extension"])
slug = File.basename(file_path, ".md")
relative_dir = File.dirname(file_path).sub(/^.*?\/public\/?/, "")
relative_dir = "" if relative_dir == "."
canonical_path = if show_extension
"/#{relative_dir}/#{slug}.html".squeeze("/")
else
"/#{relative_dir}/#{slug}/".squeeze("/")
end
html = render_layout(
site:,
page_subtitle: page_title,
canonical_url: site.url_for(canonical_path),
body: html_body,
page_description:,
page_type:
)
output_filename = if show_extension
"#{slug}.html"
else
File.join(slug, "index.html")
end
output_path = File.join(target_dir, output_filename)
FileWriter.write(path: output_path, content: html)
end
private
def parse_content(content)
if content =~ /\A---\s*\n(.*?)\n---\s*\n(.*)/m
yaml_content = $1
markdown = $2
metadata = YAML.safe_load(yaml_content) || {}
[metadata, markdown]
else
[{}, content]
end
end
def render_markdown(markdown)
Kramdown::Document.new(
markdown,
input: "GFM",
hard_wrap: false,
syntax_highlighter: "rouge",
syntax_highlighter_opts: {
line_numbers: false,
wrap: true
}
).to_html
end
def render_layout(site:, page_subtitle:, canonical_url:, body:, page_description:, page_type:)
layout = Views::Layout.new(
site:,
page_subtitle:,
canonical_url:,
page_description:,
page_type:,
content: PageView.new(page_title: page_subtitle, body:)
)
layout.call
end
class PageView < Phlex::HTML
def initialize(page_title:, body:)
@page_title = page_title
@body = body
end
def view_template
article(class: "container") do
h1 { @page_title }
raw(safe(@body))
end
div(class: "row clearfix") do
p(class: "fin") do
raw(safe(Views::Icons.code))
end
end
end
end
def generate_excerpt(markdown)
text = markdown.dup
# Drop inline and reference-style images before links are simplified.
text.gsub!(/!\[[^\]]*\]\([^)]+\)/, "")
text.gsub!(/!\[[^\]]*\]\[[^\]]+\]/, "")
# Replace inline and reference links with just their text.
text.gsub!(/\[([^\]]+)\]\([^)]+\)/, '\1')
text.gsub!(/\[([^\]]+)\]\[[^\]]+\]/, '\1')
# Remove link reference definitions such as: [foo]: http://example.com
text.gsub!(/(?m)^\[[^\]]+\]:\s*\S.*$/, "")
text.gsub!(/<[^>]+>/, "")
text.gsub!(/\s+/, " ")
text.strip!
return nil if text.empty?
"#{text[0...EXCERPT_LENGTH]}..."
end
def presence(value)
return value unless value.respond_to?(:strip)
stripped = value.strip
stripped.empty? ? nil : stripped
end
end
end
end