first commit
Some checks failed
Build / build-deploy (push) Failing after 23s

This commit is contained in:
Stephan Hadan 2025-01-27 02:54:15 +01:00
commit c7377979ad
37 changed files with 5061 additions and 0 deletions

View file

@ -0,0 +1,73 @@
name: Build
on:
push:
branches:
- main
jobs:
build-deploy:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
- run: apt-get update && apt-get install -y rsync
- name: Create private key
run: |
echo "${{ secrets.ACT_RUNNER_KEY }}" > /tmp/act_runner_key
chmod 600 /tmp/act_runner_key
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install "pelican[markdown]"
- run: make publish
- name: rsync public directory
run: |
/usr/bin/rsync -avz --delete -e "ssh -i /tmp/act_runner_key -o StrictHostKeyChecking=no" ${{ gitea.workspace }}/output/* root@vps03.hadan-it.com:/data/webspace/blog.hadan-it.com/
- name: ntfy-success-notifications
uses: https://github.com/niniyas/ntfy-action@master
if: success()
with:
title: 'Forgejo Actions'
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
priority: 4
headers: '${{ secrets.NTFY_HEADERS }}'
tags: +1,partying_face,action,successfully,completed
details: Workflow has been successfully completed!
icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Forgejo_logo.svg/512px-Forgejo_logo.svg.png'
image: true
- name: ntfy-failed-notifications
uses: https://github.com/niniyas/ntfy-action@master
if: failure()
with:
title: 'Forgejo Actions'
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
priority: 5
headers: '${{ secrets.NTFY_HEADERS }}'
tags: +1,partying_face,action,failed
details: Workflow has failed!
actions: 'default'
icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Forgejo_logo.svg/512px-Forgejo_logo.svg.png'
image: true
- name: ntfy-cancelled-notifications
uses: https://github.com/niniyas/ntfy-action@master
if: cancelled()
with:
title: 'Forgejo Actions'
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
priority: 3
headers: '${{ secrets.NTFY_HEADERS }}'
tags: +1,partying_face,action,cancelled
details: Workflow has been cancelled!
actions: '[{"action": "view", "label": "Open portal", "url": "https://blog.hadan-it.com/", "clear": true}]'
icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Forgejo_logo.svg/512px-Forgejo_logo.svg.png'
image: true
- run: echo "This job's status is ${{ job.status }}."

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
__pycache__/
output/
tmp/
.DS_Store
venv/

72
Makefile Normal file
View file

@ -0,0 +1,72 @@
PY?=
PELICAN?=pelican
PELICANOPTS=
BASEDIR=$(CURDIR)
INPUTDIR=$(BASEDIR)/content
OUTPUTDIR=$(BASEDIR)/output
CONFFILE=$(BASEDIR)/pelicanconf.py
PUBLISHCONF=$(BASEDIR)/publishconf.py
DEBUG ?= 0
ifeq ($(DEBUG), 1)
PELICANOPTS += -D
endif
RELATIVE ?= 0
ifeq ($(RELATIVE), 1)
PELICANOPTS += --relative-urls
endif
SERVER ?= "0.0.0.0"
PORT ?= 0
ifneq ($(PORT), 0)
PELICANOPTS += -p $(PORT)
endif
help:
@echo 'Makefile for a pelican Web site '
@echo ' '
@echo 'Usage: '
@echo ' make html (re)generate the web site '
@echo ' make clean remove the generated files '
@echo ' make regenerate regenerate files upon modification '
@echo ' make publish generate using production settings '
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
@echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
@echo ' make devserver [PORT=8000] serve and regenerate together '
@echo ' make devserver-global regenerate and serve on 0.0.0.0 '
@echo ' '
@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
@echo 'Set the RELATIVE variable to 1 to enable relative urls '
@echo ' '
html:
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
clean:
[ ! -d "$(OUTPUTDIR)" ] || rm -rf "$(OUTPUTDIR)"
regenerate:
"$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
serve:
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
serve-global:
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER)
devserver:
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
devserver-global:
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b 0.0.0.0
publish:
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS)
.PHONY: html help clean regenerate serve serve-global devserver devserver-global publish

45
pelicanconf.py Normal file
View file

@ -0,0 +1,45 @@
AUTHOR = 'Stephan Hadan'
DESCRIPTION = ''
SITENAME = 'News @ Hadan IT'
SITEURL = 'https://blog.hadan-it.com'
SITEIMAGE = ''
PATH = 'content'
OUTPUT_PATH = 'output'
TIMEZONE = 'Europe/Berlin'
STARTYEAR = '2025'
# comment CURRENTYEAR out if it's the same as STARTYEAR
#CURRENTYEAR = date.today().year
DEFAULT_LANG = 'de'
# Feed generation is usually not desired when developing
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
DELETE_OUTPUT_DIRECTORY = True
THEME = 'themes/business'
# Blogroll
LINKS = (
("Pelican", "https://getpelican.com/"),
("Python.org", "https://www.python.org/"),
("Jinja2", "https://palletsprojects.com/p/jinja/"),
("You can modify those links in your config file", "#"),
)
# Social widget
SOCIAL = (
("You can add links in your config file", "#"),
("Another social link", "#"),
)
DEFAULT_PAGINATION = 10
# Uncomment following line if you want document-relative URLs when developing
RELATIVE_URLS = True

24
publishconf.py Normal file
View file

@ -0,0 +1,24 @@
# This file is only used if you use `make publish` or
# explicitly specify it as your config file.
import os
import sys
sys.path.append(os.curdir)
from pelicanconf import *
# If your site is available via HTTPS, make sure SITEURL begins with https://
SITEURL = "https://blog.hadan-it.com"
PARENTURL = "https://hadan-it.com"
RELATIVE_URLS = False
THEME = "themes/business"
FEED_ALL_ATOM = "feeds/all.atom.xml"
CATEGORY_FEED_ATOM = "feeds/{slug}.atom.xml"
DELETE_OUTPUT_DIRECTORY = True
# Following items are often useful when publishing
# DISQUS_SITENAME = ""
# GOOGLE_ANALYTICS = ""

145
tasks.py Normal file
View file

@ -0,0 +1,145 @@
import os
import shlex
import shutil
import sys
from invoke import task
from invoke.main import program
from pelican import main as pelican_main
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
OPEN_BROWSER_ON_SERVE = True
SETTINGS_FILE_BASE = "pelicanconf.py"
SETTINGS = {}
SETTINGS.update(DEFAULT_CONFIG)
LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE)
SETTINGS.update(LOCAL_SETTINGS)
CONFIG = {
"settings_base": SETTINGS_FILE_BASE,
"settings_publish": "publishconf.py",
# Output path. Can be absolute or relative to tasks.py. Default: 'output'
"deploy_path": SETTINGS["OUTPUT_PATH"],
# Host and port for `serve`
"host": "localhost",
"port": 8000,
}
@task
def clean(c):
"""Remove generated files"""
if os.path.isdir(CONFIG["deploy_path"]):
shutil.rmtree(CONFIG["deploy_path"])
os.makedirs(CONFIG["deploy_path"])
@task
def build(c):
"""Build local version of site"""
pelican_run("-s {settings_base}".format(**CONFIG))
@task
def rebuild(c):
"""`build` with the delete switch"""
pelican_run("-d -s {settings_base}".format(**CONFIG))
@task
def regenerate(c):
"""Automatically regenerate site upon file modification"""
pelican_run("-r -s {settings_base}".format(**CONFIG))
@task
def serve(c):
"""Serve site at http://$HOST:$PORT/ (default is localhost:8000)"""
class AddressReuseTCPServer(RootedHTTPServer):
allow_reuse_address = True
server = AddressReuseTCPServer(
CONFIG["deploy_path"],
(CONFIG["host"], CONFIG["port"]),
ComplexHTTPRequestHandler,
)
if OPEN_BROWSER_ON_SERVE:
# Open site in default browser
import webbrowser
webbrowser.open("http://{host}:{port}".format(**CONFIG))
sys.stderr.write("Serving at {host}:{port} ...\n".format(**CONFIG))
server.serve_forever()
@task
def reserve(c):
"""`build`, then `serve`"""
build(c)
serve(c)
@task
def preview(c):
"""Build production version of site"""
pelican_run("-s {settings_publish}".format(**CONFIG))
@task
def livereload(c):
"""Automatically reload browser tab upon file modification."""
from livereload import Server
def cached_build():
cmd = "-s {settings_base} -e CACHE_CONTENT=true LOAD_CONTENT_CACHE=true"
pelican_run(cmd.format(**CONFIG))
cached_build()
server = Server()
theme_path = SETTINGS["THEME"]
watched_globs = [
CONFIG["settings_base"],
f"{theme_path}/templates/**/*.html",
]
content_file_extensions = [".md", ".rst"]
for extension in content_file_extensions:
content_glob = "{}/**/*{}".format(SETTINGS["PATH"], extension)
watched_globs.append(content_glob)
static_file_extensions = [".css", ".js"]
for extension in static_file_extensions:
static_file_glob = f"{theme_path}/static/**/*{extension}"
watched_globs.append(static_file_glob)
for glob in watched_globs:
server.watch(glob, cached_build)
if OPEN_BROWSER_ON_SERVE:
# Open site in default browser
import webbrowser
webbrowser.open("http://{host}:{port}".format(**CONFIG))
server.serve(host=CONFIG["host"], port=CONFIG["port"], root=CONFIG["deploy_path"])
@task
def publish(c):
"""Publish to production via rsync"""
pelican_run("-s {settings_publish}".format(**CONFIG))
c.run(
'rsync --delete --exclude ".DS_Store" -pthrvz -c '
'-e "ssh -p {ssh_port}" '
"{} {ssh_user}@{ssh_host}:{ssh_path}".format(
CONFIG["deploy_path"].rstrip("/") + "/", **CONFIG
)
)
def pelican_run(cmd):
cmd += " " + program.core.remainder # allows to pass-through args to pelican
pelican_main(shlex.split(cmd))

