generated from hjess/PythonTemplateProject
Compare commits
26 Commits
492d933119
...
https_shit
| Author | SHA1 | Date | |
|---|---|---|---|
| fa359f095d | |||
| 67f0096f7f | |||
| 5afecf4d11 | |||
| d4a8e20817 | |||
| c49fc5a0d5 | |||
| e728d5c14e | |||
|
|
f3ae944edf | ||
|
|
27ee0516d9 | ||
| 1fb0a762ff | |||
| 31f0f49dec | |||
| 669098e568 | |||
| 3c8d51c758 | |||
| 0936adae7d | |||
| d9001d2758 | |||
| 1faff0fbc2 | |||
| a8aa012c2a | |||
| 16578726fe | |||
| 97e77d8b75 | |||
| 1175d40710 | |||
| 1b56d7fef1 | |||
| b8f1414a58 | |||
|
|
d78efed30b | ||
|
|
3c6004a7b1 | ||
|
|
4230987b3f | ||
|
|
191b21f275 | ||
|
|
85db7fd1b3 |
@@ -17,4 +17,4 @@ COPY . .
|
||||
EXPOSE 9210
|
||||
|
||||
# Command to run the FastAPI application
|
||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "9210", "--workers", "1"]
|
||||
CMD ["uvicorn", "app:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "9210", "--workers", "1"]
|
||||
Binary file not shown.
BIN
__pycache__/app.cpython-312.pyc
Normal file
BIN
__pycache__/app.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/markdown_render.cpython-312.pyc
Normal file
BIN
__pycache__/markdown_render.cpython-312.pyc
Normal file
Binary file not shown.
100
app.py
100
app.py
@@ -1,15 +1,35 @@
|
||||
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 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 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")
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Mount static files
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
|
||||
# Templates directory
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
@@ -17,6 +37,69 @@ templates = Jinja2Templates(directory="templates")
|
||||
with open("mock_data.json") as file:
|
||||
data = json.load(file)
|
||||
|
||||
@app.get("/test", response_class=HTMLResponse)
|
||||
async def home_test():
|
||||
# Load the Markdown content from a file
|
||||
with open("templates/example.md", "r") as f:
|
||||
markdown_content = f.read()
|
||||
|
||||
# Render Markdown first, then inject Jinja2 components
|
||||
rendered_html = render_markdown_with_jinja(markdown_content)
|
||||
|
||||
# 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 + Jinja2</title>
|
||||
<style>
|
||||
.img-left-overlay img {{ width: 300px; }}
|
||||
.box {{ border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; }}
|
||||
.note {{ background-color: #e7f3fe; border-left: 4px solid #2196F3; padding: 10px; }}
|
||||
.warning {{ background-color: #fff3cd; border-left: 4px solid #ffeb3b; padding: 10px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
{rendered_html}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
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)
|
||||
async def get_index(request: Request):
|
||||
@@ -25,6 +108,19 @@ 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)
|
||||
async def get_category(request: Request, category_name: str):
|
||||
|
||||
43
convert_markdown_to_html.py
Normal file
43
convert_markdown_to_html.py
Normal 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)
|
||||
7
data/bolig/lidt_omkring_boliger.html
Normal file
7
data/bolig/lidt_omkring_boliger.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<h1>BoligBolig Bolig Bolig - Hvor skal sengen placeres</h1>
|
||||
<p>Nu bliver det spænde!</p>
|
||||
<p>
|
||||
<div class="note">
|
||||
<p>Dette er stadig en test side</p>
|
||||
</div>
|
||||
</p>
|
||||
5
data/bolig/lidt_omkring_boliger.md
Normal file
5
data/bolig/lidt_omkring_boliger.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# BoligBolig Bolig Bolig - Hvor skal sengen placeres
|
||||
|
||||
Nu bliver det spænde!
|
||||
|
||||
{{ note("Dette er stadig en test side") }}
|
||||
7
data/job/det_ved_jeg_om_job.html
Normal file
7
data/job/det_ved_jeg_om_job.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<h1>Lidt mere info om job</h1>
|
||||
<p>Der skal langt mere tekst her</p>
|
||||
<p>
|
||||
<div class="note">
|
||||
<p>Husk alpha side</p>
|
||||
</div>
|
||||
</p>
|
||||
6
data/job/det_ved_jeg_om_job.md
Normal file
6
data/job/det_ved_jeg_om_job.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Lidt mere info om job
|
||||
|
||||
Der skal langt mere tekst her
|
||||
|
||||
|
||||
{{ note("Husk alpha side") }}
|
||||
59
markdown_render.py
Normal file
59
markdown_render.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import markdown
|
||||
|
||||
def img_left_overlay(src):
|
||||
"""Render an image with overlay."""
|
||||
return f'''
|
||||
<div class="img-left-overlay">
|
||||
<img src="{src}" alt="Overlay Image">
|
||||
<div class="overlay-text">Overlay Text</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
def box(title, content):
|
||||
"""Render a box component."""
|
||||
return f'''
|
||||
<div class="box">
|
||||
<strong>{title}</strong>
|
||||
<p>{content}</p>
|
||||
</div>
|
||||
'''
|
||||
|
||||
def note(content):
|
||||
"""Render a note component."""
|
||||
return f'''
|
||||
<div class="note">
|
||||
<p>{content}</p>
|
||||
</div>
|
||||
'''
|
||||
|
||||
def warning(content):
|
||||
"""Render a warning component."""
|
||||
return f'''
|
||||
<div class="warning">
|
||||
⚠️ <p>{content}</p>
|
||||
</div>
|
||||
'''
|
||||
|
||||
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 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'])
|
||||
|
||||
# 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 {})
|
||||
|
||||
return rendered_html
|
||||
@@ -1,4 +1,23 @@
|
||||
fastapi==0.110.0 # Latest FastAPI version
|
||||
uvicorn[standard]==0.27.1 # ASGI server to run FastAPI
|
||||
annotated-types==0.7.0
|
||||
anyio==4.7.0
|
||||
click==8.1.7
|
||||
fastapi==0.115.6
|
||||
h11==0.14.0
|
||||
httptools==0.6.4
|
||||
idna==3.10
|
||||
Jinja2==3.1.4
|
||||
Markdown==3.7
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==3.0.2
|
||||
mdurl==0.1.2
|
||||
pydantic==2.6.3
|
||||
python-dotenv==1.0.1 # Manage environment variables
|
||||
pydantic_core==2.16.3
|
||||
python-dotenv==1.0.1
|
||||
PyYAML==6.0.2
|
||||
sniffio==1.3.1
|
||||
starlette==0.41.3
|
||||
typing_extensions==4.12.2
|
||||
uvicorn==0.32.1
|
||||
uvloop==0.21.0
|
||||
watchfiles==1.0.0
|
||||
websockets==14.1
|
||||
|
||||
4297
static/css/main.css
4297
static/css/main.css
File diff suppressed because it is too large
Load Diff
1
static/css/main.css.map
Normal file
1
static/css/main.css.map
Normal file
File diff suppressed because one or more lines are too long
@@ -9,20 +9,20 @@
|
||||
body, input, select, textarea {
|
||||
color: _palette(fg);
|
||||
font-family: _font(family);
|
||||
font-size: 13pt;
|
||||
font-size: 16pt;
|
||||
font-weight: _font(weight);
|
||||
line-height: 1.65;
|
||||
|
||||
@include breakpoint('<=xlarge') {
|
||||
font-size: 11pt;
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
@include breakpoint('<=large') {
|
||||
font-size: 10pt;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
@include breakpoint('<=xxsmall') {
|
||||
font-size: 9pt;
|
||||
font-size: 10pt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<title>{% block title %}PortugalFAQ{% endblock %}</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}" />
|
||||
<!-- <link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}"> -->
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
</head>
|
||||
<body class="is-preload">
|
||||
<!-- Wrapper -->
|
||||
@@ -39,10 +40,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ url_for('static', path='js/jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', path='js/browser.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', path='js/breakpoints.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', path='js/util.js') }}"></script>
|
||||
<script src="{{ url_for('static', path='js/main.js') }}"></script>
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<script src="/static/js/browser.min.js"></script>
|
||||
<script src="/static/js/breakpoints.min.js"></script>
|
||||
<script src="/static/js/util.js"></script>
|
||||
<script src="/static/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
13
templates/example.md
Normal file
13
templates/example.md
Normal 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!") }}
|
||||
18
test_markdown_render.py
Normal file
18
test_markdown_render.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from markdown_render import MarkdownRenderer
|
||||
|
||||
# Initialize MarkdownRenderer
|
||||
renderer = MarkdownRenderer()
|
||||
|
||||
# Test Markdown input
|
||||
markdown_content = """
|
||||
{img-left-overlay: src=my-cat.png}
|
||||
{box: title=Test Box, content=This is a test.}
|
||||
{note: content=This is a note.}
|
||||
{warning: content=Be careful!}
|
||||
"""
|
||||
|
||||
# Render to HTML
|
||||
print("Rendering Markdown...")
|
||||
html_output = renderer.render(markdown_content)
|
||||
print("Rendered HTML:")
|
||||
print(html_output)
|
||||
Reference in New Issue
Block a user