Compare commits

...

22 Commits

Author SHA1 Message Date
m
7fda9dde36 fix 2026-03-26 16:13:57 +01:00
m
194b1e04cc fix 2026-03-26 16:11:51 +01:00
m
f3ff920e38 render 2026-03-26 16:09:38 +01:00
m
a47ad949bd preview 2026-03-26 16:07:05 +01:00
m
2df2f5f3a8 import 2026-03-25 13:02:41 +01:00
m
62445a1812 check comp 2026-03-25 12:56:06 +01:00
m
6f046b3743 fix typo 2026-03-25 12:45:43 +01:00
m
1c23c05cc7 render fn 2026-03-25 12:42:26 +01:00
m
0272ec3d07 fix 2026-03-25 08:14:00 +01:00
m
81c093aa99 fix 2026-03-25 08:12:34 +01:00
m
2118d9fbc0 code template 2026-03-25 08:08:07 +01:00
m
20fce270a5 inject css 2026-03-25 05:03:29 +01:00
m
9a83309d36 preview 2026-03-25 01:51:21 +01:00
m
a90f06d913 combination 2026-03-25 01:32:03 +01:00
m
67ec5753bf testline 2026-03-24 21:54:07 +01:00
m
a38aad6576 add test 2026-03-24 21:47:48 +01:00
m
11aac567ec syntax fix 2026-03-24 21:44:12 +01:00
m
6c5649d721 image html 2026-03-24 21:41:05 +01:00
m
86588c0080 image templates 2026-03-24 21:33:10 +01:00
m
664900cbd1 image template 2026-03-24 21:27:59 +01:00
m
80c66c1802 blog title fix 2026-03-22 20:59:58 +01:00
m
8ad581658b title fix 2026-03-22 20:56:09 +01:00
19 changed files with 299 additions and 176 deletions

56
app.py
View File

