Compare commits

..

No commits in common. "main" and "add-newsletter" have entirely different histories.

46 changed files with 60 additions and 480 deletions

5
.gitignore vendored
View file

@ -165,7 +165,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
.env.production .env.production
media/images/
media/original_images/

View file

@ -17,7 +17,7 @@
<excludeFolder url="file://$MODULE_DIR$/env" /> <excludeFolder url="file://$MODULE_DIR$/env" />
<excludeFolder url="file://$MODULE_DIR$/venv" /> <excludeFolder url="file://$MODULE_DIR$/venv" />
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.12 virtualenv at ~/Developer/personal/iamkonstantin-web/venv" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.13 (iamkonstantin-web)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">

2
.idea/misc.xml generated
View file

@ -3,5 +3,5 @@
<component name="Black"> <component name="Black">
<option name="sdkName" value="Python 3.12 (iamkonstantin-web)" /> <option name="sdkName" value="Python 3.12 (iamkonstantin-web)" />
</component> </component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 virtualenv at ~/Developer/personal/iamkonstantin-web/venv" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (iamkonstantin-web)" project-jdk-type="Python SDK" />
</project> </project>

View file

@ -1 +0,0 @@
python 3.12.8

View file

@ -1,9 +1,12 @@
.PHONY: help bump publish .PHONY: help build publish
VERSION = 1.9.15 VERSION = 1.5.0
help: help:
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
build:
@docker build -t code.headbright.be/konstantin/iamkonstantin:$(VERSION) .
publish: publish:
# something to try: --provenance=false # something to try: --provenance=false
@docker buildx build -t code.headbright.be/konstantin/iamkonstantin:$(VERSION) --platform linux/arm64 --push . @docker buildx build -t code.headbright.be/konstantin/iamkonstantin:$(VERSION) --platform linux/arm64 --push .

View file

