This commit is contained in:
Patrick Asmus
2026-07-03 23:01:57 +02:00
parent d85326edd9
commit 48305031e2
6 changed files with 586 additions and 30 deletions

View File

@@ -1,26 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
---
Copyright © Patrick Asmus (scriptos)
Name: Patrick Asmus (scriptos)
Email: support@techniverse.net
Website: https://www.patrick-asmus.de
Blog: https://www.cleveradmin.de
---
This program 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.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

171
README.md
View File

@@ -4,10 +4,10 @@
</a>
</p>
<h1 align="center">Name des Projekts</h1>
<h1 align="center">Kutt Dark Mode CSS</h1>
<h4 align="center">
Kurzbeschreibung des Projekts/Anwendung, um die es geht
Ein sauberes Dark-Mode-Theme für Kutt, den selbst gehosteten URL-Shortener.
</h4>
<h6 align="center">
@@ -22,7 +22,170 @@
<br><br>
CONTENT BEREICH
## Vorschau
![Kutt Dark Mode CSS Vorschau](assets/screenshot1.png)
- Hintergrund: Dunkles Blaugrau (`#0f1419`)
- Akzentfarbe: Blau (`#1D6397`)
- Alle Icons (Edit, Delete, QR-Code, Stats, Ban) bleiben sichtbar und funktional
## Installation
### 1. Volume in `docker-compose.yaml` einrichten
Der Kutt-Container braucht ein Volume, das den Custom-Ordner einbindet:
```yaml
services:
kutt-app:
image: kutt/kutt:latest
volumes:
- ./data/app/custom:/kutt/custom
```
### 2. CSS-Datei kopieren
Die Datei `custom.css` in den CSS-Ordner innerhalb des Custom-Verzeichnisses legen:
```bash
mkdir -p ./data/app/custom/css
cp custom.css ./data/app/custom/css/custom.css
```
### 3. Container neu starten
```bash
docker restart kutt-app
```
### 4. Im Browser prüfen
Die Seite mit `Ctrl + Shift + R` (Hard-Reload) neu laden, damit der Browser-Cache das neue CSS holt.
![Kutt Dark Mode CSS Vorschau](assets/screenshot2.png)
## Logo anpassen
Kutt unterstützt ein eigenes Logo über das Custom-Verzeichnis:
```bash
mkdir -p ./data/app/custom/images
cp dein-logo.png ./data/app/custom/images/logo.png
```
Das Logo wird automatisch von Kutt geladen. Das CSS sorgt dafür, dass es als 32x32px Kreis dargestellt wird:
```css
img[src*="logo"] {
width: 32px;
height: 32px;
object-fit: contain;
border-radius: 50%;
}
```
Wenn du ein eckiges Logo bevorzugst, einfach `border-radius: 50%;` entfernen oder auf z.B. `border-radius: 6px;` ändern.
### Weitere anpassbare Bilder
| Datei | Zweck |
|---|---|
| `images/logo.png` | Logo im Header |
| `images/favicon.ico` | Browser-Tab-Icon |
| `images/favicon-16x16.png` | Favicon 16px |
| `images/favicon-32x32.png` | Favicon 32px |
| `images/favicon-196x196.png` | Favicon groß (Android etc.) |
| `images/card.png` | Social-Media-Vorschaubild (Open Graph) |
Alle Dateien kommen in `./data/app/custom/images/`.
## Wichtige CSS-Variablen
Die wichtigsten Farben werden über CSS Custom Properties gesteuert. Sie stehen ganz oben in der `custom.css` im `:root`-Block und können dort einfach angepasst werden:
### Akzentfarbe
```css
--color-primary: #1D6397; /* Hauptfarbe für Links und Buttons */
--outline-color: #1D6397; /* Fokus-Rahmen */
--focus-outline-color: rgba(29, 99, 151, 0.5);
--checkbox-bg-color: #1D6397; /* Checkbox-Farbe */
```
Um die Akzentfarbe zu ändern, diese vier Werte plus die Button-Gradients anpassen:
```css
--button-bg-primary: linear-gradient(to right, #1a5a8a, #1D6397);
--button-bg-primary-box-shadow-color: rgba(29, 99, 151, 0.35);
```
### Hintergründe
```css
--bg-color: #0f1419; /* Seiten-Hintergrund */
--table-bg-color: #151d28; /* Tabellen-Header/Footer */
--table-tr-hover-bg-color: #1a2535; /* Zeile beim Hover */
```
Für Tabellen und Karten wird `#141c26` als Hintergrund und `#1a2332` für erhöhte Elemente (Inputs, Buttons) verwendet. Diese Werte stehen direkt in den CSS-Regeln (nicht als Variable).
### Text
```css
--text-color: #dce0e8; /* Haupttext */
--secondary-text-color: #8b95a5; /* Gedämpfter Text */
--input-label-color: #c8cdd5; /* Label-Text */
```
## Custom Footer
Kutt erlaubt einen eigenen Footer über eine Handlebars-Vorlage:
```bash
mkdir -p ./data/app/custom/views/partials
```
Dort eine Datei `footer.hbs` anlegen, z.B.:
```html
<footer class="site-footer">
<p>
<a href="https://example.com" target="_blank" rel="noopener">Powered by Example</a>
<span aria-hidden="true">|</span>
<a href="/terms">Nutzungsbedingungen</a>
</p>
</footer>
```
Das CSS enthält bereits passende Styles für `.site-footer`.
## Verzeichnisstruktur
So sollte das Custom-Verzeichnis am Ende aussehen:
```
data/app/custom/
css/
custom.css
images/
logo.png
favicon.ico
favicon-16x16.png
favicon-32x32.png
favicon-196x196.png
card.png
views/
partials/
footer.hbs
```
## Hinweise
- Das CSS überschreibt Kutts eingebaute CSS-Variablen. Bei einem Kutt-Update könnten sich Klassennamen ändern — nach Updates kurz prüfen.
- Die Icons (Edit, Delete, QR, Stats, Ban) werden bewusst nicht über `color`-Overrides verändert, sondern behalten ihre originalen `stroke`/`fill`-Werte. Nur die Hintergründe der Action-Buttons werden dezent angepasst.
- Getestet mit Kutt `latest` (Stand Juli 2025).
<br><br>
@@ -34,4 +197,4 @@ CONTENT BEREICH
<sub>
© Patrick Asmus · Techniverse Network · <a href="./LICENSE">Lizenz</a>
</sub>
</p>
</p>

