diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000..2c4112f37
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,2 @@
+# Bulk reformats. `git config blame.ignoreRevsFile .git-blame-ignore-revs`
+68dc0914d70d63eec885d513faf9ae80c35a8ec9 # prettier + CSS comment fix
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index a6dd73d1f..fd4b2eeb0 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -4,4 +4,4 @@
# options. We do not run a GitHub Sponsors / Patreon / Ko-fi page —
# we're a Swiss Verein, not an individual maintainer.
-custom: ["https://revamp-it.ch/get-involved/donate"]
+custom: ['https://revamp-it.ch/get-involved/donate']
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 806b270de..9f136b607 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,7 +1,7 @@
name: 🐛 Bug Report
description: Create a report to help us fix a bug
-title: "[Bug]: "
-labels: ["bug", "needs-triage"]
+title: '[Bug]: '
+labels: ['bug', 'needs-triage']
body:
- type: markdown
attributes:
@@ -84,4 +84,4 @@ body:
attributes:
label: Additional Context
description: Add any other context about the problem here
- placeholder: Any additional information that might help us understand the issue
\ No newline at end of file
+ placeholder: Any additional information that might help us understand the issue
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 906d66cd3..601826364 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,7 +1,7 @@
name: ✨ Feature Request
description: Suggest an idea for RevampIT
-title: "[Feature]: "
-labels: ["enhancement", "needs-triage"]
+title: '[Feature]: '
+labels: ['enhancement', 'needs-triage']
body:
- type: markdown
attributes:
@@ -74,4 +74,4 @@ body:
options:
- label: I'd be willing to implement this feature myself
- label: I'd be willing to help with testing
- - label: I'd be willing to help with documentation
\ No newline at end of file
+ - label: I'd be willing to help with documentation
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 54fe8c06e..b88f072c7 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,76 +1,76 @@
version: 2
updates:
# JavaScript/TypeScript dependencies (npm)
- - package-ecosystem: "npm"
- directory: "/"
+ - package-ecosystem: 'npm'
+ directory: '/'
schedule:
- interval: "weekly"
- day: "monday"
+ interval: 'weekly'
+ day: 'monday'
open-pull-requests-limit: 10
# tiptap's packages share one version and break TypeScript's command
# augmentation when bumped separately — they must move as one PR.
groups:
tiptap:
patterns:
- - "@tiptap/*"
+ - '@tiptap/*'
# react-dom and the @types packages peer-pin react's major — a half-bump
# (react without react-dom, or code types split) cannot even npm ci.
react:
patterns:
- - "react"
- - "react-dom"
- - "@types/react"
- - "@types/react-dom"
+ - 'react'
+ - 'react-dom'
+ - '@types/react'
+ - '@types/react-dom'
# eslint-config-next is version-locked to next; a half-bump breaks lint.
next:
patterns:
- - "next"
- - "eslint-config-next"
+ - 'next'
+ - 'eslint-config-next'
# @auth/pg-adapter peer-depends on next-auth — the pair that produced the
# 2026-08 advisories must move together or neither installs.
next-auth:
patterns:
- - "next-auth"
- - "@auth/*"
+ - 'next-auth'
+ - '@auth/*'
# Tailwind v4 splits the engine from the PostCSS plugin; they share a
# version and a config format.
tailwind:
patterns:
- - "tailwindcss"
- - "@tailwindcss/*"
- - "postcss"
+ - 'tailwindcss'
+ - '@tailwindcss/*'
+ - 'postcss'
eslint:
patterns:
- - "eslint"
- - "@eslint/*"
- - "eslint-plugin-*"
+ - 'eslint'
+ - '@eslint/*'
+ - 'eslint-plugin-*'
jest:
patterns:
- - "jest"
- - "jest-environment-*"
- - "@types/jest"
- - "@testing-library/*"
+ - 'jest'
+ - 'jest-environment-*'
+ - '@types/jest'
+ - '@testing-library/*'
ignore:
# @types/node must track the RUNTIME major, not the newest release. CI
# (ci.yml NODE_VERSION) and the self-host deploy both pin Node 20, so a
# major bump types APIs production does not have — it also fails `verify`.
# Raise this deliberately when the runtime moves. (PR #356 closed for this.)
- - dependency-name: "@types/node"
- update-types: ["version-update:semver-major"]
+ - dependency-name: '@types/node'
+ update-types: ['version-update:semver-major']
commit-message:
- prefix: "deps"
+ prefix: 'deps'
labels:
- - "dependencies"
- - "security"
+ - 'dependencies'
+ - 'security'
# GitHub Actions
- - package-ecosystem: "github-actions"
- directory: "/"
+ - package-ecosystem: 'github-actions'
+ directory: '/'
schedule:
- interval: "weekly"
- day: "monday"
+ interval: 'weekly'
+ day: 'monday'
commit-message:
- prefix: "ci"
+ prefix: 'ci'
labels:
- - "ci"
- - "dependencies"
+ - 'ci'
+ - 'dependencies'
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 000000000..b6986633c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,31 @@
+# Build output and vendored trees — formatting these is noise.
+node_modules
+.next
+dist
+build
+out
+coverage
+.turbo
+.vercel
+*.min.js
+*.min.css
+
+# Generated during a build, so it is absent locally and present in CI — which
+# makes a clean local --check no evidence at all. Contentlayer's output also
+# uses import assertions, which prettier's parser rejects outright.
+.contentlayer
+.astro
+.svelte-kit
+storybook-static
+test-results
+playwright-report
+
+# Lockfiles are generated; prettier would rewrite them wholesale.
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
+
+# Markdown is deliberately out of scope for now. Prettier rewraps prose, which
+# is where it is most opinionated and least useful, and it would bury the real
+# diff. Remove this line when you want docs formatted too.
+*.md
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..616247af0
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "printWidth": 100,
+ "tabWidth": 2,
+ "trailingComma": "all",
+ "arrowParens": "always",
+ "endOfLine": "lf"
+}
diff --git a/__mocks__/next-intl.js b/__mocks__/next-intl.js
index cd78add93..898bee40f 100644
--- a/__mocks__/next-intl.js
+++ b/__mocks__/next-intl.js
@@ -7,40 +7,44 @@
* mock this module locally with jest.mock('next-intl', ...).
*/
-const useTranslations = (_namespace) => (key, _params) => key
+const useTranslations = (_namespace) => (key, _params) => key;
-const useLocale = () => 'de'
+const useLocale = () => 'de';
-const useMessages = () => ({})
+const useMessages = () => ({});
const useFormatter = () => ({
dateTime: (date) => String(date),
number: (n) => String(n),
relativeTime: (date) => String(date),
list: (items) => items.join(', '),
-})
+});
-const NextIntlClientProvider = ({ children }) => children
+const NextIntlClientProvider = ({ children }) => children;
-const getTranslations = async (_namespace) => (key, _params) => key
+const getTranslations = async (_namespace) => (key, _params) => key;
-const getMessages = async () => ({})
+const getMessages = async () => ({});
-const getLocale = async () => 'de'
+const getLocale = async () => 'de';
-const defineRouting = (config) => config
+const defineRouting = (config) => config;
const createNavigation = (_routing) => {
const Link = ({ href, children, className, ...props }) => {
- const React = require('react')
- return React.createElement('a', { href: typeof href === 'string' ? href : href?.pathname ?? '#', className, ...props }, children)
- }
- const redirect = jest.fn()
- const usePathname = () => '/'
- const useRouter = () => ({ push: jest.fn(), replace: jest.fn(), refresh: jest.fn() })
- const getPathname = ({ href }) => (typeof href === 'string' ? href : href?.pathname ?? '/')
- return { Link, redirect, usePathname, useRouter, getPathname }
-}
+ const React = require('react');
+ return React.createElement(
+ 'a',
+ { href: typeof href === 'string' ? href : (href?.pathname ?? '#'), className, ...props },
+ children,
+ );
+ };
+ const redirect = jest.fn();
+ const usePathname = () => '/';
+ const useRouter = () => ({ push: jest.fn(), replace: jest.fn(), refresh: jest.fn() });
+ const getPathname = ({ href }) => (typeof href === 'string' ? href : (href?.pathname ?? '/'));
+ return { Link, redirect, usePathname, useRouter, getPathname };
+};
module.exports = {
useTranslations,
@@ -53,4 +57,4 @@ module.exports = {
getLocale,
defineRouting,
createNavigation,
-}
+};
diff --git a/deliverables/2026-07-13-kivitendo-intake-ui/handoff.html b/deliverables/2026-07-13-kivitendo-intake-ui/handoff.html
index bfc7d6efa..b3bef35cb 100644
--- a/deliverables/2026-07-13-kivitendo-intake-ui/handoff.html
+++ b/deliverables/2026-07-13-kivitendo-intake-ui/handoff.html
@@ -1,187 +1,545 @@
@@ -189,9 +547,11 @@
Übergabe · Revamp-IT
Kivitendo Auftragserfassung, tablet-tauglich
-
Ein reines Aussehen-Update für die Verkaufsauftrags-Maske: grössere Schrift,
- ruhigere Kontraste, Touch-Ziele ab 44 px und eine Positions-Tabelle, die auf dem Tablet
- scrollt statt abzuschneiden. Die Kivitendo-Struktur bleibt unangetastet.
+
+ Ein reines Aussehen-Update für die Verkaufsauftrags-Maske: grössere Schrift, ruhigere
+ Kontraste, Touch-Ziele ab 44 px und eine Positions-Tabelle, die auf dem Tablet scrollt
+ statt abzuschneiden. Die Kivitendo-Struktur bleibt unangetastet.
+
CSS-onlyUpdate-sicher
@@ -210,17 +570,26 @@
Kivitendo Auftragserfassung, tablet-tauglich
ANSEHEN
Die Live-Vorschau
-
Direkt hier unten — das Ziel-Aussehen, umschaltbar zwischen Desktop und Tablet. Nichts installieren.
+
+ Direkt hier unten — das Ziel-Aussehen, umschaltbar zwischen Desktop und Tablet. Nichts
+ installieren.
+
EINBINDEN
Ein Stylesheet
-
Eine eigene .css nach der main.css laden. Kein Eingriff in Kivitendo, überlebt Updates.
+
+ Eine eigene .css nach der main.css laden. Kein Eingriff in
+ Kivitendo, überlebt Updates.
+
PRÜFEN
2 Minuten mit F12
-
Ich sehe eure Live-DOM nicht. Alle unsicheren Selektoren sind mit ⚠ PRÜFEN markiert.
+
+ Ich sehe eure Live-DOM nicht. Alle unsicheren Selektoren sind mit
+ ⚠ PRÜFEN markiert.
+
@@ -230,7 +599,10 @@
2 Minuten mit F12
02
Live-Vorschau
-
Das exakte Ziel-Aussehen. Schalte auf Tablet um — die Kopffelder stapeln, die Positions-Tabelle scrollt waagrecht.
+
+ Das exakte Ziel-Aussehen. Schalte auf Tablet um — die Kopffelder stapeln, die
+ Positions-Tabelle scrollt waagrecht.
+
@@ -244,7 +616,12 @@
Live-Vorschau
-
+
@@ -256,7 +633,10 @@
Live-Vorschau
03
Einbinden — update-sicher
-
Nicht in main.css schreiben (wird bei Updates überschrieben). Als eigene Datei laden.
+
+ Nicht in main.css schreiben (wird bei Updates überschrieben). Als eigene
+ Datei laden.
+
@@ -264,30 +644,43 @@
Einbinden — update-sicher
1
Datei ablegen
-
Speichere kivitendo-intake.css unter css/kivitendo/revamp-intake.css (oder einem eigenen Ordner deiner Wahl).
+
+ Speichere kivitendo-intake.css unter
+ css/kivitendo/revamp-intake.css (oder einem eigenen Ordner deiner Wahl).
+
2
Nach der main.css laden
-
Im Layout-Template referenzieren — nach der main.css, damit dein Stil gewinnt. So bleibt ein Kivitendo-Update unberührt.
+
+ Im Layout-Template referenzieren — nach der main.css,
+ damit dein Stil gewinnt. So bleibt ein Kivitendo-Update unberührt.
+
3
Öffnen & kurz prüfen
-
Auftragsmaske öffnen. Passt alles, bist du fertig. Greift ein Block nicht: F12 → echten Klassen-/ID-Namen ablesen → im CSS ersetzen.
+
+ Auftragsmaske öffnen. Passt alles, bist du fertig. Greift ein Block nicht: F12 → echten
+ Klassen-/ID-Namen ablesen → im CSS ersetzen.
+
⚠
-
Die Positions-Tabelle #row_table_id füllt Kivitendo — an der Struktur ändern wir nichts.
- Das CSS stylt sie nur um: grössere Zellen, fixierte Kopfzeile beim Scrollen, Zeilenstreifen, rechtsbündige Zahlen,
- waagrechtes Scrollen auf dem Tablet. Diese ID ist bestätigt; die übrigen mit ⚠ PRÜFEN markierten
- Selektoren (Kopf-Wrapper, Summen-Container, Zahlen-Klasse) sind sichere Annahmen für 3.9.x — bei Bedarf mit F12 gegenprüfen.
+
+ Die Positions-Tabelle #row_table_id füllt Kivitendo — an der
+ Struktur ändern wir nichts. Das CSS stylt sie nur um: grössere Zellen, fixierte Kopfzeile
+ beim Scrollen, Zeilenstreifen, rechtsbündige Zahlen, waagrechtes Scrollen auf dem Tablet.
+ Diese ID ist bestätigt; die übrigen mit ⚠ PRÜFEN markierten Selektoren
+ (Kopf-Wrapper, Summen-Container, Zahlen-Klasse) sind sichere Annahmen für 3.9.x — bei Bedarf
+ mit F12 gegenprüfen.
+
@@ -315,23 +708,41 @@
Das CSS zum Kopieren
05
Feintuning
-
Ganz oben im CSS gibt es einen :root-Block mit Stellschrauben.
+
+ Ganz oben im CSS gibt es einen :root-Block
+ mit Stellschrauben.
+