markdown template
Some checks failed
Build, Push, and Deploy to Nomad / docker-nomad (push) Has been cancelled

This commit is contained in:
2024-12-11 20:34:20 +01:00
parent f3ae944edf
commit e728d5c14e
6 changed files with 187 additions and 122 deletions

98
app.py
View File

@@ -1,20 +1,31 @@
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
import json
import os
from markdown_render import MarkdownRenderer
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from contextlib import asynccontextmanager
from markdown_render import render_markdown_with_jinja
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
md_renderer = MarkdownRenderer()
# Context manager for app lifespan
@asynccontextmanager
async def lifespan(app: FastAPI):
print("App startup: Processing Markdown files...")
process_markdown_files("./data", "./data") # Process all Markdown files
print("Markdown processing complete!")
yield # Allow the app to start
print("App shutdown: Cleanup complete.")
app = FastAPI(lifespan=lifespan)
app.mount("/data", StaticFiles(directory="data"), name="data")
# Mount static files
app.mount("/static", StaticFiles(directory="static"), name="static")
#app.add_middleware( HTTPSRedirectMiddleware )
app.add_middleware( HTTPSRedirectMiddleware )
# Templates directory
templates = Jinja2Templates(directory="templates")
@@ -24,34 +35,22 @@ with open("mock_data.json") as file:
data = json.load(file)
@app.get("/test", response_class=HTMLResponse)
async def mark_test():
markdown_content = """
# Custom Tags Test
async def home_test():
# Load the Markdown content from a file
with open("templates/example.md", "r") as f:
markdown_content = f.read()
Here is an image overlay:
{img-left-overlay: src=my-cat.png}
# Render Markdown first, then inject Jinja2 components
rendered_html = render_markdown_with_jinja(markdown_content)
Here is a box:
{box: title=Important, content=This is a reusable box.}
And a note:
{note: content=This is a note for the user.}
Warning section:
{warning: content=Pay attention to this warning!}
"""
# Render Markdown content
rendered_html = md_renderer.render( markdown_content )
# Wrap in a basic template
template = f"""
# Wrap in a base HTML layout
html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Markdown Tags</title>
<title>Markdown + Jinja2</title>
<style>
.img-left-overlay img {{ width: 300px; }}
.box {{ border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; }}
@@ -66,7 +65,37 @@ async def mark_test():
</body>
</html>
"""
return HTMLResponse( content = template )
return HTMLResponse(content=html_template)
def process_markdown_files(input_dir: str, output_dir: str):
"""
Recursively process all Markdown files in the input directory,
render them to HTML, and save them in the output directory.
"""
for root, _, files in os.walk(input_dir):
for file in files:
if file.endswith(".md"):
input_file_path = os.path.join(root, file)
# Determine output file path (convert .md to .html)
relative_path = os.path.relpath(input_file_path, input_dir)
output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html")
# Ensure the output directory exists
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
# Read Markdown content
with open(input_file_path, "r", encoding="utf-8") as md_file:
markdown_content = md_file.read()
# Render Markdown with Jinja2
print(f"Processing: {input_file_path} -> {output_file_path}")
rendered_html = render_markdown_with_jinja(markdown_content)
# Write the rendered HTML to the output file
with open(output_file_path, "w", encoding="utf-8") as html_file:
html_file.write(rendered_html)
# Index route
@app.get("/", response_class=HTMLResponse)
@@ -76,7 +105,18 @@ async def get_index(request: Request):
{"request": request, "data": data, "page_title": "Forside", "author": "Henrik"}
)
@app.get("/sitemap", response_class=HTMLResponse)
async def sitemap():
"""Simple home page listing available HTML files."""
links = []
for root, _, files in os.walk("./data"):
for file in files:
if file.endswith(".html"):
relative_path = os.path.relpath(os.path.join(root, file), "./data")
link = f"<a href='/data/{relative_path}'>{relative_path}</a>"
links.append(link)
links_html = "<br>".join(links)
return HTMLResponse(content=f"<h1>Available Pages</h1>{links_html}")
# Category route
@app.get("/category/{category_name}", response_class=HTMLResponse)

View File

@@ -0,0 +1,43 @@
import os
from markdown_render import render_markdown_with_jinja
def process_markdown_files(input_dir: str, output_dir: str):
"""
Recursively process all Markdown files in the input directory,
render them to HTML, and save them to the output directory.
"""
for root, _, files in os.walk(input_dir):
for file in files:
if file.endswith(".md"):
input_file_path = os.path.join(root, file)
# Determine output file path (convert .md to .html)
relative_path = os.path.relpath(input_file_path, input_dir)
output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html")
# Ensure the output directory exists
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
# Read Markdown content
with open(input_file_path, "r", encoding="utf-8") as md_file:
markdown_content = md_file.read()
# Render Markdown with Jinja2
print(f"Processing: {input_file_path} -> {output_file_path}")
rendered_html = render_markdown_with_jinja(markdown_content)
# Write the rendered HTML to the output file
with open(output_file_path, "w", encoding="utf-8") as html_file:
html_file.write(rendered_html)
print("Markdown processing complete!")
if __name__ == "__main__":
# Input directory containing Markdown files
input_directory = "./data"
# Output directory where HTML files will be stored
output_directory = "./data"
# Start the processing
process_markdown_files(input_directory, output_directory)