BIN
assets/screenshot1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
assets/screenshot2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

419
custom.css Normal file
View File

@@ -0,0 +1,419 @@
/* ==========================================================
Kutt Dark Mode Techniverse
Accent: #1D6397
========================================================== */
/* ----------------------------------------------------------
1. CSS-VARIABLEN ÜBERSCHREIBEN
---------------------------------------------------------- */
:root {
--bg-color: #0f1419;
--text-color: #dce0e8;
--color-primary: #1D6397;
--outline-color: #1D6397;
--button-bg: linear-gradient(to right, #2a3545, #1e2a38);
--button-bg-box-shadow-color: rgba(0, 0, 0, 0.4);
--button-bg-primary: linear-gradient(to right, #1a5a8a, #1D6397);
--button-bg-primary-box-shadow-color: rgba(29, 99, 151, 0.35);
--button-bg-secondary: linear-gradient(to right, hsl(262, 47%, 45%), hsl(265, 80%, 40%));
--button-bg-secondary-box-shadow-color: hsla(258, 58%, 35%, 0.4);
--button-bg-danger: linear-gradient(to right, hsl(0, 70%, 45%), hsl(0, 65%, 40%));
--button-bg-danger-box-shadow-color: hsla(0, 58%, 35%, 0.4);
--button-bg-success: linear-gradient(to right, hsl(130, 50%, 38%), hsl(130, 55%, 35%));
--button-bg-success-box-shadow-color: hsla(128, 60%, 35%, 0.4);
--button-action-shadow-color: rgba(0, 0, 0, 0.25);
--underline-color: #4a5568;
--secondary-text-color: #8b95a5;
--send-icon-hover-color: #1D6397;
--send-spinner-icon-color: #4a5568;
--success-icon-color: hsl(144, 45%, 50%);
--error-icon-color: hsl(0, 70%, 55%);
--copy-icon-color: hsl(144, 45%, 50%);
--copy-icon-bg-color: hsla(144, 40%, 30%, 0.3);
--copy-icon-shadow-color: rgba(0, 0, 0, 0.2);
--focus-outline-color: rgba(29, 99, 151, 0.5);
--checkbox-bg-color: #1D6397;
--input-shadow-color: rgba(0, 0, 0, 0.25);
--input-hover-shadow-color: rgba(0, 0, 0, 0.4);
--input-label-color: #c8cdd5;
--table-bg-color: #151d28;
--table-shadow-color: rgba(0, 0, 0, 0.35);
--table-tr-border-color: #1e2a38;
--table-tr-hover-bg-color: #1a2535;
--table-head-tr-border-color: #253342;
--table-status-gray-bg-color: #1a2332;
}
/* ----------------------------------------------------------
2. GLOBALE GRUNDLAGEN
---------------------------------------------------------- */
body {
background-color: var(--bg-color) !important;
color: var(--text-color) !important;
}
hr {
background-color: #1e2a38 !important;
}
span.underline {
border-bottom-color: #4a5568 !important;
}
/* ----------------------------------------------------------
3. BUTTONS
---------------------------------------------------------- */
a.button,
button {
color: #c8cdd5;
}
a.button.primary,
button.primary,
a.button.secondary,
button.secondary,
a.button.danger,
button.danger,
a.button.success,
button.success {
color: white;
}
button.nav {
background-color: #1a2332;
box-shadow: 0 0px 10px rgba(0, 0, 0, 0.2);
color: #c8cdd5;
}
button.nav:disabled {
background-color: #141c26;
box-shadow: 0 0px 5px rgba(0, 0, 0, 0.15);
color: #4a5568;
}
/* Action-Button Hintergründe für Dark Mode anpassen */
a.button.action.delete,
button.action.delete {
background: hsla(0, 60%, 40%, 0.2);
}
a.button.action.edit,
button.action.edit {
background: hsla(46, 70%, 40%, 0.2);
}
a.button.action.qrcode,
button.action.qrcode {
background: hsla(0, 0%, 50%, 0.15);
}
a.button.action.stats,
button.action.stats {
background: hsla(260, 60%, 50%, 0.2);
}
a.button.action.ban,
button.action.ban {
background: hsla(10, 60%, 40%, 0.2);
}
/* ----------------------------------------------------------
4. INPUTS & SELECTS
---------------------------------------------------------- */
input[type="text"],
input[type="email"],
input[type="password"] {
color: #dce0e8;
background-color: #1a2332;
border-bottom-color: #253342;
}
input[type="text"]::placeholder,
input[type="email"]::placeholder,
input[type="password"]::placeholder {
color: #5a6577;
}
.error input[type="text"],
.error input[type="email"],
.error input[type="password"] {
border-bottom-color: rgba(220, 50, 50, 0.6);
box-shadow: 0 10px 15px hsla(0, 70%, 40%, 0.15);
}
select {
color: #dce0e8;
background-color: #1a2332;
border-bottom-color: #253342;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24' fill='none' stroke='%238b95a5' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
.error select {
border-bottom-color: rgba(220, 50, 50, 0.6);
box-shadow: 0 10px 15px hsla(0, 70%, 40%, 0.15);
}
select:has(option[value=""]:checked) {
color: #5a6577;
}
select option {
background-color: #1a2332;
color: #dce0e8;
}
input[type="checkbox"] {
background-color: #1a2332;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
label {
color: var(--input-label-color);
}
p.error { color: #e5534b; }
p.success { color: #2ea043; }
/* ----------------------------------------------------------
5. TABELLEN
---------------------------------------------------------- */
table {
background-color: #141c26;
}
table thead {
background-color: var(--table-bg-color);
}
table tfoot {
background-color: var(--table-bg-color);
}
table .tab a {
color: var(--text-color);
background-color: #1a2332;
box-shadow: 0 0px 10px rgba(0, 0, 0, 0.2);
}
table .tab a.active {
background-color: #111920;
box-shadow: 0 0px 5px rgba(0, 0, 0, 0.15);
color: #4a5568;
}
#main-table-wrapper table td .description {
color: #6b7585;
}
#main-table-wrapper table td .description a {
color: #5a6577;
border-bottom-color: #5a6577;
}
#main-table-wrapper table td .description span {
color: #5a6577;
}
#main-table-wrapper table .status.gray {
background-color: var(--table-status-gray-bg-color);
}
#main-table-wrapper table .status.green {
background-color: hsla(130, 50%, 30%, 0.3);
color: #2ea043;
}
#main-table-wrapper table .status.red {
background-color: hsla(0, 50%, 30%, 0.3);
color: #e5534b;
}
/* Fade-Gradient für abgeschnittene Texte */
#main-table-wrapper table tbody td.right-fade:after {
background: linear-gradient(to left, #141c26, rgba(20, 28, 38, 0.001));
}
#main-table-wrapper table tbody tr:hover td.right-fade:after {
background: linear-gradient(to left, var(--table-tr-hover-bg-color), rgba(26, 37, 53, 0.001));
}
/* Edit-Zeile */
#main-table-wrapper table tr.edit {
background-color: #111920;
}
/* ----------------------------------------------------------
6. DIALOGE
---------------------------------------------------------- */
.dialog {
background-color: rgba(0, 0, 0, 0.75);
}
.dialog .box {
background-color: #1a2332;
}
/* ----------------------------------------------------------
7. HEADER
---------------------------------------------------------- */
header a.logo:hover {
color: inherit;
}
/* ----------------------------------------------------------
8. SHORTENER (Hauptseite)
---------------------------------------------------------- */
main #shorturl h1 span {
border-bottom-color: #4a5568;
}
main form button.submit svg.send {
fill: #5a6577;
}
/* ----------------------------------------------------------
9. TOOLTIPS
---------------------------------------------------------- */
[data-tooltip]:before {
border-top-color: #1a2332;
}
[data-tooltip]:after {
background: #1a2332;
color: #dce0e8;
box-shadow: 0 1em 2em -0.5em rgba(0, 0, 0, 0.5);
}
/* ----------------------------------------------------------
10. STATISTIKEN
---------------------------------------------------------- */
#stats {
background-color: #141c26;
}
.stats-head {
background-color: var(--table-bg-color);
}
svg.map path {
fill: #1a2332;
stroke: #0f1419;
}
svg.map path.color-1 { fill: hsla(207, 50%, 30%, 0.4); }
svg.map path.color-2 { fill: hsla(207, 50%, 35%, 0.5); }
svg.map path.color-3 { fill: hsla(207, 50%, 40%, 0.6); }
svg.map path.color-4 { fill: hsla(207, 50%, 45%, 0.7); }
svg.map path.color-5 { fill: hsla(207, 50%, 50%, 0.8); }
svg.map path.color-6 { fill: hsla(207, 50%, 55%, 0.9); }
svg.map path.active { stroke: #1D6397; }
#map-tooltip:before {
border-top-color: #1a2332;
}
#map-tooltip:after {
background: rgba(26, 35, 50, 0.95);
color: #dce0e8;
box-shadow: 0 1em 2em -0.5em rgba(0, 0, 0, 0.4);
}
/* ----------------------------------------------------------
11. SETTINGS
---------------------------------------------------------- */
h1.settings-welcome span {
border-bottom-color: #4a5568;
}
#apikey p {
border-bottom-color: #4a5568;
}
/* ----------------------------------------------------------
12. SONSTIGES
---------------------------------------------------------- */
a.wrapper-only {
color: inherit;
}
/* Scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #0f1419;
}
::-webkit-scrollbar-thumb {
background: #2a3545;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #3a4a5d;
}
/* ==========================================================
LOGO & FOOTER (Techniverse Branding)
========================================================== */
/* Logo proportional (Kreis) */
img[src*="logo"] {
width: 32px;
height: 32px;
object-fit: contain;
border-radius: 50%;
}
/* Footer */
.site-footer {
margin-top: 3rem;
text-align: center;
}
.site-footer p {
font-size: 1rem;
}
.site-footer a {
font-weight: 600;
font-size: 1.05rem;
text-decoration: none;
}
.site-footer a:hover {
text-decoration: underline;
}
.site-footer span[aria-hidden="true"] {
opacity: 0.5;
margin: 0 0.5rem;
}
.site-footer .link {
background: none;
border: none;
font-weight: 600;
font-size: 1.05rem;
}
.site-footer .link:hover {
text-decoration: underline;
}