@@ -1,7 +1,7 @@
from flask import Flask, render_template, request, redirect, url_for
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, generate_preview
# 🌟 IMPORT THE content from separate files.
from content.posts import BLOG_POSTS
from content.about_text import ABOUT, TITLE
@@ -78,13 +78,26 @@ def calculate_pagination(posts, posts_per_page, page):
'total_posts': total_posts
}
@app.route('/')
def home():
posts_with_preview = []
for post in BLOG_POSTS:
preview = generate_preview(post.get("content", ""))
post_copy = dict(post)
post_copy["preview"] = preview
posts_with_preview.append(post_copy)
"""Home page with paginated blog posts."""
page = request.args.get('page', 1, type=int)
blog_title = TITLE
pagination = calculate_pagination(BLOG_POSTS, POSTS_PER_PAGE, page)
pagination = calculate_pagination(posts_with_preview, POSTS_PER_PAGE, page)
return render_template('index.html',
posts=pagination['posts_to_show'],
@@ -107,18 +120,43 @@ def about():
@app.route('/post/<int:post_id>')
def post_detail(post_id):
# One call to get the data + the extra logic (templates/timelines)
context = {"used_components": set()}
post = get_enriched_post(post_id, BLOG_POSTS)
if not post:
return "Post not found", 404
comments = get_comments_for_post(post_id)
return render_template('post_detail.html', post=post, comments=comments, blog_title = TITLE)
comments = get_comments_for_post(post_id)
processed_content = process_post_content(
post.get('content', ''), context=context
)
css_files = collect_css(context)
return render_template(
"post_detail.html",
post=post,
content=processed_content,
comments=comments,
blog_title=TITLE,
component_css=css_files
)
@app.route('/content/image/<path:filename>')
def content_image_files(filename):
directory = 'content/image'
full_path = os.path.join(os.getcwd(), directory, filename) # Your actual file location
print(f"Requested: {filename}")
print(f"Directory: {os.getcwd()}/{directory}")
print(f"Full path: {full_path}")
print(f"Exists: {os.path.exists(full_path)}")
if not os.path.exists(full_path):
return f"File not found: {full_path}", 404
return send_from_directory(directory, filename)
if __name__ == '__main__':
app.run(debug=True)

Submodule content updated: 93b20a38f8...cb53a98cca

0
flask_logic/__init__.py Normal file
View File

60
flask_logic/components.py Normal file
View File

@@ -0,0 +1,60 @@
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>
"""
@register_component("tree", css="css/components/tree.css")
def render_tree_component(context=None):
if context:
context["used_components"].add("tree")
return f"""
<div class="background-svg">
<img src="/content/image/animation.svg" alt="" />
<br />
<p>tree source: codepen @uchardon</p>
</div>"""
@register_component("timeline", css="css/components/timeline.css")
def render_timeline_component(timeline=None, value=None, context=None):
if context:
context["used_components"].add("timeline")
timeline = timeline or value or ""
return f"""
<div class="tw-w-full tw-mx-auto tw-px-0 tw-py-12">
<ol
class="tw-relative tw-border-l-2 tw-border-gray-300 tw-list-none tw-p-0 tw-m-0 tw-ml-4"
>
{timeline}
</ol>
</div>
<li class="tw-mb-12 tw-ml-6 tw-list-none tw-relative"></li>
"""

12
flask_logic/registry.py Normal file
View 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

128
flask_logic/renderer.py Normal file
View File

@@ -0,0 +1,128 @@
import re
# FORCE component registration
import flask_logic.components
from flask_logic.registry import COMPONENTS
# ------------------------
# Content renderer (blocks)
# ------------------------
def render_blocks(blocks, context=None):
html_output = []
print(COMPONENTS)
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
def generate_preview(content, max_length=200):
if isinstance(content, str):
# old system
text = re.sub(r"<[^>]+>", "", content) # strip HTML
return text[:max_length]
elif isinstance(content, list):
# new system
for block in content:
if block.get("type") == "text":
text = re.sub(r"<[^>]+>", "", block.get("value", ""))
return text[:max_length]
return ""
# optinal, for images
def generate_preview_html(content, context=None):
if isinstance(content, list):
for block in content:
if block.get("type") == "text":
return f"<div class='blog-preview'>{block.get('value')}</div>"
elif block.get("type") in COMPONENTS:
# optional: allow image preview
render_func = COMPONENTS[block["type"]]["render"]
kwargs = {k: v for k, v in block.items() if k != "type"}
return render_func(**kwargs, context=context)
elif isinstance(content, str):
return content[:200]
return ""

View File

@@ -1,124 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 131 140">
<style>
svg {
max-height: 60vh;
overflow: visible;
}
path {
fill: #379157;
stroke: #379157;
stroke-width: 0.2;
transform: scale(0);
transform-origin: 50% 50%;
animation: star 8s ease-in-out infinite;
animation-delay: calc(var(--no) * 0.025s);
transform-box: fill-box;
}
@keyframes star {
0% {
transform: scale(0);
animation-timing-function: cubic-bezier(0.74, 1.72, 0.57, 1.01);
}
10% {
transform: scale(1);
}
65% {
transform: translateY(0px) scale(1);
}
75% {
transform: translateY(50px) scale(0);
}
100% {
transform: translateY(0px) scale(0);
}
}
</style>
<path d="m49.35 6.37-1.88-.93-1.85 1.01.32-2.07-1.54-1.43 2.08-.34.9-1.9.96 1.86 2.1.25-1.48 1.5z" style="--no:100;fill:#d8e540;stroke:#d8e540;"/>
<path d="m129.54 125.15-.82-.26-.68.53-.01-.86-.71-.48.81-.28.23-.83.52.7.86-.04-.5.7z" style="--no: 1; transform: scale(222);"/>
<path d="m126.73 127.78-1.39-.2-.95 1.03-.24-1.38-1.27-.59 1.24-.65.16-1.39 1 .98 1.38-.28-.62 1.26z" style="--no:2"/>
<path d="m120.86 129.62-1.36-.62-1.28.78.16-1.49-1.14-.97 1.46-.31.58-1.38.75 1.3 1.49.12-1 1.1z" style="--no:3"/>
<path d="m115.25 131.06-2.48-1.02-2.25 1.47.2-2.68-2.1-1.68 2.62-.64.95-2.5 1.41 2.28 2.68.12-1.73 2.05z" style="--no:4"/>
<path d="m106.57 132.05-1.32-.75-1.37.67.3-1.49-1.05-1.09 1.5-.17.71-1.34.64 1.37 1.49.27-1.12 1.02z" style="--no:5"/>
<path d="m107.36 126.39-1.26-.48-1.11.77.06-1.35-1.07-.82 1.3-.35.44-1.28.74 1.13 1.36.03-.85 1.05z" style="--no:6"/>
<path d="m101.6 129.66-3.35-1.58-3.2 1.87.47-3.68-2.77-2.46 3.64-.7 1.5-3.39 1.78 3.25 3.69.37-2.54 2.7z" style="--no:7"/>
<path d="m91.68 125.45-2.42-1.71-2.78 1.03.87-2.83-1.83-2.33 2.96-.05 1.64-2.46.96 2.8 2.85.8-2.37 1.78z" style="--no:8"/>
<path d="m88.75 115.32-1.92.87-.37 2.08-1.42-1.55-2.1.29 1.05-1.84-.93-1.9 2.07.43 1.52-1.47.24 2.1z" style="--no:9"/>
<path d="m80.86 119.34-1.99-.75-1.74 1.22.1-2.12-1.7-1.28 2.05-.57.7-2 1.17 1.77 2.12.04-1.33 1.66z" style="--no:10"/>
<path d="m80.76 112.4-1.91-.46-1.46 1.32-.16-1.96-1.7-.98 1.8-.76.4-1.92 1.3 1.49 1.95-.21-1.02 1.68z" style="--no:11"/>
<path d="m73.42 115.87-2.31-1.18-2.28 1.23.4-2.55-1.87-1.79 2.56-.4 1.11-2.34 1.18 2.3 2.57.35-1.83 1.83z" style="--no:12"/>
<path d="m73.07 106.79-.93.2-.36.87-.48-.82-.95-.07.63-.7-.22-.93.87.38.8-.5-.09.95z" style="--no:13"/>
<path d="m66.62 105.3-.92-.58-.99.42.27-1.05-.7-.81 1.07-.07.55-.92.4 1 1.05.24-.83.7z" style="--no:14"/>
<path d="m64.58 114.97-3.79-2.46-4.18 1.72 1.17-4.36-2.93-3.45 4.52-.23 2.37-3.85 1.61 4.22 4.4 1.06-3.52 2.85z" style="--no:15"/>
<path d="m57.23 104.7-1.17-.97-1.46.43.56-1.42-.86-1.26 1.52.1.94-1.2.38 1.47 1.43.51-1.28.82z" style="--no:16"/>
<path d="m51.83 107.18-2.77-.7-2.14 1.9-.2-2.85-2.46-1.45 2.65-1.07.62-2.78 1.84 2.18 2.83-.27-1.5 2.42z" style="--no:17"/>
<path d="m54.36 113.53-2.02.23-.96 1.8-.84-1.86-2-.36 1.5-1.37-.28-2.01 1.77 1 1.83-.88-.41 1.99z" style="--no:18"/>
<path d="m44.68 113.98-1.72-1.4-2.12.63.8-2.06-1.25-1.83 2.2.12 1.35-1.75.57 2.14 2.09.74-1.86 1.2z" style="--no:19"/>
<path d="m44.48 117.46-.94-.5-.94.5.18-1.05-.76-.74 1.05-.15.46-.95.48.95 1.05.15-.76.74z" style="--no:20"/>
<path d="m38.72 116.76-2.49-.72-2 1.64-.08-2.59-2.18-1.4 2.43-.87.66-2.51 1.59 2.04 2.59-.15-1.46 2.15z" style="--no:21"/>
<path d="m42.9 104.65-1.42-.85-1.5.68.37-1.6-1.1-1.21 1.63-.15.81-1.43.65 1.52 1.61.33-1.24 1.08z" style="--no:22"/>
<path d="m31.82 119.39-1.35-.43-1.12.87-.01-1.43-1.17-.8 1.34-.44.4-1.37.85 1.15 1.42-.04-.83 1.15z" style="--no:23"/>
<path d="M30.14 114.38h-1l-.54.83-.32-.94-.95-.27.8-.59-.04-.99.8.58.93-.34-.3.94z" style="--no:24"/>
<path d="m25.22 120.18-2.06-.89-1.9 1.19.21-2.24-1.72-1.44 2.2-.49.84-2.08 1.14 1.93 2.24.16-1.49 1.69z" style="--no:25"/>
<path d="m18.67 122.17-1.53-.5-1.27.99v-1.61l-1.33-.91 1.53-.5.45-1.54.95 1.3 1.6-.05-.94 1.3z" style="--no:26"/>
<path d="m12.72 123.8-1.1-.26-.84.74-.07-1.12-.97-.57 1.04-.42.24-1.1.73.86 1.11-.1-.6.95z" style="--no:27"/>
<path d="m8.25 126.29-1.18-.52-1.1.67.14-1.28-.98-.84 1.26-.26.49-1.2.65 1.12 1.28.1-.86.96z" style="--no:28"/>
<path d="m3.43 128.67-1.11-.26-.85.78-.1-1.14-1-.57 1.06-.45.22-1.12.76.86 1.14-.13-.6.99z" style="--no:29"/>
<path d="m36.74 105.6-3.33-1.68-3.27 1.79.58-3.69L28 99.46l3.68-.6 1.6-3.36 1.7 3.32 3.7.48-2.64 2.64z" style="--no:30"/>
<path d="m28.14 106.59-1.84-.42-1.39 1.28-.17-1.87-1.65-.93 1.74-.75.37-1.85 1.24 1.42 1.88-.22-.97 1.63z" style="--no:31"/>
<path d="m23.8 102.17-.71-.49-.8.31.24-.82-.54-.66.85-.03.47-.71.29.8.82.22-.68.52z" style="--no:32"/>
<path d="m20.1 108.3-1.52-1.19-1.85.58.66-1.82-1.12-1.58 1.94.07 1.16-1.55.53 1.86 1.84.62-1.61 1.08z" style="--no:33"/>
<path d="m14.73 109.75-1.37-.47-1.16.87.02-1.45-1.18-.84 1.38-.43.43-1.38.84 1.18 1.45-.02-.87 1.17z" style="--no:34"/>
<path d="m8.87 112.07-.96-.54-1 .5.22-1.1-.77-.78 1.1-.14.5-.98.47 1 1.1.19-.82.75z" style="--no:35"/>
<path d="m37.72 97.29-.82-.4-.8.45.13-.9-.67-.62.9-.16.38-.83.43.8.9.1-.63.67z" style="--no:36"/>
<path d="m43.69 97.64-1.87-1.15-2.01.88.52-2.14-1.47-1.64 2.2-.16 1.1-1.9.84 2.04 2.15.46-1.68 1.42z" style="--no:37"/>
<path d="m51.23 94.34-1.54.2-.72 1.37-.65-1.4-1.54-.27 1.14-1.05-.23-1.54 1.36.75 1.39-.7-.3 1.53z" style="--no:38"/>
<path d="m50.46 90.7-1.14-.82-1.29.58.42-1.35-.94-1.04 1.4-.02.7-1.22.45 1.33 1.38.3-1.13.84z" style="--no:39"/>
<path d="m60.25 91.43-3.43-1.99-3.46 1.93.83-3.88-2.9-2.7 3.94-.4 1.67-3.6 1.6 3.63 3.94.47-2.95 2.65z" style="--no:40"/>
<path d="m64.71 84.62-.84-.82-1.13.3.52-1.04-.64-.99 1.16.17.74-.91.2 1.15 1.09.42-1.04.55z" style="--no:41"/>
<path d="m71.62 83.43-.96-.53-.95.57.2-1.09-.82-.72 1.09-.15.43-1.01.48 1 1.1.1-.8.75z" style="--no:42"/>
<path d="m69.06 91.57-2.25-1.58-2.52 1.12.81-2.63-1.85-2.04 2.76-.05L67.38 84l.9 2.6 2.69.57-2.2 1.66z" style="--no:43"/>
<path d="m76.64 88.66-1.87-.98-1.8 1.11.35-2.08-1.61-1.36 2.09-.32.8-1.95.94 1.89 2.1.15-1.5 1.49z" style="--no:44"/>
<path d="m83.66 86.9-2.15-1.06-2 1.3.34-2.36L78 83.27l2.36-.4.86-2.24 1.11 2.12 2.4.13-1.68 1.71z" style="--no:45"/>
<path d="m89.28 83.7-1.25-.96-1.47.57.53-1.48-1-1.23 1.58.06.86-1.34.44 1.52 1.52.4-1.3.89z" style="--no:47"/>
<path d="m94.37 80.9-1.12-.38-.9.76.03-1.18-1-.62 1.12-.34.28-1.14.68.96 1.17-.09-.7.94z" style="--no:48"/>
<path d="m53.76 83.53-.99-.56-.99.55.24-1.11-.84-.78 1.13-.12.48-1.03.46 1.04 1.13.13-.84.77z" style="--no:49"/>
<path d="m49.34 84.58-2.28-1.18-2.18 1.36.41-2.53-1.96-1.66 2.54-.39.97-2.37 1.15 2.3 2.56.18-1.82 1.8z" style="--no:50"/>
<path d="m40.4 85.88-1.61-1.35-1.99.68.8-1.94-1.27-1.68 2.1.15 1.2-1.72.5 2.04 2.01.62-1.79 1.1z" style="--no:51"/>
<path d="m34.53 85.6-3.5-1.38-2.97 2.3.23-3.76-3.1-2.13 3.64-.93 1.07-3.6 2 3.17 3.77-.1-2.4 2.9z" style="--no:52"/>
<path d="m23.9 86.9-1.68-1.5-2.15.66L21 84l-1.3-1.84 2.24.24 1.35-1.8.47 2.2 2.13.72-1.95 1.13z" style="--no:53"/>
<path d="m18.21 88.34-1.62-.6-1.34 1.1.06-1.73-1.45-.94 1.66-.47.44-1.67.97 1.43 1.72-.1-1.06 1.37z" style="--no:54"/>
<path d="m35.48 77.6-1.07-.58-1.05.62.22-1.2-.92-.8 1.21-.16.48-1.12.53 1.1 1.21.11-.88.84z" style="--no:55"/>
<path d="M41.72 78.62 40.12 77l-2.2.54 1.05-2.02-1.2-1.93 2.25.37 1.47-1.73.33 2.25 2.1.85-2.03 1.02z" style="--no:56"/>
<path d="m49.62 74.51-1.93-.58-1.5 1.36-.03-2.02-1.76-1 1.9-.66.41-1.97 1.22 1.6 2-.22-1.14 1.66z" style="--no:57"/>
<path d="m55.27 71.78-1.65-.53-1.3 1.14v-1.73l-1.49-.88 1.64-.54.38-1.69 1.02 1.4 1.73-.16-1.02 1.4z" style="--no:58"/>
<path d="m63 71.81-2.43-1.38-2.42 1.38.56-2.73-2.06-1.88 2.77-.3 1.15-2.54 1.15 2.53 2.77.31-2.06 1.88z" style="--no:59"/>
<path d="m69.27 69.46-1.16-1.2-1.62.4.77-1.48-.87-1.41 1.64.27 1.08-1.27.24 1.65 1.54.64-1.49.74z" style="--no:60"/>
<path d="m76.01 70.02-1.24-.55-1.11.78.14-1.36-1.09-.82 1.33-.28.45-1.28.68 1.18 1.35.02-.9 1.01z" style="--no:61"/>
<path d="m81.2 67.28-1.02-.37-.84.7.03-1.1-.92-.58 1.05-.3.27-1.06.62.9 1.08-.06-.66.86z" style="--no:62"/>
<path d="m56.57 65.7-.93-.61-1.01.48.3-1.08-.77-.81 1.11-.05.54-.98.39 1.05 1.1.2-.88.7z" style="--no:63"/>
<path d="m50.57 67.67-1.71-1.65-2.3.63 1.04-2.14-1.3-1.98 2.35.32L50.14 61l.41 2.34 2.23.84-2.1 1.12z" style="--no:64"/>
<path d="m43.73 67.04-1.33-1.07-1.59.58.61-1.58-1.05-1.33 1.7.09.94-1.42.44 1.65 1.63.46-1.42.92z" style="--no:65"/>
<path d="m38.39 65.28-2.84-1.44-2.7 1.7.5-3.15-2.46-2.04 3.15-.5 1.18-2.97 1.45 2.84 3.19.21-2.25 2.26z" style="--no:66"/>
<path d="m29.58 65.7-1.85-.51-1.39 1.32-.08-1.91-1.69-.92 1.8-.67.35-1.89 1.2 1.51 1.9-.26-1.07 1.6z" style="--no:67"/>
<path d="m22.67 67.35-.95-.82-1.19.4.5-1.16-.75-1.01 1.25.1.73-1 .28 1.21 1.2.39-1.08.64z" style="--no:68"/>
<path d="m46.67 60.54-2.1-1.18-2.09 1.2.48-2.36-1.79-1.62 2.4-.28.99-2.2 1 2.2 2.4.26-1.78 1.62z" style="--no:69"/>
<path d="m52.22 59.39-1.15-.58-1.08.7.2-1.27-1-.82 1.27-.2.46-1.2.6 1.14 1.27.08-.9.9z" style="--no:70"/>
<path d="m57.73 56.34-.74-.95-1.19.16.67-1-.52-1.08 1.15.33.88-.82.04 1.2 1.05.57-1.12.4z" style="--no:71"/>
<path d="m66.78 48.61-1.14-.34-.88.81-.03-1.19-1.04-.59 1.12-.4.24-1.17.73.95 1.18-.13-.68.98z" style="--no:72"/>
<path d="m60.82 51.53-1.55-1.18-1.8.73.63-1.83-1.25-1.49 1.95.04 1.03-1.65.56 1.86 1.88.47-1.6 1.1z" style="--no:73"/>
<path d="m53.55 54.76-2.32-1.74-2.68 1.11.93-2.74-1.88-2.21 2.9.04 1.5-2.48.86 2.77 2.82.68-2.37 1.67z" style="--no:74"/>
<path d="M45.34 50.09 44 49.44l-1.23.82.2-1.47-1.16-.93 1.46-.26.52-1.38.7 1.3 1.48.07-1.03 1.07z" style="--no:75"/>
<path d="m40.18 48.79-1.77-1.15-1.9.93.55-2.04-1.47-1.51 2.1-.11.99-1.87.76 1.97 2.08.36-1.64 1.33z" style="--no:76"/>
<path d="m33.37 48.93-1.14-.4-.92.79.02-1.21-1.03-.64 1.16-.35.28-1.18.7 1 1.2-.1-.73.97z" style="--no:77"/>
<path d="m44 43.45-1.1-.09-.66.9-.25-1.08-1.06-.34.95-.58v-1.11l.84.73 1.06-.35-.44 1.03z" style="--no:78"/>
<path d="m47.65 45.49-1.2-1.17-1.63.44.74-1.51-.92-1.41 1.67.23 1.06-1.3.28 1.65 1.58.6-1.49.79z" style="--no:79"/>
<path d="m55.3 43.35-2.53-.88-2.06 1.72.06-2.68-2.28-1.42 2.57-.78.65-2.6 1.53 2.2 2.68-.19-1.62 2.14z" style="--no:80"/>
<path d="m59.03 37.84-1.01-.56-1 .58.22-1.13-.86-.77 1.15-.14.46-1.06.49 1.05 1.14.12-.84.78z" style="--no:81"/>
<path d="m53.55 34.33-1.91-1.11-1.93 1.07.46-2.16-1.62-1.51 2.2-.22.94-2.01.9 2.02 2.19.27-1.65 1.48z" style="--no:82"/>
<path d="m46.29 36.65-.8-.77-1.05.3.48-1-.6-.91 1.09.15.68-.85.2 1.08 1.02.39-.97.51z" style="--no:83"/>
<path d="m39.44 36.68-1.15-1.11-1.56.42.7-1.45-.88-1.34 1.6.22 1-1.25.29 1.58 1.5.57-1.42.75z" style="--no:84"/>
<path d="m46.78 32.72-2.41-1.47-2.49 1.33.65-2.75-2.03-1.96 2.8-.23 1.25-2.53 1.09 2.6 2.78.4-2.13 1.83z" style="--no:85"/>
<path d="m50.22 23.8-2.4-.6-1.74 1.73-.16-2.46-2.19-1.13 2.3-.9.39-2.44 1.57 1.9 2.43-.38-1.32 2.08z" style="--no:86"/>
<path d="m48.64 16.71-1.1-.7-1.17.59.33-1.26-.92-.93 1.3-.08.6-1.16.48 1.21 1.29.22-1.01.82z" style="--no:87"/>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,16 @@
.code-block {
display: block;
white-space: pre-wrap; /* Allows the code to wrap within the container */
word-wrap: break-word; /* Ensures long words break to fit the container */
max-width: 100%; /* Ensures the code block doesn't exceed the container's width */
padding: 10px; /* Adds padding for better readability */
background-color: #f5f5f5; /* Light gray background for contrast */
border: 1px solid #ddd; /* Subtle border to distinguish the code block */
border-radius: 5px; /* Rounded corners for aesthetics */
overflow-x: auto; /* Adds horizontal scroll if necessary */
}
.code-block .comment {
text-indent: 8em;
color: #408080;
}

View File

@@ -0,0 +1,16 @@
.image-container {
margin-top: 10px;
margin-bottom: 10px;
width: 100%;
height: 20vh; /* Show 20% of the viewport height */
overflow: hidden; /* Hide parts of the image outside the container */
position: relative; /* Position context for the image */
}
.image-container img {
width: 100%; /* Make the image fit the container width */
height: auto; /* Maintain aspect ratio */
position: absolute; /* Position image relative to container */
top: 50%; /* Move image down by 50% of its height */
transform: translateY(-50%); /* Pull it back up by 50% of its own height */
}

View File

@@ -0,0 +1,10 @@
/* --- Decoration --- */
.background-svg {
position: fixed;
bottom: 100px;
right: 200px;
width: 200px;
z-index: -1;
pointer-events: none;
opacity: 0.6;
}

View File

@@ -221,17 +221,6 @@ nav {
border-color: #ccc;
}
/* --- Decoration --- */
.background-svg {
position: fixed;
bottom: 100px;
right: 200px;
width: 200px;
z-index: -1;
pointer-events: none;
opacity: 0.6;
}
/* Login, Sign up, New post */
.login,
.signup {

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %} {% block title %}About - Simple Blog Template{%
endblock %} {% block content %}
{% extends "base.html" %} {% block title %}{{blog_title.title}}{% endblock %}{%
block content %}
<div class="row">
<div class="col-lg-12">
<!-- Post Content -->

View File

@@ -31,10 +31,6 @@
href="{{ url_for('static', filename='css/blog.css') }}"
rel="stylesheet"
/>
<link
href="{{ url_for('static', filename='css/components/timeline.css') }}"
rel="stylesheet"
/>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
@@ -45,6 +41,7 @@
};
</script>
<script src="{{ url_for('static', filename='js/timeline.js') }}"></script>
<style></style>
</head>
<body>

View File

@@ -1,5 +0,0 @@
<div class="background-svg">
<img src="{{ url_for('static', filename='animation.svg') }}" alt="" />
<br />
<p>tree source: codepen @uchardon</p>
</div>

View File

@@ -6,7 +6,7 @@
{% else %}
<div class="blog-preview">{{ post.content | striptags | truncate(200) }}</div>
<div class="blog-preview">{{ post.preview }}</div>
<a class="btn-read-more" href="{{ url_for('post_detail', post_id=post.id) }}">
Read More

View File

@@ -1,3 +0,0 @@
{% macro render_post(post) %}
<article class="blog-content">{{ post.content | safe }}</article>
{% if post.template %} {% include post.template %} {% endif %} {% endmacro %}

View File

@@ -1,9 +0,0 @@
<div class="tw-w-full tw-mx-auto tw-px-0 tw-py-12">
<ol
class="tw-relative tw-border-l-2 tw-border-gray-300 tw-list-none tw-p-0 tw-m-0 tw-ml-4"
>
{{ post.timeline | safe }}
</ol>
</div>
<li class="tw-mb-12 tw-ml-6 tw-list-none tw-relative"></li>

View File

@@ -1,6 +1,7 @@
{% extends "base.html" %} {% block title %}{{ post.title }} - Simple Blog
Template{% endblock %} {% block content %} {% from
"components/post_renderer.html" import render_post %} {% from
{% for css in component_css %}
<link rel="stylesheet" href="{{ url_for('static', filename=css) }}" />
{% endfor %} {% extends "base.html" %} {% block title %}{{ post.title }} -
Simple Blog Template{% endblock %} {% block content %} {% from
"components/comment_renderer.html" import render_comment %}
<div class="row">
<div class="col-lg-12">
@@ -9,7 +10,7 @@ Template{% endblock %} {% block content %} {% from
<p>
<span class="glyphicon glyphicon-time"></span> Posted on {{ post.date }}
</p>
{{ render_post(post) }}
{{ content | safe }}
<div class="post-actions">
<a href="{{ url_for('home') }}" class="btn btn-default btn-custom"
>← Back to Posts</a

View File

@@ -1,3 +0,0 @@
<h1 class="text-3xl font-bold mb-8">Project Timeline</h1>
{% include "components/timeline.html" %}