1
0
mirror of https://github.com/venthur/blag.git synced 2025-11-25 20:52:43 +00:00

Improved the default theme.

Closes: #48
This commit is contained in:
Bastian Venthur
2023-06-13 16:29:44 +02:00
parent e1b1ebde32
commit fe268516e3
18 changed files with 515 additions and 43 deletions

View File

@@ -14,6 +14,11 @@
New users are not affected as `blag quickstart` will generate the needed New users are not affected as `blag quickstart` will generate the needed
templates. templates.
### Changed
* blag comes now with a simple yet good looking default theme that supports
syntax highlighting and a light- and dark theme.
## [1.5.0] - 2023-04-16 ## [1.5.0] - 2023-04-16

8
blag/content/about.md Normal file
View File

@@ -0,0 +1,8 @@
title: About Me
description: Short description of this page.
## About Me
This is a regular page, i.e. not a blog post. Feel free to delete this page,
populate it with more content or generate more [pages like this](testpage.md).

View File

@@ -0,0 +1,51 @@
Title: Hello World!
Description: Hello there, this is the first blog post. You should read me first.
Date: 2023-01-01 12:00
Tags: blag, pygments
## Hello World
This is an example blog post. Internally, blag differentiates between **pages**
and **articles**. Intuitively, pages are simple pages and articles are blog
posts. The decision whether a document is a page or an article is made
depending on the presence of the `date` metadata element: Any document that
contains the `date` metadata element is an article, everything else a page.
This differentiation has consequences:
* blag uses different templates: `page.html` and `article.html`
* only articles are collected in the Atom feed
* only articles are aggregated in the tag pages
For more detailed information, please refer to the [documentation][doc]
[doc]: https://blag.readthedocs.io
### Syntax Highlighting
```python
def foo(bar):
"""This is a docstring.
"""
# comment
return bar
```
Syntax highlighting is done via [Pygments][pygments]. For code blocks, blag
generates the necessary CSS classes by default, which you can use to style your
code using CSS. It provides you with a default light- and dark theme, for more
information on how to generate a different theme, please refer to [Pygments'
documentation][pygments].
[pygments]: https://pygments.org
### Next Steps
* Adapt the files in `templates` to your needs
* Check out the files in `static` and modify as needed
* Add some content
* Change the [favicon.ico](favicon.ico)

View File

@@ -0,0 +1,9 @@
Title: Second Post
Description: This is the second blog post, so you can see how it looks like on the front page.
Date: 2023-01-02 12:00
Tags: blag
## Second Post
This page serves no purpose :)

46
blag/content/testpage.md Normal file
View File

