]> OzVa Git service - blog/commitdiff
Added first page main
authorwill <greenwoodw50@gmail.com>
Wed, 13 Nov 2024 20:09:41 +0000 (20:09 +0000)
committerwill <greenwoodw50@gmail.com>
Wed, 13 Nov 2024 20:09:41 +0000 (20:09 +0000)
index.py
pages/champagne.md [new file with mode: 0644]
static/literata.css
templates/page.html

index 80cb9d02c87cdce116763ee82ac10a8d795e9fa7..abc7c2917df4579cbbdb74e82971bee64ef39619 100755 (executable)
--- a/index.py
+++ b/index.py
@@ -4,123 +4,172 @@ from flask import Flask, Response, request, render_template, redirect
 import markdown
 from os import listdir
 from markdown.extensions.toc import TocExtension
 import markdown
 from os import listdir
 from markdown.extensions.toc import TocExtension
+import re
+import mmap
 
 app = Flask(__name__)
 md = markdown.Markdown(extensions = ['meta', 'tables', 'footnotes', TocExtension(title = "Table of contents")])
 
 class Page():
 
 app = Flask(__name__)
 md = markdown.Markdown(extensions = ['meta', 'tables', 'footnotes', TocExtension(title = "Table of contents")])
 
 class Page():
-    def __init__(
-        self,
-        title: str = "Unamed page",
-        abstract: str = "...",
-        keywords: list = ["Undefined"],
-        date: str = "n.d.",
-        content: str = "",
-        template: str = "page.html"
-        ):
-
-        self.title = title
-        self.abstract = abstract
-        self.keywords = keywords
-        self.date = date
-        self.content = content
-
-    def from_metadata(self, metadata):
-        if "title" in metadata: self.title = metadata["title"].title()
-        if "abstract" in metadata: self.abstract = metadata["abstract"]
-        if "keywords" in metadata: self.keywords = [x.strip().title() for x in metadata["keywords"].split(",")]
-        if "date" in metadata: self.date = metadata["date"]
-
-    def make(self):
-        format_keywords = " - ".join([f"<a href='/categories?name={key.lower()}'>{key}</a>" for key in self.keywords])
-
-        page = render_template(
-            "page.html",
-            title = self.title,
-            date = self.date,
-            abstract = self.abstract,
-            keywords = format_keywords,
-            content = self.content
-            )
-
-        return Response(page, mimetype="text/html")
+       def __init__(
+               self,
+               title: str = "Unamed page",
+               abstract: str = "",
+               keywords: list = ["Undefined"],
+               date: str = "n.d.",
+               content: str = "",
+               template: str = "page.html"
+               ):
+
+               self.title = title
+               self.abstract = abstract
+               self.keywords = keywords
+               self.date = date
+               self.content = content
+
+       def from_metadata(self, metadata):
+               if "title" in metadata: self.title = metadata["title"].title()
+               if "abstract" in metadata: self.abstract = metadata["abstract"]
+               if "keywords" in metadata: self.keywords = [x.strip().title() for x in metadata["keywords"].split(",")]
+               if "date" in metadata: self.date = metadata["date"]
+
+       def make(self):
+               format_keywords = " - ".join([f"<a href='/categories?name={key.lower()}'>{key}</a>" for key in self.keywords])
+
+               page = render_template(
+                       "page.html",
+                       title = self.title,
+                       date = self.date,
+                       abstract = self.abstract,
+                       keywords = format_keywords,
+                       content = self.content
+                       )
+
+               return Response(page, mimetype="text/html")
 
 @app.route("/")
 def homepage():
 
 @app.route("/")
 def homepage():
