Σύστημα Theme¶
Η Φάση 58 (v1.41.0) αντικατέστησε το παλιό ζεύγος φωτεινό/σκοτεινό με
ένα σύστημα από έξι κλασικά themes σε μία μόνο διάσταση data-theme,
συν μια επιλογή auto, που ακολουθεί το λειτουργικό σύστημα. Η Φάση 63
(v1.63.0) πρόσθεσε έξι προτεινόμενα presets WCAG-AA, ώστε ο picker
να φέρει συνολικά 12 themes.
Προτεινόμενα presets (Φάση 63 / v1.63.0)¶
Ο picker στις Ρυθμίσεις → Εμφάνιση ξεκινά με μια υποκαρτέλα Προτεινόμενα:
- Φωτεινά:
catppuccin-latte,supabase,graphite - Σκοτεινά:
catppuccin-mocha,soft-pop,amethyst-haze
Δημιουργήθηκαν από presets tweakcn μέσω
scripts/generate_preset_themes.py ως πλήρη themes 44 token, με
υπολογιστικά επιβαλλόμενο WCAG AA (contrast.test.ts σε όλα τα 12
themes). Τα κλασικά έξι (light, dark, ocean, forest,
high-contrast, sepia) παραμένουν αμετάβλητα.
Τρόπος λειτουργίας¶
- Τα κανονικά χρωματικά tokens βρίσκονται στο
frontend/src/styles/themes/theme-<id>.css, ένα μπλοκ ανά τιμήdata-theme(light,dark,ocean,forest,high-contrast,sepia). Κάθε αρχείο ορίζει το πλήρες σημασιολογικό σύνολο token - δεν υπάρχει πέρασμα στο φωτεινό.
- Τα tokens ανεξάρτητα από theme (αποστάσεις, ακτίνα, γραμματοσειρές,
η παλέτα μεθόδων της μάρκας) και τα Legacy-Aliase (
--bg,--surface,--fg,--danger, ...) βρίσκονται στοstyles/global.css :root. Τα aliases επιλύονται μέσω των κανονικών tokens και ακολουθούν έτσι αυτόματα το ενεργό theme. - Τα αρχεία theme εισάγονται στο
main.tsx, πρώτα το φωτεινό, ώστε το ενεργό theme να κερδίζει την ισοπαλία ειδικότητας έναντι του:root. - Το
frontend/src/lib/themes.tsείναι το μητρώο:THEMES, οι τύποιThemeId/ThemeChoice,resolveTheme(choice, prefersDark)για την αντιστοίχισηautoκαι τα δείγματα χρώματος προεπισκόπησης. - Το
frontend/src/hooks/useTheme.tsκατέχει το εφαρμοσμένο attributedata-themeκαι αποθηκεύει την επιλογή στοadaptive-learner.theme(μεταφέρει εφάπαξ το παλιό κλειδίadaptive-learner-theme). - Το
index.htmlπεριέχει ένα μικρό inline-script, που εφαρμόζει το αποθηκευμένο theme πριν το πρώτο paint (χωρίς τρεμόπαιγμα). Αντικατοπτρίζει την επίλυση του hook· κράτα τα δύο συγχρονισμένα. - Τα διαγράμματα (Recharts) δεν μπορούν να διαβάσουν μεταβλητές CSS σε
attributes SVG, γι' αυτό τα
lib/chartTheme.ts+useChartThemeδιαβάζουν τις υπολογισμένες τιμές token και τις ξαναδιαβάζουν σε αλλαγήdata-theme.
Σύνολο token (οριζόμενο από κάθε theme)¶
Φόντα (--bg-primary/secondary/surface/elevated/overlay), κείμενο
(--fg-primary/secondary/muted/inverse), περιγράμματα
(--border-primary/subtle/accent), διαδραστικά
(--interactive-bg/hover/active/disabled), τονισμός (--accent,
-hover, -fg, -subtle, -rgb), ζεύγη κατάστασης (--success/-bg,
--error/-bg, --warning/-bg, --info/-bg), ανατροφοδότηση ασκήσεων
(--exercise-correct/-wrong/-selected/-matched), --star, σειρές
διαγραμμάτων (--chart-1..6) και σκιές
(--shadow-card/-elevated/-md).
Το styles/themes/themes.test.ts αποτυγχάνει, αν σε ένα theme λείπει
κάποιο από αυτά τα tokens ή έχει ένα επιπλέον· το
styles/contrast.test.ts ελέγχει το WCAG 2.1 AA σε όλα τα 12 themes.
Η πλήρης αναφορά token βρίσκεται στο
Αρχιτεκτονική Design-Token.
Προσθήκη ενός νέου theme¶
- Αντίγραψε ένα υπάρχον αρχείο, π.χ.
cp theme-dark.css theme-midnight.css, και άλλαξε τον selector σε[data-theme="midnight"]. Κράτα κάθε token - άλλαξε μόνο τις τιμές. Κανένα στυλ component εδώ. - Καταχώρισέ το στο
lib/themes.ts: πρόσθεσε στοTHEMESμια καταχώρησηThemeMeta(id, αγγλικόlabel,familylight|dark και έναswatchγια την προεπισκόπηση των Ρυθμίσεων) και πρόσθεσε το id στην ένωσηThemeId. - Εισήγαγέ το στο
main.tsxμετά τοtheme-light.css(η σειρά μετρά μόνο σε σχέση με το φωτεινό). - Επίτρεψέ το στον Pre-Paint-Guard: πρόσθεσε το id στον πίνακα
validστο inline<script>τουindex.html. - i18n: πρόσθεσε το
ui.themes.midnightσε όλους τους οκτώ καταλόγους στοbackend/config/i18n/*.yamlκαι εκτέλεσεmake sync-i18n. - Έλεγξε:
npx vitest run src/styles/themes src/styles/contrast- τα pins πληρότητας και αντίθεσης πρέπει να παραμείνουν πράσινα (προσάρμοσε τις τιμές, μέχρι η αντίθεση στο νέο theme να πληροί το AA).
Αυτό ήταν - ο ThemePicker, το Pre-Paint-Skript, τα διαγράμματα και κάθε component αναλαμβάνουν το νέο theme αυτόματα, επειδή όλα διαβάζουν τα κανονικά tokens.
Κανόνες¶
- Κανένα σταθερά κωδικοποιημένο χρώμα σε components. Το
styles/no-hardcoded-colors.test.tsτο επιβάλλει για τα στυλ.tsx(μια τεκμηριωμένη allowlist καλύπτει resolvers διαγραμμάτων, διακοσμητικό κονφετί και χρώματα δεδομένων). - Κάθε theme ορίζει κάθε token. Καμία κενότητα με κληρονομικότητα από το φωτεινό - αυτό ήταν το σφάλμα του ελέγχου F1 (μη ορισμένα tokens, που έδειχναν φωτεινό hex στο σκοτεινό mode).
- Η αλλαγή theme είναι ακαριαία - μια ανταλλαγή
data-theme, ποτέ μια επαναφόρτωση.