roundabout,
created on Saturday, 20 April 2024, 08:45:31 (1713602731),
received on Monday, 29 April 2024, 06:47:46 (1714373266)
Author identity: vlad <vlad.muntoiu@gmail.com>
237c006c97957e907ed3ecaaeb8dad51cb908f7f
.idea/misc.xml
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="Black"> <option name="sdkName" value="Python 3.10 (blog)" /> </component><component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (blog)" project-jdk-type="Python SDK" /> </project>
.idea/workspace.xml
@@ -1,14 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="AutoImportSettings"> <option name="autoReloadType" value="SELECTIVE" /> </component><component name="ChangeListManager"> <list default="true" id="b2c629ea-d173-4caf-b306-cbeaee617270" name="Changes" comment=""><list default="true" id="b2c629ea-d173-4caf-b306-cbeaee617270" name="Changes" comment="Font attribution"> <change afterPath="$PROJECT_DIR$/templates/project.html" afterDir="false" /> <change afterPath="$PROJECT_DIR$/templates/projects.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/articles/ampoule.md" beforeDir="false" afterPath="$PROJECT_DIR$/projects/ampoule.md" afterDir="false" /><change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/static/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/style.css" afterDir="false" /></list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="LAST_RESOLUTION" value="IGNORE" /> </component> <component name="Git.Settings"> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> </component><component name="ProjectColorInfo"><![CDATA[{ "associatedIndex": 7 }]]></component>
@@ -18,6 +30,24 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="showLibraryContents" value="true" /> </component> <component name="PropertiesComponent"><![CDATA[{ "keyToString": { "RunOnceActivity.ShowReadmeOnStart": "true", "git-widget-placeholder": "master", "last_opened_file_path": "/home/vlad/blog/static/fonts" } }]]></component> <component name="RecentsManager"> <key name="CopyFile.RECENT_KEYS"> <recent name="$PROJECT_DIR$/static/fonts" /> <recent name="$PROJECT_DIR$" /> </key> <key name="MoveFile.RECENT_KEYS"> <recent name="$PROJECT_DIR$/projects" /> <recent name="$PROJECT_DIR$/articles" /> <recent name="$PROJECT_DIR$" /> </key> </component><component name="RunManager"> <configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true"> <module name="blog" />
@@ -58,17 +88,48 @@
<option name="presentableId" value="Default" /> <updated>1713536817770</updated> </task> <task id="LOCAL-00001" summary="Blog"> <option name="closed" value="true" /> <created>1713552319159</created> <option name="number" value="00001" /> <option name="presentableId" value="LOCAL-00001" /> <option name="project" value="LOCAL" /> <updated>1713552319159</updated> </task> <task id="LOCAL-00002" summary="Add missing files"> <option name="closed" value="true" /> <created>1713553990582</created> <option name="number" value="00002" /> <option name="presentableId" value="LOCAL-00002" /> <option name="project" value="LOCAL" /> <updated>1713553990582</updated> </task> <task id="LOCAL-00003" summary="Font attribution"> <option name="closed" value="true" /> <created>1713554601045</created> <option name="number" value="00003" /> <option name="presentableId" value="LOCAL-00003" /> <option name="project" value="LOCAL" /> <updated>1713554601045</updated> </task> <option name="localTasksCounter" value="4" /><servers /> </component> <component name="XDebuggerManager"><breakpoint-manager><breakpoints><line-breakpoint enabled="true" suspend="THREAD" type="python-line"><url>file://$PROJECT_DIR$/main.py</url><line>8</line><option name="timeStamp" value="1" /></line-breakpoint></breakpoints></breakpoint-manager><component name="Vcs.Log.Tabs.Properties"> <option name="TAB_STATES"> <map> <entry key="MAIN"> <value> <State /> </value> </entry> </map> </option> </component> <component name="VcsManagerConfiguration"> <MESSAGE value="Blog" /> <MESSAGE value="Add missing files" /> <MESSAGE value="Font attribution" /> <option name="LAST_COMMIT_MESSAGE" value="Font attribution" /></component> </project>
articles/ampoule.md
@@ -1,14 +0,0 @@
---title: Ampoule---Ampoule is a lightweight, simple yet flexible, static site generator written in Python.It uses Jinja2 for templating.Header 2--------### Header 3#### Header 4##### Header 5###### Header 6
main.py
@@ -5,10 +5,10 @@ import string
import ampoule_ssg as ampoule from ampoule_ssg import markdown my_site = ampoule.Site("my_site")site = ampoule.Site("my_site")@my_site.filter("markdown")@site.filter("markdown")def markdown_filter(text): return markdown.markdown2html(text)
@@ -27,20 +27,31 @@ def article_url(url):
# Set context my_site.context["timestamp"] = datetime.now()my_site.context["ampoule"] = ampoulesite.context["timestamp"] = datetime.now() site.context["ampoule"] = ampoule# Add articles articles = ampoule.Index("articles", url_transform=article_url)my_site.add_from_index(articles, "/articles", "article.html")articles = ampoule.Index("articles", url_transform=article_url, sort_by=lambda x: x.date) site.add_from_index(articles, "/articles", "article.html")# Create the first pagemy_first_page = ampoule.Page(my_site, "home.html", articles=articles)# Add projects projects = ampoule.Index("projects", url_transform=article_url, sort_by=lambda x: x.file_name) site.add_from_index(projects, "/projects", "project.html")# Add the page to the sitemy_site.add_page("/", my_first_page)# Create the index pages main_page = ampoule.Page(site, "home.html", articles=articles) projects_page = ampoule.Page(site, "projects.html", projects=projects)# Add static filesmy_site.add_from_index(ampoule.Index("static", recursive=True), "/static", None, static=True)# Add the pages to the site site.add_page("/", main_page) site.add_page("/projects/", projects_page)my_site.build()# Add static files site.add_from_index( ampoule.Index("static", recursive=True, exclude=r"\.md$"), "/static", None, static=True ) site.build()
projects/ampoule.md
@@ -0,0 +1,117 @@
--- title: Ampoule --- Ampoule is a lightweight, simple yet flexible, static site generator written in Python. It uses Jinja2 for templating. Features -------- * Extremely simple and small, only a few hundred lines of code. * Only depends on Jinja2, Ruamel YAML, and colorama. * Jinja2 templating will be familiar to Flask users. Now you can use the same templates for both dynamic and static sites. * More of a framework. Sites are generated by a short Python script that you write to customise what pages it loads, which templates it uses, and what data it passes to them, or create custom filters, tests and more. * Supports YAML front matter for pages. It can be accessed using indexing syntax. * Indexes can be sorted using a function, iterated and can index any directory, recursively or not. They can also transform URLs to make them end in ".html". * Object-oriented design. The same objects used in that script can also be passed to the templates. * Any markup language can be used, as long as it can be converted to HTML. You just need to configure a filter for it. * Ships with a light markdown implementation. * Easy to use for both programmers and non-programmers. While you do need a script, you can also use an off-the-shelf one. * Themes can be exactly how you want. * Keeping static files is easy, because indexes can be static. * Static files are always binary and not templated. The same happens for files that can't be decoded. * URL-based definitions. Pages are added using the URL that will be used to access them. * Reinforces the web as a publishing medium. Static sites are not for everyone, but if you want to publish something, it's the best way. * And GitHub will give you free hosting, because it's static and very cheap to serve. Roundabout-host will soon offer this as well (`your.site.roundabout-host.com`). * It's free software and available under the GPLv3. * No JavaScript is required, but it can of course be used if you want. * Decently fast: even if you've got a huge site, it should not take more than 30 seconds. Local rebuilding will also be added. And it's still much faster than any dynamic site. * Beautiful logging thanks to colorama. * Great for educational use; you can learn Python, HTML, CSS, JavaScript, and Jinja2 all at once. * You can make your site in an hour, and then it's time to focus on writing what you want to publish. Minimal example --------------- ```python import string from datetime import datetime import string import ampoule_ssg as ampoule from ampoule_ssg import markdown # Create a site object. This is where we are adding pages to. The argument is the directory # where the site will be built. site = ampoule.Site("my_site") # Use this as "| markdown" in Jinja2 templates to convert any Markdown source to HTML. @site.filter("markdown") def markdown_filter(text): return markdown.markdown2html(text) # Make the URLs web-friendly and make it end in ".html" so it will be correctly formatted # by dumb servers. def article_url(url): url = url.lower().rpartition(".")[0] new_url = "" for i in url: if i in string.ascii_lowercase: new_url += i elif i in string.whitespace: new_url += "-" return new_url + ".html" # Set context that will be passed to all templates. You can still override this. site.context["timestamp"] = datetime.now() site.context["ampoule"] = ampoule # Add the index of articles. In the template, we're looping over it to list them all. articles = ampoule.Index("articles", url_transform=article_url, sort_by=lambda x: x.date) # This makes it take all indexed files and put them under the /articles URL, keeping the # index's URL transformation and placing all of them in the article.html template. This # will be passed as "document" to the template. site.add_from_index(articles, "/articles", "article.html") # Create the main page which has access to the index so it can list all articles. main_page = ampoule.Page(site, "home.html", articles=articles) # Add the page. Note how we're binding it to a path; it will automatically be set as # index.html in that directory, and the URL is site-relative, not the OS root. site.add_page("/", main_page) # Add static files using a recursive static index. It will add all files in the static # directory and all its subdirectories, without putting them into templates. You could # still use them in templates, so you can make a photo gallery or something. site.add_from_index( # We're excluding Markdown files because we're using them as licence information # for when the site is distributed together with the fonts. You can exclude any # file you want using regex. ampoule.Index("static", recursive=True, exclude=r"\.md$"), "/static", # There is no template, because the index is static. static=True ) # Makes Ampoule take all pages and put them in a directory. site.build() ```
static/style.css
@@ -46,6 +46,7 @@ body {
flex-direction: column; align-items: center; background: #eceff1; font-variation-settings: "opsz" 14;} a {
templates/project.html
@@ -0,0 +1,10 @@
{% extends "default.html" %} {% block title %} {{ document["title"] }} {% endblock %} {% block content %} <h1>{{ document["title"] }}</h1> <article class="content-area"> {{ document.content | markdown }} </article> {% endblock %}
templates/projects.html
@@ -0,0 +1,12 @@
{% extends "default.html" %} {% block title %}Projects{% endblock %} {% block content %} <h1>Projects</h1> {% for article in projects %} <article class="content-area"> <h2><a href="/projects/{{ article.file_name }}" class="article-title">{{ article["title"] }}</a></h2> <p>{{ article.content | markdown }}</p> </article> {% endfor %} {% endblock %}