-    page = Page(
-        title = "Home",
-        abstract = "",
-        content = "",
-        template = "home.html"
-        )
-    return page.make()
+       page = Page(
+               title = "Home",
+               abstract = "Blog and portfolio of Will Greenwood.",
+               keywords = [],
+               date = "",
+               template = "home.html"
+               )
+       return page.make()
+
+def get_search():
+       names = [re.sub('[\W_]+', '', name) for name in request.args.get("name").split()]
+
+       name_string = "</em>' '<em>".join(names)
+       content = f"<h1>Search '<em>{name_string}</em>'</h1><ul>"
+
+       for file_name in listdir("./pages"):
+               with open(f"./pages/{file_name}", "r") as f:
+                       s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
+                       for name in names:
+                               i = s.find(str.encode(name))
+                               if i != -1:
+                                       post_content = f.read()
+
+                                       post_content = re.sub('<.*>', ' ', post_content)
+                                       post_content = re.sub('.[^\s\d\w]', ' ', post_content)
+                                       post_content = re.sub('  ', ' ', post_content)
+
+                                       i = post_content.find(name)
+                                       excerpt = "'..." + post_content[i-50:i] + "</em><b>" + post_content[i:i+len(name)] + "</b><em>" + post_content[i+len(name):i+50] + "...'"
+
+                                       lines = post_content.split("\n")
+                                       title = "Unamed page"
+                                       for line in lines:
+                                               line = line.split()
+                                               print(line)
+                                               if len(line) == 2 and line[0] == "title":
+                                                       title = line[1].strip().title()
+                                               elif len(line) == 2: pass
+                                               else: break
+
+                                       content += f"<li><a href='/{file_name[:-3]}'>{title}</a> - <em>{excerpt}</em></li>"
+                                       break
+
+       content += "</ul>"
+
+       page = Page(
+               title = "Post search",
+               date = "",
+               keywords = [],
+               content = content
+               )
+       return page.make()
 
 @app.route("/categories")
 def get_categories():
 
 @app.route("/categories")
 def get_categories():
-    name = request.args.get('name')
-    index = {}
-
-    if name == "all":
-        return redirect("/categories")
-
-    for file_name in listdir("./pages"):
-        keywords = ["Undefined"]
-        title = "Untitled post"
-        abstract = "..."
-        with open(f"./pages/{file_name}", "r") as f:
-            while keywords == ["Undefined"]:
-                line = f.readline().split(":")
-                if len(line) == 2:
-                    key,  value = line
-                    match key:
-                        case "title":
-                            title = value.strip().title()
-                        case "abstract":
-                            abstract = value.strip()
-                        case "keywords":
-                            keywords = [x.strip() for x in value.split(",")]
-                else:
-                    break
-
-        entry = {"title": title, "abstract": abstract,  "path": f"/{file_name[:-3]}"}
-        for key in keywords:
-            if key in index:
-                index[key] += [entry]
-            elif key == name or name is None:
-                index.update({key: [entry]})
-
-    content = ""
-    for c in index:
-        content += f"<h1>{c}</h1><ul>"
-
-        for post in index[c]:
-            content += f"<li><a href='{post['path']}'>{post['title']} - <em>{abstract}</em></a></li>"
-
-        content += "</ul>"
-
-    page = Page(
-        title = "Keywords",
-        keywords = [c.title() for c in index] + ["All"],
-        content = content
-        )
-    return page.make()
+       name = request.args.get("name")
+       index = {}
+
+       if name == "all":
+               return redirect("/categories")
+
+       for file_name in listdir("./pages"):
+               keywords = ["Undefined"]
+               title = "Untitled post"
+               abstract = "..."
+               with open(f"./pages/{file_name}", "r") as f:
+                       while keywords == ["Undefined"]:
+                               line = f.readline().split(":")
+                               if len(line) == 2:
+                                       key,  value = line
+                                       match key:
+                                               case "title":
+                                                       title = value.strip().title()
+                                               case "abstract":
+                                                       abstract = value.strip()
+                                               case "keywords":
+                                                       keywords = [x.strip() for x in value.split(",")]
+                               else:
+                                       break
+
+               entry = {"title": title, "abstract": abstract,  "path": f"/{file_name[:-3]}"}
+               for key in keywords:
+                       if key in index:
+                               index[key] += [entry]
+                       elif key == name or name is None:
+                               index.update({key: [entry]})
+
+       content = ""
+       for c in index:
+               content += f"<h1>{c}</h1><ul>"
+
+               for post in index[c]:
+                       content += f"<li><a href='{post['path']}'>{post['title']}</a> - <em>{abstract}</em></li>"
+
+               content += "</ul>"
+
+       page = Page(
+               title = "Keyword search",
+               abstract = "Click on a keyword to see all pages tagged with that keyword.",
+               date = "",
+               keywords = [c.title() for c in index] + ["All"],
+               content = content
+               )
+       return page.make()
 
 @app.route("/<string:title>")
 def generate_page(title):
 
 @app.route("/<string:title>")
 def generate_page(title):
