This commit is contained in:
Zan
2025-12-10 22:15:41 +01:00
parent a40b5db6f9
commit f52017585f
14 changed files with 1408 additions and 345 deletions

View File

@@ -184,6 +184,7 @@
getAvailableLanguages: () => [
{ code: "hu", name: "Magyar" },
{ code: "en", name: "English" },
{ code: "de", name: "Deutsch" },
],
};
})();

View File

@@ -14,15 +14,13 @@
function applyCustomThemeColors(theme) {
const root = document.documentElement;
const isDark = theme.mode === "dark";
root.style.setProperty("--background", theme.colors.background);
root.style.setProperty("--background-0", theme.colors.background + "00");
root.style.setProperty("--card-card", theme.colors.card);
root.style.setProperty("--card-translucent", theme.colors.card + "80");
root.style.setProperty("--accent-accent", theme.colors.accent);
root.style.setProperty("--text-primary", theme.colors.text);
// Származtatott színek
root.style.setProperty("--text-secondary", theme.colors.text + "cc");
root.style.setProperty("--text-teritary", theme.colors.text + "80");
root.style.setProperty("--accent-15", theme.colors.accent + "26");
@@ -30,19 +28,22 @@
root.style.setProperty("--accent-secondary", isDark ? lightenColor(theme.colors.accent, 20) : darkenColor(theme.colors.accent, 20));
root.style.setProperty("--shadow-blur", isDark ? "0" : "2px");
root.style.setProperty("--accent-shadow", isDark ? "#0000" : theme.colors.accent + "26");
// SVG ikon filter beállítása a kiemelő szín alapján
root.style.setProperty("--warning-accent", "#FFA046");
root.style.setProperty("--warning-text", isDark ? "#f0b37a" : "#8F531B");
root.style.setProperty("--warning-15", "#ffa04626");
root.style.setProperty("--warning-card", isDark ? "#201203" : "#FAEBDC");
root.style.setProperty("--error-accent", "#FF54A1");
root.style.setProperty("--error-text", isDark ? "#f59ec5" : "#8F1B4F");
root.style.setProperty("--error-15", "#FF54A126");
root.style.setProperty("--error-card", isDark ? "#1e030f" : "#FADCE9");
root.style.setProperty("--icon-filter", hexToFilter(theme.colors.accent));
}
// Hex szín átalakítása CSS filterré
function hexToFilter(hex) {
// Hex -> RGB
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
// RGB -> HSL
const rNorm = r / 255;
const gNorm = g / 255;
const bNorm = b / 255;
@@ -66,10 +67,6 @@
const hue = Math.round(h * 360);
const saturation = Math.round(s * 100);
const lightness = Math.round(l * 100);
// Filter létrehozása
// Ez egy egyszerűsített megközelítés - a pontos szín reprodukálásához
// komplexebb számítás kellene, de ez megfelelő a legtöbb esetben
const brightnessVal = lightness > 50 ? 1 + (lightness - 50) / 100 : 0.5 + lightness / 100;
const saturateVal = saturation > 0 ? 1 + saturation / 100 : 0;
@@ -100,20 +97,20 @@
"--background", "--background-0", "--card-card", "--card-translucent",
"--accent-accent", "--text-primary", "--text-secondary", "--text-teritary",
"--accent-15", "--button-secondaryFill", "--accent-secondary",
"--shadow-blur", "--accent-shadow", "--icon-filter"
"--shadow-blur", "--accent-shadow", "--icon-filter",
"--warning-accent", "--warning-text", "--warning-15", "--warning-card",
"--error-accent", "--error-text", "--error-15", "--error-card"
];
customProps.forEach(prop => root.style.removeProperty(prop));
}
async function setTheme(theme) {
try {
// Töröljük az előző egyéni téma stílusait
clearCustomThemeStyles();
document.documentElement.setAttribute("data-theme", theme);
await storageManager.set("themePreference", theme);
// Ha egyéni téma, alkalmazzuk a színeket
if (theme.startsWith("custom-")) {
await loadCustomThemes();
const themeId = theme.replace("custom-", "");
@@ -244,7 +241,6 @@
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "changeTheme") {
// Ha egyéni témák is jöttek az üzenetben, frissítsük a lokális listát
if (message.customThemes) {
customThemes = message.customThemes;
}

537
i18n/de.json Normal file
View File

@@ -0,0 +1,537 @@
{
"loading": {
"text": "Laden...",
"subtext": "Bitte warten!"
},
"settings": {
"title": "Einstellungen",
"appearance": "Erscheinungsbild",
"theme": "Design",
"language": "Sprache",
"tabs": {
"home": "Startseite",
"appearance": "Erscheinungsbild",
"settings": "Einstellungen",
"about": "Über"
},
"page_settings": {
"title": "Seiteneinstellungen",
"current_page": "Aktuelle Seite",
"no_settings": "Keine benutzerdefinierten Einstellungen für diese Seite verfügbar.",
"login": {
"hide_system_message": "Systemmeldung ausblenden",
"hide_system_message_desc": "Systemmeldung auf der Anmeldeseite ausblenden",
"hide_school_info": "Schulname und ID ausblenden",
"hide_school_info_desc": "Der Schulname und die KRÉTA-ID werden nicht angezeigt"
},
"roleselect": {
"auto_redirect": "Automatische Weiterleitung",
"auto_redirect_desc": "Automatische Weiterleitung zum Notenbuch",
"hide_school_info": "Schule und Name ausblenden",
"hide_school_info_desc": "Der Schulname und Benutzername werden nicht angezeigt"
},
"bulletin": {
"hide_grades": "Noten ausblenden",
"hide_grades_desc": "Die Notenkarte ausblenden",
"hide_absences": "Fehlzeiten ausblenden",
"hide_absences_desc": "Die Fehlzeitenkarte ausblenden",
"hide_notes": "Notizen ausblenden",
"hide_notes_desc": "Die Notizenkarte ausblenden",
"hide_exams": "Angekündigte Prüfungen ausblenden",
"hide_exams_desc": "Die Karte für angekündigte Prüfungen ausblenden"
},
"grades": {
"hide_chart": "Diagramm ausblenden",
"hide_chart_desc": "Das Notendiagramm ausblenden",
"hide_class_average": "Klassendurchschnitt ausblenden",
"hide_class_average_desc": "Klassendurchschnittswerte ausblenden"
}
},
"themes": {
"light_green": "Hellgrün",
"dark_green": "Dunkelgrün",
"dark_red": "Dunkelrot",
"dark_purple": "Dunkellila",
"dark_orange": "Dunkelorange",
"dark_pink": "Dunkelrosa",
"dark_yellow": "Dunkelgelb",
"dark_cyan": "Dunkelcyan",
"dark_lime": "Dunkellime",
"dark_indigo": "Dunkelindigo"
},
"custom_themes": {
"title": "Benutzerdefinierte Designs",
"no_themes": "Noch keine benutzerdefinierten Designs",
"create": "Neues Design erstellen",
"edit": "Design bearbeiten",
"name": "Designname",
"mode": "Modus",
"dark_mode": "Dunkel",
"light_mode": "Hell",
"colors": "Farben",
"accent_color": "Akzentfarbe",
"background_color": "Hintergrundfarbe",
"card_color": "Kartenfarbe",
"text_color": "Textfarbe",
"preview": "Vorschau",
"share": "Design teilen",
"share_description": "Kopieren Sie den Code und teilen Sie ihn mit anderen:",
"import": "Design importieren",
"import_description": "Fügen Sie den Design-Code ein:",
"import_error_empty": "Bitte fügen Sie den Design-Code ein!",
"import_error_invalid": "Ungültiger Design-Code!",
"delete_confirm": "Möchten Sie dieses Design wirklich löschen?",
"manage": "Verwalten"
},
"languages": {
"hu": "Magyar",
"en": "English",
"de": "Deutsch"
},
"about": {
"title": "Über",
"description": "Firka ist ein Open-Source-Projekt, das eine benutzerdefinierte Benutzeroberfläche für das KRÉTA-System erstellt.",
"github": "GitHub"
},
"support": {
"title": "Unterstützung",
"description": "Wenn Ihnen unsere Arbeit gefällt und Sie die Entwicklung unterstützen möchten, können Sie dies folgendermaßen tun:",
"kofi": "Ko-Fi"
},
"error_reporting": {
"title": "Fehlerberichterstattung",
"enable": "Fehlerberichterstattung aktivieren",
"enable_desc": "Automatische Fehlerberichte an Entwickler senden, um die Erweiterung zu verbessern",
"report_issue": "Fehler oder Idee melden",
"report_issue_desc": "Öffnen Sie ein GitHub-Issue"
}
},
"navigation": {
"dashboard": "Dashboard",
"timetable": "Stundenplan",
"grades": "Noten",
"homework": "Hausaufgaben",
"absences": "Fehlzeiten",
"messages": "Nachrichten",
"profile": "Profil",
"settings": "Einstellungen",
"logout": "Abmelden",
"nav_toggle": "Navigation öffnen"
},
"dashboard": {
"welcome": "Willkommen",
"recent_grades": "Letzte Noten",
"upcoming_lessons": "Kommende Stunden",
"homework_due": "Fällige Hausaufgaben",
"news": "Nachrichten",
"grades": "Ihre Bewertungen",
"absences": "Fehlzeiten",
"notes": "Notizen",
"exams": "Angekündigte Prüfungen",
"all_news": "Alle Nachrichten",
"all_grades": "Alle Noten",
"all_absences": "Alle Fehlzeiten",
"all_messages": "Alle Nachrichten",
"all_exams": "Alle Prüfungen",
"not_supported": "Derzeit sind keine Daten zum Laden verfügbar",
"evaluation": "Bewertung"
},
"grades": {
"title": "Noten",
"subject": "Fach",
"grade": "Note",
"date": "Datum",
"teacher": "Lehrer",
"average": "Durchschnitt",
"chart_title": "Noten",
"semester_evaluation": "Semesterbewertung",
"semester_evaluations": "Semesterbewertungen",
"year_end_evaluations": "Jahresabschlussbewertungen",
"semester_average": "Semesterdurchschnitt",
"no_grades": "Keine Noten",
"september": "September",
"october": "Oktober",
"november": "November",
"december": "Dezember",
"january_1": "JanuarI",
"january_2": "JanuarII",
"february": "Februar",
"march": "März",
"april": "April",
"may": "Mai",
"june_1": "JuniI",
"june_2": "JuniII"
},
"timetable": {
"title": "Stundenplan",
"lesson": "Stunde",
"time": "Zeit",
"subject": "Fach",
"teacher": "Lehrer",
"classroom": "Klassenzimmer",
"homework_indicator": "Hausaufgaben",
"test_indicator": "Prüfung",
"teacher_label": "Lehrer:",
"substitute_teacher_label": "Vertretungslehrer:",
"classroom_label": "Raum:",
"time_label": "Zeit:",
"status_label": "Status:",
"substitution": "Vertretung",
"cancelled": "Abgesagt",
"has_homework": "Hat Hausaufgaben",
"no_lessons_this_week": "Keine Stunden in dieser Woche oder Zeitüberschreitung",
"monday": "Montag",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"found_current_week": "Aktuelle Woche gefunden",
"open_homework": "Zu den Hausaufgaben gehen",
"all_day": "Ganztägig",
"special_day": "Besonderer Tag",
"unknown_subject": "Unbekanntes Fach",
"lesson_topic": "Stundenthema",
"homework_completed": "Hausaufgabe erledigt",
"homework_mark_completed": "Als erledigt markieren",
"homework_mark_uncompleted": "Erledigt - Klicken zum Rückgängigmachen",
"custom_homework": "Eigene Hausaufgaben",
"custom_test": "Eigene Prüfung",
"add_homework_test": "Hausaufgaben oder Prüfung hinzufügen",
"close": "Schließen",
"add": "Hinzufügen",
"homework_details_loading": "Hausaufgabendetails werden geladen...",
"homework_details_error": "Fehler beim Laden der Hausaufgabendetails.",
"test_details_loading": "Details werden geladen...",
"test_details_error": "Prüfungsdetails konnten nicht geladen werden.",
"test_details_error_general": "Fehler beim Laden der Prüfungsdetails.",
"custom_homework_title": "Eigene Hausaufgaben:",
"custom_tests_title": "Eigene Prüfungen:",
"delete_homework_confirm": "Möchten Sie diese Hausaufgabe wirklich löschen?",
"delete_test_confirm": "Möchten Sie diese Prüfung wirklich löschen?",
"task_label": "Aufgabe:",
"deadline_label": "Frist:",
"name_label": "Name:",
"type_label": "Typ:",
"announce_date_label": "Ankündigungsdatum:",
"no_name": "Kein Name",
"no_type": "Kein Typ angegeben",
"no_date": "Kein Datum"
},
"homework": {
"title": "Hausaufgaben",
"due_date": "Fälligkeitsdatum",
"subject": "Fach",
"description": "Beschreibung",
"filter_title": "Filter",
"all_subjects": "Alle Fächer",
"all_teachers": "Alle Lehrer",
"all_deadlines": "Alle Fristen",
"tomorrow_deadline": "Frist morgen",
"this_week": "Diese Woche",
"next_week": "Nächste Woche",
"no_homework": "Keine anzeigbaren Hausaufgaben.",
"no_filtered_homework": "Keine Hausaufgaben, die den Filterkriterien entsprechen.",
"teacher": "Lehrer",
"no_matching_homework": "Keine Hausaufgaben, die den Filterkriterien entsprechen.",
"items": "Element",
"status": "Status",
"total_homework": "Alle Aufgaben",
"urgent_homework": "Dringende Aufgaben",
"completed_homework": "Erledigte Aufgaben",
"pending_homework": "Ausstehende Aufgaben",
"completed": "Abgeschlossen",
"urgent": "Dringend",
"pending": "Ausstehend"
},
"absences": {
"title": "Fehlzeiten",
"date": "Datum",
"lesson": "Stunde",
"type": "Typ",
"justified": "Entschuldigt",
"unjustified": "Unentschuldigt",
"filter_title": "Filter",
"all_subjects": "Alle Fächer",
"all_types": "Alle",
"pending": "Wartet auf Entschuldigung",
"subject": "Fach",
"justification": "Entschuldigung",
"hours": "Stunden",
"page_transform_error": "Fehler bei der Seitentransformation",
"time_period": "Zeitraum",
"all_periods": "Alle Zeiträume",
"current_month": "Aktueller Monat",
"last_month": "Letzter Monat",
"current_semester": "Aktuelles Semester",
"last_30_days": "Letzte 30 Tage",
"total_absences": "Alle Fehlzeiten",
"topic": "Thema",
"status": "Status"
},
"profile": {
"title": "Profil",
"name": "Name",
"class": "Klasse",
"school": "Schule",
"student_id": "Schüler-ID",
"settings_title": "Profileinstellungen",
"tab_settings": "Einstellungen",
"tab_password": "Passwort ändern",
"tab_security": "Sicherheitseinstellungen",
"tab_contacts": "Kontakte",
"two_factor_description": "Um die Zwei-Faktor-Authentifizierung zu verwenden, installieren Sie eine zeitbasierte Einmalpasswort-App (TOTP):",
"android": "Android",
"iphone": "iPhone",
"enable_2fa": "Zwei-Faktor-Authentifizierung aktivieren",
"security_key": "Sicherheitsschlüssel:",
"verification_code_label": "Bestätigungscode",
"verification_code_help": "Geben Sie den 6-stelligen Code aus der Authentifizierungs-App ein.",
"verification_code_placeholder": "123456",
"verify_and_activate": "Überprüfen und aktivieren",
"backup_codes_description": "Sie können die folgenden Sicherheitscodes zum Anmelden verwenden, wenn Sie keinen Zugriff auf Ihre Authentifizierungs-App haben. Jeder Code kann nur einmal verwendet werden.",
"email_label": "E-Mail-Adresse",
"email_help": "Die E-Mail-Adresse ist für die Passwort-Erinnerung erforderlich.",
"phone_label": "Telefonnummer",
"phone_help": "Die Angabe einer Telefonnummer ist optional.",
"phone_placeholder": "+49 xxx xxxxxx",
"current_password": "Aktuelles Passwort",
"new_password": "Neues Passwort",
"new_password_help": "Das Passwort muss mindestens 8 Zeichen lang sein.",
"confirm_password": "Neues Passwort bestätigen",
"change_password": "Passwort ändern",
"show_tips": "Tipps anzeigen",
"show_tips_help": "Tipps ein-/ausblenden.",
"email_required": "Die E-Mail-Adresse ist erforderlich!",
"email_invalid": "Bitte geben Sie eine gültige E-Mail-Adresse ein!",
"phone_invalid": "Bitte geben Sie eine gültige Telefonnummer ein!",
"contacts_saved": "Kontakte erfolgreich gespeichert!",
"contacts_save_error": "Fehler beim Speichern. Bitte versuchen Sie es später erneut.",
"settings_saved": "Einstellungen erfolgreich gespeichert! Bitte melden Sie sich erneut an, um die Änderungen zu übernehmen.",
"settings_save_error": "Fehler beim Speichern. Bitte versuchen Sie es später erneut.",
"password_fields_required": "Bitte füllen Sie alle Felder aus!",
"passwords_not_match": "Die neuen Passwörter stimmen nicht überein!",
"password_too_short": "Das neue Passwort muss mindestens 8 Zeichen lang sein!",
"password_changed": "Passwort erfolgreich geändert!",
"password_change_error": "Fehler beim Ändern des Passworts. Bitte versuchen Sie es später erneut."
},
"login": {
"title": "Anmelden",
"username": "Benutzername",
"password": "Passwort",
"login_button": "Anmelden",
"forgot_password": "Passwort vergessen",
"two_factor_title": "Zwei-Faktor-Authentifizierung",
"verification_code": "Bestätigungscode",
"username_placeholder": "Benutzername",
"password_placeholder": "Passwort",
"username_required": "Bitte geben Sie Ihren Benutzernamen ein.",
"password_required": "Bitte geben Sie Ihr Passwort ein.",
"help_login": "Anmeldeprobleme?",
"help_link": "Hilfe",
"system_message": "Systemmeldung",
"privacy_policy": "Datenschutzerklärung",
"kreta_id": "KRÉTA-ID",
"system_notification": "Systembenachrichtigung"
},
"forgot_password": {
"title": "Passwort vergessen",
"om_id": "Ihre OM-ID",
"email": "E-Mail-Adresse",
"om_id_placeholder": "Geben Sie Ihre OM-ID ein",
"email_placeholder": "Geben Sie Ihre E-Mail-Adresse ein",
"om_id_required": "Bitte geben Sie Ihre OM-ID ein.",
"email_required": "Bitte geben Sie Ihre E-Mail-Adresse ein."
},
"two_factor": {
"title": "Zwei-Faktor-Authentifizierung",
"code_placeholder": "Einmalpasswort",
"code_required": "Bitte geben Sie das Einmalpasswort ein.",
"verify_button": "Code überprüfen",
"verifying": "Überprüfung...",
"trust_device": "Diesem Gerät vertrauen"
},
"logout": {
"title": "Abmelden",
"message": "Möchten Sie sich wirklich abmelden?",
"confirm": "Ja",
"cancel": "Abbrechen",
"success": "Erfolgreich abgemeldet!",
"continue": "Weiter"
},
"setup": {
"welcome": "Richten Sie die Erweiterung in wenigen einfachen Schritten ein",
"steps": {
"theme": "Design",
"language": "Sprache",
"finish": "Fertig"
},
"theme": {
"title": "Design wählen",
"description": "Wählen Sie das für Sie am besten geeignete Erscheinungsbild"
},
"language": {
"title": "Sprache wählen",
"description": "Wählen Sie die Sprache, die Sie verwenden möchten"
},
"finish": {
"title": "Alles erledigt!",
"description": "Die Einstellungen wurden erfolgreich gespeichert. Viel Erfolg beim Lernen!",
"about": "Über uns",
"about_desc": "Erfahren Sie mehr über das Projekt",
"support": "Unterstützung",
"support_desc": "Unterstützen Sie die Entwicklung",
"github": "GitHub",
"github_desc": "Sehen Sie sich den Quellcode an",
"discord": "Discord",
"discord_desc": "Treten Sie der Community bei",
"start": "Start"
}
},
"common": {
"save": "Speichern",
"cancel": "Abbrechen",
"close": "Schließen",
"loading": "Laden...",
"error": "Fehler",
"success": "Erfolgreich",
"warning": "Warnung",
"info": "Information",
"yes": "Ja",
"no": "Nein",
"continue": "Weiter",
"back": "Zurück",
"next": "Weiter",
"previous": "Zurück",
"all": "Alle",
"none": "Keine",
"filter": "Filter",
"search": "Suchen",
"select": "Wählen",
"required": "Erforderlich",
"optional": "Optional",
"api_error": "API-Fehler",
"api_load_error": "API-Ladefehler",
"monday": "Montag",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"saturday": "Samstag",
"sunday": "Sonntag",
"today": "Heute",
"tomorrow": "Morgen"
},
"months": {
"january": "Januar",
"february": "Februar",
"march": "März",
"april": "April",
"may": "Mai",
"june": "Juni",
"july": "Juli",
"august": "August",
"september": "September",
"october": "Oktober",
"november": "November",
"december": "Dezember"
},
"roleselect": {
"student_book": "Notenbuch",
"student_description": "Noten, Fehlzeiten, Stundenplan und andere Informationen anzeigen.",
"dkt_title": "Digitaler Kollaborationsraum (DKT)",
"dkt_description": "Klassenzimmerkommunikation und Aufgaben.",
"logout_title": "Abmelden",
"logout_description": "Vom System abmelden",
"role_change_error": "Fehler beim Wechseln der Rolle."
},
"maintenance": {
"title": "Wartung",
"message1": "Das KRÉTA-System wird derzeit aktualisiert und wird bald wieder verfügbar sein.",
"message2": "Vielen Dank für Ihre Geduld und Ihr Verständnis!",
"team": "KRÉTA-Team"
},
"about": {
"title": "Über",
"description": "Firka ist ein Open-Source-Projekt, das eine benutzerdefinierte Benutzeroberfläche für das KRÉTA-System erstellt.",
"support_title": "Unterstützung",
"support_description": "Wenn Ihnen unsere Arbeit gefällt und Sie die Entwicklung unterstützen möchten, können Sie dies folgendermaßen tun:",
"version": "v1.3.0"
},
"app": {
"title": "Firka - KRÉTA",
"settings_title": "Firxa - Einstellungen"
},
"forgotpassword": {
"title": "Passwort vergessen",
"om_id_label": "OM-ID",
"om_id_placeholder": "Geben Sie Ihre OM-ID ein",
"om_id_required": "Die OM-ID ist erforderlich",
"email_label": "E-Mail-Adresse",
"email_placeholder": "Geben Sie Ihre E-Mail-Adresse ein",
"email_required": "Die E-Mail-Adresse ist erforderlich",
"back_to_login": "Zurück zur Anmeldung",
"reset_button": "Passwort zurücksetzen",
"error_message": "Fehler beim Zurücksetzen des Passworts",
"success_message": "Link zum Zurücksetzen des Passworts an Ihre E-Mail-Adresse gesendet",
"invalid_data": "Ungültige Daten",
"invalid_email": "Ungültiges E-Mail-Format",
"recaptcha_required": "Bitte füllen Sie das reCAPTCHA aus"
},
"modal": {
"add_item_title": "Neues Element hinzufügen",
"type_label": "Typ:",
"homework_option": "Hausaufgaben",
"test_option": "Prüfung",
"description_label": "Beschreibung:",
"cancel": "Abbrechen",
"save": "Speichern"
},
"search": {
"choose_school": "Schule wählen",
"privacy_policy": "Datenschutzrichtlinie",
"title": "Schule wählen",
"select_institution": "Bitte wählen Sie eine Einrichtung aus, um fortzufahren!"
},
"icons": {
"cancel": "cancel",
"pending": "pending"
},
"messages": {
"title": "Nachrichten",
"back": "Zurück",
"surveys": "Umfragen",
"loading": "Nachrichten werden geladen...",
"error": {
"title": "Fehler aufgetreten",
"description": "Nachrichten konnten nicht geladen werden.",
"retry": "Erneut versuchen"
},
"empty": {
"title": "Keine Nachrichten",
"description": "Derzeit sind keine eingegangenen Nachrichten vorhanden."
},
"sender": "Absender",
"subject": "Betreff",
"date": "Datum",
"unread": "Ungelesen",
"read": "Gelesen",
"message_detail": {
"title": "Nachrichtendetails",
"loading": "Nachricht wird geladen...",
"error": "Fehler beim Laden der Nachricht.",
"from": "Von",
"to": "An",
"subject": "Betreff",
"date": "Datum",
"content": "Inhalt",
"attachments": "Anhänge",
"no_attachments": "Keine Anhänge",
"reply": "Antworten",
"forward": "Weiterleiten",
"delete": "Löschen",
"mark_read": "Als gelesen markieren",
"mark_unread": "Als ungelesen markieren",
"back_to_messages": "Zurück zu den Nachrichten"
}
}
}

View File

@@ -9,7 +9,7 @@
"theme": "Theme",
"language": "Language",
"tabs": {
"home": "Home",
"appearance": "Appearance",
"settings": "Settings",
"about": "About"
},
@@ -73,17 +73,20 @@
"card_color": "Card color",
"text_color": "Text color",
"preview": "Preview",
"share": "Share theme",
"share": "Share",
"share_description": "Copy the code and share it with others:",
"import": "Import theme",
"import": "Import",
"import_description": "Paste the theme code:",
"import_error_empty": "Please paste the theme code!",
"import_error_invalid": "Invalid theme code!",
"delete_confirm": "Are you sure you want to delete this theme?"
"delete_confirm": "Are you sure you want to delete this theme?",
"delete": "Delete",
"manage": "Manage"
},
"languages": {
"hu": "Magyar",
"en": "English"
"en": "English",
"de": "Deutsch"
},
"about": {
"title": "About",
@@ -94,6 +97,13 @@
"title": "Support",
"description": "If you like our work and would like to support the development, you can do so in the following way:",
"kofi": "Ko-Fi"
},
"error_reporting": {
"title": "Error Reporting",
"enable": "Enable error reporting",
"enable_desc": "Send automatic error reports to developers to help fix the extension",
"report_issue": "Report bug or idea",
"report_issue_desc": "Open a GitHub issue"
}
},
"navigation": {

View File

@@ -9,7 +9,7 @@
"theme": "Téma",
"language": "Nyelv",
"tabs": {
"home": "Főoldal",
"appearance": "Megjelenés",
"settings": "Beállítások",
"about": "Névjegy"
},
@@ -63,7 +63,7 @@
"custom_themes": {
"title": "Egyéni témák",
"no_themes": "Még nincsenek egyéni témák",
"create": "Új téma létrehozása",
"create": "Új téma",
"edit": "Téma szerkesztése",
"name": "Téma neve",
"mode": "Mód",
@@ -75,17 +75,20 @@
"card_color": "Kártya szín",
"text_color": "Szöveg szín",
"preview": "Előnézet",
"share": "Téma megosztása",
"share": "Megosztás",
"share_description": "Másold ki a kódot és oszd meg másokkal:",
"import": "Téma importálása",
"import": "Importálás",
"import_description": "Illeszd be a téma kódot:",
"import_error_empty": "Kérlek illeszd be a téma kódot!",
"import_error_invalid": "Érvénytelen téma kód!",
"delete_confirm": "Biztosan törölni szeretnéd ezt a témát?"
"delete_confirm": "Biztosan törölni szeretnéd ezt a témát?",
"delete": "Törlés",
"manage": "Kezelés"
},
"languages": {
"hu": "Magyar",
"en": "English"
"en": "English",
"de": "Deutsch"
},
"about": {
"title": "Névjegy",
@@ -96,6 +99,13 @@
"title": "Támogatás",
"description": "Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:",
"kofi": "Ko-Fi"
},
"error_reporting": {
"title": "Hibajelentés",
"enable": "Hibajelentés engedélyezése",
"enable_desc": "Automatikus hibajelentés küldése a fejlesztőknek a bővítmény javításához",
"report_issue": "Hiba vagy ötlet jelentése",
"report_issue_desc": "Nyiss egy GitHub issue-t"
}
},
"navigation": {

View File

@@ -40,7 +40,9 @@
"grades/chart.js",
"i18n/*.json",
"tools/storageManager.js",
"tools/storageTest.js"
"tools/storageTest.js",
"tools/sentry.js",
"tools/sentry-browser.min.js"
],
"matches": [
"<all_urls>"
@@ -65,6 +67,8 @@
"https://eugyintezes.e-kreta.hu/*"
],
"js": [
"tools/sentry-browser.min.js",
"tools/sentry.js",
"global/language.js",
"global/theme.js",
"tools/loadingScreen.js",

View File

@@ -32,6 +32,7 @@
{
"resources": [
"settings/*",
"setup/*",
"global/language.js",
"images/*",
"fonts/*.woff2",
@@ -39,7 +40,9 @@
"grades/chart.js",
"i18n/*.json",
"tools/storageManager.js",
"tools/storageTest.js"
"tools/storageTest.js",
"tools/sentry.js",
"tools/sentry-browser.min.js"
],
"matches": [
"<all_urls>"
@@ -64,6 +67,8 @@
"https://eugyintezes.e-kreta.hu/*"
],
"js": [
"tools/sentry-browser.min.js",
"tools/sentry.js",
"global/language.js",
"global/theme.js",
"tools/loadingScreen.js",

View File

@@ -124,6 +124,89 @@ h2 {
font-size:16px;
color:var(--text-primary);
}
.setting-header-left {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.setting-header.theme-header {
justify-content: space-between;
}
.theme-manage-dropdown {
position: relative;
}
.theme-manage-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
border-radius: 8px;
background: var(--accent-15);
color: var(--accent-accent);
cursor: pointer;
transition: all 0.2s ease;
}
.theme-manage-btn:hover {
background: var(--accent-accent);
color: var(--button-secondaryFill);
}
.theme-manage-menu {
position: absolute;
top: calc(100% + 4px);
right: 0;
background: var(--card-card);
border: 1px solid var(--border-border);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
min-width: 200px;
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all 0.2s ease;
z-index: 100;
overflow: hidden;
}
.theme-manage-menu.active {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.theme-manage-item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 12px 16px;
border: none;
background: transparent;
color: var(--text-primary);
font-family: "Montserrat", serif;
font-size: 14px;
font-weight: 500;
text-align: left;
cursor: pointer;
transition: background 0.2s ease;
}
.theme-manage-item:hover {
background: var(--accent-15);
}
.theme-manage-item .material-icons-round {
font-size: 20px;
color: var(--accent-accent);
}
.theme-grid,.language-grid {
display:grid;
grid-template-columns:repeat(2,1fr);
@@ -139,10 +222,158 @@ h2 {
align-items:center;
gap:8px;
transition:transform 0.2s ease;
position: relative;
}
.theme-option:hover,.language-option:hover {
transform:translateY(-2px);
}
.theme-option.disabled {
opacity:0.5;
cursor:not-allowed;
position:relative;
}
.theme-option.disabled::after {
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background-color:rgba(0,0,0,0.1);
border-radius:8px;
}
.language-option {
background:var(--button-secondaryFill);
border:1px solid var(--border-border);
border-radius:8px;
padding:12px;
transition:all 0.2s ease;
}
.language-option:hover {
border-color:var(--accent-accent);
}
.language-option.active {
background:var(--accent-accent);
border-color:var(--accent-accent);
color:white;
}
.language-name {
color:var(--text-primary);
font-size:12px;
font-weight:500;
font-family: "Montserrat", serif;
}
.custom-theme-option {
position: relative;
}
.custom-theme-option .theme-preview {
position: relative;
overflow: visible;
}
.custom-theme-settings-btn {
position: absolute !important;
top: 8px !important;
right: 8px !important;
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: none;
border-radius: 6px;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
color: white;
cursor: pointer;
transition: all 0.2s ease;
z-index: 10;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.custom-theme-option:hover .custom-theme-settings-btn {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
.custom-theme-settings-btn:hover {
background: var(--accent-accent);
transform: scale(1.1);
}
.custom-theme-settings-btn .material-icons-round {
font-size: 18px;
}.custom-theme-dropdown {
position: fixed;
background: var(--card-card);
border: 1px solid var(--border-border);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
min-width: 160px;
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all 0.2s ease;
overflow: hidden;
z-index: 10000;
pointer-events: none;
}
.custom-theme-dropdown.active {
opacity: 1;
visibility: visible;
transform: translateY(0);
pointer-events: auto;
}
.custom-theme-dropdown-item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 10px 12px;
border: none;
background: transparent;
color: var(--text-primary);
font-family: "Montserrat", serif;
font-size: 13px;
font-weight: 500;
text-align: left;
cursor: pointer;
transition: background 0.2s ease;
}
.custom-theme-dropdown-item:hover {
background: var(--accent-15);
}
.custom-theme-dropdown-item.delete {
color: #ff5050;
}
.custom-theme-dropdown-item.delete:hover {
background: rgba(255, 80, 80, 0.1);
}
.custom-theme-dropdown-item .material-icons-round {
font-size: 18px;
color: var(--accent-accent);
}
.custom-theme-dropdown-item.delete .material-icons-round {
color: #ff5050;
}
.theme-option.active .theme-preview {
outline:2px solid var(--accent-accent);
outline-offset:2px;
@@ -157,42 +388,24 @@ h2 {
border-radius:8px;
overflow:hidden;
position:relative;
display: flex;
flex-direction: column;
}
.theme-option.disabled {
opacity:0.5;
cursor:not-allowed;
position:relative;
}
.theme-option.disabled::after {
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background-color:rgba(0,0,0,0.1);
border-radius:8px;
}
.language-option {
background:var(--button-secondaryFill);
border:1px solid var(--border-border);
border-radius:8px;
padding:12px;
transition:all 0.2s ease;
}
.language-option:hover {
border-color:var(--accent-accent);
}
.language-option.active {
background:var(--accent-accent);
border-color:var(--accent-accent);
color:white;
}
.language-name {
color:var(--text-primary);
font-size:12px;
font-weight:500;
font-family: "Montserrat", serif;
.theme-name {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 8px;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
color: white;
font-size: 11px;
font-weight: 600;
text-align: center;
z-index: 5;
border-radius: 8px;
}
.theme-preview.light-green {
@@ -217,19 +430,22 @@ h2 {
.preview-header {
height:30%;
width:100%;
flex-shrink: 0;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.preview-content {
padding:8px;
flex: 1;
display: flex;
align-items: center;
}
.preview-card {
width: 100%;
height:30px;
border-radius:4px;
}
.theme-name {
color:var(--text-primary);
font-size:12px;
font-weight:500;
}
.about-content,.support-content {
color:var(--text-secondary);
font-size:14px;
@@ -240,29 +456,48 @@ h2 {
}
.about-links {
display: flex;
flex-direction: column;
flex-direction: row;
gap: 8px;
margin-top: 8px;
}
.about-link {
display:inline-flex;
align-items:center;
gap:6px;
color:var(--accent-accent);
text-decoration:none;
font-weight:500;
transition:color 0.2s;
padding: 4px 0;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 10px 8px;
background: var(--accent-15);
border-radius: 10px;
color: var(--text-primary);
text-decoration: none;
font-weight: 500;
font-size: 12px;
transition: all 0.2s ease;
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
}
.about-link:hover {
color:var(--accent-secondary);
background: var(--accent-accent);
color: var(--button-secondaryFill);
transform: translateY(-1px);
}
.about-link .material-icons-round {
color: var(--text-primary);
font-size: 20px;
}
.about-link:hover .material-icons-round {
color: var(--button-secondaryFill);
font-size: 20px;
}
.support-buttons {
display:flex;
gap:8px;
margin-top:12px;
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
}
.support-button {
flex:1;
@@ -297,146 +532,6 @@ h2 {
vertical-align:middle;
}
.custom-themes-section {
margin-top: 16px;
}
.custom-themes-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
font-weight: 600;
font-size: 14px;
color: var(--text-primary);
}
.custom-themes-buttons {
display: flex;
gap: 8px;
align-items: center;
}
.theme-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
border-radius: 8px;
background: var(--accent-15);
color: var(--accent-accent);
cursor: pointer;
transition: all 0.2s ease;
}
.theme-btn:hover {
background: var(--accent-accent);
color: var(--button-secondaryFill);
}
.custom-themes-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
min-height: 50px;
}
.custom-theme-option {
position: relative;
display: flex;
flex-direction: column;
background: var(--button-secondaryFill);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border-border, var(--text-teritary));
transition: all 0.2s ease;
}
.custom-theme-option:hover {
border-color: var(--accent-accent);
transform: translateY(-2px);
}
.custom-theme-option.active {
border-color: var(--accent-accent);
box-shadow: 0 0 0 2px var(--accent-15);
}
.custom-theme-option .theme-preview {
height: 70px;
border-radius: 0;
}
.custom-theme-option .theme-info {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
background: var(--button-secondaryFill);
border-top: 1px solid var(--border-border, var(--text-teritary));
gap: 8px;
}
.custom-theme-option .theme-name {
font-size: 12px;
font-weight: 600;
color: var(--text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.custom-theme-option .theme-actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
.theme-action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: none;
border-radius: 6px;
background: var(--accent-15);
color: var(--accent-accent);
cursor: pointer;
transition: all 0.2s ease;
}
.theme-action-btn:hover {
background: var(--accent-accent);
color: var(--button-secondaryFill);
}
.theme-action-btn.delete-theme {
background: rgba(255, 80, 80, 0.15);
color: #ff5050;
}
.theme-action-btn.delete-theme:hover {
background: #ff5050;
color: white;
}
.theme-action-btn .material-icons-round {
font-size: 16px;
}
.no-custom-themes {
grid-column: 1 / -1;
text-align: center;
color: var(--text-secondary);
font-size: 12px;
padding: 20px 0;
}
.modal-overlay {
position: fixed;
top: 0;
@@ -464,14 +559,13 @@ h2 {
.modal-content {
background: var(--card-card);
border-radius: 20px;
border-radius: 16px;
width: 100%;
max-width: 420px;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow), 0 12px 32px rgba(0, 0, 0, 0.2);
animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid var(--border-border, var(--text-teritary));
}
@keyframes slideUp {
@@ -489,13 +583,12 @@ h2 {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 1px solid var(--border-border, var(--text-teritary));
padding: 16px 16px 0px 16px;
}
.modal-header h3 {
font-size: 18px;
font-weight: 700;
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
@@ -504,20 +597,19 @@ h2 {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
width: 32px;
height: 32px;
border: none;
border-radius: 10px;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-secondary);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transition: all 0.2s ease;
}
.modal-close:hover {
background: var(--error-15);
color: var(--error-accent);
transform: rotate(90deg);
background: var(--accent-15);
color: var(--accent-accent);
}
.modal-close .material-icons-round {
@@ -525,14 +617,13 @@ h2 {
}
.modal-body {
padding: 20px;
padding: 16px;
}
.modal-footer {
display: flex;
gap: 8px;
padding: 16px;
border-top: 1px solid var(--border-border, var(--text-teritary));
padding: 0px 16px 16px 16px;
}
.modal-footer button {
@@ -566,28 +657,29 @@ h2 {
}
.theme-form .form-group {
margin-bottom: 16px;
margin-bottom: 12px;
}
.theme-form label {
display: block;
font-size: 13px;
font-size: 12px;
font-weight: 500;
color: var(--text-primary);
margin-bottom: 8px;
color: var(--text-secondary);
margin-bottom: 6px;
}
.theme-form input[type="text"] {
width: 150px;
width: 100%;
padding: 10px 12px;
border: 1px solid var(--border-border, var(--text-teritary));
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-size: 14px;
font-size: 13px;
font-family: "Montserrat", serif;
outline: none;
transition: border-color 0.2s ease;
border: none !important
}
.theme-form input[type="text"]:focus {
@@ -606,42 +698,42 @@ h2 {
justify-content: center;
gap: 6px;
padding: 10px;
border: 1px solid var(--border-border, var(--text-teritary));
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-secondary);
background: var(--accent-15);
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s ease;
font-family: "Montserrat", serif;
font-size: 13px;
font-size: 12px;
font-weight: 500;
border:none !important
}
.mode-option:hover {
border-color: var(--accent-accent);
background: var(--accent-15);
}
.mode-option.active {
background: var(--accent-15);
border-color: var(--accent-accent);
color: var(--accent-accent);
background: var(--accent-accent);
color:var(--button-secondaryFill)
}
.color-section {
margin-top: 20px;
margin-top: 16px;
}
.color-section h4 {
font-size: 14px;
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
margin: 0 0 12px 0;
margin: 0 0 10px 0;
}
.color-group {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
margin-bottom: 10px;
gap: 12px;
}
@@ -651,6 +743,7 @@ h2 {
margin: 0;
white-space: nowrap;
flex-shrink: 0;
font-weight: 500;
}
.color-input-wrapper {
@@ -668,7 +761,7 @@ h2 {
padding: 0;
background: transparent;
flex-shrink: 0;
border: 1px solid var(--border-border, var(--text-teritary));
border: 1px solid var(--text-teritary);
}
.color-input-wrapper input[type="color"]::-webkit-color-swatch-wrapper {
@@ -683,7 +776,6 @@ h2 {
.color-hex {
width: 72px;
padding: 6px 8px;
border: 1px solid var(--border-border, var(--text-teritary));
border-radius: 6px;
background: var(--button-secondaryFill);
color: var(--text-primary);
@@ -691,6 +783,13 @@ h2 {
font-family: monospace;
text-transform: uppercase;
flex-shrink: 0;
outline: none;
transition: border-color 0.2s ease;
max-width: 200px;
}
.color-hex:focus {
border-color: var(--accent-accent);
}
.theme-preview-section {
@@ -741,14 +840,15 @@ h2 {
width: 100%;
min-height: 80px;
padding: 12px;
border: 1px solid var(--border-border, var(--text-teritary));
border: 1px solid var(--text-teritary);
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-family: monospace;
font-size: 12px;
font-size: 11px;
resize: none;
outline: none;
transition: border-color 0.2s ease;
}
.share-code-wrapper textarea:focus,
@@ -790,9 +890,10 @@ h2 {
min-height: 16px;
}
.import-modal .modal-body p {
.import-modal .modal-body p,
.share-modal .modal-body p {
color: var(--text-secondary);
font-size: 13px;
font-size: 12px;
margin-bottom: 8px;
}
@@ -944,3 +1045,108 @@ h2 {
.setting-select:focus {
border-color: var(--accent-accent);
}
.error-reporting-card {
background: var(--card-card);
border-radius: 16px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
}
.error-reporting-card h2 {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
}
.error-reporting-content {
display: flex;
flex-direction: column;
gap: 12px;
}
.report-issue-button-wrapper {
margin-top: 4px;
}
.report-issue-button {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: var(--accent-15);
border-radius: 10px;
text-decoration: none;
transition: all 0.2s ease;
cursor: pointer;
color: var(--text-primary);
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
}
.report-issue-button:hover {
background: var(--accent-accent);
}
.report-issue-button:hover .material-icons-round {
color: var(--button-secondaryFill);
}
.report-issue-button:hover .report-issue-text {
color: var(--button-secondaryFill);
}
.report-issue-button .material-icons-round {
color: var(--accent-accent);
font-size: 24px;
transition: color 0.2s ease;
}
.report-issue-text {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1;
color: var(--text-primary);
transition: color 0.2s ease;
}
.report-issue-title {
font-size: 13px;
font-weight: 600;
}
.report-issue-desc {
font-size: 11px;
color: var(--text-secondary);
transition: color 0.2s ease;
}
.report-issue-button:hover .report-issue-desc {
color: var(--button-secondaryFill);
opacity: 0.8;
}
.notification {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--accent-accent);
color: #000;
padding: 12px 20px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
font-family: "Montserrat", serif;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
z-index: 10001;
}
.notification.show {
opacity: 1;
transform: translateY(0);
}

View File

@@ -23,9 +23,9 @@
</header>
<div class="tab-navigation">
<button class="tab-button active" data-tab="home">
<span class="material-icons-round">home</span>
<span data-i18n="settings.tabs.home">Főoldal</span>
<button class="tab-button active" data-tab="appearance">
<span class="material-icons-round">palette</span>
<span data-i18n="settings.tabs.appearance">Megjelenés</span>
</button>
<button class="tab-button" data-tab="settings">
<span class="material-icons-round">tune</span>
@@ -37,16 +37,32 @@
</button>
</div>
<div class="tab-content active" id="tab-home">
<div class="tab-content active" id="tab-appearance">
<div class="settings-card">
<h2 data-i18n="settings.appearance">Megjelenés</h2>
<div class="settings-group">
<div class="setting-section">
<div class="setting-header">
<span class="material-icons-round">palette</span>
<span data-i18n="settings.theme">Téma</span>
<div class="setting-header theme-header">
<div class="setting-header-left">
<span class="material-icons-round">palette</span>
<span data-i18n="settings.theme">Téma</span>
</div>
<div class="theme-manage-dropdown">
<button class="theme-manage-btn" id="themeManageBtn">
<span class="material-icons-round">settings</span>
</button>
<div class="theme-manage-menu" id="themeManageMenu">
<button class="theme-manage-item" id="addCustomTheme">
<span class="material-icons-round">add</span>
<span data-i18n="settings.custom_themes.create">Új téma létrehozása</span>
</button>
<button class="theme-manage-item" id="importCustomTheme">
<span class="material-icons-round">download</span>
<span data-i18n="settings.custom_themes.import">Importálás</span>
</button>
</div>
</div>
</div>
<div class="theme-grid">
<div class="theme-grid" id="allThemesGrid">
<button class="theme-option" data-theme="light-green">
<div class="theme-preview light-green">
<div class="preview-header"></div>
@@ -67,22 +83,6 @@
<span class="theme-name" data-i18n="settings.themes.dark_green">Sötét Zöld</span>
</button>
</div>
<div class="custom-themes-section">
<div class="custom-themes-header">
<span data-i18n="settings.custom_themes.title">Egyéni témák</span>
<div class="custom-themes-buttons">
<button class="theme-btn" id="addCustomTheme" title="Új téma">
<span class="material-icons-round">add</span>
</button>
<button class="theme-btn" id="importCustomTheme" title="Téma importálása">
<span class="material-icons-round">download</span>
</button>
</div>
</div>
<div class="theme-grid custom-themes-grid" id="customThemesGrid">
</div>
</div>
</div>
<div class="setting-section">
<div class="setting-header">
@@ -96,6 +96,9 @@
<button class="language-option" data-language="en">
<span class="language-name" data-i18n="settings.languages.en">English</span>
</button>
<button class="language-option" data-language="de">
<span class="language-name" data-i18n="settings.languages.de">Deutsch</span>
</button>
</div>
</div>
</div>
@@ -118,6 +121,30 @@
<p data-i18n="settings.page_settings.no_settings">Ehhez az oldalhoz nincsenek egyéni beállítások.</p>
</div>
</div>
</div>
<div class="error-reporting-card">
<h2 data-i18n="settings.error_reporting.title">Hibajelentés</h2>
<div class="error-reporting-content">
<div class="setting-item">
<div class="setting-item-info">
<div class="setting-item-label" data-i18n="settings.error_reporting.enable">Hibajelentés engedélyezése</div>
<div class="setting-item-description" data-i18n="settings.error_reporting.enable_desc">Automatikus hibajelentés küldése a fejlesztőknek a bővítmény javításához</div>
</div>
<label class="toggle-switch">
<input type="checkbox" id="errorReportingToggle" checked>
<span class="toggle-slider"></span>
</label>
</div>
<div class="report-issue-button-wrapper">
<a href="https://github.com/QwIT-Development/firka-extension/issues/new" target="_blank" class="report-issue-button">
<span class="material-icons-round">bug_report</span>
<div class="report-issue-text">
<span class="report-issue-title" data-i18n="settings.error_reporting.report_issue">Hiba vagy ötlet jelentése</span>
<span class="report-issue-desc" data-i18n="settings.error_reporting.report_issue_desc">Nyiss egy GitHub issue-t</span>
</div>
</a>
</div>
</div>
</div>
</div>
@@ -277,6 +304,9 @@
</div>
</div>
<script src="../tools/sentry-browser.min.js"></script>
<script src="../tools/sentry.js"></script>
<script src="../tools/helper.js"></script>
<script src="../tools/storageManager.js"></script>
<script src="../global/language.js"></script>
<script src="index.js"></script>

View File

@@ -11,7 +11,7 @@ document.addEventListener("DOMContentLoaded", async () => {
const tabButtons = document.querySelectorAll(".tab-button");
const tabContents = document.querySelectorAll(".tab-content");
const lastTab = localStorage.getItem("settingsLastTab") || "home";
const lastTab = localStorage.getItem("settingsLastTab") || "appearance";
switchTab(lastTab);
tabButtons.forEach(button => {
@@ -369,19 +369,12 @@ document.addEventListener("DOMContentLoaded", async () => {
}
function renderCustomThemes() {
const grid = document.getElementById("customThemesGrid");
const grid = document.getElementById("allThemesGrid");
if (!grid) return;
grid.querySelectorAll(".custom-theme-option").forEach(el => el.remove());
document.querySelectorAll(".custom-theme-dropdown").forEach(el => el.remove());
if (customThemes.length === 0) {
helper.clearElement(grid);
const noThemes = document.createElement('div');
noThemes.className = 'no-custom-themes';
noThemes.setAttribute('data-i18n', 'settings.custom_themes.no_themes');
noThemes.textContent = 'Még nincsenek egyéni témák';
grid.appendChild(noThemes);
if (window.LanguageManager) {
window.LanguageManager.loadTranslationsForPage();
}
return;
}
@@ -393,60 +386,89 @@ document.addEventListener("DOMContentLoaded", async () => {
<div class="preview-content">
<div class="preview-card" style="background: ${theme.colors.accent}20; border: 1px solid ${theme.colors.accent};"></div>
</div>
</div>
<div class="theme-info">
<span class="theme-name">${theme.name}</span>
<div class="theme-actions">
<span class="theme-action-btn edit-theme" data-id="${theme.id}" title="Szerkesztés">
<span class="material-icons-round">edit</span>
</span>
<span class="theme-action-btn share-theme" data-id="${theme.id}" title="Megosztás">
<span class="material-icons-round">share</span>
</span>
<span class="theme-action-btn delete-theme" data-id="${theme.id}" title="Törlés">
<span class="material-icons-round">delete</span>
</span>
<div class="custom-theme-settings-btn" role="button" tabindex="0" data-id="${theme.id}">
<span class="material-icons-round">settings</span>
</div>
</div>
</button>
`).join("");
helper.clearElement(grid);
grid.appendChild(template.content);
grid.appendChild(template.content);
const dropdownTemplate = document.createElement('template');
dropdownTemplate.innerHTML = customThemes.map(theme => `
<div class="custom-theme-dropdown" data-dropdown-id="${theme.id}">
<button class="custom-theme-dropdown-item" data-action="share" data-id="${theme.id}">
<span class="material-icons-round">share</span>
<span data-i18n="settings.custom_themes.share">Megosztás</span>
</button>
<button class="custom-theme-dropdown-item" data-action="edit" data-id="${theme.id}">
<span class="material-icons-round">edit</span>
<span data-i18n="settings.custom_themes.edit">Szerkesztés</span>
</button>
<button class="custom-theme-dropdown-item delete" data-action="delete" data-id="${theme.id}">
<span class="material-icons-round">delete</span>
<span data-i18n="settings.custom_themes.delete">Törlés</span>
</button>
</div>
`).join("");
document.body.appendChild(dropdownTemplate.content);
grid.querySelectorAll(".custom-theme-option").forEach(btn => {
btn.addEventListener("click", (e) => {
if (e.target.closest(".theme-action-btn")) return;
if (e.target.closest(".theme-hover-btn")) return;
const themeId = btn.dataset.theme;
applyTheme(themeId);
});
});
grid.querySelectorAll(".edit-theme").forEach(btn => {
grid.querySelectorAll(".custom-theme-settings-btn").forEach(btn => {
btn.addEventListener("click", (e) => {
e.stopPropagation();
const id = btn.dataset.id;
editTheme(id);
const dropdown = document.querySelector(`[data-dropdown-id="${id}"]`);
document.querySelectorAll(".custom-theme-dropdown").forEach(d => {
if (d !== dropdown) d.classList.remove("active");
});
if (dropdown) {
const isActive = dropdown.classList.contains("active");
if (!isActive) {
const btnRect = btn.getBoundingClientRect();
dropdown.style.top = `${btnRect.bottom + 4}px`;
dropdown.style.left = `${btnRect.right - 160}px`;
}
dropdown.classList.toggle("active");
}
});
});
grid.querySelectorAll(".share-theme").forEach(btn => {
document.querySelectorAll(".custom-theme-dropdown-item").forEach(btn => {
btn.addEventListener("click", (e) => {
e.stopPropagation();
const action = btn.dataset.action;
const id = btn.dataset.id;
shareTheme(id);
const dropdown = btn.closest(".custom-theme-dropdown");
dropdown?.classList.remove("active");
if (action === "share") shareTheme(id);
else if (action === "edit") editTheme(id);
else if (action === "delete") deleteTheme(id);
});
});
grid.querySelectorAll(".delete-theme").forEach(btn => {
btn.addEventListener("click", (e) => {
e.stopPropagation();
const id = btn.dataset.id;
deleteTheme(id);
});
document.addEventListener("click", (e) => {
if (!e.target.closest(".custom-theme-settings")) {
document.querySelectorAll(".custom-theme-dropdown").forEach(d => d.classList.remove("active"));
}
});
updateThemeButtons(getCurrentTheme());
if (window.LanguageManager) {
window.LanguageManager.loadTranslationsForPage();
}
}
function openThemeEditor(theme = null) {
@@ -576,8 +598,45 @@ document.addEventListener("DOMContentLoaded", async () => {
};
const code = btoa(JSON.stringify(shareData));
document.getElementById("shareCode").value = code;
document.getElementById("shareThemeModal").classList.add("active");
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(code).then(() => {
showNotification('Téma kód vágólapra másolva!');
}).catch(() => {
copyToClipboardFallback(code);
showNotification('Téma kód vágólapra másolva!');
});
} else {
copyToClipboardFallback(code);
showNotification('Téma kód vágólapra másolva!');
}
}
function copyToClipboardFallback(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
function showNotification(message) {
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.add('show');
}, 10);
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
notification.remove();
}, 300);
}, 3000);
}
function deleteTheme(id) {
@@ -689,19 +748,14 @@ document.addEventListener("DOMContentLoaded", async () => {
}
async function applyLanguage(language) {
localStorage.setItem("languagePreference", language);
updateLanguageButtons(language);
const tabs = await chrome.tabs.query({});
tabs.forEach((tab) => {
chrome.tabs
.sendMessage(tab.id, {
action: "changeLanguage",
language: language,
})
.catch(() => {});
});
try {
if (window.LanguageManager) {
await window.LanguageManager.changeLanguage(language);
}
updateLanguageButtons(language);
} catch (error) {
console.error("Error applying language:", error);
}
}
async function applyTheme(theme) {
@@ -736,7 +790,7 @@ document.addEventListener("DOMContentLoaded", async () => {
function applyCustomThemeColors(theme) {
const root = document.documentElement;
const isDark = theme.mode === "dark";
root.style.setProperty("--background", theme.colors.background);
root.style.setProperty("--card-card", theme.colors.card);
root.style.setProperty("--accent-accent", theme.colors.accent);
@@ -748,6 +802,15 @@ document.addEventListener("DOMContentLoaded", async () => {
root.style.setProperty("--accent-secondary", isDark ? lightenColor(theme.colors.accent, 20) : darkenColor(theme.colors.accent, 20));
root.style.setProperty("--shadow-blur", isDark ? "0" : "2px");
root.style.setProperty("--accent-shadow", isDark ? "#0000" : theme.colors.accent + "26");
root.style.setProperty("--warning-accent", "#FFA046");
root.style.setProperty("--warning-text", isDark ? "#f0b37a" : "#8F531B");
root.style.setProperty("--warning-15", "#ffa04626");
root.style.setProperty("--warning-card", isDark ? "#201203" : "#FAEBDC");
root.style.setProperty("--error-accent", "#FF54A1");
root.style.setProperty("--error-text", isDark ? "#f59ec5" : "#8F1B4F");
root.style.setProperty("--error-15", "#FF54A126");
root.style.setProperty("--error-card", isDark ? "#1e030f" : "#FADCE9");
root.style.setProperty("--icon-filter", hexToFilter(theme.colors.accent));
}
@@ -755,7 +818,7 @@ document.addEventListener("DOMContentLoaded", async () => {
const root = document.documentElement;
const properties = [
"--background",
"--card-card",
"--card-card",
"--accent-accent",
"--text-primary",
"--text-secondary",
@@ -765,9 +828,17 @@ document.addEventListener("DOMContentLoaded", async () => {
"--accent-secondary",
"--shadow-blur",
"--accent-shadow",
"--icon-filter"
"--icon-filter",
"--warning-accent",
"--warning-text",
"--warning-15",
"--warning-card",
"--error-accent",
"--error-text",
"--error-15",
"--error-card"
];
properties.forEach(prop => root.style.removeProperty(prop));
}
@@ -850,12 +921,31 @@ document.addEventListener("DOMContentLoaded", async () => {
});
});
document.getElementById("addCustomTheme")?.addEventListener("click", () => openThemeEditor());
const themeManageBtn = document.getElementById("themeManageBtn");
const themeManageMenu = document.getElementById("themeManageMenu");
themeManageBtn?.addEventListener("click", (e) => {
e.stopPropagation();
themeManageMenu.classList.toggle("active");
});
document.addEventListener("click", (e) => {
if (!e.target.closest(".theme-manage-dropdown")) {
themeManageMenu?.classList.remove("active");
}
});
document.getElementById("addCustomTheme")?.addEventListener("click", () => {
themeManageMenu?.classList.remove("active");
openThemeEditor();
});
document.getElementById("closeThemeEditor")?.addEventListener("click", closeThemeEditor);
document.getElementById("cancelThemeEditor")?.addEventListener("click", closeThemeEditor);
document.getElementById("saveTheme")?.addEventListener("click", saveThemeFromEditor);
document.getElementById("importCustomTheme")?.addEventListener("click", () => {
themeManageMenu?.classList.remove("active");
document.getElementById("importThemeModal").classList.add("active");
});
@@ -957,4 +1047,23 @@ document.addEventListener("DOMContentLoaded", async () => {
});
await initTabs();
await initErrorReporting();
});
async function initErrorReporting() {
const toggle = document.getElementById('errorReportingToggle');
if (!toggle) return;
const result = await storageManager.get('firka_errorReporting', true);
toggle.checked = result !== false;
toggle.addEventListener('change', async () => {
const enabled = toggle.checked;
await storageManager.set('firka_errorReporting', enabled);
const tabs = await chrome.tabs.query({});
tabs.forEach((tab) => {
chrome.tabs.sendMessage(tab.id, {
action: 'errorReportingChanged',
enabled: enabled
}).catch(() => {});
});
});
}

View File

@@ -152,6 +152,8 @@
</div>
</div>
<script src="../tools/sentry-browser.min.js"></script>
<script src="../tools/sentry.js"></script>
<script src="../tools/storageManager.js"></script>
<script src="../global/language.js"></script>
<script src="setup.js"></script>

View File

@@ -1,3 +1,24 @@
const SENTRY_DSN = 'https://c7d88b71f550a276f973885a44b6536d@o4510511576055808.ingest.de.sentry.io/4510511935193168';
async function initSentry() {
try {
const result = await chrome.storage.sync.get('firka_errorReporting');
const enabled = result.firka_errorReporting !== false;
if (enabled) {
self.addEventListener('error', (event) => {
console.error('[Background Error]', event.error || event);
});
self.addEventListener('unhandledrejection', (event) => {
console.error('[Background Unhandled Rejection]', event.reason);
});
}
} catch (error) {
console.error('[Sentry] Nem sikerült inicializálni:', error);
}
}
chrome.runtime.onInstalled.addListener(async (details) => {
if (details.reason === 'install') {
const setupCompleted = await chrome.storage.sync.get('firka_setupCompleted');
@@ -8,6 +29,8 @@ chrome.runtime.onInstalled.addListener(async (details) => {
});
}
}
await initSentry();
});
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {

3
tools/sentry-browser.min.js vendored Normal file

File diff suppressed because one or more lines are too long

127
tools/sentry.js Normal file
View File

@@ -0,0 +1,127 @@
(function() {
'use strict';
const SENTRY_DSN = 'https://c7d88b71f550a276f973885a44b6536d@o4510511576055808.ingest.de.sentry.io/4510511935193168';
let sentryInitialized = false;
async function isErrorReportingEnabled() {
try {
const result = await chrome.storage.sync.get('firka_errorReporting');
return result.firka_errorReporting !== false;
} catch (error) {
return true;
}
}
async function initSentry() {
if (sentryInitialized) {
return;
}
const enabled = await isErrorReportingEnabled();
if (!enabled) {
return;
}
setTimeout(() => {
configureSentry();
}, 100);
}
function configureSentry() {
try {
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
if (!SentrySDK) {
setTimeout(configureSentry, 500);
return;
}
if (!SentrySDK.init) {
return;
}
const manifest = chrome.runtime.getManifest();
SentrySDK.init({
dsn: SENTRY_DSN,
release: `firka-extension@${manifest.version}`,
environment: 'production',
integrations: [],
beforeSend(event, hint) {
if (event.request) {
delete event.request.cookies;
delete event.request.headers;
}
return event;
},
});
sentryInitialized = true;
} catch (error) {
}
}
window.addEventListener('error', function(event) {
if (sentryInitialized) {
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
if (SentrySDK && SentrySDK.captureException) {
SentrySDK.captureException(event.error || new Error(event.message));
} else {
console.warn('[Sentry] SDK not available for capturing');
}
} else {
console.warn('[Sentry] Not initialized yet, cannot capture error');
}
}, true);
window.addEventListener('unhandledrejection', function(event) {
if (sentryInitialized) {
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
if (SentrySDK && SentrySDK.captureException) {
SentrySDK.captureException(event.reason);
}
}
}, true);
if (typeof chrome !== 'undefined' && chrome.storage) {
chrome.storage.onChanged.addListener(function(changes, namespace) {
if (namespace === 'sync' && changes.firka_errorReporting) {
const newValue = changes.firka_errorReporting.newValue;
if (newValue === false && sentryInitialized) {
if (typeof Sentry !== 'undefined' && Sentry.close) {
Sentry.close();
sentryInitialized = false;
}
} else if (newValue !== false && !sentryInitialized) {
initSentry();
}
}
});
}
window.FirkaSentry = {
init: initSentry,
isEnabled: isErrorReportingEnabled,
captureException: function(error) {
if (sentryInitialized) {
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
if (SentrySDK && SentrySDK.captureException) {
SentrySDK.captureException(error);
}
}
},
captureMessage: function(message, level = 'info') {
if (sentryInitialized) {
const SentrySDK = window.Sentry || (typeof Sentry !== 'undefined' ? Sentry : null);
if (SentrySDK && SentrySDK.captureMessage) {
SentrySDK.captureMessage(message, level);
}
}
}
};
initSentry();
})();