Files
schakal00783andClaude Opus 5 ef676a95f4 feat: perinco Pulse - Zeiterfassung fuer perinco
Erste Fassung, live unter https://pulse.perinco.de.

Frontend React 19 + TypeScript + Tailwind 4 (Vite), Backend Express mit
mysql2 auf MariaDB, Exporte als PDF (pdfkit), Excel (exceljs) und CSV.
Aufbau, Designsystem und die sieben Themes kommen aus dem perinco CRM.

Fachlich:
- Buchung mit Wochen-, Monats- und Jahresansicht, Zeiten als 1:23 oder 1,5
- Projekte mit n Budgettoepfen: Laufzeit, Volumen, Sperre bei Ablauf oder
  aufgebrauchtem Budget, Buchung nur auf den passenden Topf
- Kunden, Team mit Hierarchie, Reports im Harvest-Stil, Monatsexporte
- Rollen user/lead/management/admin, doppelt geprueft (Menue und Backend)
- SSO gegen Microsoft Entra ID, Uebernahme der AD-Benutzer per Drag & Drop

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 22:52:20 +02:00

107 lines
5.3 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 900" width="260" height="900" preserveAspectRatio="xMidYMax slice">
<!--
Cyberpunk, Seitenleiste: Blick durch ein Fenster in eine regnerische Gasse.
Aufbau von hinten nach vorn: Fensterreihen der Haeuser, senkrechte
Neonroehren, eine Pfuetze mit Spiegelung, der Regen davor. Die Roehren sind
wieder doppelt gezeichnet - breit und unscharf als Schein, duenn und hell
als Glas.
Die obere Haelfte bleibt ruhig: dort stehen die Menuepunkte. Die Gasse steht
in den unteren rund 350 px, wo die Leiste frei ist.
-->
<defs>
<filter id="schein" x="-100%" y="-40%" width="300%" height="180%">
<feGaussianBlur stdDeviation="6" />
</filter>
<filter id="weiterSchein" x="-200%" y="-60%" width="500%" height="220%">
<feGaussianBlur stdDeviation="16" />
</filter>
<!--
Kein Schwarz: ein farbiger Dunst statt einer dunklen Flaeche. Ueber der
dunklen Flaeche des Dunkelmodus wirkt er wie Tiefe, ueber der weissen des
hellen Modus wie ein kuehler Schleier - grau wird er in keinem von beiden.
-->
<linearGradient id="tiefe" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#3a4a80" stop-opacity="0" />
<stop offset="0.4" stop-color="#33407a" stop-opacity="0.16" />
<stop offset="1" stop-color="#2b3a72" stop-opacity="0.3" />
</linearGradient>
<linearGradient id="pfuetze" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#22d3ee" stop-opacity="0.35" />
<stop offset="1" stop-color="#22d3ee" stop-opacity="0" />
</linearGradient>
</defs>
<!-- Die Gasse wird nach unten dichter -->
<rect y="450" width="260" height="450" fill="url(#tiefe)" />
<!-- Fensterreihen: warm und kalt gemischt, wie bewohnte Haeuser -->
<g opacity="0.5">
<g fill="#f0b356">
<rect x="18" y="612" width="5" height="7" /><rect x="34" y="648" width="5" height="7" />
<rect x="18" y="700" width="5" height="7" /><rect x="50" y="676" width="5" height="7" />
<rect x="208" y="624" width="5" height="7" /><rect x="224" y="668" width="5" height="7" />
<rect x="240" y="708" width="5" height="7" />
</g>
<g fill="#7cc4ef">
<rect x="34" y="588" width="5" height="7" /><rect x="18" y="664" width="5" height="7" />
<rect x="50" y="628" width="5" height="7" /><rect x="224" y="596" width="5" height="7" />
<rect x="208" y="688" width="5" height="7" /><rect x="240" y="640" width="5" height="7" />
</g>
</g>
<!-- Senkrechte Neonroehren links und rechts, wie Schilder an den Haeusern -->
<g>
<rect x="26" y="520" width="10" height="180" fill="#c026d3" opacity="0.4" filter="url(#weiterSchein)" />
<rect x="29" y="520" width="4" height="180" fill="#e879f9" opacity="0.8" filter="url(#schein)" />
<rect x="30" y="520" width="2" height="180" fill="#fbe3ff" opacity="0.9" />
<rect x="222" y="580" width="10" height="230" fill="#0891b2" opacity="0.4" filter="url(#weiterSchein)" />
<rect x="225" y="580" width="4" height="230" fill="#22d3ee" opacity="0.8" filter="url(#schein)" />
<rect x="226" y="580" width="2" height="230" fill="#d6feff" opacity="0.9" />
<rect x="126" y="700" width="8" height="120" fill="#7326d6" opacity="0.35" filter="url(#weiterSchein)" />
<rect x="128" y="700" width="4" height="120" fill="#a24cff" opacity="0.75" filter="url(#schein)" />
</g>
<!-- Waagerechtes Schild, quer zur Gasse -->
<g>
<rect x="60" y="756" width="140" height="8" fill="#c026d3" opacity="0.4" filter="url(#weiterSchein)" />
<rect x="60" y="758" width="140" height="4" fill="#f0a6ff" opacity="0.8" filter="url(#schein)" />
</g>
<!-- Nasser Boden mit Spiegelung: die Roehren strahlen nach unten aus -->
<rect y="828" width="260" height="72" fill="#243060" opacity="0.3" />
<g>
<rect x="26" y="828" width="10" height="60" fill="url(#pfuetze)" filter="url(#schein)" />
<rect x="222" y="828" width="10" height="60" fill="url(#pfuetze)" filter="url(#schein)" />
<rect x="126" y="828" width="8" height="46" fill="url(#pfuetze)" filter="url(#schein)" />
</g>
<!-- Zwei Lichtstreifen als nasser Glanz -->
<g fill="#7ce9f7" opacity="0.16">
<rect x="0" y="846" width="260" height="2" />
<rect x="0" y="872" width="260" height="1.5" />
</g>
<!-- Regen ueber die ganze Hoehe, oben blasser -->
<g stroke="#a5c8ff" stroke-linecap="round">
<g stroke-width="1.2" opacity="0.12">
<path d="M20 60 l-6 40" /><path d="M78 20 l-6 40" /><path d="M140 90 l-6 40" />
<path d="M198 40 l-6 40" /><path d="M246 110 l-6 40" /><path d="M46 150 l-6 40" />
<path d="M112 130 l-6 40" /><path d="M176 170 l-6 40" /><path d="M228 200 l-6 40" />
</g>
<g stroke-width="1.3" opacity="0.2">
<path d="M32 300 l-7 46" /><path d="M96 340 l-7 46" /><path d="M158 310 l-7 46" />
<path d="M214 360 l-7 46" /><path d="M62 420 l-7 46" /><path d="M128 400 l-7 46" />
<path d="M190 440 l-7 46" /><path d="M244 410 l-7 46" />
</g>
<g stroke-width="1.6" opacity="0.3">
<path d="M24 520 l-9 56" /><path d="M88 560 l-9 56" /><path d="M150 530 l-9 56" />
<path d="M206 580 l-9 56" /><path d="M54 640 l-9 56" /><path d="M118 620 l-9 56" />
<path d="M182 660 l-9 56" /><path d="M240 630 l-9 56" /><path d="M40 740 l-9 56" />
<path d="M104 760 l-9 56" /><path d="M168 730 l-9 56" /><path d="M232 770 l-9 56" />
</g>
</g>
</svg>