-    title = title.replace("/", "")
-    try:
-        with open(f"pages/{title}.md", "r") as f:
-            html = md.convert(f.read())
-            metadata = {k: v[0] for k, v in md.Meta.items()}
-            md.reset()
+       title = title.replace("/", "")
+       try:
+               with open(f"pages/{title}.md", "r") as f:
+                       html = md.convert(f.read())
+                       metadata = {k: v[0] for k, v in md.Meta.items()}
+                       md.reset()
 
 
-        page = Page(content = html)
-        page.from_metadata(metadata)
-        return page.make()
+               page = Page(content = html)
+               page.from_metadata(metadata)
+               return page.make()
 
 
-    except FileNotFoundError:
-        page = Page(title = "404", abstract = "Page not found!")
-        return page.make()
+       except FileNotFoundError:
+               page = Page(title = "404", abstract = "Page not found!")
+               return page.make()
 
 if __name__ == "__main__":
 
 if __name__ == "__main__":
-    app.run(host='127.0.0.1', port=5000)
+       app.run(host='127.0.0.1', port=5000)
diff --git a/pages/champagne.md b/pages/champagne.md
new file mode 100644 (file)
index 0000000..7a006e0
--- /dev/null
@@ -0,0 +1,30 @@
+title: A bottle to smash on the hull of my boat
+abstract: My boat is a small mini-project dynamic blog. My breakaway bottle is sticky to the touch, filled with tap-water.
+keywords: programming,meta
+date: 29/10/2024
+
+Last year I decided to setup a small blog. Knowing full well that I could build my own, but also that it would be a huge time-sink that I really didnt have the time for, I decided to simply use Blogspot. It's surpisingly good and uses rich-text levels of formatting to produce slightly disapointing looking pages. My usual lean towards minimalism and accessibility was completely undermined by the control I had over how the blog looked. So it has sinc upset me, as somone so keen on self-hosting, that my blog (and emails) is managed by Google.
+
+# One year on and It's been a huge time-sink.
+
+Well about a week. But it's more difficult now. I'm at that sweet spot in learning a skill where i'm just good enough to basically make whatever I might want, but I still mess up enough to keep it interesting. It makes such a strong pull I have been able to think about very little that *isn't* dynamic page generation.
+
+I am, yet again, going with minimalism, combined with the nomenclature of acedemic writing.
+
+This is mirrored in both the approach i've taken to the various important desisions when building the generator, as well as words and styling of the pages. For example, the title / abstract / keywords / content structure, whether accurate to acedemia or not, reflects some kind of constant confort-structure. Not only this but it serves, as in acedemia, to give the reader some taste of the body of text before the continue. Combined with keywords and a future search system, this provides both this confort-structure and a robust way of narrowing down your reading. These features are handeled when generating every page, and although it is possible to exclude the date when not neccicary (such as the keyword search page), this must be done consiously and manually.
+
+This kind of structure (written out by hand, by me, every time) ensures that each page is sorted and labeled properly in a way that Blogger made barely dooable and also unplesant.
+
+2 semi-structural elements also included is the table of contents (TOC) and footnotes. Although the TOC could be programatically included within the generator, I made the desision to require it to be consiously included within the page. This not only adds weight to larger pages, requiring a TOC, but also allows page-by-page desision on where that TOC should be placed.
+
+I've also chosen to move away from any concept of time. With gaps between posts unpredictable, I would rather it not be immediately obvious that I did 2 posts a day for a month and then stopped for 5. Not that date-of-writing will not be open information, but it will not be sorted by the metric, and will not be ranked anywhere by most recent.
+
+I would describe this approach as:
+
+# Just enough.
+
+There are just enough features, and if I really need anything else, it can be added. If search proves too difficult, or breaks with the approach, it can be left out. Sites are simple HTML, with few stylings, all preloaded on hover for speed. And the "just enough" amount of marking-down for this minimalist writing is markdown. Future-proof should I ever choose to migrate again, lightweight should I keep writing and it can even do tables! The code for the generator is open-source and can be see at the repo. Over the next few weeks, I will atempt to migrate the old blog over to this system.
+
+Thanks,
+
+Will
index fdfa1eafeea27904a0bcde54cd26e9d46b487813..5a1cd8581ba19e6812869a63b58e40919d74e7eb 100644 (file)
 * Literata ExtraBold 
 * Literata ExtraBoldItalic 
 * Literata Black 
 * Literata ExtraBold 
 * Literata ExtraBoldItalic 
 * Literata Black 