View File

@@ -0,0 +1,5 @@
# BoligBolig Bolig Bolig - Hvor skal sengen placeres
Nu bliver det spænde!
{{ note("Dette er stadig en test side") }}

View File

@@ -0,0 +1,6 @@
# Lidt mere info om job
Der skal langt mere tekst her
{{ note("Husk alpha side") }}

View File

@@ -1,9 +1,8 @@
from markdown_it import MarkdownIt
import re
from jinja2 import Environment, FileSystemLoader
import markdown
class MarkdownRenderer:
def render_img_left_overlay(self, params):
src = params.get("src", "")
def img_left_overlay(src):
"""Render an image with overlay."""
return f'''
<div class="img-left-overlay">
<img src="{src}" alt="Overlay Image">
@@ -11,9 +10,8 @@ class MarkdownRenderer:
</div>
'''
def render_box(self, params):
title = params.get("title", "Box")
content = params.get("content", "")
def box(title, content):
"""Render a box component."""
return f'''
<div class="box">
<strong>{title}</strong>
@@ -21,81 +19,41 @@ class MarkdownRenderer:
</div>
'''
def render_note(self, params):
content = params.get("content", "")
def note(content):
"""Render a note component."""
return f'''
<div class="note">
<p>{content}</p>
</div>
'''
def render_warning(self, params):
content = params.get("content", "")
def warning(content):
"""Render a warning component."""
return f'''
<div class="warning">
⚠️ <p>{content}</p>
</div>
'''
def __init__(self):
self.md = MarkdownIt()
self.TAG_RENDERERS = {
"img-left-overlay": self.render_img_left_overlay,
"box": self.render_box,
"note": self.render_note,
"warning": self.render_warning,
}
self._add_custom_tags_plugin()
print("Custom Markdown renderer initialized!")
def create_jinja_environment(template_dir="templates"):
"""Set up Jinja2 environment and register custom components."""
env = Environment(loader=FileSystemLoader(template_dir))
env.globals.update({
"img_left_overlay": img_left_overlay,
"box": box,
"note": note,
"warning": warning,
})
return env
def _add_custom_tags_plugin(self):
def custom_tag_rule(state, silent):
# Match custom tags
pattern = r"^\{(\w+):\s*([^}]*)\}$"
line = state.src[state.pos:].strip()
print(f"Parsing line: '{line}'") # Debug current line
def render_markdown_with_jinja(markdown_content, template_data=None):
"""Process Markdown first, then inject Jinja2 components."""
# Step 1: Convert Markdown to HTML
md_html = markdown.markdown(markdown_content, extensions=['extra', 'nl2br'])
match = re.match(pattern, line)
if not match:
print("No match for custom tag.")
return False
# Step 2: Use Jinja2 to inject components into the already-rendered HTML
env = create_jinja_environment()
template = env.from_string(md_html)
rendered_html = template.render(template_data or {})
tag_name = match.group(1)
params_raw = match.group(2)
print(f"Matched tag: {tag_name}, Params: {params_raw}")
# Parse parameters
params = {}
for pair in params_raw.split(","):
if "=" in pair:
key, value = pair.split("=", 1)
params[key.strip()] = value.strip()
# Check if the tag_name exists in TAG_RENDERERS
if tag_name in self.TAG_RENDERERS:
print(f"Tag '{tag_name}' found. Creating token...")
token = state.push("custom_tag", "", 0)
token.meta = {"tag_name": tag_name, "params": params}
state.pos += len(line)
return True
print(f"Tag '{tag_name}' not found in TAG_RENDERERS.")
return False
def render_custom_tag(tokens, idx, options, env, *args):
token = tokens[idx]
tag_name = token.meta["tag_name"]
params = token.meta["params"]
print(f"Rendering tag '{tag_name}' with params: {params}")
if tag_name in self.TAG_RENDERERS:
return self.TAG_RENDERERS[tag_name](params)
return ""
# Register the plugin
self.md.inline.ruler.before("emphasis", "custom_tags", custom_tag_rule)
self.md.add_render_rule("custom_tag", render_custom_tag)
print("Custom tag plugin registered!")
def render(self, markdown_content):
print("Rendering Markdown content...")
return self.md.render(markdown_content)
return rendered_html

13
templates/example.md Normal file
View File

@@ -0,0 +1,13 @@
# Welcome to My Page
Here is an image overlay:
{{ img_left_overlay("my-cat.png") }}
Here is a box:
{{ box("Important Notice", "This is a reusable box.") }}
Here is a note:
{{ note("This is a very important note for the user.") }}
Here is a warning:
{{ warning("Be cautious when proceeding!") }}