15
themes/business/README.md Normal file
View file

@ -0,0 +1,15 @@
# business
A custom [pelican][pl] theme for the blog of Stephan Hadan Professional IT-Services. It's based on the
[aboutwilson][aw] theme with some minor tweaks, which are listed below.
* Updated to FontAwesome 5
* Reduced number of icons
* Different font family for body and headings
* Changed colour theme to blue
* "Tags: " text is only shown if the post has tags
* Site title is aligned with the post titles
* New `STARTYEAR` pelican config option
[pl]: https://getpelican.com
[aw]: https://github.com/getpelican/pelican-themes/tree/master/aboutwilson

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
viewBox="0 0 2.4898222 2.4794246"
id="svg10"
width="2.4898221"
height="2.4794245"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#">
<g
transform="translate(2.8898221,0.05769865)"
id="g9">
<g
clip-path="url(#SvgjsClipPath1012)"
id="g8">
<g
clip-path="url(#SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d)"
id="g3">
<path
d="m -0.39967561,1.8529838 -0.001946,0.00195 c -0.44607815,0.6134951 -1.30455689,0.75019 -1.91911709,0.3055758 v 0 l -0.00195,-0.00195 C -2.9364565,1.7126872 -3.0733224,0.85404639 -2.628589,0.23944648 v 0 l 0.00162,-0.001946 0.074611,0.0538495 0.07753,0.0532007 v 0.001946 C -2.8610501,0.87676571 -2.7449316,1.6196339 -2.2153126,2.0067468 v 0 h 0.00195 c 0.5303144,0.3860342 1.27303659,0.2699385 1.66025008,-0.2595154 v 0 -0.00227 l 0.0746107,0.054174 z"
fill="#bab9b4"
fill-rule="evenodd"
id="path3" />
</g>
<g
clip-path="url(#SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d)"
id="g4">
<path
d="m -1.6901162,0.85968841 c -0.075534,0.0711827 -0.1007471,0.18085869 -0.063882,0.27788069 0.036865,0.097022 0.1285487,0.1622808 0.2322934,0.165343 0.1037447,0.00306 0.1991174,-0.056675 0.2416413,-0.1513539 0.042524,-0.094679 0.023823,-0.20565081 -0.04738,-0.28116477 -0.046634,-0.0495827 -0.1110779,-0.078576 -0.1791158,-0.0805842 -0.068038,-0.002008 -0.1340795,0.0231335 -0.1835569,0.0698792 z"
fill="#4e888f"
fill-rule="evenodd"
id="path4" />
</g>
<g
clip-path="url(#SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d)"
id="g5">
<path
d="m -1.4306007,2.150129 c -0.6051712,0.038763 -1.128917,-0.4165181 -1.1747608,-1.0211941 -0.045844,-0.60467602 0.4032753,-1.13371509 1.0073733,-1.18663361 l 0.012327,0.15635806 c -0.5233206,0.03950434 -0.9155312,0.49576413 -0.8760269,1.01908475 0.039504,0.5233206 0.4957642,0.9155312 1.0190848,0.8760268 z"
fill="#404040"
fill-rule="evenodd"
id="path5" />
</g>
<g
clip-path="url(#SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d)"
id="g6">
<path
d="M -1.9084336,1.6933818 C -2.1428652,1.5540816 -2.2843723,1.2995639 -2.2789729,1.0269221 c 0.0054,-0.27264189 0.1568728,-0.52135733 0.396636,-0.65126642 0.2397631,-0.1299091 0.5308365,-0.1209755 0.7621815,0.0233928 l -0.066825,0.10899649 C -1.4836967,0.33414422 -1.8650488,0.43035158 -2.0437629,0.72419368 -2.222477,1.0180358 -2.1324984,1.4009054 -1.8416083,1.5843853 Z"
fill="#bab9b4"
fill-rule="evenodd"
id="path6" />
</g>
<g
clip-path="url(#SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d)"
id="g7">
<path
d="m -1.8711282,0.87720571 -0.041522,-0.0275735 -0.044118,-0.0217344 C -1.8361852,0.58354994 -1.540448,0.48308353 -1.2959771,0.6034169 h 0.0026 c 0.2429328,0.12124838 0.34201177,0.4161642 0.2215613,0.6594936 v 0.00227 l -0.00195,0.00292 -0.043793,-0.025627 -0.044118,-0.021734 c 0.096279,-0.1954685 0.01599,-0.43197973 -0.17939,-0.52843835 v 0 c -0.1953937,-0.0957958 -0.431459,-0.0154146 -0.5277907,0.17971425 v 0.002595 z"
fill="#404040"
fill-rule="evenodd"
id="path7" />
</g>
</g>
</g>
<defs
id="defs10">
<clipPath
id="SvgjsClipPath1012">
<path
d="M -2.8900508,-0.05769871 H -0.4 V 2.4219714 h -2.4900508 z"
id="path9" />
</clipPath>
<clipPath
id="SvgjsClipPath10062902d424-a408-471b-990d-be55cd49b26d">
<path
d="M -2.8900508,-0.05769871 H -0.4 V 2.4219714 h -2.4900508 z"
id="path10" />
</clipPath>
</defs>
<metadata
id="metadata10">
<rdf:RDF>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-nd/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
</cc:License>
<cc:Work
rdf:about="">
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-nd/4.0/" />
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,133 @@
.my-list-style {
margin-left: 0;
}
.aw-bottom {
padding: 2em;
}
.aw-footer {
margin-top: 2em;
border-top: 2px solid lightgrey;
border-bottom: 2px solid lightgrey;
/* height: 250px;*/
padding-top: 2em;
padding-bottom: 2em;
}
.aw-footer li {
line-height: 200%;
}
.summary {
margin-bottom: 2em;
margin-top: 2em;
color: black;
}
.summary pre { display: none; }
.article-body {
margin-top: 2em;
color: black;
}
.article-title {
margin-bottom: 1em;
}
.article-header {
margin-bottom: 1em;
}
/**
* Overrides of notebook CSS for static HTML export
**/
div.entry-content {
overflow: visible;
padding: 8px;
}
.inner_cell {
width: 100%;
}
.input_area {
padding: 0.2em;
}
a.heading-anchor {
white-space: normal;
}
.rendered_html code {
font-size: .8em;
}
pre.ipynb {
color: black;
background: #f7f7f7;
border: none;
box-shadow: none;
margin-bottom: 0;
padding: 0;
margin: 0px;
font-size: 13px;
}
/* remove the prompt div from text cells */
.prompt {
display: none;
}
/* remove horizontal padding from text cells, */
/* so it aligns with outer body text */
div.text_cell_render {
padding: 0.5em 0em;
}
img.anim_icon {
padding: 0;
border: 0;
vertical-align: middle;
-webkit-box-shadow: none;
-box-shadow: none;
}
div.collapseheader {
width: 100%;
background-color: #d3d3d3;
padding: 2px;
cursor: pointer;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
/* codeberg custom */
body,
h1, h2, h3, h4, h5, h6 {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-weight: initial;
}
h1, h2 { font-weight: 300; }
[class^="cb-"], [class*=" cb-"] {
display: inline-block;
}
.page-header {
display: flex;
}
.page-header img {
height: 75px;
margin-left: 20%;
}
/* remove left padding, used for site title */
.cb-rm-l-padding {
padding-left: 0;
}

View file

@ -0,0 +1,62 @@
/*Syntax highlighting for pygments*/
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #60a0b0; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #808080 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #40a070 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #40a070 } /* Literal.Number.Float */
.highlight .mh { color: #40a070 } /* Literal.Number.Hex */
.highlight .mi { color: #40a070 } /* Literal.Number.Integer */
.highlight .mo { color: #40a070 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -0,0 +1,4 @@
// iepp v2.1pre @jon_neal & @aFarkas github.com/aFarkas/iepp
// html5shiv @rem remysharp.com/html5-enabling-script
// Dual licensed under the MIT or GPL Version 2 licenses
/*@cc_on(function(a,b){function r(a){var b=-1;while(++b<f)a.createElement(e[b])}if(!window.attachEvent||!b.createStyleSheet||!function(){var a=document.createElement("div");return a.innerHTML="<elem></elem>",a.childNodes.length!==1}())return;a.iepp=a.iepp||{};var c=a.iepp,d=c.html5elements||"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|subline|summary|time|video",e=d.split("|"),f=e.length,g=new RegExp("(^|\\s)("+d+")","gi"),h=new RegExp("<(/*)("+d+")","gi"),i=/^\s*[\{\}]\s*$/,j=new RegExp("(^|[^\\n]*?\\s)("+d+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),k=b.createDocumentFragment(),l=b.documentElement,m=b.getElementsByTagName("script")[0].parentNode,n=b.createElement("body"),o=b.createElement("style"),p=/print|all/,q;c.getCSS=function(a,b){try{if(a+""===undefined)return""}catch(d){return""}var e=-1,f=a.length,g,h=[];while(++e<f){g=a[e];if(g.disabled)continue;b=g.media||b,p.test(b)&&h.push(c.getCSS(g.imports,b),g.cssText),b="all"}return h.join("")},c.parseCSS=function(a){var b=[],c;while((c=j.exec(a))!=null)b.push(((i.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(g,"$1.iepp-$2")+c[4]);return b.join("\n")},c.writeHTML=function(){var a=-1;q=q||b.body;while(++a<f){var c=b.getElementsByTagName(e[a]),d=c.length,g=-1;while(++g<d)c[g].className.indexOf("iepp-")<0&&(c[g].className+=" iepp-"+e[a])}k.appendChild(q),l.appendChild(n),n.className=q.className,n.id=q.id,n.innerHTML=q.innerHTML.replace(h,"<$1font")},c._beforePrint=function(){if(c.disablePP)return;o.styleSheet.cssText=c.parseCSS(c.getCSS(b.styleSheets,"all")),c.writeHTML()},c.restoreHTML=function(){if(c.disablePP)return;n.swapNode(q)},c._afterPrint=function(){c.restoreHTML(),o.styleSheet.cssText=""},r(b),r(k);if(c.disablePP)return;m.insertBefore(o,m.firstChild),o.media="print",o.className="iepp-printshim",a.attachEvent("onbeforeprint",c._beforePrint),a.attachEvent("onafterprint",c._afterPrint)})(this,document)@*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

2280
themes/business/static/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,11 @@
function toggleDarkMode(){
halfmoon.toggleDarkMode();
var fa = document.getElementsByClassName("fa");
for (var i = 0; i < fa.length; i++) {
if (fa[i].classList.contains('fa-moon') || fa[i].classList.contains('fa-sun')){
fa[i].classList.toggle('fa-sun');
fa[i].classList.toggle('fa-moon');
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
{% if GOOGLE_ANALYTICS %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{{ GOOGLE_ANALYTICS }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}

View file

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block title %}Archives — {{ SITENAME }}{% endblock %}
{% block description %}Find all posts on one page.{% endblock %}
{% block content %}
<h1>Archives</h1>
<table class="table">
<tbody>
{% for article in dates %}
<tr>
<td>{{ article.date.strftime("%d %b %Y") }}</td>
<td><a href='{{ SITEURL }}/{{ article.url }}'>{{ article.title }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,49 @@
{% extends "base.html" %}
{% block title %}{{ article.title }} — {{ SITENAME }}{% endblock %}
{% block description %}{{ article.summary | striptags | truncate(80, False, '...', 0) }}{% endblock %}
{% block content %}
<div class="article mx-auto" itemscope itemtype="http://schema.org/BlogPosting">
<div class="text-center article-header">
<h1 itemprop="name headline" class="article-title">{{ article.title }}</h1>
{% if article.authors %}
<h4>{{ article.authors | join(', ') }}</h4>
{% elif article.author %}
<span itemprop="author" itemscope itemtype="http://schema.org/Person">
<h4 itemprop="name">{{ article.author }}</h4>
</span>
{% endif %}
<span class="text-muted">
<i class="fas fa-clock"></i>
<time datetime="{{ article.date.isoformat() }}" itemprop="datePublished">{{ article.locale_date }}</time>
</span>
</div>
{% if article.category %}
<div class="text-muted">
<span><i class="fas fa-folder"></i> Category:</span>
<span itemprop="articleSection">
<a href="{{ SITEURL }}/{{ article.category.url }}" rel="category">{{ article.category }}</a>
</span>
</div>
{% endif %}
{% if article.tags %}
<div class="text-muted">
<span><i class="fas fa-tags"></i> Tags:</span>
{% for tag in article.tags %}
<span itemprop="keywords">
<a href="{{ SITEURL }}/{{ tag.url }}" rel="tag">#{{ tag }}</a>
</span>
{% endfor %}
</div>
{% endif %}
<div itemprop="articleBody" class="article-body">{{ article.content }}</div>
{% include "twitter.html" %}
{% include "liberapay.html" %}
{% include 'disqus.html' %}
</div>
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends "index.html" %}
{% block title %}{{ author }} — {{ SITENAME }}{% endblock %}
{% block description %}All posts written by {{ author }}.{% endblock %}
{% block content %}
<h1>Author <b>{{author}}</b></h1>
<table class="table">
<tbody>
{% for article in articles %}
<tr>
<td>{{ article.date.strftime("%d %b %Y") }}</td>
<td><a href='{{ SITEURL }}/{{ article.url }}'>{{ article.title }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Authors — {{ SITENAME }}{% endblock %}
{% block description %}Authors page lists all post authors.{% endblock %}
{% block content %}
<h1>Authors</h1>
<ul>
{% for author, articles in authors %}
<li><a href="{{ SITEURL }}/{{ author.url }}">{{ author }} ({{ articles | count }})</li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html lang="{{ DEFAULT_LANG }}" class="business-design">
<head>
<meta charset="utf-8">
<title>{% block title %}{{ SITENAME }}{% endblock %}</title>
<meta name="description" content="{% block description %}{{ DESCRIPTION }}{% endblock %}">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block meta %}<meta name="author" content="{{ AUTHOR }}">{% endblock %}
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/pygments.css">
<link rel="stylesheet" href="https://design.hadan-it.com/business/design-kit/v1/css/business.css">
<link href="https://fonts.hadan-it.com/dist/inter/web/inter.css" rel="stylesheet">
<link href="https://fonts.hadan-it.com/dist/fontawesome5/css/all.min.css" rel="stylesheet">
<script defer src="{{ SITEURL }}/theme/js/darkmode.js"></script>
<script defer src="https://design.hadan-it.com/business/design-kit/v1/js/business.js"></script>
<script defer src="https://design.hadan-it.com/business/design-kit/v1/js/business-components.js"></script>
<link rel="icon" href="{{ SITEURL }}/theme/css/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ SITEURL }}/theme/css/favicon.svg" type="image/svg+xml">
{% block head %}{% endblock %}
{% if FEED_ALL_ATOM %}
<link href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" title="Blog" rel="alternate" type="application/atom+xml">
{% endif %}
</head>
<body class="with-custom-webkit-scrollbars with-custom-css-scrollbars" data-dm-shortcut-enabled="true" data-sidebar-shortcut-enabled="true" data-set-preferred-theme-onload="true">
<style type="text/css" media="screen">
.business-design .content {
max-width: 80ch;
margin-left: auto;
margin-right: auto;
}
.business-design .content-wrapper {
padding-left: 20px;
padding-right: 20px;
}
.business-design img {
max-width: 100%;
}
</style>
<div class="page-wrapper with-navbar with-sidebar" data-sidebar-type="overlayed-sm-and-down">
<nav class="navbar">
<div class="navbar-content">
<button class="btn btn-primary" type="button" onclick="halfmoon.toggleSidebar()">
<i class="fa fa-bars" aria-hidden="true"></i>
<span class="sr-only">Toggle sidebar</span>
</button>
</div>
<a href="{{ SITEURL }}" class="navbar-brand" title="Codeberg News">
<img src="https://design.hadan-it.com/business/logo-set/plain-transparent/svg/logo-transparent-background.svg" alt="Stephan Hadan Professional IT-Services">
News
</a>
<ul class="navbar-nav d-none d-md-flex w-full">
{% if LINKS %}
{% for name, link in LINKS %}
<li class="nav-item">
<a href="{{ link }}" class="nav-link">{{ name }}</a>
</li>
{% endfor %}
{% endif %}
<li class="nav-item ml-auto">
<a href="javascript:;" onclick="toggleDarkMode()" class="nav-link text-center">
<i class="fa fa-moon"></i>
</a>
</li>
</ul>
<div class="navbar-content d-md-none ml-auto">
<div class="dropdown with-arrow">
<button class="btn" data-toggle="dropdown" type="button" id="navbar-dropdown-toggle-btn-1">
Menu <i class="fa fa-angle-down" aria-hidden="true"></i>
</button>
<div class="dropdown-menu dropdown-menu-right w-200" aria-labelledby="navbar-dropdown-toggle-btn-1">
<a href="{{ SITEURL }}" class="dropdown-item">Home</a>
{% if LINKS %}
<div class="dropdown-divider my-5"></div>
{% for name, link in LINKS %}
<a href="{{ link }}" class="dropdown-item">{{ name }}</a>
{% endfor %}
{% endif %}
{% if SOCIAL %}
<div class="dropdown-divider my-5"></div>
{% for name, link in SOCIAL %}
<a rel="me" href="{{ link }}" class="dropdown-item">
<i class="fab fa-{{ name.lower() }} " aria-hidden="true"></i> {{ name }}
</a>
{% endfor %}
{% endif %}
<div class="dropdown-divider my-5"></div>
<a href="javascript:;" onclick="toggleDarkMode()" class="dropdown-item">
<i class="fa fa-moon"></i>&nbsp; Toggle Dark Mode
</a>
</div>
</div>
</div>
</nav>
<div class="sidebar-overlay" onclick="halfmoon.toggleSidebar()"></div>
<div class="sidebar">
<div class="sidebar-menu">
<div class="sidebar-title">Navigation</div>
<div class="sidebar-divider"></div>
<a class="sidebar-link" href="{{ SITEURL }}">Home</a>
<a class="sidebar-link" href="{{ SITEURL }}/archives.html">Archives</a>
<a class="sidebar-link" href="{{ SITEURL }}/authors.html">Authors</a>
{% for title, link in MENUITEMS %}
<a href="{{ SITEURL }}/{{ link }}" class="sidebar-link">{{ title }}</a>
{% endfor %}
{% if DISPLAY_PAGES_ON_MENU %}
{% for page in pages %}
<a href="{{ SITEURL }}/{{ page.url }}" class="sidebar-link">{{ page.title }}</a>
{% endfor %}
{% endif %}
{% if FEED_ALL_ATOM %}
<a href="{{ FEED_DOMAIN }}/{{ FEED_ALL_ATOM }}" type="application/atom+xml" class="sidebar-link">
Atom
</a>
{% endif %}
{% if FEED_ALL_RSS %}
<a href="{{ FEED_DOMAIN }}/{{ FEED_ALL_RSS }}" type="application/rss+xml" class="sidebar-link">
RSS
</a>
{% endif %}
<br>
<div class="sidebar-title">Categories</div>
<div class="sidebar-divider"></div>
{% for cat, art in categories %}
<a href="{{ SITEURL }}/category/{{ cat | replace(" ", "-") | lower }}.html" class="sidebar-link">
{{ cat }} ({{ art | count }})
</a>
{% endfor %}
<br>
<div class="sidebar-title">Socials</div>
<div class="sidebar-divider"></div>
{% if SOCIAL %}
{% for name, link in SOCIAL %}
<a href="{{ link }}" class="sidebar-link">
<i class="fab fa-{{ name.lower() }} pr-5" aria-hidden="true"></i> {{ name }}
</a>
{% endfor %}
{% endif %}
</div>
<div class="sidebar-divider"></div>
<p class="mt-10 mb-5 mx-20 px-5 text-muted">&copy; {{ AUTHOR }} {{ STARTYEAR }}{% if CURRENTYEAR %}{{ CURRENTYEAR }}{% endif %}</p>
<a href="https://codeberg.org/codeberg/org/src/Imprint.md" class="sidebar-link">Codeberg Imprint</a>
<a href="https://blog.getpelican.com" class="sidebar-link">Powered by Pelican</a>
</div>
<div class="content-wrapper">
<div class="container-fluid">
<div class="content">
<div class="row">
<div class="col-md-12">
{% block content %}{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
{% include "github.html" %}
</body>
</html>

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Categories — {{ SITENAME }}{% endblock %}
{% block description %}Categories page lists all categories used to classify the posts.{% endblock %}
{% block content %}
<h1>Categories</h1>
<ul>
{% for category, articles in categories %}
<li><a href="{{ SITEURL }}/{{ category.url }}">{{ category }} ({{ articles | count }})</li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block title %}{{ category }} — {{ SITENAME }}{% endblock %}
{% block description %}All posts which refer to category {{ category }}.{% endblock %}
{% block content %}
<h1>Category <b>{{category}}</b></h1>
<table class="table">
<tbody>
{% for article in articles %}
<tr>
<td>{{ article.date.strftime("%d %b %Y") }}</td>
<td><a href='{{ SITEURL }}/{{ article.url }}'>{{ article.title }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,14 @@
{% if DISQUS_SITENAME %}
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = '{{ DISQUS_SITENAME }}';
var disqus_title = '{{ article.title }}';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
{% endif %}

View file

@ -0,0 +1,3 @@
{% if GITHUB_URL %}
<a href="{{ GITHUB_URL }}"><img style="position: absolute; top: 40px; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png" alt="Fork me on GitHub" /></a>
{% endif %}

View file

@ -0,0 +1,38 @@
{% extends "base.html" %}
{% block content_title %}{% endblock %}
{% block content %}
{% if articles %}
{% for article in articles_page.object_list %}
<div class="article card mx-auto" itemscope itemtype="http://schema.org/BlogPosting">
<a href="{{ SITEURL }}/{{ article.url }}">
<h2 class="card-title" itemprop="name headline">{{ article.title }}</h2>
</a>
<p class="text-muted">
<i class="fas fa-clock"></i>
<time datetime="{{ article.date.isoformat() }}" itemprop="datePublished">{{ article.locale_date }}</time>
</p>
<div class="summary">{{ article.summary }}</div>
{% if article.category %}
<span class="text-muted"><i class="fas fa-folder"></i> Category:</span>
<span itemprop="articleSection">
<a href="{{ SITEURL }}/{{ article.category.url }}" rel="category">{{ article.category }}</a>
</span>
{% endif %}
{% if article.tags %}
<span class="text-muted"><i class="fas fa-tags ml-10"></i> Tags:</span>
{% for tag in article.tags %}
<span itemprop="keywords">
<a href="{{ SITEURL }}/{{ tag.url }}" rel="tag">#{{ tag }}</a>
</span>
{% endfor %}
{% endif %}
</div>
{% endfor %}
{% include 'pagination.html' %}
{% endif %}
{% endblock content %}

View file

@ -0,0 +1,4 @@
{% if LIBERAPAY_USERNAME %}
<p>Support us on Liberapay: <script src="https://liberapay.com/{{LIBERAPAY_USERNAME}}/widgets/button.js"></script>
<noscript><a href="https://liberapay.com/{{LIBERAPAY_USERNAME}}/donate"><img src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript></p>
{% endif %}

View file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block description %}{{ page.description }}{% endblock %}
{% block title %}{{ page.title }} — {{ SITENAME }} {% endblock %}
{% block content %}
<section id="content" class="body">
{{ page.content }}
</section>
{% endblock %}

View file

@ -0,0 +1,30 @@
<nav>
<ul class="pagination text-center">
{% if articles_page.has_previous() %}
{% set num = articles_page.previous_page_number() %}
<li class="page-item prev">
<a class="page-link" href="{{ SITEURL }}/{{ page_name }}{{ num if num > 1 else '' }}.html">&larr; Previous</a>
</li>
{% else %}
<li class="page-item prev disabled">
<a class="page-link" href="#">&larr; Previous</a>
</li>
{% endif %}
{% for num in range( 1, 1 + articles_paginator.num_pages ) %}
<li class="page-item {{ 'active' if num == articles_page.number else '' }}">
<a class="page-link" href="{{ SITEURL }}/{{ page_name }}{{ num if num > 1 else '' }}.html">{{ num }}</a>
</li>
{% endfor %}
{% if articles_page.has_next() %}
<li class="page-item next">
<a class="page-link" href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">Next &rarr;</a>
</li>
{% else %}
<li class="page-item next disabled">
<a class="page-link" href="#">&rarr; Next</a>
</li>
{% endif %}
</ul>
</nav>

View file

@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block title %}{{ tag }} — {{ SITENAME }}{% endblock %}
{% block description %}All posts which refer to tag {{ tag }}.{% endblock %}
{% block content %}
<h1>Tag <b>{{tag}}</b></h1>
<table class="table">
<tbody>
{% for article in articles %}
<tr>
<td>{{ article.date.strftime("%d %b %Y") }}</td>
<td><a href='{{ SITEURL }}/{{ article.url }}'>{{ article.title }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Tags — {{ SITENAME }}{% endblock %}
{% block description %}The Tags page lists all tags used to classify the posts.{% endblock %}
{% block content %}
<h1>Tags</h1>
<ul>
{% for tag, posts in tags %}
<li><a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }} ({{ posts | count }})</li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,3 @@
{% if TWITTER_USERNAME %}
<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="{{TWITTER_USERNAME}}">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
{% endif %}