diff --git a/requirements.txt b/requirements.txt index ca7213b..f952ae2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,6 +18,8 @@ Pillow==9.2.0 pluggy==1.0.0 py==1.11.0 pycparser==2.21 +Pygments==2.13.0 +pymdown-extensions==9.5 pyparsing==3.0.9 pypugjs==5.9.11 pytest==7.1.2 diff --git a/tests/snapshots/goodbye-cruel-world.snapshot.html b/tests/snapshots/goodbye-cruel-world.snapshot.html index fad6242..309dd74 100644 --- a/tests/snapshots/goodbye-cruel-world.snapshot.html +++ b/tests/snapshots/goodbye-cruel-world.snapshot.html @@ -593,7 +593,8 @@
Hello Mr. Fancy Manager, +: -++Hello Mr. Fancy Manager, I am pleased to supply you with features maintained in the new version of the site. @@ -603,6 +604,7 @@The engineer
The engineer's written proof reassured the
diff --git a/tests/snapshots/hello-world.snapshot.html b/tests/snapshots/hello-world.snapshot.html index a209b1a..ffd21e2 100644 --- a/tests/snapshots/hello-world.snapshot.html +++ b/tests/snapshots/hello-world.snapshot.html @@ -88,8 +88,23 @@
print('Hello World!') +++
++ ++ +++1++ ++++print('Hello World!')Save your work, and close the text editor. Open up a terminal application like Powershell on Windows or bash on Ubuntu. If you're on Windows, it is as easy as hitting your Windows Key and searching for
diff --git a/website/__init__.py b/website/__init__.py index 231d344..38c316a 100644 --- a/website/__init__.py +++ b/website/__init__.py @@ -26,8 +26,7 @@ import markdown from flask_talisman import Talisman -from website.repositories import (Repository, blog_repositories, - image_repositories) +from website.repositories import blog_repositories, image_repositories app = flask.Flask(__name__) @@ -52,6 +51,7 @@ blog_repo = blog_repositories.PostRepository('blog') image_repo = image_repositories.ImageRepository('images') +icon_repo = image_repositories.ImageRepository('static/icons') @app.route('/') def index() -> str: @@ -152,17 +152,16 @@ def article(year: int, month: int, day: int, description: str) -> str: """ try: post = blog_repo.get(f"{year}/{month}/{day}/{description}") - except Repository.NotFound: + except Exception: flask.abort(404) return flask.render_template( 'article.pug', title=post.title, - # Day Month Year date=post.date.strftime('%d %B %Y'), content=markdown.markdown( post.content, - extensions=['fenced_code', 'toc', 'tables'], + extensions=['pymdownx.superfences', 'toc', 'tables', 'codehilite'], ) ) @@ -204,18 +203,25 @@ def sitemap() -> str: Returns: str: The rendered template. """ - sorted_items = sorted( + sorted_articles = sorted( blog_repo.get_all(), key=lambda post: post.date, reverse=True, ) + sorted_images = sorted( + image_repo.get_all(), + key=lambda image: image.created, + reverse=True, + ) response = flask.make_response( flask.render_template( 'sitemap.xml', - items=sorted_items, + articles=sorted_articles, + images=sorted_images, ) ) response.mimetype = 'application/xml' + return response @@ -228,17 +234,17 @@ def favicon() -> flask.Response: Returns: flask.Response: The image response. """ - directory = os.path.join( - app.root_path, - 'static', - 'icons', - ) - images = os.listdir(directory) + images = icon_repo.get_all() image = random.choice(images) - return flask.send_from_directory( - directory, - image, + mimetype = 'image/jpeg' if image.extension == 'jpg' else 'image/png' + mimetype = 'favicon' if image.extension == 'ico' else mimetype + img_io = io.BytesIO(image.content) + img_io.seek(0) + + return flask.send_file( + img_io, + mimetype=mimetype, ) with open('website/static/faq.md', 'r') as file: diff --git a/website/blog/2020/hello_world.md b/website/blog/2020/hello_world.md index 0466f3f..1185152 100644 --- a/website/blog/2020/hello_world.md +++ b/website/blog/2020/hello_world.md @@ -16,7 +16,7 @@ This example will be using the programming language [Python](https://www.python. Writing and executing a simple "Hello World" program is fairly simple. Most languages require you to tell the computer using a specific command that you would like to output some characters, in this case, "Hello World," to the screen. The ```print``` command allows us to output some text to the screen. Please note that we don't always output the screen (the terminal), and in the past, we've output to a physical printer or similar device. Using your preferred text editor, write the following in a new file named ```hello_world.py```: -```python +```{.python .codehilite linenums="1"} print('Hello World!') ``` diff --git a/website/blog/2022/missed-article-titles.md b/website/blog/2022/missed-article-titles.md index cbedd8c..a7c9609 100644 --- a/website/blog/2022/missed-article-titles.md +++ b/website/blog/2022/missed-article-titles.md @@ -20,15 +20,14 @@ Blocks, such as the title, can be overridden in the layout. The `block` tag acce The default looks like this: -```pugjs +```{.pugjs .codehilite linenums="1"} block title title Engineer, Researcher, Entrepreneur - Johnathan Irvin ``` The layout contains the default title. I overrode the block in the `article.pug` file. -``` -pugjs +```{.pugjs .codehilite linenums="1"} block title title {{ title }} - Johnathan Irvin ``` diff --git a/website/repositories/image_repositories.py b/website/repositories/image_repositories.py index 5c3511f..7486d7f 100644 --- a/website/repositories/image_repositories.py +++ b/website/repositories/image_repositories.py @@ -55,9 +55,6 @@ def _load_images(self, directory: str) -> dict[str, Image]: directory = os.path.join('website', directory) for _, _, files in os.walk(directory): for file in files: - if not file.endswith('.jpg') and not file.endswith('.png'): - continue - with open(os.path.join(directory, file), 'rb') as f: content = f.read() created = os.path.getctime(os.path.join(directory, file)) diff --git a/website/static/css/hilite.css b/website/static/css/hilite.css new file mode 100644 index 0000000..9a05b3a --- /dev/null +++ b/website/static/css/hilite.css @@ -0,0 +1,74 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.codehilite .hll { background-color: #ffffcc } +.codehilite { background: #f8f8f8; } +.codehilite .c { color: #3D7B7B; font-style: italic } /* Comment */ +.codehilite .err { border: 1px solid #FF0000 } /* Error */ +.codehilite .k { color: #008000; font-weight: bold } /* Keyword */ +.codehilite .o { color: #666666 } /* Operator */ +.codehilite .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.codehilite .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.codehilite .cp { color: #9C6500 } /* Comment.Preproc */ +.codehilite .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.codehilite .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.codehilite .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.codehilite .gd { color: #A00000 } /* Generic.Deleted */ +.codehilite .ge { font-style: italic } /* Generic.Emph */ +.codehilite .gr { color: #E40000 } /* Generic.Error */ +.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.codehilite .gi { color: #008400 } /* Generic.Inserted */ +.codehilite .go { color: #717171 } /* Generic.Output */ +.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.codehilite .gs { font-weight: bold } /* Generic.Strong */ +.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.codehilite .gt { color: #0044DD } /* Generic.Traceback */ +.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.codehilite .kp { color: #008000 } /* Keyword.Pseudo */ +.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.codehilite .kt { color: #B00040 } /* Keyword.Type */ +.codehilite .m { color: #666666 } /* Literal.Number */ +.codehilite .s { color: #BA2121 } /* Literal.String */ +.codehilite .na { color: #687822 } /* Name.Attribute */ +.codehilite .nb { color: #008000 } /* Name.Builtin */ +.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.codehilite .no { color: #880000 } /* Name.Constant */ +.codehilite .nd { color: #AA22FF } /* Name.Decorator */ +.codehilite .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.codehilite .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.codehilite .nf { color: #0000FF } /* Name.Function */ +.codehilite .nl { color: #767600 } /* Name.Label */ +.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.codehilite .nv { color: #19177C } /* Name.Variable */ +.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.codehilite .w { color: #bbbbbb } /* Text.Whitespace */ +.codehilite .mb { color: #666666 } /* Literal.Number.Bin */ +.codehilite .mf { color: #666666 } /* Literal.Number.Float */ +.codehilite .mh { color: #666666 } /* Literal.Number.Hex */ +.codehilite .mi { color: #666666 } /* Literal.Number.Integer */ +.codehilite .mo { color: #666666 } /* Literal.Number.Oct */ +.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */ +.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */ +.codehilite .sc { color: #BA2121 } /* Literal.String.Char */ +.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */ +.codehilite .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.codehilite .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.codehilite .sx { color: #008000 } /* Literal.String.Other */ +.codehilite .sr { color: #A45A77 } /* Literal.String.Regex */ +.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */ +.codehilite .ss { color: #19177C } /* Literal.String.Symbol */ +.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #0000FF } /* Name.Function.Magic */ +.codehilite .vc { color: #19177C } /* Name.Variable.Class */ +.codehilite .vg { color: #19177C } /* Name.Variable.Global */ +.codehilite .vi { color: #19177C } /* Name.Variable.Instance */ +.codehilite .vm { color: #19177C } /* Name.Variable.Magic */ +.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/website/templates/article.pug b/website/templates/article.pug index d862406..6e22abb 100644 --- a/website/templates/article.pug +++ b/website/templates/article.pug @@ -5,6 +5,7 @@ block title block styles link(href="{{ url_for('static', filename='css/article.css') }}", rel="stylesheet") + link(href="{{ url_for('static', filename='css/hilite.css') }}", rel="stylesheet") block content h1.post-title.h1 {{title}} diff --git a/website/templates/sitemap.xml b/website/templates/sitemap.xml index 14cb467..df42c9d 100644 --- a/website/templates/sitemap.xml +++ b/website/templates/sitemap.xml @@ -1,7 +1,30 @@- {% for item in items %} - \ No newline at end of file- +{{ 'articles/' + item.get_identifier() }} -+ +index ++ + {% for item in articles %} +faq ++ {% endfor %} + {% for item in images %} +{{ 'articles/' + item.get_identifier() }} ++ +{{ 'images/' + item.get_identifier() }} ++ + {% endfor %} +{{ 'images/' + item.get_identifier() + '/thumbnail'}} ++ +favicon ++ +rss ++ sitemap +