|
|
|
@@ -249,9 +249,10 @@ templates/ |
|
|
|
|
|
|
|
``` |
|
|
|
assets/styles/ |
|
|
|
├── main.scss ← Entry Point |
|
|
|
├── main.scss ← Entry Point + globale [hidden]-Regel |
|
|
|
├── atoms/ |
|
|
|
│ ├── _variables.scss ← SCSS-Vars + :root CSS Custom Properties |
|
|
|
│ ├── _mixins.scss ← Wiederverwendbare Mixins (card, icon-btn, page-shell, etc.) |
|
|
|
│ ├── _typography.scss |
|
|
|
│ ├── _buttons.scss ← .btn, .btn-primary, .btn-secondary |
|
|
|
│ └── _inputs.scss ← .input, .select, .textarea |
|
|
|
@@ -285,6 +286,8 @@ assets/styles/ |
|
|
|
assets/ |
|
|
|
├── app.js ← Entry: importiert main.scss, calendar.js, entries.js |
|
|
|
└── scripts/ |
|
|
|
├── utils.js ← Gemeinsame Hilfsfunktionen: esc(), createTranslator(), |
|
|
|
│ removeWithAnimation(), animateIn(), Konstanten |
|
|
|
├── calendar.js ← WeekCalendar (Wochennavigation, Monatsansicht) |
|
|
|
│ Positioniert Monatskalender relativ zum Cal-Icon |
|
|
|
├── entries.js ← EntryManager (CRUD, fetch, localStorage) |
|
|
|
@@ -316,18 +319,41 @@ assets/ |
|
|
|
|
|
|
|
## Wichtige Konventionen |
|
|
|
|
|
|
|
### Translations — keine hardcodierten Strings |
|
|
|
- **Alle** UI-Texte leben in `translations/messages.de.yaml` — nirgends deutsche Strings direkt im Code |
|
|
|
- **Twig**: `{{ 'app.section.key'|trans }}`, mit Platzhaltern: `{{ 'app.key'|trans({'%name%': value}) }}` |
|
|
|
- **PHP Controller/Services**: `TranslatorInterface` injizieren → `$this->translator->trans('app.key')` |
|
|
|
- **JS**: Strings als `window.XX.i18n`-Objekt im Twig-Template übergeben (z.B. `window.CRUD.i18n`, `window.ACCOUNT.i18n`), Zugriff via `createTranslator('XX')` aus `utils.js` |
|
|
|
- **Schlüsselstruktur**: `app.{section}.{key}` (z.B. `app.team.btn_new`, `app.error.access_denied`) |
|
|
|
- Datums-Arrays weiterhin in `AppExtension.php` als Twig-Funktionen: `deMonths()`, `deMonthsShort()`, `deWeekdays()`, `deWeekdaysShort()` |
|
|
|
|
|
|
|
### Kein Inline-CSS |
|
|
|
- Keine `style="..."`-Attribute in Twig-Templates oder JS-generiertem HTML |
|
|
|
- Stattdessen eigene SCSS-Klassen anlegen |
|
|
|
|
|
|
|
### SCSS: Mixins statt Duplikation |
|
|
|
- Wiederkehrende Patterns in `atoms/_mixins.scss`: `card()`, `icon-btn()`, `page-shell`, `section-header`, `text-truncate`, `form-label` |
|
|
|
- Neue Komponenten sollen vorhandene Mixins nutzen statt CSS-Properties zu duplizieren |
|
|
|
- `main.scss` enthält `[hidden] { display: none !important; }` — kein separates `&[hidden]` pro Komponente nötig |
|
|
|
|
|
|
|
### JS: utils.js — gemeinsame Hilfsfunktionen |
|
|
|
- `esc(str)` — HTML-Escaping für User-Daten in JS-generiertem HTML (XSS-Prävention, immer nutzen!) |
|
|
|
- `createTranslator(namespace)` — i18n-Zugriff (siehe Translations) |
|
|
|
- `removeWithAnimation()` / `animateIn()` — animierte DOM-Operationen |
|
|
|
- Konstanten: `ANIMATION_MS`, `FADE_MS`, `MINUTES_PER_DAY` |
|
|
|
|
|
|
|
### PHP: `readonly` Constructor Promotion |
|
|
|
- Controller-Abhängigkeiten immer mit `private readonly` deklarieren |
|
|
|
|
|
|
|
### Twig: Wiederverwendbare Macros |
|
|
|
- Komplexe Logik die in mehreren Templates vorkommt → `templates/_macros/helpers.html.twig` als Macro (z.B. `smart_date`) |
|
|
|
|
|
|
|
### Durations |
|
|
|
- Gespeichert als **Integer (Minuten)** in der DB |
|
|
|
- Eingabe: `1:30`, `8 12` (von-bis), `1,75` (Dezimal), `0:00` (Reset) |
|
|
|
- Runden: konfigurierbar per `Account.trackingInterval` (1, 15, 30, 60 Minuten) |
|
|
|
- Anzeige: `formatMinutes()` → `"1:30"` |
|
|
|
|
|
|
|
### Translations |
|
|
|
- Alle UI-Strings in `translations/messages.de.yaml` |
|
|
|
- Datums-Arrays in `AppExtension.php` als Twig-Funktionen: `deMonths()`, `deMonthsShort()`, `deWeekdays()`, `deWeekdaysShort()` |
|
|
|
- JS bekommt Strings via `window.TT.i18n` (Timetracking) bzw. `window.Report.i18n` (Report) etc. |
|
|
|
- JS-Zugriff: `function t(key) { return window.X?.i18n?.[key] ?? key; }` |
|
|
|
|
|
|
|
### API-Pattern |
|
|
|
- Alle API-Routen unter `/api/...` |
|
|
|
- JSON Request/Response |
|
|
|
|