@ -1,4 +1,3 @@
from wagtail.api import APIField
from wagtail.blocks import ( from wagtail.blocks import (
CharBlock, CharBlock,
ChoiceBlock, ChoiceBlock,
@ -15,13 +14,6 @@ class ImageBlock(StructBlock):
caption = CharBlock(required=False) caption = CharBlock(required=False)
attribution = CharBlock(required=False) attribution = CharBlock(required=False)
api_fields = [
APIField('image'),
# Adds a URL to a rendered thumbnail of the image to the API
APIField('caption'),
APIField('attribution'),
]
class Meta: class Meta:
icon = "image" icon = "image"
template = "base/blocks/image_block.html" template = "base/blocks/image_block.html"

View file

@ -5,8 +5,6 @@ from urllib.parse import urlparse
from base.indexnow import get_key from base.indexnow import get_key
import requests import requests
from blog.models import BlogPage
@hooks.register('after_publish_page') @hooks.register('after_publish_page')
def after_publish_page(request, page): def after_publish_page(request, page):
@ -16,9 +14,6 @@ def after_publish_page(request, page):
if urlparse(page_url).hostname == "localhost": if urlparse(page_url).hostname == "localhost":
print("not notifying indexnow for localhost" + get_key() + ", page url: " + page_url) print("not notifying indexnow for localhost" + get_key() + ", page url: " + page_url)
return return
if urlparse(page_url).path.endswith("--priv") or urlparse(page_url).path.endswith("--priv/"):
print("not notifying indexnow for blog page --priv")
return
session = requests.Session() session = requests.Session()
session.post( session.post(
"https://api.indexnow.org/indexnow", "https://api.indexnow.org/indexnow",

View file

@ -1,218 +0,0 @@
# Generated by Django 5.1.6 on 2025-05-06 17:00
import django.db.models.deletion
from django.db import migrations, models
from home.models import HomePage
STRUCT_ORG_FIELDS = [
"struct_org_type",
"struct_org_name",
"struct_org_logo_id",
"struct_org_image_id",
"struct_org_phone",
"struct_org_address_street",
"struct_org_address_locality",
"struct_org_address_region",
"struct_org_address_postal",
"struct_org_address_country",
"struct_org_geo_lat",
"struct_org_geo_lng",
"struct_org_hours",
"struct_org_actions",
"struct_org_extra_json", ]
# put here every model names of yours that could have been filled with structured seo data;
# order will matter when searching for pages data
SEO_MODELS = [HomePage]
def fill_settings_from_pages_struct_org(apps, schema_editor):
"""
Search for pages where seo struct info was filled and use that to
fill new settings struct data
"""
SeoSettings = apps.get_model("wagtailseo", "SeoSettings")
Site = apps.get_model("wagtailcore", "Site")
for site in Site.objects.all().select_related("root_page"):
for model_name in SEO_MODELS:
model = apps.get_model("home", model_name)
page = model.objects.filter(
path__startswith=site.root_page.path,
depth__gte=site.root_page.depth
).order_by(
'path'
).exclude(struct_org_name__exact="").first()
# if you are sure that only root pages were used to fill structured data,
# you can directly use:
# page = site.root_page.specific if site.root_page.specific._meta.model_name in SEO_MODELS else None
if page is not None:
seo_settings, _ = SeoSettings.objects.get_or_create(site=site)
for field in STRUCT_ORG_FIELDS:
setattr(seo_settings, field, getattr(page, field))
seo_settings.save()
break
def fill_pages_from_settings_struct_org(apps, schema_editor):
"""
The reverse migration.
For every site, find the most top-level page inheriting from SeoMixin
and fill its struct information using the site's settings
"""
SeoSettings = apps.get_model("wagtailseo", "SeoSettings")
for seo_settings in SeoSettings.objects.all().select_related("site", "site__root_page"):
for model_name in SEO_MODELS:
model = apps.get_model("home", model_name)
page = model.objects.filter(
path__startswith=seo_settings.site.root_page.path,
depth__gte=seo_settings.site.root_page.depth
).order_by('path').first()
if page is not None:
for field in STRUCT_ORG_FIELDS:
setattr(page, field, getattr(seo_settings, field))
page.save()
break
class Migration(migrations.Migration):
dependencies = [
('blog', '0014_alter_blogpage_body'),
('wagtailimages', '0027_image_description'),
("wagtailseo", "0003_seosettings_struct_org_fields"),
]
operations = [
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_actions',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_address_country',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_address_locality',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_address_postal',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_address_region',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_address_street',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_extra_json',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_geo_lat',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_geo_lng',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_hours',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_image',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_logo',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_name',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_phone',
),
migrations.RemoveField(
model_name='blogindexpage',
name='struct_org_type',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_actions',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_address_country',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_address_locality',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_address_postal',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_address_region',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_address_street',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_extra_json',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_geo_lat',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_geo_lng',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_hours',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_image',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_logo',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_name',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_phone',
),
migrations.RemoveField(
model_name='blogpage',
name='struct_org_type',
),
migrations.AlterField(
model_name='blogindexpage',
name='og_image',
field=models.ForeignKey(blank=True, help_text='Shown when linking to this page on social media. If blank, may show an image from the page, or the default from Settings > SEO.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Preview image'),
),
migrations.AlterField(
model_name='blogpage',
name='og_image',
field=models.ForeignKey(blank=True, help_text='Shown when linking to this page on social media. If blank, may show an image from the page, or the default from Settings > SEO.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Preview image'),
),
]

View file

@ -5,8 +5,6 @@ from django.db import models
from modelcluster.fields import ParentalKey, ParentalManyToManyField from modelcluster.fields import ParentalKey, ParentalManyToManyField
from modelcluster.contrib.taggit import ClusterTaggableManager from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase from taggit.models import TaggedItemBase
from wagtail.api import APIField
from wagtail.images.api.fields import ImageRenditionField
from wagtail.models import Page, Orderable from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField, StreamField from wagtail.fields import RichTextField, StreamField
@ -76,14 +74,6 @@ class BlogPage(SeoMixin, Page):
else: else:
return None return None
# Export fields over the API
api_fields = [
APIField('gallery_images'),
# Adds a URL to a rendered thumbnail of the image to the API
APIField('body'),
APIField('intro'),
APIField('tags'),
]
search_fields = Page.search_fields + [ search_fields = Page.search_fields + [
index.SearchField('intro'), index.SearchField('intro'),
index.SearchField('body'), index.SearchField('body'),
@ -132,9 +122,6 @@ class BlogPageGalleryImage(Orderable):
FieldPanel('image'), FieldPanel('image'),
FieldPanel('caption'), FieldPanel('caption'),
] ]
api_fields = [
APIField('image'),
]
@register_snippet @register_snippet

View file

@ -5,7 +5,7 @@
{% block body_class %}template-blogpage{% endblock %} {% block body_class %}template-blogpage{% endblock %}
{% block content %} {% block content %}
<section class="flex flex-col justify-center h-full px-0 md:px-4 lg:px-8"> <section class="flex flex-col items-center justify-center h-full px-0 md:px-4 lg:px-8">
<article class="mb-16 px-1 md:px-4 lg:px-8"> <article class="mb-16 px-1 md:px-4 lg:px-8">
<h1>{{ page.title }}</h1> <h1>{{ page.title }}</h1>
@ -54,12 +54,12 @@
{% with tags=page.tags.all %} {% with tags=page.tags.all %}
{% if tags %} {% if tags %}
<div class="flex items-center justify-center gap-x-4 text-xs my-6"> <div class="flex items-center gap-x-4 text-xs my-6">
<div class="tags"> <div class="tags">
<h2 class="sr-only">Tags</h2> <h2 class="sr-only">Tags</h2>
<ul class="flex"> <ul class="flex">
{% for tag in tags %} {% for tag in tags %}
<li><span class="emoji">🏷</span> <li class="space-x-2"><span class="emoji">🏷</span>
<a class="pr-2" href="{% slugurl 'tags' %}?tag={{ tag }}">{{ tag }}</a> <a class="pr-2" href="{% slugurl 'tags' %}?tag={{ tag }}">{{ tag }}</a>
</li> </li>
{% endfor %} {% endfor %}
@ -74,9 +74,13 @@
</article> </article>
<nav class="w-full text-center px-2 lg:px-4 return"> <nav class="w-full text-center px-2 lg:px-4">
<a href="{{ page.get_parent.url }}" class="font-bold">Return to blog</a> <a href="{{ page.get_parent.url }}" class="font-bold">Return to blog</a>
</nav> </nav>
</section> </section>
<section>
{% include 'newsletter/snippets/signup_form.html' %}
</section>
{% endblock %} {% endblock %}

View file

@ -1,80 +0,0 @@
# Generated by Django 5.1.6 on 2025-05-06 17:00
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0006_alter_homepage_body'),
('wagtailimages', '0027_image_description'),
]
operations = [
migrations.RemoveField(
model_name='homepage',
name='struct_org_actions',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_address_country',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_address_locality',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_address_postal',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_address_region',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_address_street',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_extra_json',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_geo_lat',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_geo_lng',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_hours',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_image',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_logo',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_name',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_phone',
),
migrations.RemoveField(
model_name='homepage',
name='struct_org_type',
),
migrations.AlterField(
model_name='homepage',
name='og_image',
field=models.ForeignKey(blank=True, help_text='Shown when linking to this page on social media. If blank, may show an image from the page, or the default from Settings > SEO.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Preview image'),
),
]

View file

@ -9,13 +9,13 @@
> >
<figure class="w-1/2" style="min-width: 24rem"> <figure class="w-1/2" style="min-width: 24rem">
<figcaption class="sr-only"> <figcaption class="sr-only">
Hero image Drawing of my computer desk where we see a computer with an open Terminal
</figcaption>
<img src="/static/images/my-office.png" alt="Drawing of my computer desk where we see a computer with an open Terminal
with Elixir code snippets. On the shelf behind we can see programming with Elixir code snippets. On the shelf behind we can see programming
books for Rust, Elixir and JavaScript. The books are arranges vertically books for Rust, Elixir and JavaScript. The books are arranges vertically
next to a small flower pot. The flower has big green leaves. A cup of next to a small flower pot. The flower has big green leaves. A cup of
steaming coffee sits on the desk, to the left of the computer. The cup has a Python logo on it." /> steaming coffee sits on the desk, to the left of the computer. The cup has a Python logo on it.
</figcaption>
<img src="/static/images/my-office.png" />
</figure> </figure>
<section class="w-100 text-lg dark:text-white mx-2"> <section class="w-100 text-lg dark:text-white mx-2">
<h1 <h1
@ -25,8 +25,8 @@
><img ><img
width="48px" width="48px"
height="48px" height="48px"
alt="waving hand emoji" src="static/images/waving-hand-sign_1f44b.png" /></span
src="static/images/waving-hand-sign_1f44b.png" /></span>Hi! I'm Konstantin >Hi! I'm Konstantin
</h1> </h1>
</section> </section>
@ -50,7 +50,7 @@
<ul class="mx-auto mt-8 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-3"> <ul class="mx-auto mt-8 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-3">
{% for post in recent_blog_items %} {% for post in recent_blog_items %}
{% with post=post.specific %} {% with post=post.specific %}
<li class="flex flex-col items-center justify-start max-w-xl"> <article class="flex flex-col items-center justify-start max-w-xl">
<div class="group relative w-full"> <div class="group relative w-full">
<h3 class=""> <h3 class="">
<a href="{% pageurl post %}"> <a href="{% pageurl post %}">
@ -60,7 +60,6 @@
</h3> </h3>
<p class="mt-5 leading-6">{{ post.intro }}</p> <p class="mt-5 leading-6">{{ post.intro }}</p>
</div> </div>
{% if post.main_image %} {% if post.main_image %}
<div class="relative mx-auto"> <div class="relative mx-auto">
{% with post.main_image as main_image %} {% with post.main_image as main_image %}
@ -70,7 +69,7 @@
<div class="absolute inset-0 rounded-2xl ring-1 ring-inset ring-gray-900/10"></div> <div class="absolute inset-0 rounded-2xl ring-1 ring-inset ring-gray-900/10"></div>
</div> </div>
{% endif %} {% endif %}
</li> </article>
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
</ul> </ul>
@ -82,4 +81,7 @@
</div> </div>
</section> </section>
<section>
{% include 'newsletter/snippets/signup_form.html' %}
</section>
{% endblock content %} {% endblock content %}

View file

@ -1,15 +0,0 @@
from wagtail.api.v2.views import PagesAPIViewSet
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.images.api.v2.views import ImagesAPIViewSet
from wagtail.documents.api.v2.views import DocumentsAPIViewSet
# Create the router. "wagtailapi" is the URL namespace
api_router = WagtailAPIRouter('wagtailapi')
# Add the three endpoints using the "register_endpoint" method.
# The first parameter is the name of the endpoint (such as pages, images). This
# is used in the URL of the endpoint
# The second parameter is the endpoint class that handles the requests
api_router.register_endpoint('pages', PagesAPIViewSet)
api_router.register_endpoint('images', ImagesAPIViewSet)
api_router.register_endpoint('documents', DocumentsAPIViewSet)

View file

@ -35,7 +35,6 @@ INSTALLED_APPS = [
"wagtail.contrib.settings", "wagtail.contrib.settings",
"wagtail.contrib.forms", "wagtail.contrib.forms",
"wagtail.contrib.redirects", "wagtail.contrib.redirects",
"wagtail.contrib.simple_translation",
"wagtail.embeds", "wagtail.embeds",
"wagtail.sites", "wagtail.sites",
"wagtail.users", "wagtail.users",
@ -44,9 +43,6 @@ INSTALLED_APPS = [
"wagtail.images", "wagtail.images",
"wagtail.search", "wagtail.search",
"wagtail.admin", "wagtail.admin",
"wagtail.locales",
"wagtail.api.v2",
"rest_framework",
"wagtail", "wagtail",
"modelcluster", "modelcluster",
"taggit", "taggit",
@ -72,7 +68,6 @@ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"wagtail.contrib.redirects.middleware.RedirectMiddleware", "wagtail.contrib.redirects.middleware.RedirectMiddleware",
"blog.middleware.BlogRedirectMiddleware", "blog.middleware.BlogRedirectMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django_browser_reload.middleware.BrowserReloadMiddleware" "django_browser_reload.middleware.BrowserReloadMiddleware"
] ]
@ -133,7 +128,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/ # https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = "en" LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC" TIME_ZONE = "UTC"
@ -141,18 +136,6 @@ USE_I18N = True
USE_TZ = True USE_TZ = True
WAGTAIL_I18N_ENABLED = True
USE_L10N = True # allows dates to be shown in the user's locale
WAGTAIL_CONTENT_LANGUAGES = LANGUAGES = [
('en', "English"),
('fr', "French"),
('es', "Spanish"),
('nl', "Dutch"),
]
WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = False
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/ # https://docs.djangoproject.com/en/5.0/howto/static-files/
@ -203,9 +186,6 @@ WAGTAILSEARCH_BACKENDS = {
# Base URL to use when referring to full URLs within the Wagtail admin backend - # Base URL to use when referring to full URLs within the Wagtail admin backend -
# e.g. in notification emails. Don't include '/admin' or a trailing slash # e.g. in notification emails. Don't include '/admin' or a trailing slash
WAGTAILADMIN_BASE_URL = "https://iamkonstantin.eu" WAGTAILADMIN_BASE_URL = "https://iamkonstantin.eu"
WAGTAILAPI_BASE_URL = "https://iamkonstantin.eu"
WAGTAILAPI_SEARCH_ENABLED = True
WAGTAIL_CODE_BLOCK_LANGUAGES = ( WAGTAIL_CODE_BLOCK_LANGUAGES = (
('bash', 'Bash/Shell'), ('bash', 'Bash/Shell'),

View file

@ -4,8 +4,7 @@
<html lang="en" class="h-full antialiased"> <html lang="en" class="h-full antialiased">
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width"> <meta name="fediverse:creator" content="@konstantin@toot.iamkonstantin.eu" />
<meta name="fediverse:creator" content="@iamkonstantin@mastodon.social" />
{% include "wagtailseo/meta.html" %} {% include "wagtailseo/meta.html" %}
<title> <title>
{% block title %} {% block title %}
@ -81,6 +80,5 @@
{# Override this in templates to add extra javascript #} {# Override this in templates to add extra javascript #}
{% endblock %} {% endblock %}
{% include "wagtailseo/struct_data.html" %} {% include "wagtailseo/struct_data.html" %}
{% include "wagtailseo/struct_org_data.html" %}
</body> </body>
</html> </html>

View file

@ -3,7 +3,7 @@
<a href="#main" class="skip-link">Skip to content</a> <a href="#main" class="skip-link">Skip to content</a>
{% get_site_root as site_root %} {% get_site_root as site_root %}
<nav class="w-full flex justify-center my-8 main"> <nav class="w-full flex justify-center my-8">
<ul class="flex space-x-8"> <ul class="flex space-x-8">
<li><a href="{% pageurl site_root %}">{{ site_root.title }}</a></li> <li><a href="{% pageurl site_root %}">{{ site_root.title }}</a></li>
{% for menuitem in site_root.get_children.live.in_menu %} {% for menuitem in site_root.get_children.live.in_menu %}

View file

@ -1,5 +1,4 @@
from django.conf import settings from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path from django.urls import include, path
from django.contrib import admin from django.contrib import admin
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
@ -9,7 +8,6 @@ from wagtail import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls from wagtail.documents import urls as wagtaildocs_urls
from blog.feeds import RssBlogFeed from blog.feeds import RssBlogFeed
from iamkonstantin_web.api import api_router
from newsletter import views as newsletter_views from newsletter import views as newsletter_views
from search import views as search_views from search import views as search_views
from wagtail.contrib.sitemaps.views import sitemap from wagtail.contrib.sitemaps.views import sitemap
@ -27,17 +25,6 @@ urlpatterns = [
path('newsletter/thanks', newsletter_views.thanks, name='thanks') path('newsletter/thanks', newsletter_views.thanks, name='thanks')
] ]
urlpatterns += [
path('api/v2/', api_router.urls),
]
# Translatable URLs
# These will be available under a language code prefix. For example /en/search/
urlpatterns += i18n_patterns(
path("", include(wagtail_urls)),
prefix_default_language=False,
)
if settings.DEBUG: if settings.DEBUG:
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib.staticfiles.urls import staticfiles_urlpatterns
@ -47,12 +34,12 @@ if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += path("__reload__/", include("django_browser_reload.urls")), urlpatterns += path("__reload__/", include("django_browser_reload.urls")),
# urlpatterns = urlpatterns + [ urlpatterns = urlpatterns + [
# # For anything not caught by a more specific rule above, hand over to # For anything not caught by a more specific rule above, hand over to
# # Wagtail's page serving mechanism. This should be the last pattern in # Wagtail's page serving mechanism. This should be the last pattern in
# # the list: # the list:
# path("", include(wagtail_urls)), path("", include(wagtail_urls)),
# # Alternatively, if you want Wagtail pages to be served from a subpath # Alternatively, if you want Wagtail pages to be served from a subpath
# # of your site, rather than the site root: # of your site, rather than the site root:
# # path("pages/", include(wagtail_urls)), # path("pages/", include(wagtail_urls)),
# ] ]

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -1,4 +1,4 @@
<div class="py-16 sm:py-24 lg:py-32"> <div class="py-16 sm:py-24 lg:py-32">
<iframe data-w-type="embedded" title="Newsletter" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://sgx7y.mjt.lu/wgt/sgx7y/xtn1/form?c=c9b8015e" width="100%" style="height: 0;"></iframe> <iframe data-w-type="embedded" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://sgx7y.mjt.lu/wgt/sgx7y/xtn1/form?c=c9b8015e" width="100%" style="height: 0;"></iframe>
<script type="text/javascript" src="https://app.mailjet.com/pas-nc-embedded-v1.js"></script> <script type="text/javascript" src="https://app.mailjet.com/pas-nc-embedded-v1.js"></script>
</div> </div>

View file

@ -4,14 +4,8 @@
{% block body_class %}template-portfolio{% endblock %} {% block body_class %}template-portfolio{% endblock %}
{% block content %} {% block content %}
<section class="flex flex-col items-center justify-center h-full px-0 md:px-4 lg:px-8"> <h1>{{ page.title }}</h1>
<article class="mb-16 px-1 md:px-4 lg:px-8">
<h1>{{ page.title }}</h1> {{ page.body }}
<div class="blog-content w-full">
{{ page.body }}
</div>
</article>
</section>
{% endblock %} {% endblock %}

View file

@ -1,8 +1,8 @@
Django>=5.2.1,<5.3 Django>=4.2,<5.2
wagtail>=6.4,<7.1 wagtail>=6.3,<6.4
whitenoise>=6.6,<7.0 whitenoise>=6.6,<7.0
wagtailcodeblock>=1.29.0.2,<2.0 wagtailcodeblock>=1.29.0.2,<2.0
django-tailwind>=3.6.0 django-tailwind>=3.6.0
django-browser-reload>=1.17 django-browser-reload>=1.12
Wand==0.6.13 Wand==0.6.13
wagtail-seo==3.0.0 wagtail-seo==2.5.0

View file

@ -13,11 +13,13 @@
<form action="{% url 'search' %}" method="get" class="container"> <form action="{% url 'search' %}" method="get" class="container">
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
<label for="query" class="sr-only block text-sm font-medium leading-6">Search</label> <label for="query" class="sr-only block text-sm font-medium leading-6">Search</label>
<div class="mt-2 flex space-x-4"> <div class="mt-2">
<input type="text" placeholder="Type search keywords..." <input type="text" placeholder="Type search keywords..."
class="block w-full rounded-xl border-0 py-1.5 px-2 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-klavender sm:text-sm sm:leading-6" class="block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-klavender sm:text-sm sm:leading-6"
id="query" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}> id="query" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}>
</div>
<div>
<input type="submit" class="primary-button" value="Search"> <input type="submit" class="primary-button" value="Search">
</div> </div>
</div> </div>
@ -28,7 +30,7 @@
</div> </div>
</section> </section>
<section class="h-full px-0 md:px-4 lg:px-8 search"> <section class="h-full px-0 md:px-4 lg:px-8">
<div class="px-0 md:px-4 lg:px-8"> <div class="px-0 md:px-4 lg:px-8">
<h2 class="sr-only">Search results</h2> <h2 class="sr-only">Search results</h2>
@ -46,8 +48,6 @@
<h4><a href="{% pageurl result %}">{{ result }}</a></h4> <h4><a href="{% pageurl result %}">{{ result }}</a></h4>
{% if result.search_description %} {% if result.search_description %}
{{ result.search_description }} {{ result.search_description }}
{% elif result.post.intro %}
{{ result.post.intro }}
{% endif %} {% endif %}
</li> </li>
{% endfor %} {% endfor %}

View file

@ -45,7 +45,7 @@
} }
h3 { h3 {
@apply mt-10 mb-3 text-xl sm:text-2xl lg:text-2xl leading-none font-extrabold tracking-tight text-black dark:text-white; @apply mt-12 mb-2 text-xl sm:text-2xl lg:text-2xl leading-none font-extrabold tracking-tight text-black dark:text-white;
} }
h4 { h4 {
@ -56,23 +56,11 @@
@apply my-2 mb-3 text-lg leading-relaxed; @apply my-2 mb-3 text-lg leading-relaxed;
} }
li {
@apply my-2 text-lg;
}
.search li {
@apply my-6;
}
.search li h4 {
@apply inline;
}
.blog-content ul, .home-content ul { .blog-content ul, .home-content ul {
@apply list-none list-inside; @apply list-none list-inside;
} }
.blog-content ul li::before, .home-content ul li::before, .search li::before { .blog-content ul li::before, .home-content ul li::before {
content: "👉"; content: "👉";
font-family: NotoEmoji; font-family: NotoEmoji;
@apply inline-block mr-2 py-1; @apply inline-block mr-2 py-1;
@ -89,57 +77,24 @@
@media print { @media print {
h1 { h1 {
@apply m-0 my-2 text-xl; @apply mt-6 mb-4 text-xl;
} }
h2 { h2 {
@apply m-0 mt-2 text-base; @apply mt-4 mb-2 text-base;
} }
h3 { h3 {
@apply m-0 mt-2 text-base; @apply text-base;
}
h4 {
@apply m-0 text-base;
} }
p { p {
@apply text-sm my-1; @apply text-sm my-1;
} }
li {
@apply text-sm my-0;
}
.ppb { .ppb {
page-break-before: always; page-break-before: always;
} }
nav.main {
@apply hidden;
}
main {
@apply mx-0 px-0;
}
footer {
@apply hidden !important;
}
nav.return {
@apply hidden;
}
/*.blog-content ul, .home-content ul {*/
/* @apply list-none list-inside list-disc;*/
/* @apply inline-block mr-0;*/
/*}*/
/*.blog-content ul li::before, .home-content ul li::before, .search li::before {*/
/* content: "";*/
/*}*/
} }
.primary-button { .primary-button {
@ -157,11 +112,11 @@
} }
.tags ul { .tags ul {
@apply flex-col sm:flex-row sm:space-x-2 text-center text-sm; @apply flex space-x-4 text-center text-sm;
} }
.tags li { .tags li {
@apply p-3 inline-flex items-center rounded-2xl px-2 py-1 text-sm text-black dark:text-white ring-1 ring-inset ring-orange-700/20 dark:ring-white bg-orange-50 dark:bg-transparent; @apply p-4 inline-flex items-center rounded-2xl bg-green-50 px-2 py-1 font-medium text-green-700 ring-1 ring-inset ring-green-600/20;
} }
.tags ul li::before { .tags ul li::before {
@ -170,7 +125,7 @@
} }
.tags a { .tags a {
@apply border-b-0 w-full m-0; @apply border-b-0 w-full;
} }
.blog-pages a { .blog-pages a {