Release v1.7.2: Clean separation of pretix core & Falkenthal theme plugin

This commit is contained in:
root committed 2026-11-06 14:05:08 +01:00
commit 5003dada3c
15 files changed
+1210

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
__pycache__/
*.py[cod]
*$py.class
*.egg-info/
dist/
build/
.eggs/
.DS_Store
*.swp
+50
View File
@@ -0,0 +1,50 @@
FROM pretix/standalone:stable
USER root
# 1. Theme-Plugin-Repository in das Build-Verzeichnis kopieren
COPY . /tmp/pretix-falkenthal-theme
# 2. Öffentliche Plugins + Falkenthal Theme-Plugin installieren
RUN pip3 install --no-cache-dir \
pretix-passbook \
pretix-zugferd \
pretix-pages \
/tmp/pretix-falkenthal-theme
# 3. Primäre Fallback-Farbwerte (#3b1c4a) im Quellbaum auf Royalblau/Indigo umstellen
# (Veranstalter können ihre Shop-Farben weiterhin frei im Web-Interface überschreiben)
RUN sed -i 's/#3b1c4a/#4f46e5/gI' /pretix/src/pretix/base/settings.py && \
find /pretix/src/pretix -type f \( -name "*.scss" -o -name "*.less" -o -name "*.css" \) -exec sed -i \
-e 's/#3b1c4a/#2563eb/gI' \
-e 's/#5f2977/#4f46e5/gI' \
-e 's/#7f4a88/#475569/gI' \
-e 's/#8e44ad/#4f46e5/gI' \
-e 's/#281233/#0f172a/gI' {} +
# 4. Basis-Templates patchen (Orig. Pretix-Link bleibt erhalten + separater Theme-Link)
RUN python3 /tmp/pretix-falkenthal-theme/patch_templates.py && \
chown -R pretixuser:pretixuser /pretix/src/pretix
USER pretixuser
# 5. Compressor-Cache leeren und Assets als pretixuser neu kompilieren
RUN rm -rf /pretix/src/pretix/static.dist/CACHE && \
cd /pretix/src && make production
USER root
# 6. Vorkompilierte CSS-Dateien bereinigen & statische Theme-Assets bereitstellen
RUN find /pretix/src/pretix/static.dist -type f -name "*.css" -exec sed -i \
-e 's/#3b1c4a/#2563eb/gI' \
-e 's/#5f2977/#4f46e5/gI' \
-e 's/#7f4a88/#475569/gI' \
-e 's/#6c3386/#4f46e5/gI' \
-e 's/#4c2460/#1e293b/gI' \
-e 's/#281233/#0f172a/gI' {} + && \
mkdir -p /pretix/src/pretix/static.dist/whitelabel && \
cp -r /tmp/pretix-falkenthal-theme/pretix_whitelabel/static/whitelabel/* /pretix/src/pretix/static.dist/whitelabel/ && \
chown -R pretixuser:pretixuser /pretix/src/pretix/static.dist && \
rm -rf /tmp/pretix-falkenthal-theme
USER pretixuser
+29
View File
@@ -0,0 +1,29 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2026 Tino Falkenthal (Plugin Code & Stylesheets)
ADDITIONAL TERMS PURSUANT TO SECTION 7 OF THE GNU AGPLv3:
1. Attribution of Core Software: This plugin builds upon pretix
(https://github.com/pretix/pretix), Copyright (C) rami.io GmbH. All original
pretix copyright notices and attribution links must remain intact.
2. Trademark & Asset Exclusion (Section 7(e)): This License does NOT grant any
rights under trademark, name, or copyright law to use the trade names,
trademarks, service marks, or brand assets of Tino Falkenthal (specifically
the name "FALKENTHAL", the Origami Falcon emblem, and the SVG files
logo.svg, login-logo.svg, and favicon.svg). See LICENSE-ASSETS.md for
details. All rights to these brand assets are strictly reserved.
---
This program's source code (.py, .css, build scripts) is free software: you
can redistribute it and/or modify it under the terms of the GNU Affero General
Public License as published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
Full license text: https://www.gnu.org/licenses/agpl-3.0.txt
+16
View File
@@ -0,0 +1,16 @@
# Urheberrechts- und Markenvorbehalt für Grafiken, Logos und Kennzeichen
**Copyright © 2026 Tino Falkenthal. Alle Rechte vorbehalten (All Rights Reserved).**
Gemäß Abschnitt 7 lit. e der GNU Affero General Public License v3.0 (AGPLv3) wird ausdrücklich klargestellt, dass diese Lizenz **keine Rechte** zur Nutzung von Marken, geschäftlichen Bezeichnungen, Namen oder Logos des Urhebers einräumt.
Insbesondere sind folgende Bestandteile dieses Repositories **nicht** unter der GNU AGPLv3 lizenziert:
1. Die Bild- und Vektordateien:
- `pretix_whitelabel/static/whitelabel/logo.svg`
- `pretix_whitelabel/static/whitelabel/login-logo.svg`
- `pretix_whitelabel/static/whitelabel/favicon.svg`
2. Das geometrische **Origami-Falken-Bildzeichen**.
3. Der Name und das Unternehmenskennzeichen **„FALKENTHAL“** (geschützt nach § 12 BGB und § 5 MarkenG).
Jede Vervielfältigung, Verbreitung, öffentliche Zugänglichmachung oder Nutzung dieser Grafiken und Kennzeichen außerhalb der vom Rechtsinhaber selbst betriebenen Plattform (`tickets.falkenthal.me`) ist ohne vorherige schriftliche Zustimmung von Tino Falkenthal untersagt. Bei einer Weiterverwendung (Fork) des Quellcodes müssen diese Dateien durch eigene Grafiken ersetzt werden.
+5
View File
@@ -0,0 +1,5 @@
recursive-include pretix_whitelabel/static *
include LICENSE
include LICENSE-ASSETS.md
include NOTICE
include README.md
+22
View File
@@ -0,0 +1,22 @@
================================================================================
ATTRIBUTION & COPYRIGHT NOTICE
================================================================================
1. Core Software (pretix):
This plugin is designed for use with "pretix" (https://pretix.eu).
pretix is Copyright (C) rami.io GmbH and contributors, licensed under the
GNU Affero General Public License v3.0 (AGPLv3) with additional terms
pursuant to Section 7.
Official pretix source code: https://github.com/pretix/pretix
2. Theme Plugin & Deployment Scripts (pretix-falkenthal-theme):
Copyright (C) 2026 Tino Falkenthal (https://git.falkenthal.me/falkenthal/pretix-falkenthal-theme).
The Python code, CSS stylesheets (control.css, presale.css), and build
scripts in this repository are licensed under the GNU Affero General Public
License v3.0 (AGPLv3).
3. Excluded Trademarks, Names & Brand Assets (Section 7(e) AGPLv3):
The trade name "FALKENTHAL", the geometric Origami Falcon logo, and the vector
files (logo.svg, login-logo.svg, favicon.svg) are NOT licensed under the
AGPLv3. All rights to these brand assets are strictly reserved by
Tino Falkenthal (see LICENSE-ASSETS.md).
+26
View File
@@ -0,0 +1,26 @@
# pretix-falkenthal-theme
Eigenständiges Design- und White-Label-Plugin (`control.css` & `presale.css`) für [pretix](https://github.com/pretix/pretix), eingesetzt auf `tickets.falkenthal.me`.
## Trennung von Kernsystem und Plugin
Dieses Repository enthält **ausschließlich** das von Tino Falkenthal entwickelte Design-Plugin sowie die zugehörigen Docker-Build-Skripte. Das Kernsystem **pretix** wird unverändert aus dem offiziellen Image `pretix/standalone:stable` bezogen:
* **Kernsystem:** [pretix](https://pretix.eu) – Quellcode unter [github.com/pretix/pretix](https://github.com/pretix/pretix) (AGPLv3, Copyright rami.io GmbH).
* **Design-Plugin (`pretix-falkenthal-theme`):**
1. `control.css`: Dunkles Slate-Sidebar-Theme (`#0f172a`), optimierte Kontraste und zentrierter Dark-Glassmorphism-Login-Screen für das Admin-Backend.
2. `presale.css`: Farbneutrales UI/UX-Upgrade für den öffentlichen Ticketshop (moderne Card-Radien, Schatten und Hover-Effekte unter 100 % Wahrung individueller Veranstalter-Farben).
3. `Dockerfile` & `patch_templates.py`: Setzt den Standard-Farbwert auf Indigo (`#4f46e5`), bindet das Plugin ein und ergänzt den separaten Quellcode-Nachweis im Footer.
## Lizenz & Schutz der Marken-Assets
Für dieses Repository gilt eine geteilte Lizenzierung (Split-License gemäß AGPLv3 § 7 lit. e):
* **Plugin-Quellcode (`.py`, `.css`, Build-Skripte):** Lizenziert unter der **GNU Affero General Public License v3.0 (AGPLv3)** (siehe `LICENSE` und `NOTICE`).
* **Logos, Grafiken & Kennzeichen (`logo.svg`, `login-logo.svg`, `favicon.svg`, Origami-Falke & Name „FALKENTHAL“):** **Alle Rechte vorbehalten (All Rights Reserved) – © 2026 Tino Falkenthal** (siehe `LICENSE-ASSETS.md`). Bei Nutzung dieses Plugins für eigene Installationen müssen die drei SVG-Dateien im Ordner `pretix_whitelabel/static/whitelabel/` durch eigene Grafiken ersetzt werden.
## Installation / Docker-Build
Image reproduzierbar bauen:
docker build -t pretix-custom:local .
+55
View File
@@ -0,0 +1,55 @@
import re
THEME_REPO_URL = "https://git.falkenthal.me/falkenthal/pretix-falkenthal-theme"
control_files = [
'/pretix/src/pretix/control/templates/pretixcontrol/base.html',
'/pretix/src/pretix/control/templates/pretixcontrol/auth/base.html',
]
# Regex findet den originalen Pretix-Quellcode-Link und behält ihn vollständig bei (\1)
pretix_src_pattern = re.compile(
r'(<a[^>]*href=[\"\']https://github\.com/pretix/pretix[\"\'][^>]*>.*?</a>\s*\)?)',
re.I | re.S
)
theme_credit_html = (
rf'\1 · <a href="{THEME_REPO_URL}" target="_blank" rel="noopener">'
r'Theme-Plugin (Quellcode)</a>'
)
for p in control_files:
with open(p, 'r', encoding='utf-8') as f:
c = f.read()
# Standard-Favicon-Tags entfernen, damit das Falken-SVG geladen wird
c = re.sub(r'<link[^>]*rel=[\"\'](shortcut )?icon[\"\'][^>]*>', '', c, flags=re.I)
if '/static/whitelabel/control.css' not in c:
c = c.replace(
'</head>',
'<link rel="icon" type="image/svg+xml" href="/static/whitelabel/favicon.svg?v=7">'
'<link rel="shortcut icon" href="/static/whitelabel/favicon.svg?v=7">'
'<link rel="stylesheet" type="text/css" href="/static/whitelabel/control.css?v=7"></head>'
)
# Separaten Theme-Plugin-Link hinter dem originalen Pretix-Quellcode-Link anfügen
if THEME_REPO_URL not in c:
c = pretix_src_pattern.sub(theme_credit_html, c)
with open(p, 'w', encoding='utf-8') as f:
f.write(c)
presale_file = '/pretix/src/pretix/presale/templates/pretixpresale/base.html'
with open(presale_file, 'r', encoding='utf-8') as f:
c = f.read()
c = re.sub(r'<link[^>]*rel=[\"\'](shortcut )?icon[\"\'][^>]*>', '', c, flags=re.I)
if '/static/whitelabel/presale.css' not in c:
c = c.replace(
'</head>',
'<link rel="icon" type="image/svg+xml" href="/static/whitelabel/favicon.svg?v=7">'
'<link rel="shortcut icon" href="/static/whitelabel/favicon.svg?v=7">'
'<link rel="stylesheet" type="text/css" href="/static/whitelabel/presale.css?v=7"></head>'
)
if THEME_REPO_URL not in c:
c = pretix_src_pattern.sub(theme_credit_html, c)
with open(presale_file, 'w', encoding='utf-8') as f:
f.write(c)
print("Pretix templates patched: Original Pretix links preserved + Theme-Plugin source link added.")
+21
View File
@@ -0,0 +1,21 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy
class WhiteLabelApp(AppConfig):
name = "pretix_whitelabel"
verbose_name = "Falkenthal White Label Theme"
class PretixPluginMeta:
name = gettext_lazy("Falkenthal White Label Theme")
author = "Tino Falkenthal"
description = gettext_lazy(
"Custom Slate & Blue-Violet theme plugin for pretix control and presale UI."
)
visible = False
version = "1.7.2"
category = "CUSTOMIZATION"
default_app_config = "pretix_whitelabel.WhiteLabelApp"
PretixPluginMeta = WhiteLabelApp.PretixPluginMeta
@@ -0,0 +1,729 @@
/* ==========================================================================
FALKENTHAL ADMIN BACKEND & LOGIN THEME (control.css - v7)
========================================================================== */
:root {
--fk-bg-dark: #0b1120;
--fk-bg-sidebar: #0f172a;
--fk-bg-sidebar-elevated: #1e293b;
--fk-bg-content: #f8fafc;
--fk-card-bg: #ffffff;
--fk-text-main: #0f172a;
--fk-text-secondary: #334155;
--fk-text-muted: #64748b;
--fk-cyan: #00e5ff;
--fk-blue: #2563eb;
--fk-indigo: #4f46e5;
--fk-purple: #7c3aed;
--fk-border: #e2e8f0;
--fk-gradient-primary: linear-gradient(135deg, #2563eb 0%, #4f46e5 55%, #7c3aed 100%);
--fk-gradient-hover: linear-gradient(135deg, #1d4ed8 0%, #4338ca 55%, #6d28d9 100%);
}
body {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif !important;
background-color: var(--fk-bg-content);
color: var(--fk-text-main);
-webkit-font-smoothing: antialiased;
}
a {
color: var(--fk-blue);
transition: color 0.15s ease;
}
a:hover,
a:focus {
color: var(--fk-indigo);
}
/* ==========================================================================
1. TOP NAVBAR & FALKENTHAL LOGO
========================================================================== */
.navbar-inverse,
header.navbar,
nav.navbar-inverse {
background: linear-gradient(90deg, #0b1120 0%, #0f172a 65%, #1e1b4b 100%) !important;
border: none !important;
border-bottom: 1px solid rgba(99, 102, 241, 0.25) !important;
box-shadow: 0 2px 12px rgba(11, 17, 32, 0.12) !important;
min-height: 54px !important;
}
.navbar-brand img,
.navbar-header img {
display: none !important;
width: 0 !important;
height: 0 !important;
}
.navbar-header .navbar-brand,
a.navbar-brand {
font-size: 0 !important;
color: transparent !important;
background-image: url('/static/whitelabel/logo.svg?v=7') !important;
background-repeat: no-repeat !important;
background-position: 14px center !important;
background-size: auto 34px !important;
width: 215px !important;
height: 54px !important;
display: block !important;
}
.navbar-inverse .navbar-nav > li > a {
color: #cbd5e1 !important;
font-weight: 500;
}
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:focus {
color: #ffffff !important;
background-color: rgba(255, 255, 255, 0.08) !important;
}
/* ==========================================================================
2. SEITENLEISTE LINKS (NAHTLOSER HINTERGRUND, NUTZERAUSWAHL & MENÜ)
========================================================================== */
/* Alle Ebenen der Sidebar auf exakt denselben Dunkelton setzen (verhindert weiße Kästen) */
#wrapper,
.sidebar,
.navbar-default.sidebar,
.sidebar .sidebar-nav,
.sidebar .navbar-collapse,
#side-menu,
#side-menu > li {
background-color: var(--fk-bg-sidebar) !important;
border: none !important;
box-shadow: none !important;
}
#wrapper {
min-height: 100vh !important;
}
#side-menu li {
position: relative !important;
}
/* --- A) NUTZER- & VERANSTALTUNGSAUSWAHL OBEN LINKS --- */
#side-menu > li.context-selector,
.sidebar .context-selector {
background-color: var(--fk-bg-sidebar) !important;
padding: 12px 10px 10px 10px !important;
margin: 0 0 6px 0 !important;
border-bottom: 1px solid rgba(148, 163, 184, 0.12) !important;
}
.sidebar .context-selector > a.dropdown-toggle {
background-color: #162036 !important;
border: 1px solid rgba(148, 163, 184, 0.2) !important;
border-radius: 10px !important;
padding: 10px 12px !important;
margin: 0 !important;
color: #f8fafc !important;
display: flex !important;
align-items: center !important;
justify-content: space-between !important;
gap: 10px !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25) !important;
text-decoration: none !important;
transition: all 0.15s ease !important;
}
.sidebar .context-selector > a.dropdown-toggle:hover,
.sidebar .context-selector > a.dropdown-toggle:focus,
.sidebar .context-selector.open > a.dropdown-toggle {
background-color: var(--fk-bg-sidebar-elevated) !important;
border-color: #60a5fa !important;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2) !important;
}
/* Icon-Stack links in der Auswahl */
.sidebar .context-selector .fa-stack {
flex-shrink: 0 !important;
}
.sidebar .context-selector .fa-stack .fa-circle {
color: var(--fk-indigo) !important;
}
.sidebar .context-selector .fa-stack .fa-inverse,
.sidebar .context-selector .fa-stack .fa-stack-1x:not(.fa-circle) {
color: #ffffff !important;
}
/* Textblock in der Mitte sauber kürzen, damit der Pfeil rechts nicht überlappt */
.sidebar .context-selector .context-indicator {
background: transparent !important;
border-radius: 0 !important;
box-shadow: none !important;
flex: 1 1 auto !important;
min-width: 0 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
padding-right: 4px !important;
}
.sidebar .context-selector .context-name,
.sidebar .context-selector span:not(.fa-stack):not(.caret) {
color: #f8fafc !important;
font-weight: 600 !important;
display: block !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.sidebar .context-selector .context-meta,
.sidebar .context-selector small {
color: #94a3b8 !important;
font-weight: 400 !important;
font-size: 12px !important;
display: block !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
/* Kleines Dreieck (Caret) rechts sauber ausrichten */
.sidebar .context-selector .caret {
flex-shrink: 0 !important;
color: #94a3b8 !important;
border-top-color: #94a3b8 !important;
margin-left: 4px !important;
}
/* Aufklappendes Dropdown-Menü der Nutzerauswahl */
.sidebar .context-selector .dropdown-menu {
background-color: #162036 !important;
border: 1px solid rgba(99, 102, 241, 0.4) !important;
border-radius: 10px !important;
box-shadow: 0 16px 36px rgba(0, 0, 0, 0.6) !important;
padding: 8px !important;
left: 10px !important;
right: 10px !important;
width: auto !important;
margin-top: 4px !important;
}
.sidebar .context-selector .dropdown-menu input.form-control {
background-color: #0b1120 !important;
border: 1px solid rgba(148, 163, 184, 0.3) !important;
color: #f8fafc !important;
height: 36px !important;
}
.sidebar .context-selector .dropdown-menu li a {
color: #e2e8f0 !important;
border-radius: 6px !important;
padding: 8px 10px !important;
}
.sidebar .context-selector .dropdown-menu li a:hover,
.sidebar .context-selector .dropdown-menu li.active a {
background-color: rgba(37, 99, 235, 0.3) !important;
color: #ffffff !important;
}
/* --- B) TESTMODUS-WARNBUTTON (Hoher Kontrast: Dunkelslate auf Amber) --- */
#side-menu li a[href$="/live/"],
#side-menu li a.testmode,
#side-menu li a.btn-warning {
background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%) !important;
border: 1px solid #fcd34d !important;
color: #0f172a !important;
font-weight: 700 !important;
font-size: 12.5px !important;
letter-spacing: 0.05em !important;
border-radius: 8px !important;
padding: 9px 14px !important;
margin: 4px 10px 10px 10px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
box-shadow: 0 2px 10px rgba(245, 158, 11, 0.25) !important;
}
#side-menu li a[href$="/live/"] i.fa,
#side-menu li a[href$="/live/"] span.fa,
#side-menu li a.testmode i.fa {
color: #0f172a !important;
margin: 0 !important;
width: auto !important;
}
#side-menu li a[href$="/live/"]:hover {
background: linear-gradient(135deg, #fbbf24 0%, #fde047 100%) !important;
color: #000000 !important;
transform: translateY(-1px);
}
/* --- C) HAUPTMENÜPUNKTE (Flache Spezifität für garantierte Aktiv-Kontraste) --- */
#side-menu > li > a {
color: #cbd5e1 !important;
font-weight: 500 !important;
padding: 10px 38px 10px 14px !important;
margin: 3px 10px !important;
border-radius: 8px !important;
display: block !important;
transition: background-color 0.15s ease, color 0.15s ease !important;
}
#side-menu > li > a i.fa,
#side-menu > li > a span.fa:not(.arrow) {
color: #60a5fa !important;
width: 20px !important;
text-align: center !important;
margin-right: 8px !important;
transition: color 0.15s ease !important;
}
/* Hover auf inaktiven Menüpunkten */
#side-menu > li > a:hover,
#side-menu > li > a:focus {
background-color: rgba(255, 255, 255, 0.08) !important;
color: #ffffff !important;
}
#side-menu > li > a:hover i.fa,
#side-menu > li > a:hover span.fa:not(.arrow) {
color: var(--fk-cyan) !important;
}
/* Geöffneter Eltern-Menüpunkt (z.B. "Einstellungen", wenn Unterpunkt aktiv ist) */
#side-menu > li.active > a {
background-color: rgba(255, 255, 255, 0.06) !important;
color: #ffffff !important;
font-weight: 600 !important;
}
#side-menu > li.active > a i.fa,
#side-menu > li.active > a span.fa:not(.arrow) {
color: var(--fk-cyan) !important;
}
/* AKTIVER HAUPTMENÜPUNKT (z.B. "Übersicht") -> Garantiert weiße Schrift & weißes Icon! */
#side-menu > li > a.active,
#side-menu > li.active > a.active {
background: var(--fk-gradient-primary) !important;
color: #ffffff !important;
font-weight: 600 !important;
box-shadow: 0 4px 14px rgba(79, 70, 229, 0.4) !important;
}
#side-menu > li > a.active i.fa,
#side-menu > li > a.active span.fa:not(.arrow),
#side-menu > li.active > a.active i.fa,
#side-menu > li.active > a.active span.fa:not(.arrow) {
color: #ffffff !important;
}
/* --- D) EINKLAPP-PFEILE (< / v) RECHTSBÜNDIG & GUT SICHTBAR --- */
#side-menu li > a.arrow {
position: absolute !important;
right: 12px !important;
top: 3px !important;
width: 34px !important;
height: 38px !important;
padding: 0 !important;
margin: 0 !important;
background: transparent !important;
border: none !important;
box-shadow: none !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
color: #94a3b8 !important;
z-index: 5 !important;
border-radius: 6px !important;
}
#side-menu li > a.arrow:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
color: #ffffff !important;
}
#side-menu li.active > a.arrow {
color: #e2e8f0 !important;
}
#side-menu li > a.arrow .fa.arrow {
margin: 0 !important;
width: auto !important;
color: inherit !important;
float: none !important;
font-size: 13px !important;
}
/* --- E) UNTERMENÜS (Modernes Tree-Layout mit vertikaler Führungslinie) --- */
#side-menu .nav-second-level,
#side-menu .nav-third-level {
background-color: transparent !important;
margin: 2px 10px 8px 24px !important;
padding: 2px 0 2px 8px !important;
border-left: 2px solid rgba(148, 163, 184, 0.18) !important;
border-radius: 0 !important;
}
#side-menu .nav-second-level li a:not(.arrow) {
padding: 7px 12px !important;
margin: 2px 0 !important;
font-size: 13.5px !important;
color: #94a3b8 !important;
font-weight: 500 !important;
border-radius: 6px !important;
display: block !important;
transition: all 0.15s ease !important;
}
#side-menu .nav-second-level li a:not(.arrow):hover {
background-color: rgba(255, 255, 255, 0.06) !important;
color: #f8fafc !important;
}
/* Aktiver Untermenüpunkt (z.B. "Erweiterungen") */
#side-menu .nav-second-level li a.active:not(.arrow) {
background: var(--fk-gradient-primary) !important;
color: #ffffff !important;
font-weight: 600 !important;
box-shadow: 0 2px 10px rgba(79, 70, 229, 0.35) !important;
}
/* ==========================================================================
3. HAUPTBEREICH, TABS, BUTTON-GRUPPEN & DASHBOARD-KACHELN
========================================================================== */
#page-wrapper {
background-color: var(--fk-bg-content) !important;
min-height: calc(100vh - 54px) !important;
padding: 28px 34px !important;
border-left: none !important;
}
#page-wrapper h1 {
font-weight: 700 !important;
color: var(--fk-text-main) !important;
letter-spacing: -0.02em;
margin-top: 4px !important;
margin-bottom: 20px !important;
}
#page-wrapper h1 small {
color: var(--fk-text-muted) !important;
font-weight: 400 !important;
}
legend,
fieldset legend {
background-color: transparent !important;
color: var(--fk-text-main) !important;
font-weight: 600 !important;
border-bottom: 1px solid var(--fk-border) !important;
padding-bottom: 8px !important;
}
/* Reiter / Tabs */
.nav-tabs {
border-bottom: 1px solid var(--fk-border) !important;
margin-bottom: 24px !important;
}
.nav-tabs > li > a {
color: var(--fk-text-muted) !important;
font-weight: 500 !important;
border: none !important;
border-bottom: 2px solid transparent !important;
padding: 10px 16px !important;
background: transparent !important;
}
.nav-tabs > li > a:hover {
color: var(--fk-text-main) !important;
background-color: rgba(15, 23, 42, 0.03) !important;
border-bottom-color: #cbd5e1 !important;
}
.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
color: var(--fk-indigo) !important;
font-weight: 600 !important;
background-color: transparent !important;
border: none !important;
border-bottom: 2px solid var(--fk-indigo) !important;
}
/* --- DASHBOARD-KACHELN (Doppelte graue Außenkästen entfernen & lesbare Typografie) --- */
/* 1. Äußere Widget-Box als einzige saubere weiße Card definieren */
.dashboard .widget-container .widget,
.event-dashboard .widget-container .widget {
background-color: var(--fk-card-bg) !important;
border: 1px solid var(--fk-border) !important;
border-radius: 12px !important;
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.04) !important;
padding: 20px 16px !important;
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease !important;
text-decoration: none !important;
}
.dashboard .widget-container .widget::before,
.dashboard .widget-container .widget::after {
display: none !important;
}
.dashboard .widget-container .widget:hover {
transform: translateY(-2px) !important;
box-shadow: 0 10px 22px -5px rgba(37, 99, 235, 0.12) !important;
border-color: #93c5fd !important;
}
/* 2. Innere .numwidget-Box komplett neutralisieren (verhindert Box-in-Box-Effekt) */
.dashboard .widget .numwidget,
.numwidget {
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
/* 3. Zahlen dunkel & kontraststark, Labels dezent grau statt alles blau */
.dashboard .widget .numwidget .num,
.numwidget .num {
color: var(--fk-text-main) !important;
font-weight: 700 !important;
font-size: 32px !important;
line-height: 1.2 !important;
display: block !important;
margin-bottom: 6px !important;
}
.dashboard .widget:hover .numwidget .num {
color: var(--fk-indigo) !important;
}
.dashboard .widget .numwidget .text,
.numwidget .text {
color: var(--fk-text-muted) !important;
font-weight: 500 !important;
font-size: 13.5px !important;
display: block !important;
}
/* Event-Kacheln auf der globalen Start-Übersicht */
.dashboard .event {
background-color: var(--fk-card-bg) !important;
border: 1px solid var(--fk-border) !important;
border-radius: 12px !important;
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.04) !important;
overflow: hidden !important;
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease !important;
}
.dashboard .event .toprow,
.dashboard .event > a {
border: none !important;
background: transparent !important;
}
.dashboard .event:hover {
transform: translateY(-2px) !important;
box-shadow: 0 10px 25px -5px rgba(37, 99, 235, 0.14) !important;
border-color: #60a5fa !important;
}
.dashboard .event .name {
color: var(--fk-text-main) !important;
font-weight: 600 !important;
}
.dashboard .event .bottomrow .orders,
.dashboard .event .bottomrow > div:first-child,
.dashboard .event .bottomrow > span:first-child {
background-color: #1e293b !important;
color: #f8fafc !important;
}
/* Panels & Inhaltsboxen */
.panel,
.jumbotron {
background-color: var(--fk-card-bg) !important;
border: 1px solid var(--fk-border) !important;
border-radius: 12px !important;
box-shadow: 0 2px 8px rgba(15, 23, 42, 0.03) !important;
}
.panel-default > .panel-heading,
.panel-primary > .panel-heading {
background: #ffffff !important;
color: var(--fk-text-main) !important;
border-bottom: 1px solid var(--fk-border) !important;
font-weight: 600 !important;
padding: 14px 18px !important;
border-top-left-radius: 12px !important;
border-top-right-radius: 12px !important;
}
/* --- BUTTONS, UMSCHALTER ("Alle | aktiv") & BADGES --- */
.btn {
border-radius: 8px !important;
font-weight: 500 !important;
transition: all 0.18s ease !important;
}
/* Sekundäre Buttons ("Deaktivieren", "Gehe zu") mit sanftem Rahmen statt Schwarz */
.btn-default {
background-color: #ffffff !important;
border: 1px solid #cbd5e1 !important;
color: var(--fk-text-secondary) !important;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03) !important;
}
.btn-default:hover,
.btn-default:focus {
background-color: #f1f5f9 !important;
border-color: #94a3b8 !important;
color: var(--fk-text-main) !important;
}
/* Aktive Umschalt-Buttons (behebt das dunkle Lila bei "Alle | aktiv") */
.btn-default.active,
.btn-default:active,
.btn-group > .btn.active,
.open > .dropdown-toggle.btn-default {
background: var(--fk-gradient-primary) !important;
border-color: var(--fk-indigo) !important;
color: #ffffff !important;
box-shadow: 0 2px 8px rgba(79, 70, 229, 0.25) !important;
}
.btn-primary {
background: var(--fk-gradient-primary) !important;
border: none !important;
color: #ffffff !important;
font-weight: 600 !important;
box-shadow: 0 2px 8px rgba(79, 70, 229, 0.25) !important;
}
.btn-primary:hover,
.btn-primary:focus {
background: var(--fk-gradient-hover) !important;
box-shadow: 0 4px 14px rgba(79, 70, 229, 0.38) !important;
transform: translateY(-1px);
}
/* "aktiv"-Badge in Smaragdgrün */
.label-success,
.badge-success {
background-color: #10b981 !important;
color: #ffffff !important;
border-radius: 6px !important;
padding: 4px 8px !important;
font-weight: 600 !important;
}
.form-control {
border-radius: 8px !important;
border: 1px solid #cbd5e1 !important;
background-color: #ffffff !important;
color: var(--fk-text-main) !important;
}
.form-control:focus {
border-color: var(--fk-indigo) !important;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15) !important;
outline: none !important;
}
/* ==========================================================================
4. LOGIN-SCREEN (EXAKT MITTIG ZENTRIERT & SYMMETRISCHES LOGO)
========================================================================== */
body:has(img.logo),
body.login {
background-color: #060b16 !important;
background-image:
radial-gradient(circle at 50% 35%, rgba(37, 99, 235, 0.22) 0%, rgba(124, 58, 237, 0.10) 45%, transparent 75%),
linear-gradient(to right, rgba(56, 189, 248, 0.035) 1px, transparent 1px),
linear-gradient(to bottom, rgba(56, 189, 248, 0.035) 1px, transparent 1px) !important;
background-size: 100% 100%, 40px 40px, 40px 40px !important;
color: #e2e8f0 !important;
min-height: 100vh !important;
margin: 0 !important;
padding: 20px !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
}
body:has(img.logo) > .container {
width: 100% !important;
max-width: 420px !important;
margin: 0 auto !important;
padding: 0 !important;
}
body:has(img.logo) > .container .row {
margin: 0 !important;
}
body:has(img.logo) > .container [class*="col-"] {
width: 100% !important;
margin: 0 !important;
padding: 0 !important;
float: none !important;
}
.container img.logo,
.container-fluid img.logo,
.form-signin img.logo {
content: url('/static/whitelabel/login-logo.svg?v=7') !important;
height: 115px !important;
max-height: 115px !important;
width: auto !important;
margin: 0 auto 24px auto !important;
display: block !important;
filter: drop-shadow(0 0 18px rgba(0, 229, 255, 0.28)) !important;
}
body:has(img.logo) .panel,
body:has(img.logo) .well,
body:has(img.logo) .form-signin,
.login-panel {
background: rgba(15, 23, 42, 0.78) !important;
backdrop-filter: blur(16px) !important;
-webkit-backdrop-filter: blur(16px) !important;
border: 1px solid rgba(99, 102, 241, 0.28) !important;
border-radius: 16px !important;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 30px rgba(37, 99, 235, 0.12) !important;
color: #f1f5f9 !important;
padding: 28px !important;
margin-bottom: 18px !important;
}
body:has(img.logo) label,
body:has(img.logo) .control-label,
body:has(img.logo) .checkbox label {
color: #cbd5e1 !important;
}
body:has(img.logo) .form-control {
background-color: rgba(6, 11, 22, 0.78) !important;
border: 1px solid rgba(148, 163, 184, 0.28) !important;
color: #f8fafc !important;
height: 42px !important;
}
body:has(img.logo) .form-control:focus {
border-color: var(--fk-cyan) !important;
box-shadow: 0 0 0 3px rgba(0, 229, 255, 0.18) !important;
}
body:has(img.logo) a {
color: #60a5fa !important;
}
@@ -0,0 +1,39 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100%" height="100%">
<!-- Copyright (c) 2026 Tino Falkenthal. All Rights Reserved. Excluded from AGPLv3 pursuant to Sec. 7(e). -->
<defs>
<linearGradient id="f-cyan-blue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00e5ff"/>
<stop offset="100%" stop-color="#2563eb"/>
</linearGradient>
<linearGradient id="f-blue-purple" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1d4ed8"/>
<stop offset="100%" stop-color="#7c3aed"/>
</linearGradient>
<linearGradient id="f-wing-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<linearGradient id="f-wing-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2563eb"/>
<stop offset="100%" stop-color="#6d28d9"/>
</linearGradient>
<linearGradient id="f-lower-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#60a5fa"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<linearGradient id="f-lower-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4f46e5"/>
<stop offset="100%" stop-color="#9333ea"/>
</linearGradient>
</defs>
<polygon points="50,7 35,19 50,29" fill="url(#f-cyan-blue)"/>
<polygon points="50,7 65,19 50,29" fill="url(#f-blue-purple)"/>
<polygon points="50,29 7,19 35,43" fill="url(#f-wing-left)"/>
<polygon points="50,29 93,19 65,43" fill="url(#f-wing-right)"/>
<polygon points="35,43 1,38 28,60" fill="url(#f-lower-left)"/>
<polygon points="65,43 99,38 72,60" fill="url(#f-lower-right)"/>
<polygon points="50,29 35,43 50,80" fill="url(#f-cyan-blue)"/>
<polygon points="50,29 65,43 50,80" fill="url(#f-blue-purple)"/>
<polygon points="50,81 40,68 50,93" fill="#00e5ff"/>
<polygon points="50,81 60,68 50,93" fill="#7c3aed"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,48 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 135" width="100%" height="100%">
<!-- Copyright (c) 2026 Tino Falkenthal. All Rights Reserved. Excluded from AGPLv3 pursuant to Sec. 7(e). -->
<defs>
<linearGradient id="c-cyan-blue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00e5ff"/>
<stop offset="100%" stop-color="#2563eb"/>
</linearGradient>
<linearGradient id="c-blue-purple" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1d4ed8"/>
<stop offset="100%" stop-color="#7c3aed"/>
</linearGradient>
<linearGradient id="c-wing-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<linearGradient id="c-wing-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2563eb"/>
<stop offset="100%" stop-color="#6d28d9"/>
</linearGradient>
<linearGradient id="c-lower-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#60a5fa"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<linearGradient id="c-lower-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4f46e5"/>
<stop offset="100%" stop-color="#9333ea"/>
</linearGradient>
</defs>
<g transform="translate(105, 2) scale(0.9)">
<polygon points="50,7 35,19 50,29" fill="url(#c-cyan-blue)"/>
<polygon points="50,7 65,19 50,29" fill="url(#c-blue-purple)"/>
<polygon points="50,29 7,19 35,43" fill="url(#c-wing-left)"/>
<polygon points="50,29 93,19 65,43" fill="url(#c-wing-right)"/>
<polygon points="35,43 1,38 28,60" fill="url(#c-lower-left)"/>
<polygon points="65,43 99,38 72,60" fill="url(#c-lower-right)"/>
<polygon points="50,29 35,43 50,80" fill="url(#c-cyan-blue)"/>
<polygon points="50,29 65,43 50,80" fill="url(#c-blue-purple)"/>
<polygon points="50,81 40,68 50,93" fill="#00e5ff"/>
<polygon points="50,81 60,68 50,93" fill="#7c3aed"/>
</g>
<text x="154" y="122"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
font-size="18"
font-weight="700"
fill="#f8fafc"
letter-spacing="7">FALKENTHAL</text>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,48 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 80" width="100%" height="100%">
<!-- Copyright (c) 2026 Tino Falkenthal. All Rights Reserved. Excluded from AGPLv3 pursuant to Sec. 7(e). -->
<defs>
<linearGradient id="l-cyan-blue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00e5ff"/>
<stop offset="100%" stop-color="#2563eb"/>
</linearGradient>
<linearGradient id="l-blue-purple" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1d4ed8"/>
<stop offset="100%" stop-color="#7c3aed"/>
</linearGradient>
<linearGradient id="l-wing-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<linearGradient id="l-wing-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2563eb"/>
<stop offset="100%" stop-color="#6d28d9"/>
</linearGradient>
<linearGradient id="l-lower-left" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#60a5fa"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<linearGradient id="l-lower-right" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4f46e5"/>
<stop offset="100%" stop-color="#9333ea"/>
</linearGradient>
</defs>
<g transform="translate(4, 2) scale(0.76)">
<polygon points="50,7 35,19 50,29" fill="url(#l-cyan-blue)"/>
<polygon points="50,7 65,19 50,29" fill="url(#l-blue-purple)"/>
<polygon points="50,29 7,19 35,43" fill="url(#l-wing-left)"/>
<polygon points="50,29 93,19 65,43" fill="url(#l-wing-right)"/>
<polygon points="35,43 1,38 28,60" fill="url(#c-lower-left)"/>
<polygon points="35,43 1,38 28,60" fill="url(#l-lower-left)"/>
<polygon points="65,43 99,38 72,60" fill="url(#l-lower-right)"/>
<polygon points="50,29 35,43 50,80" fill="url(#l-cyan-blue)"/>
<polygon points="50,29 65,43 50,80" fill="url(#l-blue-purple)"/>
<polygon points="50,81 40,68 50,93" fill="#00e5ff"/>
<polygon points="50,81 60,68 50,93" fill="#7c3aed"/>
</g>
<text x="90" y="47"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
font-size="21"
font-weight="700"
fill="#f8fafc"
letter-spacing="4.5">FALKENTHAL</text>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,92 @@
/* ==========================================================================
FALKENTHAL MODERN SHOP UI/UX UPGRADE (presale.css)
Farbneutral: Respektiert 100 % der Veranstalter-Farben, Logos & Hintergründe!
========================================================================== */
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
line-height: 1.6;
}
/* 1. MODERNE CARDS & PANELS IM TICKETSHOP */
.panel {
border-radius: 12px;
border: 1px solid rgba(15, 23, 42, 0.08);
box-shadow: 0 4px 20px -2px rgba(15, 23, 42, 0.05);
overflow: hidden;
transition: box-shadow 0.2s ease;
}
.panel-heading {
padding: 15px 20px;
font-weight: 600;
letter-spacing: -0.01em;
}
/* 2. PRODUKT- & TICKETZEILEN (MICRO-INTERACTIONS) */
.product-row,
.variation-row {
border-radius: 8px;
padding: 12px 10px;
transition: background-color 0.18s ease;
}
.product-row:hover {
background-color: rgba(15, 23, 42, 0.025);
}
/* 3. BUTTONS & EINGABEFELDER (MODERNE GEOMETRIE OHNE FARB-ZWANG) */
.btn {
border-radius: 8px;
font-weight: 600;
padding: 9px 18px;
transition: transform 0.15s ease, box-shadow 0.2s ease, background-color 0.18s ease;
}
.btn:hover,
.btn:focus {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
}
.btn:active {
transform: translateY(0);
}
.form-control {
border-radius: 8px;
height: 40px;
border: 1px solid rgba(15, 23, 42, 0.18);
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.02);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.form-control:focus {
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
outline: none;
}
/* 4. KALENDER & EVENT-KACHELN IN REIHEN */
.event-calendar td.has-events {
border-radius: 8px;
transition: transform 0.15s ease;
}
.subevent-list .subevent-row {
border-radius: 10px;
padding: 12px 16px;
margin-bottom: 8px;
transition: box-shadow 0.2s ease, transform 0.15s ease;
}
/* 5. WARENKORB & CHECKOUT-FORTSCHRITT */
.cart-row {
padding: 12px 8px;
}
.alert {
border-radius: 10px;
border: none;
box-shadow: 0 2px 10px rgba(15, 23, 42, 0.05);
}
+21
View File
@@ -0,0 +1,21 @@
from setuptools import setup, find_packages
with open("README.md", encoding="utf-8") as f:
long_description = f.read()
setup(
name="pretix-falkenthal-theme",
version="1.7.2",
description="Modern Slate & Blue-Violet White-Label Theme Plugin for pretix",
long_description=long_description,
long_description_content_type="text/markdown",
author="Tino Falkenthal",
url="https://git.falkenthal.me/falkenthal/pretix-falkenthal-theme",
license="AGPLv3 (Plugin Code) / All Rights Reserved (Brand Assets & Logos)",
packages=find_packages(),
include_package_data=True,
entry_points="""
[pretix.plugin]
pretix_whitelabel=pretix_whitelabel:PretixPluginMeta
""",
)