diff --git a/app.py b/app.py index 533ecd8..1024aac 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,7 @@ from flask import Flask, render_template, request, redirect, url_for, send_from_directory from content.posts import BLOG_POSTS 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. from content.posts import BLOG_POSTS 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) + @app.route('/post/') def post_detail(post_id): context = {"used_components": set()} @@ -113,28 +114,23 @@ def post_detail(post_id): post = get_enriched_post(post_id, BLOG_POSTS) if not post: return "Post not found", 404 - + 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 = [] - for comp in context["used_components"]: - css_files.append(f"css/components/{comp}.css") + css_files = collect_css(context) return render_template( "post_detail.html", post=post, - comments=comments, - blog_title = TITLE, + content=processed_content, + comments=comments, + blog_title=TITLE, component_css=css_files ) - - - @app.route('/content/image/') def content_image_files(filename): directory = 'content/image' diff --git a/flask_logic/__init__.py b/flask_logic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flask_logic/components.py b/flask_logic/components.py new file mode 100644 index 0000000..1d1ebff --- /dev/null +++ b/flask_logic/components.py @@ -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'
{caption}
' if caption else "" + + return f""" +
+ {caption or ''} + {caption_html} +
+ """ + +@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""" +
{code}
+ """ \ No newline at end of file diff --git a/flask_logic/registery.py b/flask_logic/registery.py new file mode 100644 index 0000000..3ac54a5 --- /dev/null +++ b/flask_logic/registery.py @@ -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 \ No newline at end of file diff --git a/flask_logic/renderer.py b/flask_logic/renderer.py new file mode 100644 index 0000000..a033a5d --- /dev/null +++ b/flask_logic/renderer.py @@ -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[^\|\]]+)(?:\|(?P[^\]]+))?\]" + 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 \ No newline at end of file diff --git a/templates/post_detail.html b/templates/post_detail.html index da48e4e..56255db 100644 --- a/templates/post_detail.html +++ b/templates/post_detail.html @@ -11,7 +11,7 @@ Simple Blog Template{% endblock %} {% block content %} {% from

Posted on {{ post.date }}

- {{ render_post(post) }} + {{ content | safe }}
← Back to Posts