-* Literata BlackItalic 
-* Literata Variable (Variable font)
-* Literata VariableItalic (Variable font)
-*/
+* Literata BlackItalic
+**/
+
 @font-face {
   font-family: 'Literata';
   src: url('/static/fonts/Literata-ExtraLight.woff2') format('woff2'),
 @font-face {
   font-family: 'Literata';
   src: url('/static/fonts/Literata-ExtraLight.woff2') format('woff2'),
   font-display: swap;
   font-style: italic;
 }
   font-display: swap;
   font-style: italic;
 }
-/**
-* This is a variable font
-* You can control variable axes as shown below:
-* font-variation-settings: wght 900.0opsz 7.0;
-*
-* available axes:
-'wght' (range from 200.0 to 900.0'opsz' (range from 7.0 to 72.0
-*/
-@font-face {
-  font-family: 'Literata-Variable';
-  src: url('/static/fonts/Literata-Variable.woff2') format('woff2'),
-       url('/static/fonts/Literata-Variable.woff') format('woff'),
-       url('/static/fonts/Literata-Variable.ttf') format('truetype');
-  font-weight: 200 900;
-  font-display: swap;
-  font-style: normal;
-}
-/**
-* This is a variable font
-* You can control variable axes as shown below:
-* font-variation-settings: wght 900.0opsz 7.0;
-*
-* available axes:
-'wght' (range from 200.0 to 900.0'opsz' (range from 7.0 to 72.0
-*/
-@font-face {
-  font-family: 'Literata-VariableItalic';
-  src: url('/static/fonts/Literata-VariableItalic.woff2') format('woff2'),
-       url('/static/fonts/Literata-VariableItalic.woff') format('woff'),
-       url('/static/fonts/Literata-VariableItalic.ttf') format('truetype');
-  font-weight: 200 900;
-  font-display: swap;
-  font-style: italic;
-}
 
 
index 4a8525e9555f72910e48a9c14cc7b007b3bc9a54..5aebe1228ac06799af54017e58f3f5d451dd58af 100644 (file)
@@ -9,7 +9,13 @@
        <body>
                <nav>
                        <h1>Will Greenwood</h1>
        <body>
                <nav>
                        <h1>Will Greenwood</h1>
-                       <p>Blog - <a href="/">Home</a></p>
+                       <p>Blog - <a href="/">Home</a> - <a href="/categories">Categories</a></p>
+                       <!--<search>
+                       <form action="./search">
+                               <input type="search" name="name" />
+                               <button type="submit">Search</button>
+                       </form>
+                       </search>-->
                        <hr>
                        <ul>
                                <li>
                        <hr>
                        <ul>
                                <li>
                        </ul>
                </nav><main>
                        <h1 class='mainTitle'>{{title}}</h1>
                        </ul>
                </nav><main>
                        <h1 class='mainTitle'>{{title}}</h1>
+                       {% if date %}
                        <h2>{{date}}</h2>
                        <h2>{{date}}</h2>
+                       {% endif %}
+                       {% if abstract %}
                        <p>Abstract: <em>{{abstract}}</em></p>
                        <p>Abstract: <em>{{abstract}}</em></p>
+                       {% endif %}
+                       {% if keywords %}
                        <p>Keywords: <em>{{keywords|safe}}<br><a href="/categories">See more keywords...</a></em></p>
                        <p>Keywords: <em>{{keywords|safe}}<br><a href="/categories">See more keywords...</a></em></p>
+                       {% endif %}
                        <hr>
                        <div>
                                {{content|safe}}
                        <hr>
                        <div>
                                {{content|safe}}