@@ -0,0 +1,46 @@
# This Is A Headline
This is some **bold text** with some `code` inside. This is _some_underlined_
text with some `code` inside. This is some text with some `code` inside. This
is some text with some `code` inside. This is some text with some `code`
inside. This is some text with some `code` inside. This is some text with some
`code` inside. This is some text with some `code` inside.
This is some [link](https://example.com) inside the text -- it does not really
lead anywhere! This is some [link](https://example.com) inside the text -- it
does not really lead anywhere! This is some [link](https://example.com) inside
the text -- it does not really lead anywhere!
* some bullets
* some other
* bullets
* foo
```python
# this is some python code
class Foo:
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def do_something():
"""This is the docstring of this method.
"""
return foo
```
## Some other headline
This is some other text
```makefile
# some comment
foo:
ls -lh
```

View File

@@ -37,20 +37,25 @@ def get_input(question: str, default: str) -> str:
return reply return reply
def copy_templates() -> None: def copy_default_theme() -> None:
"""Copy templates into current directory. """Copy default theme into current directory.
The default theme contains the 'templates', 'content' and 'static'
directories shipped with blag.
It will not overwrite existing files. It will not overwrite existing files.
""" """
print("Copying templates...") print("Copying default theme...")
try: for dir_ in 'templates', 'content', 'static':
shutil.copytree( print(f" Copying {dir_}...")
os.path.join(blag.__path__[0], 'templates'), try:
'templates', shutil.copytree(
) os.path.join(blag.__path__[0], dir_),
except FileExistsError: dir_,
print("Templates already exist. Skipping.") )
except FileExistsError:
print(f" {dir_} already exist. Skipping.")
def quickstart(args: argparse.Namespace | None) -> None: def quickstart(args: argparse.Namespace | None) -> None:
@@ -92,4 +97,4 @@ def quickstart(args: argparse.Namespace | None) -> None:
with open('config.ini', 'w') as fh: with open('config.ini', 'w') as fh:
config.write(fh) config.write(fh)
copy_templates() copy_default_theme()

83
blag/static/code-dark.css Normal file
View File

@@ -0,0 +1,83 @@
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; }
.hll { background-color: #49483e }
.c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */
.esc { color: #f8f8f2 } /* Escape */
.g { color: #f8f8f2 } /* Generic */
.k { color: #66d9ef } /* Keyword */
.l { color: #ae81ff } /* Literal */
.n { color: #f8f8f2 } /* Name */
.o { color: #f92672 } /* Operator */
.x { color: #f8f8f2 } /* Other */
.p { color: #f8f8f2 } /* Punctuation */
.ch { color: #75715e } /* Comment.Hashbang */
.cm { color: #75715e } /* Comment.Multiline */
.cp { color: #75715e } /* Comment.Preproc */
.cpf { color: #75715e } /* Comment.PreprocFile */
.c1 { color: #75715e } /* Comment.Single */
.cs { color: #75715e } /* Comment.Special */
.gd { color: #f92672 } /* Generic.Deleted */
.ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */
.gr { color: #f8f8f2 } /* Generic.Error */
.gh { color: #f8f8f2 } /* Generic.Heading */
.gi { color: #a6e22e } /* Generic.Inserted */
.go { color: #66d9ef } /* Generic.Output */
.gp { color: #f92672; font-weight: bold } /* Generic.Prompt */
.gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */
.gu { color: #75715e } /* Generic.Subheading */
.gt { color: #f8f8f2 } /* Generic.Traceback */
.kc { color: #66d9ef } /* Keyword.Constant */
.kd { color: #66d9ef } /* Keyword.Declaration */
.kn { color: #f92672 } /* Keyword.Namespace */
.kp { color: #66d9ef } /* Keyword.Pseudo */
.kr { color: #66d9ef } /* Keyword.Reserved */
.kt { color: #66d9ef } /* Keyword.Type */
.ld { color: #e6db74 } /* Literal.Date */
.m { color: #ae81ff } /* Literal.Number */
.s { color: #e6db74 } /* Literal.String */
.na { color: #a6e22e } /* Name.Attribute */
.nb { color: #f8f8f2 } /* Name.Builtin */
.nc { color: #a6e22e } /* Name.Class */
.no { color: #66d9ef } /* Name.Constant */
.nd { color: #a6e22e } /* Name.Decorator */
.ni { color: #f8f8f2 } /* Name.Entity */
.ne { color: #a6e22e } /* Name.Exception */
.nf { color: #a6e22e } /* Name.Function */
.nl { color: #f8f8f2 } /* Name.Label */
.nn { color: #f8f8f2 } /* Name.Namespace */
.nx { color: #a6e22e } /* Name.Other */
.py { color: #f8f8f2 } /* Name.Property */
.nt { color: #f92672 } /* Name.Tag */
.nv { color: #f8f8f2 } /* Name.Variable */
.ow { color: #f92672 } /* Operator.Word */
.pm { color: #f8f8f2 } /* Punctuation.Marker */
.w { color: #f8f8f2 } /* Text.Whitespace */
.mb { color: #ae81ff } /* Literal.Number.Bin */
.mf { color: #ae81ff } /* Literal.Number.Float */
.mh { color: #ae81ff } /* Literal.Number.Hex */
.mi { color: #ae81ff } /* Literal.Number.Integer */
.mo { color: #ae81ff } /* Literal.Number.Oct */
.sa { color: #e6db74 } /* Literal.String.Affix */
.sb { color: #e6db74 } /* Literal.String.Backtick */
.sc { color: #e6db74 } /* Literal.String.Char */
.dl { color: #e6db74 } /* Literal.String.Delimiter */
.sd { color: #e6db74 } /* Literal.String.Doc */
.s2 { color: #e6db74 } /* Literal.String.Double */
.se { color: #ae81ff } /* Literal.String.Escape */
.sh { color: #e6db74 } /* Literal.String.Heredoc */
.si { color: #e6db74 } /* Literal.String.Interpol */
.sx { color: #e6db74 } /* Literal.String.Other */
.sr { color: #e6db74 } /* Literal.String.Regex */
.s1 { color: #e6db74 } /* Literal.String.Single */
.ss { color: #e6db74 } /* Literal.String.Symbol */
.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.fm { color: #a6e22e } /* Name.Function.Magic */
.vc { color: #f8f8f2 } /* Name.Variable.Class */
.vg { color: #f8f8f2 } /* Name.Variable.Global */
.vi { color: #f8f8f2 } /* Name.Variable.Instance */
.vm { color: #f8f8f2 } /* Name.Variable.Magic */
.il { color: #ae81ff } /* Literal.Number.Integer.Long */

View File

@@ -0,0 +1,73 @@
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; }
.hll { background-color: #ffffcc }
.c { color: #3D7B7B; font-style: italic } /* Comment */
.err { border: 1px solid #FF0000 } /* Error */
.k { color: #008000; font-weight: bold } /* Keyword */
.o { color: #666666 } /* Operator */
.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
.cp { color: #9C6500 } /* Comment.Preproc */
.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #E40000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #008400 } /* Generic.Inserted */
.go { color: #717171 } /* Generic.Output */
.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #0044DD } /* Generic.Traceback */
.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.kp { color: #008000 } /* Keyword.Pseudo */
.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.kt { color: #B00040 } /* Keyword.Type */
.m { color: #666666 } /* Literal.Number */
.s { color: #BA2121 } /* Literal.String */
.na { color: #687822 } /* Name.Attribute */
.nb { color: #008000 } /* Name.Builtin */
.nc { color: #0000FF; font-weight: bold } /* Name.Class */
.no { color: #880000 } /* Name.Constant */
.nd { color: #AA22FF } /* Name.Decorator */
.ni { color: #717171; font-weight: bold } /* Name.Entity */
.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
.nf { color: #0000FF } /* Name.Function */
.nl { color: #767600 } /* Name.Label */
.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.nt { color: #008000; font-weight: bold } /* Name.Tag */
.nv { color: #19177C } /* Name.Variable */
.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mb { color: #666666 } /* Literal.Number.Bin */
.mf { color: #666666 } /* Literal.Number.Float */
.mh { color: #666666 } /* Literal.Number.Hex */
.mi { color: #666666 } /* Literal.Number.Integer */
.mo { color: #666666 } /* Literal.Number.Oct */
.sa { color: #BA2121 } /* Literal.String.Affix */
.sb { color: #BA2121 } /* Literal.String.Backtick */
.sc { color: #BA2121 } /* Literal.String.Char */
.dl { color: #BA2121 } /* Literal.String.Delimiter */
.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.s2 { color: #BA2121 } /* Literal.String.Double */
.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
.sh { color: #BA2121 } /* Literal.String.Heredoc */
.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
.sx { color: #008000 } /* Literal.String.Other */
.sr { color: #A45A77 } /* Literal.String.Regex */
.s1 { color: #BA2121 } /* Literal.String.Single */
.ss { color: #19177C } /* Literal.String.Symbol */
.bp { color: #008000 } /* Name.Builtin.Pseudo */
.fm { color: #0000FF } /* Name.Function.Magic */
.vc { color: #19177C } /* Name.Variable.Class */
.vg { color: #19177C } /* Name.Variable.Global */
.vi { color: #19177C } /* Name.Variable.Instance */
.vm { color: #19177C } /* Name.Variable.Magic */
.il { color: #666666 } /* Literal.Number.Integer.Long */

BIN
blag/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

166
blag/static/style.css Normal file
View File

@@ -0,0 +1,166 @@
@import "code-light.css" (prefers-color-scheme: light);
@import "code-dark.css" (prefers-color-scheme: dark);
@media (prefers-color-scheme: light) {
:root {
--background: #FFFFFF;
--background-dim: #f5f7f9;
--foreground: #2B303A;
--foreground-dim: #576379;
--foreground-heavy: #191C22;
--primary-color: #375287;
}
}
@media (prefers-color-scheme: dark) {
:root {
--background: #2B363B;
--background-dim: #2F3C42;
--foreground: #f0f2f3;
--foreground-dim: #d5d5d5;
--foreground-heavy: #f2f4f5;
--primary-color: #A1C5FF;
}
}
html {
font-size: 18px;
font-family: serif;
}
body {
margin: 0 auto;
max-width: 50rem;
background: var(--background);
color: var(--foreground);
line-height: 1.5;
padding: 0rem 0.5rem;
}
aside {
font-size: smaller;
font-style: italic;
color: var(--foreground-dim);
}
h1,
h2,
h3,
h4,
h5,
h6,
strong {
color: var(--foreground-heavy);
}
a {
color: var(--primary-color);
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
text-decoration: none;
}
h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover {
text-decoration: underline;
}
nav ul {
list-style: none;
}
nav li {
display: inline;
}
nav li + li:before {
content: " · ";
margin: 0 0.5ex;
}
article header {
display: flex;
flex-direction: row;
margin: 1rem 0;
}
article header time {
white-space: nowrap;
color: var(--foreground-dim);
font-style: italic;
flex: 0 0 12ex;
}
article header h2,
article header p {
font-size: 1rem;
display: inline;
}
code,
pre {
background: var(--background-dim);
border-radius: 0.3rem;
font-family: monospace;
}
pre {
padding: 1rem;
border-left: 2px solid var(--primary-color);
overflow: auto;
}
code {
padding: 0.1rem 0.2rem;
}
/* reset the padding for code inside pre */
pre code {
padding: 0;
}
blockquote {
background: var(--background-dim);
border-radius: 0 0.3rem 0.3rem 0;
font-style: italic;
border-left: 2px solid var(--primary-color);
margin: 0;
padding: 1rem;
}
/* reset the margin for p inside blockquotes */
blockquote p {
margin: 0;
}
body > header {
padding: 2rem 0;
}
body footer {
margin: 3rem 0;
color: var(--foreground-dim);
font-size: smaller;
text-align: center;
}
header nav {
display: flex;
flex-direction: row;
justify-content: space-between;
}
header h1 {
margin: 0 auto;
color: var(--primary-color);
}
header h2 {
display: inline;
font-size: 1.2rem;
}

View File

@@ -3,18 +3,21 @@
{% block title %}{{ site.title }}{% endblock %} {% block title %}{{ site.title }}{% endblock %}
{% block content %} {% block content %}
{% for entry in archive %} {% for entry in archive %}
{% if entry.title %} <article>
<h1><a href="{{entry.dst}}">{{entry.title}}</a></h1> <header>
<time datetime="{{ entry.date }}">{{ entry.date.date() }}</time>
{% if entry.description %} <div>
<p>— {{ entry.description }}</p> <h2><a href="{{ entry.dst }}">{{ entry.title }}</a></h2>
{% endif %} {% if entry.description %}
<p>— {{ entry.description }}</p>
{% endif %} {% endif %}
</div>
<p>Written on {{ entry.date.date() }}.</p> </header>
</article>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View File

@@ -22,7 +22,6 @@
</p> </p>
</aside> </aside>
{{ content }} {{ content }}
{% endblock %} {% endblock %}

View File

@@ -4,12 +4,15 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<meta name="author" content="{{ site.author }}"> <meta name="author" content="{{ site.author }}">
{%- if description %} {%- if description %}
<meta name="description" content="{{ description }}"> <meta name="description" content="{{ description }}">
{%- else %} {%- else %}
<meta name="description" content="{{ site.description }}"> <meta name="description" content="{{ site.description }}">
{%- endif %} {%- endif %}
<link rel="alternate" href="/atom.xml" type="application/atom+xml">
<link rel="stylesheet" href="/style.css" type="text/css">
<title>{% block title %}{% endblock %} | {{ site.description }}</title> <title>{% block title %}{% endblock %} | {{ site.description }}</title>
</head> </head>
@@ -19,9 +22,10 @@
<nav> <nav>
<h2>{{ site.description }}</h2> <h2>{{ site.description }}</h2>
<ul> <ul>
<li><a href="/">Blog</a></li> <li><h2><a href="/">Blog</a></h2></li>
<li><a href="/tags/">Tags</a></li> <li><h2><a href="/tags/">Tags</a></h2></li>
<li><a href="/atom.xml">Atom Feed</a></li> <li><h2><a href="/about.html">About Me</a></h2></li>
<li><h2><a href="/atom.xml">Feed</a></h2></li>
</ul> </ul>
</nav> </nav>
</header> </header>
@@ -31,7 +35,15 @@
{% endblock %} {% endblock %}
</main> </main>
<footer>
<p>This website was built with <a href="https://github.com/venthur/blag">blag</a>.
<br>
Contact me via
<a rel="me" href="TODO">[TODO] Mastodon</a>,
<a href="TODO">[TODO] Twitter</a> or
<a href="TODO">[TODO] Github</a>.
</p>
</footer>
</body> </body>
</html> </html>

View File

@@ -3,5 +3,7 @@
{% block title %}{{ title }}{% endblock %} {% block title %}{{ title }}{% endblock %}
{% block content %} {% block content %}
{{ content }}
{{ content }}
{% endblock %} {% endblock %}

View File

@@ -1,20 +1,25 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %}Tag {{ tag }}{% endblock %} {% block title %}Tag: {{ tag }}{% endblock %}
{% block content %} {% block content %}
<h2>Articles tagged "{{ tag }}"</h2>
{% for entry in archive %} {% for entry in archive %}
{% if entry.title %} <article>
<h1><a href="/{{entry.dst}}">{{entry.title}}</a></h1> <header>
<time datetime="{{ entry.date }}">{{ entry.date.date() }}</time>
{% if entry.description %} <div>
<p>— {{ entry.description }}</p> <h2><a href="../{{ entry.dst }}">{{ entry.title }}</a></h2>
{% endif %} {% if entry.description %}
<p>— {{ entry.description }}</p>
{% endif %} {% endif %}
</div>
<p>Written on {{ entry.date.date() }}.</p> </header>
</article>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View File

@@ -48,10 +48,16 @@ version = {attr = "blag.__VERSION__" }
packages = [ packages = [
"blag", "blag",
"blag.templates", "blag.templates",
"blag.static",
"blag.content",
] ]
[tool.setuptools.package-data] [tool.setuptools.package-data]
blag = ["templates/*"] blag = [
"templates/*",
"static/*",
"content/*",
]
[tool.pytest.ini_options] [tool.pytest.ini_options]
addopts = """ addopts = """

View File

@@ -60,14 +60,13 @@ author = a. u. thor
""" """
with TemporaryDirectory() as dir: with TemporaryDirectory() as dir:
for d in 'content', 'build', 'static': os.mkdir(f'{dir}/build')
os.mkdir(f'{dir}/{d}')
with open(f'{dir}/config.ini', 'w') as fh: with open(f'{dir}/config.ini', 'w') as fh:
fh.write(config) fh.write(config)
# change directory # change directory
old_cwd = os.getcwd() old_cwd = os.getcwd()
os.chdir(dir) os.chdir(dir)
quickstart.copy_templates() quickstart.copy_default_theme()
yield dir yield dir
# and change back afterwards # and change back afterwards
os.chdir(old_cwd) os.chdir(old_cwd)

View File

@@ -70,7 +70,7 @@ def test_tag(tag_template: Template) -> None:
'archive': archive, 'archive': archive,
} }
result = tag_template.render(ctx) result = tag_template.render(ctx)
assert 'Tag foo' in result assert 'foo' in result
assert 'this is a title' in result assert 'this is a title' in result
assert '1980-05-09' in result assert '1980-05-09' in result