Initial commit

This commit is contained in:
SG
2025-06-05 13:40:53 +03:00
parent 31c1b8d9c1
commit f9f6d70d8e
9 changed files with 236 additions and 0 deletions

6
config.py Normal file
View File

@@ -0,0 +1,6 @@
import os
class Config:
MAIN_PAGE_TITLE = "Selected poems"
CONTENT_DIR = os.environ.get('CONTENT_DIR') or 'content'
HEADER_IMAGE = 'static/header.jpg'

88
hydrogen.py Normal file
View File

@@ -0,0 +1,88 @@
from pathlib import Path
import frontmatter
import markdown
from jinja2 import Environment, FileSystemLoader
import shutil
from config import Config
content_dir = Path('content')
template_dir = Path('templates')
output_dir = Path('public')
img_dir = Path('public/images')
assets_dir = Path('public/assets')
assets_css_dir = Path('public/assets/css')
assets_js_dir = Path('public/assets/js')
static_dir = Path('static')
header_image = Config.HEADER_IMAGE or '/static/header.jpg'
class ContentItemPrototype:
def render_content(self):
if self.image_src_file.exists():
shutil.copyfile(self.image_src_file, output_dir / self.image)
if self.custom_css_src_file.exists():
shutil.copyfile(self.custom_css_src_file, output_dir / self.custom_css)
if self.custom_js_src_file.exists():
shutil.copyfile(self.custom_js_src_file, output_dir / self.custom_js)
with self.content_output_path.open("w", encoding="utf-8") as f:
#f.write(content_item_template.render(page_title = self.title, header_image = header_image, image = self.image, custom_css = self.custom_css, custom_js = self.custom_js, content=self.html))
f.write(content_item_template.render(content_item = self, page_title = self.title))
def __init__(self, md_file):
self.slug = md_file.stem
self.data = frontmatter.load(md_file)
self.html = markdown.markdown(self.data.content)
self.preview = self.html[:300] + " <a href=" + f"{self.slug}.html" + ">...read more</a>"
self.title = self.data.get("title", self.slug)
self.omit_second_title = self.data.get("omit_second_title", False)
self.date = self.data.get("data", "2000-01-01T00:00:00+03:00")
self.content_output_path = output_dir / f"{self.slug}.html"
self.image_src_file = Path(f"{content_dir}/{md_file.stem}.jpg")
self.image = f"images/{md_file.stem}.jpg" if self.image_src_file.exists() else None
if self.slug == 'about':
self.image = 'static/about.jpg'
self.custom_css_src_file = Path(f"{content_dir}/{md_file.stem}.css")
self.custom_css = f"assets/css/{md_file.stem}.css" if self.custom_css_src_file.exists() else None
self.custom_js_src_file = Path(f"{content_dir}/{md_file.stem}.js")
self.custom_js = f"assets/js/{md_file.stem}.js" if self.custom_js_src_file.exists() else None
# Recreate the output dir if needed
if output_dir.exists():
shutil.rmtree(output_dir)
output_dir.mkdir()
# Create public subdirs
img_dir.mkdir()
assets_dir.mkdir()
assets_css_dir.mkdir()
assets_js_dir.mkdir()
# Copy static files if exist
if static_dir.exists():
shutil.copytree(static_dir, output_dir / "static")
# Prepare template rendering engine
env = Environment(loader=FileSystemLoader(str(template_dir)))
env.globals['header_image'] = header_image
index_template = env.get_template("index.html")
content_item_template = env.get_template("content_item.html")
# Parse the content files
content_items = []
for md_file in content_dir.glob("*.md"):
citem = ContentItemPrototype(md_file)
citem.render_content()
content_items.append({
"slug": citem.slug,
"title": citem.title,
"date": citem.date,
"preview": markdown.markdown(citem.preview),
"image": citem.image,
})
# Render the index file
with (output_dir / "index.html").open("w", encoding="utf-8") as f:
f.write(index_template.render(page_title = Config.MAIN_PAGE_TITLE, content_items=content_items))
# Render the about file
about_content = ContentItemPrototype(Path('static/about.md'))
about_content.render_content()

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
python-frontmatter
jinja2
markdown

BIN
static/about.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

6
static/about.md Normal file
View File

@@ -0,0 +1,6 @@
---
title: "About"
omit_second_title: True
---

BIN
static/header.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -0,0 +1,24 @@
{% extends "default.html" %}
{% block head_includes %}
{% if content_item.custom_css %}
<link href="{{ content_item.custom_css }}">
{% endif %}
{% endblock %}
{% block content %}
<div class="container mt-4 mb-5">
{% if content_item.image %}<img src="{{ content_item.image }}" class="img-fluid mb-5" style="border-radius: 5px;">{% endif %}
{% if not content_item.omit_second_title %}
<h1>{{ content_item.title }}</h1>
{% endif %}
<article>{{ content_item.html | safe }}</article>
<a href="index.html" class="btn btn-secondary mt-4">← Back</a>
</div>
{% endblock %}
{% block footer_includes %}
{% if content_item.custom_js %}
<script src="{{ content_item.custom_js }}"></script>
{% endif %}
{% endblock %}

90
templates/default.html Normal file
View File

@@ -0,0 +1,90 @@
<!doctype html>
<html>
<head>
{% set base = "" %}
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
<title>{{ page_title }}</title>
<style>
.top_header {
position: relative;
height: 250px;
background: rgb(70, 70, 124);
background-image: url("{{ header_image }}");
background-size: cover;
background-position: center;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.top_header_text {
position: absolute;
bottom: 10px;
left: 10px;
color: white;
font-weight: bold;
font-size: 2.5rem;
background: rgba(0, 0, 0, 0.05);
border-radius: 5px;
padding: 10px 20px;
border-radius: 10px;
}
.top_menu a {
font-weight: bold;
color: #333;
padding: 6px 12px;
margin-left: 10px;
text-decoration: none;
transition: background 0.2s ease;
}
.top_menu a:hover {
background: rgba(255, 255, 255, 0.3);
}
@media (min-width: 768px) {
.top_header_text {
font-size: 4rem;
}
}
.card-title {
font-weight: bold;
}
article {
font-size: 1.1rem;
line-height: 1.6;
}
{% block head_includes %}
{% endblock %}
</style>
</head>
<body>
<div class="top_header">
<div >
<h1 class="top_header_text"><a style="border-radius: 5px; padding: 10px; opacity: 0.7; background: black">{{ page_title }}</a></h1>
</div>
</div>
<div class="top_menu d-flex justify-content-end" style="margin-bottom: 20px;">
<a href="index.html">Home</a>
<a href="about.html">About</a>
</div>
<div id="content">{% block content %}{% endblock %}</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script>
{% block footer_includes %}
{% endblock %}
</body>

19
templates/index.html Normal file
View File

@@ -0,0 +1,19 @@
{% extends "default.html" %}
{% block content %}
<div class="row row-cols-1 row-cols-md-3 g-4 px-1 py-2">
{% for content_item in content_items %}
<div class="col mb-3">
<div class="card h-100" style="border-radius: 5px;">
<img src="{{ content_item.image }}" alt="{{ content_item.title }}" class="card-img-top img-fluid" style="background: rgb(77, 77, 77); object-fit: cover; height: 200px; border-radius: 5px;">
<div class="card-body d-flex flex-column">
<h5 class="card-title">{{ content_item.title }}</h5>
<p class="card-text mb-3">{{ content_item.preview | safe}}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}