render fn
This commit is contained in:
18
app.py
18
app.py
@@ -1,7 +1,7 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for, send_from_directory
|
from flask import Flask, render_template, request, redirect, url_for, send_from_directory
|
||||||
from content.posts import BLOG_POSTS
|
from content.posts import BLOG_POSTS
|
||||||
from flask_logic.logic import get_enriched_post, get_comments_for_post, save_comment
|
from flask_logic.logic import get_enriched_post, get_comments_for_post, save_comment
|
||||||
|
from flask_logic.renderer import process_post_content, collect_css
|
||||||
# 🌟 IMPORT THE content from separate files.
|
# 🌟 IMPORT THE content from separate files.
|
||||||
from content.posts import BLOG_POSTS
|
from content.posts import BLOG_POSTS
|
||||||
from content.about_text import ABOUT, TITLE
|
from content.about_text import ABOUT, TITLE
|
||||||
@@ -106,6 +106,7 @@ def about():
|
|||||||
return render_template('about.html', about_txt = about_txt, blog_title = TITLE)
|
return render_template('about.html', about_txt = about_txt, blog_title = TITLE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/post/<int:post_id>')
|
@app.route('/post/<int:post_id>')
|
||||||
def post_detail(post_id):
|
def post_detail(post_id):
|
||||||
context = {"used_components": set()}
|
context = {"used_components": set()}
|
||||||
@@ -115,26 +116,21 @@ def post_detail(post_id):
|
|||||||
return "Post not found", 404
|
return "Post not found", 404
|
||||||
|
|
||||||
comments = get_comments_for_post(post_id)
|
comments = get_comments_for_post(post_id)
|
||||||
context["used_components"].add("image")
|
|
||||||
context["used_components"].add("code")
|
|
||||||
|
|
||||||
|
processed_content = process_post_content(
|
||||||
|
post.get('content', ''), context=context
|
||||||
|
)
|
||||||
|
|
||||||
#processed_content = render_content(post['content'], context=context)
|
css_files = collect_css(context)
|
||||||
|
|
||||||
css_files = []
|
|
||||||
for comp in context["used_components"]:
|
|
||||||
css_files.append(f"css/components/{comp}.css")
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"post_detail.html",
|
"post_detail.html",
|
||||||
post=post,
|
post=post,
|
||||||
|
content=processed_content,
|
||||||
comments=comments,
|
comments=comments,
|
||||||
blog_title=TITLE,
|
blog_title=TITLE,
|
||||||
component_css=css_files
|
component_css=css_files
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/content/image/<path:filename>')
|
@app.route('/content/image/<path:filename>')
|
||||||
def content_image_files(filename):
|
def content_image_files(filename):
|
||||||
directory = 'content/image'
|
directory = 'content/image'
|
||||||
|
|||||||
0
flask_logic/__init__.py
Normal file
0
flask_logic/__init__.py
Normal file
30
flask_logic/components.py
Normal file
30
flask_logic/components.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from flask_logic.registry import register_component
|
||||||
|
|
||||||
|
|
||||||
|
@register_component("image", css="css/components/image.css")
|
||||||
|
def render_image_component(src, caption=None, css_class=None, context=None):
|
||||||
|
if context:
|
||||||
|
context["used_components"].add("image")
|
||||||
|
|
||||||
|
base_class = "image-container"
|
||||||
|
full_class = f"{base_class} {css_class}" if css_class else base_class
|
||||||
|
|
||||||
|
caption_html = f'<div class="caption">{caption}</div>' if caption else ""
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
<div class="{full_class}">
|
||||||
|
<img src="/content/image/{src}" alt="{caption or ''}">
|
||||||
|
{caption_html}
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@register_component("code", css="css/components/code.css")
|
||||||
|
def render_code_block(value=None, code=None, context=None):
|
||||||
|
if context:
|
||||||
|
context["used_components"].add("code")
|
||||||
|
|
||||||
|
code = code or value or ""
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
<pre class="code-block"><code>{code}</code></pre>
|
||||||
|
"""
|
||||||
12
flask_logic/registery.py
Normal file
12
flask_logic/registery.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# component_registry.py
|
||||||
|
|
||||||
|
COMPONENTS = {}
|
||||||
|
|
||||||
|
def register_component(name, css=None):
|
||||||
|
def decorator(func):
|
||||||
|
COMPONENTS[name] = {
|
||||||
|
"render": func,
|
||||||
|
"css": css
|
||||||
|
}
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
92
flask_logic/renderer.py
Normal file
92
flask_logic/renderer.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import re
|
||||||
|
from flask_logic.registry import COMPONENTS
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Content renderer (blocks)
|
||||||
|
# ------------------------
|
||||||
|
def render_blocks(blocks, context=None):
|
||||||
|
html_output = []
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
block_type = block.get("type")
|
||||||
|
|
||||||
|
if block_type == "text":
|
||||||
|
html_output.append(block.get("value", ""))
|
||||||
|
|
||||||
|
elif block_type in COMPONENTS:
|
||||||
|
render_func = COMPONENTS[block_type]["render"]
|
||||||
|
|
||||||
|
# remove "type" before passing kwargs
|
||||||
|
kwargs = {k: v for k, v in block.items() if k != "type"}
|
||||||
|
|
||||||
|
html_output.append(
|
||||||
|
render_func(**kwargs, context=context)
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(html_output)
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Old string renderer (tokens)
|
||||||
|
# ------------------------
|
||||||
|
def parse_options(option_string):
|
||||||
|
options = {}
|
||||||
|
if not option_string:
|
||||||
|
return options
|
||||||
|
|
||||||
|
parts = option_string.split("|")
|
||||||
|
for part in parts:
|
||||||
|
if "=" in part:
|
||||||
|
key, value = part.split("=", 1)
|
||||||
|
options[key.strip()] = value.strip()
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def render_content(content, context=None):
|
||||||
|
if not content:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def replace_image(match):
|
||||||
|
src = match.group("src").strip()
|
||||||
|
options = parse_options(match.group("options"))
|
||||||
|
|
||||||
|
render_func = COMPONENTS["image"]["render"]
|
||||||
|
|
||||||
|
return render_func(
|
||||||
|
src=src,
|
||||||
|
caption=options.get("caption"),
|
||||||
|
css_class=options.get("class"),
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
|
||||||
|
pattern = r"\[image:(?P<src>[^\|\]]+)(?:\|(?P<options>[^\]]+))?\]"
|
||||||
|
return re.sub(pattern, replace_image, content)
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Unified entry
|
||||||
|
# ------------------------
|
||||||
|
def process_post_content(content, context=None):
|
||||||
|
if isinstance(content, str):
|
||||||
|
return render_content(content, context=context)
|
||||||
|
|
||||||
|
elif isinstance(content, list):
|
||||||
|
return render_blocks(content, context=context)
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# CSS collector
|
||||||
|
# ------------------------
|
||||||
|
def collect_css(context):
|
||||||
|
css_files = []
|
||||||
|
|
||||||
|
for comp in context["used_components"]:
|
||||||
|
css = COMPONENTS.get(comp, {}).get("css")
|
||||||
|
if css:
|
||||||
|
css_files.append(css)
|
||||||
|
|
||||||
|
return css_files
|
||||||
@@ -11,7 +11,7 @@ Simple Blog Template{% endblock %} {% block content %} {% from
|
|||||||
<p>
|
<p>
|
||||||
<span class="glyphicon glyphicon-time"></span> Posted on {{ post.date }}
|
<span class="glyphicon glyphicon-time"></span> Posted on {{ post.date }}
|
||||||
</p>
|
</p>
|
||||||
{{ render_post(post) }}
|
{{ content | safe }}
|
||||||
<div class="post-actions">
|
<div class="post-actions">
|
||||||
<a href="{{ url_for('home') }}" class="btn btn-default btn-custom"
|
<a href="{{ url_for('home') }}" class="btn btn-default btn-custom"
|
||||||
>← Back to Posts</a
|
>← Back to Posts</a
|
||||||
|
|||||||
Reference in New Issue
Block a user