15 Commits

Author SHA1 Message Date
Zan1456
eef39c28d2 removed unused 2025-06-13 14:49:40 +02:00
Zan1456
89266bc3c9 Fixed week select 2025-06-13 14:41:21 +02:00
Zan1456
5408a1e08a . 2025-06-13 14:02:54 +02:00
Zan1456
107e20f5c1 . 2025-06-13 13:26:21 +02:00
Zan1456
cb54d51b8c Added store logos 2025-06-10 22:58:14 +02:00
Zan1456
8eb7256f5b . 2025-06-10 22:54:27 +02:00
Zan
3510288181 Added firefox addonstore 2025-06-10 22:37:28 +02:00
Zan1456
8c9e1b215f version bump 2025-06-09 16:13:19 +02:00
Zan1456
e930706eb1 Fully working 2025-06-09 16:11:15 +02:00
Zan1456
5340c1dff0 Full rework 2025-06-09 16:10:15 +02:00
Zan1456
f3439a93d0 Merge branch 'main' of https://github.com/QwIT-Development/firka-extension 2025-06-09 13:46:42 +02:00
Zan1456
3e7b7089dd better scrolling 2025-06-09 13:33:44 +02:00
Anchietae
185f486a62 typo 2025-06-09 09:52:03 +02:00
Zan
048f249dc5 Update README.md 2025-06-08 23:29:44 +02:00
Zan1456
5d9ae6971b version dump 2025-06-08 23:24:06 +02:00
36 changed files with 3406 additions and 987 deletions

View File

@@ -19,6 +19,15 @@
</a>
</p>
<p align="center">
<a href="https://chromewebstore.google.com/detail/firxa/emafoaifbfppcccgfmpcoheonhjnpldj?hl=hu">
<img src="https://github.com/QwIT-Development/firka-extension/blob/main/images/chrome.png?raw=true" alt="Elérhető a Chrome Web Store-on" width="200">
</a>
<a href="https://addons.mozilla.org/hu/firefox/addon/firxa/">
<img src="https://github.com/QwIT-Development/firka-extension/blob/main/images/firefox.png?raw=true" alt="Elérhető a Firefox add-ons oldalon" width="200">
</a>
</p>
## 📱 Funkciók
- **Modern Dizájn**: Teljesen újratervezett, modern felhasználói felület
@@ -34,19 +43,7 @@
## 🚀 Telepítés
1. Töltsd le a legfrissebb verziót a [Releases](https://github.com/QwIT-Development/firka-extension/releases/) oldalról
### Chromium alapú böngészők esetén
2. Navigálj a `chrome://extensions` oldalra
3. Kapcsold be a "Fejlesztői mód"-ot a jobb felső sarokban
4. Keresd meg a letöltött zip fájlt
5. Húzd a letöltött zip fájlt a böngészőbe
### Firefox alapú böngészők esetén
2. Navigálj az `about:addons` oldalra
3. Kattints rá a fogaskerék ikonra (⚙️) a jobb felső sarokban
4. Ebben a menüben válaszd a(z) "Kiegészítő telepítése fájlból..."/"Install Add-on From File..."
5. Válaszd ki a `.zip` fájlt amit letöltöttél
### Kész!
6. A bővítmény automatikusan működésbe lép, amikor megnyitod az e-KRÉTA oldalt
1. Töltsd le a legfrissebb verziót a fenti gombok segítségével a böngésződnek megfelelően.
## ⚙️ Beállítások
@@ -67,6 +64,7 @@ A bővítmény jelenleg az alábbi e-KRÉTA oldalakat támogatja:
- Hiányzások
- Házi feladatok
- Jegyek
- Intézménykereső
## 👥 Csapat

View File

@@ -54,23 +54,23 @@ async function transformAbsencesPage() {
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>Szűrés</h2>
<h2>${LanguageManager.t('absences.filter_title')}</h2>
</div>
<div class="filter-content">
<div class="filter-group">
<label>
<span class="material-icons-round">date_range</span>
Dátum
${LanguageManager.t('absences.date')}
</label>
<input type="date" id="dateFilter" class="filter-input" disabled>
</div>
<div class="filter-group">
<label>
<span class="material-icons-round">school</span>
Tantárgy
${LanguageManager.t('absences.subject')}
</label>
<select id="subjectFilter" class="filter-input">
<option value="">Minden tantárgy</option>
<option value="">${LanguageManager.t('absences.all_subjects')}</option>
${[...new Set(absences.map(a => a.subject))].sort().map(subject =>
`<option value="${subject}">${subject}</option>`
).join('')}
@@ -79,13 +79,13 @@ async function transformAbsencesPage() {
<div class="filter-group">
<label>
<span class="material-icons-round">check_circle</span>
Igazolás
${LanguageManager.t('absences.justification')}
</label>
<select id="justificationFilter" class="filter-input">
<option value="">Mindegy</option>
<option value="justified">Igazolt</option>
<option value="unjustified">Igazolatlan</option>
<option value="pending">Igazolásra vár</option>
<option value="">${LanguageManager.t('absences.all_types')}</option>
<option value="justified">${LanguageManager.t('absences.justified')}</option>
<option value="unjustified">${LanguageManager.t('absences.unjustified')}</option>
<option value="pending">${LanguageManager.t('absences.pending')}</option>
</select>
</div>
</div>
@@ -97,7 +97,7 @@ async function transformAbsencesPage() {
<div class="absence-date">
<span class="material-icons-round">event</span>
${date}
<span class="absence-count">${dayAbsences.length} óra</span>
<span class="absence-count">${dayAbsences.length} ${LanguageManager.t('absences.hours')}</span>
</div>
<div class="absence-list">
${dayAbsences.map(absence => `
@@ -106,7 +106,7 @@ async function transformAbsencesPage() {
data-justified="${absence.justified}">
<div class="absence-time">
<span class="material-icons-round">schedule</span>
${absence.lesson}. óra
${absence.lesson}. ${LanguageManager.t('absences.lesson').toLowerCase()}
</div>
<div class="absence-details">
<div class="absence-subject">${absence.subject}</div>
@@ -114,10 +114,10 @@ async function transformAbsencesPage() {
</div>
<div class="absence-status ${absence.justificationStatus}">
${absence.justificationStatus === 'justified' ?
`Igazolt <span class="material-icons-round">check_circle</span>` :
`${LanguageManager.t('absences.justified')} <span class="material-icons-round">check_circle</span>` :
absence.justificationStatus === 'unjustified' ?
`Igazolatlan <span class="material-icons-round">cancel</span>` :
`Igazolásra vár <span class="material-icons-round">pending</span>`}
`${LanguageManager.t('absences.unjustified')} <span class="material-icons-round">cancel</span>` :
`${LanguageManager.t('absences.pending')} <span class="material-icons-round">pending</span>`}
</div>
</div>
`).join('')}
@@ -252,6 +252,6 @@ function setupFilters() {
if (window.location.href.includes('/Hianyzas/Hianyzasok')) {
transformAbsencesPage().catch(error => {
console.error('Hiba történt az oldal átalakítása során:', error);
console.error(LanguageManager.t('absences.page_transform_error'), error);
});
}

View File

@@ -14,6 +14,10 @@ body {
font-size: 16px;
}
h2 {
background-color: #00000000 !important;
}
.kreta-container {
min-height: 100vh;
display: flex;
@@ -35,42 +39,191 @@ body {
gap: 20px;
}
.card {
.widget-card {
background: var(--card-card);
padding: 20px;
padding-top: 5px !important;
border-radius: 24px;
overflow: hidden;
animation: fadeIn 0.5s ease forwards;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
display: flex;
flex-direction: column;
height: 100%;
border: none;
min-height: 400px;
}
.widget-header {
padding: 20px 20px 0 20px;
background: var(--card-card) !important;
}
.widget-card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
padding-bottom: 16px;
}
.widget-content {
flex: 1;
padding: 0 20px;
background: var(--card-card);
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.widget-footer {
padding: 0px 20px 20px 20px;
background: var(--card-card);
}
.widget-link {
margin: 0;
padding: 0;
}
.card h2 {
font-size: 16px;
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
background-color: var(--card-card);
margin: 0;
padding: 20px 0 16px 0;
}
.card:last-child {
grid-column: 1 / -1;
}
.grade-item, .absence-item, .note-item, .exam-item, .news-item {
border-radius: 6px;
.widget-item {
border-radius: 12px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
border: 1px solid var(--card-card);
border: none;
background: var(--card-card);
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
display: flex;
flex-direction: column;
margin-bottom: 12px;
padding: 12px;
padding: 8px;
position: relative;
min-height: 80px;
}
.widget-item:hover {
transform: translateY(-2px);
box-shadow: 0px 2px calc(var(--shadow-blur, 2px) * 2) 0px var(--accent-shadow);
}
.widget-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
width: 100%;
gap: 12px;
min-height: 40px;
}
.widget-row.grade-row {
align-items: center;
justify-content: flex-start;
}
.widget-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.widget-details.grade-details {
flex: 1;
margin-right: auto;
}
.widget-title {
color: var(--text-primary);
font-weight: 600;
font-size: 16px;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.widget-subtitle {
color: var(--text-secondary);
font-weight: 500;
font-size: 14px;
line-height: 1.2;
}
.widget-content {
color: var(--text-secondary);
font-size: 14px;
line-height: 1.4;
margin-top: 4px;
}
.widget-date {
color: var(--text-secondary);
font-size: 14px;
font-weight: 500;
white-space: nowrap;
text-align: right;
align-self: center;
}
.grade-type-with-date {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
gap: 8px;
}
.grade-type-with-date .grade-type {
flex: 1;
min-width: 0;
}
.note-author {
color: var(--text-tertiary);
font-size: 12px;
font-weight: 400;
margin-top: 4px;
}
.grade-date {
color: var(--text-secondary);
font-size: 13px;
font-weight: 400;
white-space: nowrap;
text-align: right;
}
.widget-author {
color: var(--text-tertiary);
font-size: 12px;
font-weight: 400;
}
.widget-meta {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
text-align: right;
}
.widget-empty {
color: var(--text-secondary);
font-style: italic;
text-align: center;
padding: 20px;
}
.grade {
width: 32px;
@@ -84,15 +237,25 @@ body {
color: var(--text-primary);
font-size: 22px;
}
.subject-name, .absence-type, .note-title, .exam-subject {
color: var(--text-primary);
font-weight: 600;
.news-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
}
.grade-type, .absence-date, .note-date, .exam-date {
color: var(--text-secondary);
font-weight: 500;
.news-content {
font-size: 14px;
line-height: 1.4;
color: var(--text-secondary);
}
.exam-type {
color: var(--accent-accent);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.more-link {
margin-top: auto;
@@ -180,15 +343,25 @@ body {
width: 20px;
height: 20px;
}
.subject-name, .absence-type, .note-title, .exam-subject {
color: var(--text-primary);
font-weight: 600;
.news-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
}
.grade-type, .absence-date, .note-date, .exam-date {
color: var(--text-secondary);
font-weight: 500;
.news-content {
font-size: 14px;
line-height: 1.4;
color: var(--text-secondary);
}
.exam-type {
color: var(--accent-accent);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.more-link {
margin-top: auto;
@@ -212,22 +385,12 @@ body {
font-size: 0.875rem;
}
.grade-row {
.exam-info {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.grade-details {
flex: 1;
margin-right: 10px;
}
.grade-date, .exam-date {
gap: 8px;
margin-top: 4px;
color: var(--text-secondary);
font-size: 14px;
white-space: nowrap;
}
.exam-info {

View File

@@ -1,4 +1,4 @@
const utils = {
const DashboardUtils = {
formatGradeValue(value) {
const trimmedValue = value?.trim() || '';
if (trimmedValue.toLowerCase() === 'szöveges') {
@@ -10,7 +10,7 @@ const utils = {
parseDate(dateStr) {
return dateStr?.trim() || '';
},
formatHungarianDate(dateStr) {
if (!dateStr) return '';
@@ -21,20 +21,29 @@ const utils = {
const day = parseInt(dateParts[2], 10);
if (isNaN(month) || month < 1 || month > 12) return dateStr;
const hungarianMonths = [
'január', 'február', 'március', 'április', 'május', 'június',
'július', 'augusztus', 'szeptember', 'október', 'november', 'december'
if (typeof window.LanguageManager !== 'undefined') {
const monthKeys = [
'months.january', 'months.february', 'months.march', 'months.april',
'months.may', 'months.june', 'months.july', 'months.august',
'months.september', 'months.october', 'months.november', 'months.december'
];
const monthName = window.LanguageManager.t(monthKeys[month - 1]);
return `${monthName} ${day}.`;
}
const monthKeys = [
'months.january', 'months.february', 'months.march', 'months.april', 'months.may', 'months.june',
'months.july', 'months.august', 'months.september', 'months.october', 'months.november', 'months.december'
];
return `${hungarianMonths[month - 1]} ${day}.`;
return `${LanguageManager.t(monthKeys[month - 1])} ${day}.`;
}
};
class DashboardDataExtractor {
class DashboardDataManager {
constructor() {
this.data = {
this.dashboardData = {
grades: [],
absences: [],
notes: [],
@@ -43,46 +52,69 @@ class DashboardDataExtractor {
};
}
extractGrades() {
extractGradeData() {
const gradeRows = document.querySelectorAll('#legutobbiErtekelesek tr:not(:first-child)');
this.data.grades = Array.from(gradeRows).map(row => {
this.dashboardData.grades = Array.from(gradeRows).map(row => {
const gradeValue = row.querySelector('span[style*="font-size: 200%"]')?.textContent;
const gradeInfo = row.querySelector('span[style*="float: right"]')?.textContent;
if (!gradeValue || !gradeInfo) return null;
const [fullSubject, date] = gradeInfo.split('\n').map(str => str.trim());
const { subject, type } = this.parseSubjectInfo(fullSubject);
const { subject, type, dateInSubject } = this.parseSubjectInformation(fullSubject);
return {
value: utils.formatGradeValue(gradeValue),
value: DashboardUtils.formatGradeValue(gradeValue),
subject,
date: utils.parseDate(date),
type: type || 'Értékelés'
date: DashboardUtils.parseDate(date),
type: type || LanguageManager.t('dashboard.evaluation'),
dateInSubject: dateInSubject || null
};
}).filter(Boolean);
}
parseSubjectInfo(fullSubject) {
const months = ['január', 'február', 'március', 'április', 'május', 'június',
'július', 'augusztus', 'szeptember', 'október', 'november', 'december'];
const monthPattern = new RegExp(months.join('|'), 'i');
const monthMatch = fullSubject.match(monthPattern);
parseSubjectInformation(fullSubject) {
const hungarianMonths = ['január', 'február', 'március', 'április', 'május', 'június',
'július', 'augusztus', 'szeptember', 'október', 'november', 'december'];
const monthPattern = hungarianMonths.join('|');
const datePattern = new RegExp(`(${monthPattern})\\s+(\\d{1,2})\\.?$`, 'i');
const dateMatch = fullSubject.match(datePattern);
if (!monthMatch) return { subject: fullSubject, type: '' };
if (dateMatch) {
const subjectPart = fullSubject.substring(0, dateMatch.index).trim();
const datePart = dateMatch[0].trim();
return {
subject: subjectPart,
type: '',
dateInSubject: datePart
};
}
const months = [
LanguageManager.t('months.january'), LanguageManager.t('months.february'), LanguageManager.t('months.march'),
LanguageManager.t('months.april'), LanguageManager.t('months.may'), LanguageManager.t('months.june'),
LanguageManager.t('months.july'), LanguageManager.t('months.august'), LanguageManager.t('months.september'),
LanguageManager.t('months.october'), LanguageManager.t('months.november'), LanguageManager.t('months.december')
];
const fallbackMonthPattern = new RegExp(months.join('|'), 'i');
const monthMatch = fullSubject.match(fallbackMonthPattern);
const monthIndex = fullSubject.lastIndexOf(monthMatch[0]);
return {
subject: fullSubject.substring(0, monthIndex).trim(),
type: fullSubject.substring(monthIndex).trim()
};
if (monthMatch) {
const monthIndex = fullSubject.lastIndexOf(monthMatch[0]);
return {
subject: fullSubject.substring(0, monthIndex).trim(),
type: fullSubject.substring(monthIndex).trim()
};
}
return { subject: fullSubject, type: '' };
}
extractAbsences() {
extractAbsenceData() {
const absenceRows = document.querySelectorAll('#legutobbiMulasztasok tr:not(:first-child)');
this.data.absences = Array.from(absenceRows).map(row => {
this.dashboardData.absences = Array.from(absenceRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 4) return null;
@@ -95,10 +127,10 @@ class DashboardDataExtractor {
}).filter(Boolean);
}
extractNotes() {
extractNoteData() {
const noteRows = document.querySelectorAll('#legutobbiFeljegyzesek tr:not(:first-child)');
this.data.notes = Array.from(noteRows).map(row => {
this.dashboardData.notes = Array.from(noteRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 3) return null;
@@ -110,10 +142,10 @@ class DashboardDataExtractor {
}).filter(Boolean);
}
extractExams() {
extractExamData() {
const examRows = document.querySelectorAll('#legutobbiBejelentettSzamonkeres tr:not(:first-child)');
this.data.upcomingExams = Array.from(examRows).map(row => {
this.dashboardData.upcomingExams = Array.from(examRows).map(row => {
const spans = row.querySelectorAll('span');
if (spans.length < 4) return null;
@@ -126,56 +158,79 @@ class DashboardDataExtractor {
}).filter(Boolean);
}
extractNews() {
const newsContainer = document.querySelector('.faliujsag-lista, #faliujsagLista');
if (!newsContainer) return;
async extractNewsData() {
const newsItems = newsContainer.querySelectorAll('.nb-item, .news-item');
this.data.news = Array.from(newsItems).map(item => {
const titleElement = item.querySelector('.subject h4, .news-title');
const contentElement = item.querySelector('.content, .news-content');
try {
const timestamp = Date.now();
const apiUrl = `https://${window.location.hostname}/Intezmeny/Faliujsag/GetMoreEntries?startindex=0&range=10&_=${timestamp}`;
const dateElement = item.querySelector('.nb-date, .news-date');
let dateStr = '';
if (dateElement) {
const yearElement = dateElement.querySelector('.year');
const monthElement = dateElement.querySelector('.month');
const dayElement = dateElement.querySelector('.day');
if (yearElement && monthElement && dayElement) {
dateStr = `${yearElement.textContent} ${monthElement.textContent} ${dayElement.textContent}`;
} else {
dateStr = dateElement.textContent;
const response = await fetch(apiUrl, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) {
throw new Error(`API request failed with status: ${response.status}`);
}
const data = await response.json();
const authorElement = item.querySelector('.auth-name span, .news-author');
if (!data.FaliujsagElemek || !Array.isArray(data.FaliujsagElemek)) {
return;
}
return {
title: titleElement?.textContent?.trim() || '',
date: dateStr.trim(),
content: contentElement?.textContent?.trim() || '',
author: authorElement?.textContent?.trim() || ''
};
}).filter(news => news.title || news.content);
data.FaliujsagElemek.forEach((item, index) => {
let formattedDate = '';
if (item.DatumNap && item.DatumHonap && item.DatumEv) {
formattedDate = `${item.DatumEv}. ${item.DatumHonap} ${item.DatumNap}.`;
} else if (item.Idopont) {
const match = item.Idopont.match(/\/Date\((\d+)\)\//);
if (match) {
const timestamp = parseInt(match[1]);
const date = new Date(timestamp);
formattedDate = date.toLocaleDateString('hu-HU');
}
}
if (!formattedDate) {
formattedDate = new Date().toLocaleDateString('hu-HU');
}
let cleanContent = item.EsemenySzovege || '';
cleanContent = cleanContent.replace(/<[^>]*>/g, '');
cleanContent = cleanContent.replace(/\r\n/g, ' ');
cleanContent = cleanContent.replace(/\s+/g, ' ').trim();
const newsItem = {
title: item.EsemenyCime || `Hír ${index + 1}`,
content: cleanContent || 'Nincs elérhető tartalom',
date: formattedDate,
author: `${item.Nev || 'Ismeretlen'} (${item.Munkakor || 'Ismeretlen'})`
};
this.dashboardData.news.push(newsItem);
});
} catch (error) {
console.error('❌ Error fetching news from API:', error);
}
}
extractAll() {
this.extractGrades();
this.extractAbsences();
this.extractNotes();
this.extractExams();
this.extractNews();
return this.data;
async extractAllData() {
this.extractGradeData();
this.extractAbsenceData();
this.extractNoteData();
this.extractExamData();
await this.extractNewsData();
return this.dashboardData;
}
}
class DashboardUI {
class DashboardRenderer {
constructor(data) {
this.data = {
...data,
@@ -192,134 +247,204 @@ class DashboardUI {
this.shortenedSchoolName = helper.shortenSchoolName(this.schoolNameFull);
}
generateMainContentHTML() {
generateMainContent() {
return `
<main class="kreta-main">
<div class="grid-container">
${this.generateGradeCard()}
${this.generateAbsenceCard()}
${this.generateNoteCard()}
${this.generateExamCard()}
${this.generateNewsCard()}
${this.createGradeCard()}
${this.createAbsenceCard()}
${this.createNoteCard()}
${this.createExamCard()}
${this.createNewsCard()}
</div>
</main>
`;
}
generateNewsCard() {
createNewsCard() {
const newsItems = this.data.news.map(news => `
<div class="news-item">
<div class="news-header">
<div class="news-date">${news.date}</div>
${news.author ? `<div class="news-author">${news.author}</div>` : ''}
</div>
<div class="news-details">
<h3 class="news-title">${news.title}</h3>
<div class="news-content">${news.content}</div>
</div>
</div>
`).join('');
return this.generateCard('Hírek', newsItems || 'Jelenleg ez egy nem támogatott funkció', '/Intezmeny/Faliujsag', 'Összes hír');
}
generateGradeCard() {
const gradeItems = this.data.grades.map(grade => `
<div class="grade-item">
<div class="grade-row">
<div class="grade grade-${grade.value}">${grade.value}</div>
<div class="grade-details">
<div class="subject-name">${grade.subject}</div>
<div class="grade-type">${grade.type}</div>
<div class="widget-item news-item">
<div class="widget-row">
<div class="widget-details news-details">
<div class="widget-title news-title">${news.title}</div>
<div class="widget-content news-content">${news.content}</div>
</div>
<div class="widget-meta">
${news.date ? `<div class="widget-date news-date">${news.date}</div>` : ''}
${news.author ? `<div class="widget-author news-author">${news.author}</div>` : ''}
</div>
${grade.date ? `<div class="grade-date">${grade.date}</div>` : ''}
</div>
</div>
`).join('');
return this.generateCard('Értékeléseid', gradeItems, '/TanuloErtekeles/Osztalyzatok', 'Összes jegyed');
return this.createCard(LanguageManager.t('dashboard.news'), newsItems || LanguageManager.t('dashboard.not_supported'), '/Intezmeny/Faliujsag', LanguageManager.t('dashboard.all_news'));
}
generateAbsenceCard() {
createGradeCard() {
const gradeItems = this.data.grades.map(grade => `
<div class="widget-item grade-item">
<div class="widget-row grade-row">
<div class="grade grade-${grade.value}">${grade.value}</div>
<div class="widget-details grade-details">
<div class="widget-title subject-name">${grade.subject}</div>
<div class="grade-type-with-date">
<div class="widget-subtitle grade-type">${grade.type}</div>
${grade.dateInSubject || grade.date ? `<div class="widget-subtitle grade-date">${grade.dateInSubject || grade.date}</div>` : ''}
</div>
</div>
</div>
</div>
`).join('');
return this.createCard(LanguageManager.t('dashboard.grades'), gradeItems, '/TanuloErtekeles/Osztalyzatok', LanguageManager.t('dashboard.all_grades'));
}
createAbsenceCard() {
const absenceItems = this.data.absences.map(absence => `
<div class="absence-item">
<div class="absence-details">
<div class="absence-type">${absence.type}</div>
<div class="absence-date">${absence.date}</div>
<div class="widget-item absence-item">
<div class="widget-row">
<div class="widget-details absence-details">
<div class="widget-title absence-type">${absence.type}</div>
<div class="widget-subtitle absence-date">${absence.date}</div>
</div>
${absence.day ? `<div class="widget-date">${absence.day}</div>` : ''}
</div>
</div>
`).join('');
return this.generateCard('Mulasztások', absenceItems, '/Hianyzas/Hianyzasok', 'Összes mulasztás');
return this.createCard(LanguageManager.t('dashboard.absences'), absenceItems, '/Hianyzas/Hianyzasok', LanguageManager.t('dashboard.all_absences'));
}
generateNoteCard() {
createNoteCard() {
const noteItems = this.data.notes.map(note => `
<div class="note-item">
<div class="note-details">
<div class="note-title">${note.title}</div>
<div class="note-date">${note.date}</div>
<div class="widget-item note-item">
<div class="widget-row">
<div class="widget-details note-details">
<div class="widget-title note-title">${note.title}</div>
<div class="widget-subtitle note-date">${note.date}</div>
</div>
${note.author ? `<div class="widget-author note-author">${note.author}</div>` : ''}
</div>
</div>
`).join('');
return this.generateCard('Feljegyzések', noteItems, '/TanuloErtekeles/InformaciokFeljegyzesek', 'Összes üzeneted');
return this.createCard(LanguageManager.t('dashboard.notes'), noteItems, '/TanuloErtekeles/InformaciokFeljegyzesek', LanguageManager.t('dashboard.all_messages'));
}
generateExamCard() {
createExamCard() {
const examItems = this.data.upcomingExams.map(exam => `
<div class="exam-item">
<div class="exam-details">
<div class="exam-subject">${exam.subject}</div>
<div class="exam-date">${utils.formatHungarianDate(exam.date)}</div>
<div class="widget-item exam-item">
<div class="widget-row">
<div class="widget-details exam-details">
<div class="widget-title exam-subject">${exam.subject}</div>
<div class="widget-subtitle exam-type">${exam.type || ''}</div>
</div>
<div class="widget-date exam-date">${DashboardUtils.formatHungarianDate(exam.date)}</div>
</div>
</div>
`).join('');
return this.generateCard('Bejelentett dolgozatok', examItems, '/Tanulo/TanuloBejelentettSzamonkeresek', 'Összes dolgozat');
return this.createCard(LanguageManager.t('dashboard.exams'), examItems, '/Tanulo/TanuloBejelentettSzamonkeresek', LanguageManager.t('dashboard.all_exams'));
}
generateCard(title, content, linkHref, linkText) {
createCard(title, content, linkHref, linkText) {
return `
<div class="card">
<h2>${title}</h2>
<div class="card-content">
${content || `Jelenleg ez egy nem támogatott funkció`}
<a href="${linkHref}" class="more-link">
<div class="widget-card card">
<div class="widget-header">
<h2 class="widget-card-title">${title}</h2>
</div>
<div class="widget-content card-content">
${content || `<div class="widget-empty">${LanguageManager.t('dashboard.not_supported')}</div>`}
</div>
<div class="widget-footer">
<a href="${linkHref}" class="widget-link more-link">
${linkText}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none">
<path d="M11.2997 5.19947L5.64282 5.19947M11.2997 5.19947L11.2997 10.8563M11.2997 5.19947L4.70001 11.7991" stroke="var(--accent-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</svg>
</a>
</div>
</div>
`;
}
render() {
document.body.innerHTML = `
<div class="kreta-container">
${createTemplate.header()}
${this.generateMainContentHTML()}
${this.generateMainContent()}
</div>
`;
setupUserDropdown();
}
}
class DashboardApp {
class DashboardApplication {
constructor() {
this.initialize();
this.init();
}
async initialize() {
if (!window.location.href.includes('/Intezmeny/Faliujsag')) return;
async init() {
if (!window.location.href.includes('/Intezmeny/Faliujsag')) {
return;
}
while (typeof window.LanguageManager === 'undefined' ||
!window.LanguageManager.t('dashboard.grades') ||
window.LanguageManager.t('dashboard.grades') === 'dashboard.grades') {
await new Promise(resolve => setTimeout(resolve, 50));
}
while (!document.querySelector('.faliujsag-lista, #faliujsagLista')) {
await new Promise(resolve => setTimeout(resolve, 100));
}
let newsItemsFound = false;
let attempts = 0;
const maxAttempts = 50;
while (!newsItemsFound && attempts < maxAttempts) {
const newsContainer = document.querySelector('.faliujsag-lista, #faliujsagLista');
if (newsContainer) {
const possibleSelectors = [
'.nb-item',
'.news-item',
'.faliujsag-item',
'.list-group-item',
'li',
'div[class*="item"]',
'div[class*="news"]'
];
for (const selector of possibleSelectors) {
const items = newsContainer.querySelectorAll(selector);
if (items.length > 0) {
newsItemsFound = true;
break;
}
}
if (!newsItemsFound) {
if (newsContainer.children.length > 0 || newsContainer.textContent.trim().length > 0) {
newsItemsFound = true;
}
}
}
if (!newsItemsFound) {
attempts++;
await new Promise(resolve => setTimeout(resolve, 100));
}
}
try {
const dataExtractor = new DashboardDataExtractor();
const dashboardData = dataExtractor.extractAll();
const dataManager = new DashboardDataManager();
const dashboardData = await dataManager.extractAllData();
createTemplate.importFonts();
const ui = new DashboardUI(dashboardData);
ui.render();
const renderer = new DashboardRenderer(dashboardData);
renderer.render();
} catch (error) {
console.error('Error initializing dashboard:', error);
}
}
}
new DashboardApp();
new DashboardApplication();

View File

@@ -1,202 +1,176 @@
:root {
--primary: #050B15;
--secondary: #3F444F;
--tertiary: #1C469A;
--icon: #0A2456;
--accent: #3673EE;
--bg: #DAE4F7;
--card: #EDF3FF;
--cardsec: #FBFCFF;
--error: #E32D2D;
--error-bg: rgba(227, 45, 45, 0.05);
}
:root[data-theme="dark"] {
--primary: #EBF1FD;
--secondary: #CFD8E9;
--tertiary: #AEC8FC;
--icon: #BAD1FF;
--accent: #3673ed;
--bg: #070A0E;
--card: #0F131B;
--cardsec: #131822;
--error: #FF4444;
--error-bg: rgba(255, 68, 68, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
color: var(--primary);
background-color: var(--bg) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
color: var(--primary);
background-color: var(--bg) !important;
font-family: "Montserrat", serif !important;
min-height: 100vh;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.forgot-container {
width: 100%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
}
.forgot-header {
text-align: center;
margin-bottom: 24px;
}
.logo-text {
color: var(--icon);
font-size: 24px;
font-weight: 600;
margin: 16px 0;
display: flex;
align-items: center;
justify-content: center;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 8px;
}
.forgot-card {
background: var(--card);
padding: 24px;
border-radius: 24px;
margin-bottom: 16px;
}
.forgot-title {
font-size: 18px;
font-weight: 600;
color: var(--primary);
margin-bottom: 24px;
text-align: center;
}
.form-group {
margin-bottom: 16px;
}
.form-label {
display: block;
color: var(--secondary);
font-size: 14px;
margin-bottom: 8px;
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 2px solid transparent;
border-radius: 12px;
font-size: 16px;
font-family: "Montserrat", serif;
background: var(--cardsec);
color: var(--primary);
transition: all 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent);
}
.form-control::placeholder {
color: var(--secondary);
}
.form-actions {
margin-top: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.help-link {
color: var(--accent);
text-decoration: none;
font-size: 14px;
transition: color 0.2s ease;
}
.help-link:hover {
color: var(--tertiary);
}
.btn-submit {
padding: 12px 24px;
background: var(--accent);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
font-family: "Montserrat", serif;
cursor: pointer;
transition: background 0.2s ease;
}
.btn-submit:hover {
background: var(--tertiary);
}
.btn-submit:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.error-message {
color: var(--error);
font-size: 14px;
margin-top: 4px;
display: none;
}
.error-message.show {
display: block;
animation: fadeIn 0.2s ease;
}
.g-recaptcha {
margin-top: 24px;
display: flex;
justify-content: center;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 600px) {
.forgot-container {
width: 100%;
max-width: 500px;
padding: 20px;
margin: 0 auto;
}
.forgot-header {
text-align: center;
margin-bottom: 24px;
}
.logo-text {
color: var(--icon);
font-size: 24px;
font-weight: 600;
margin: 16px 0;
display: flex;
align-items: center;
justify-content: center;
}
.logo {
width: 24px;
border-radius: 8px;
margin-right: 8px;
padding: 16px;
}
.forgot-card {
background: var(--card);
padding: 24px;
border-radius: 24px;
margin-bottom: 16px;
}
.forgot-title {
font-size: 18px;
font-weight: 600;
color: var(--primary);
margin-bottom: 24px;
text-align: center;
}
.form-group {
margin-bottom: 16px;
}
.form-label {
display: block;
color: var(--secondary);
font-size: 14px;
margin-bottom: 8px;
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 2px solid transparent;
border-radius: 12px;
font-size: 16px;
font-family: "Montserrat", serif;
background: var(--cardsec);
color: var(--primary);
transition: all 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent);
}
.form-control::placeholder {
color: var(--secondary);
padding: 20px;
}
.form-actions {
margin-top: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.help-link {
color: var(--accent);
text-decoration: none;
font-size: 14px;
transition: color 0.2s ease;
}
.help-link:hover {
color: var(--tertiary);
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.btn-submit {
padding: 12px 24px;
background: var(--accent);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
font-family: "Montserrat", serif;
cursor: pointer;
transition: background 0.2s ease;
width: 100%;
}
.btn-submit:hover {
background: var(--tertiary);
}
.btn-submit:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.error-message {
color: var(--error);
font-size: 14px;
margin-top: 4px;
display: none;
}
.error-message.show {
display: block;
animation: fadeIn 0.2s ease;
}
.g-recaptcha {
margin-top: 24px;
display: flex;
justify-content: center;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 600px) {
.forgot-container {
padding: 16px;
}
.forgot-card {
padding: 20px;
}
.form-actions {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.btn-submit {
width: 100%;
}
}
}

View File

@@ -25,31 +25,31 @@
</header>
<div class="forgot-card">
<h1 class="forgot-title">Elfelejtett jelszó</h1>
<h1 class="forgot-title">${LanguageManager.t('forgotpassword.title')}</h1>
<form id="forgotForm" novalidate>
<div class="form-group">
<label class="form-label" for="username">OM azonosítód</label>
<label class="form-label" for="username">${LanguageManager.t('forgotpassword.om_id_label')}</label>
<input type="text" id="username" name="username" class="form-control"
placeholder="Add meg az OM azonosítód" required>
<div class="error-message">Kérjük, add meg az OM azonosítód.</div>
placeholder="${LanguageManager.t('forgotpassword.om_id_placeholder')}" required>
<div class="error-message">${LanguageManager.t('forgotpassword.om_id_required')}</div>
</div>
<div class="form-group">
<label class="form-label" for="email">E-mail cím</label>
<label class="form-label" for="email">${LanguageManager.t('forgotpassword.email_label')}</label>
<input type="email" id="email" name="email" class="form-control"
placeholder="Add meg az e-mail címed" required>
<div class="error-message">Kérjük, add meg az e-mail címed.</div>
placeholder="${LanguageManager.t('forgotpassword.email_placeholder')}" required>
<div class="error-message">${LanguageManager.t('forgotpassword.email_required')}</div>
</div>
<div class="g-recaptcha" data-sitekey="6LcmPB8dAAAAACJPQBj7WfpBoBsEfyibZeIG5Vbl"></div>
<div class="form-actions">
<a href="/Adminisztracio/Login" class="help-link">
Vissza a bejelentkezéshez
${LanguageManager.t('forgotpassword.back_to_login')}
</a>
<button type="submit" class="btn-submit">
Jelszó visszaállítása
${LanguageManager.t('forgotpassword.reset_button')}
</button>
</div>
</form>
@@ -130,7 +130,7 @@
window.location.href = '/Adminisztracio/Login';
} else {
alert(result.Message || 'Hiba történt a jelszó visszaállítása során. (Kérlek használd az eredeti kréta oldalt erre)');
alert(result.Message || LanguageManager.t('forgotpassword.error_message'));
grecaptcha.reset();
}
} catch (error) {

131
global/language.js Normal file
View File

@@ -0,0 +1,131 @@
(function() {
let currentLanguage = 'hu';
let translations = {};
async function setLanguage(language) {
try {
currentLanguage = language;
cookieManager.set('languagePreference', language);
localStorage.setItem('languagePreference', language);
await loadTranslations(language);
applyTranslations();
window.dispatchEvent(new CustomEvent('languageChanged', {
detail: { language: language }
}));
chrome.runtime.sendMessage({
action: 'languageChanged',
language: language
}).catch(() => {});
} catch (error) {}
}
async function loadTranslations(language) {
try {
const url = chrome.runtime.getURL(`i18n/${language}.json`);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to load ${language}.json - Status: ${response.status}`);
}
translations = await response.json();
} catch (error) {
if (language !== 'hu') {
try {
const fallbackUrl = chrome.runtime.getURL('i18n/hu.json');
const response = await fetch(fallbackUrl);
translations = await response.json();
} catch (fallbackError) {}
}
}
}
function applyTranslations() {
const elements = document.querySelectorAll('[data-i18n]');
elements.forEach(element => {
const key = element.getAttribute('data-i18n');
const translation = getTranslation(key);
if (translation && translation !== key) {
const attr = element.getAttribute('data-i18n-attr');
if (attr) {
element.setAttribute(attr, translation);
} else {
element.textContent = translation;
}
}
});
}
function getTranslation(keyPath, fallback = '') {
const keys = keyPath.split('.');
let value = translations;
for (const key of keys) {
if (value && typeof value === 'object' && key in value) {
value = value[key];
} else {
return fallback || keyPath;
}
}
return typeof value === 'string' ? value : fallback || keyPath;
}
async function initializeLanguage() {
const cookieLanguage = cookieManager.get('languagePreference');
const localStorageLanguage = localStorage.getItem('languagePreference');
const language = cookieLanguage || localStorageLanguage || 'hu';
await setLanguage(language);
if (cookieLanguage !== localStorageLanguage) {
if (cookieLanguage) {
localStorage.setItem('languagePreference', cookieLanguage);
} else if (localStorageLanguage) {
cookieManager.set('languagePreference', localStorageLanguage);
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeLanguage);
} else {
initializeLanguage();
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'changeLanguage') {
setLanguage(message.language);
sendResponse({ success: true });
}
if (message.action === 'getLanguage') {
sendResponse({ language: currentLanguage });
}
return true;
});
window.LanguageManager = {
getCurrentLanguage: () => currentLanguage,
changeLanguage: setLanguage,
t: getTranslation,
getAvailableLanguages: () => [
{ code: 'hu', name: 'Magyar' },
{ code: 'en', name: 'English' }
]
};
})();

View File

@@ -1,3 +1,28 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
body.maintenance-mode {
margin: 0;
padding: 0;
@@ -7,7 +32,7 @@ body.maintenance-mode {
justify-content: center;
background-color: var(--background);
color: var(--text-primary);
font-family: 'Inter', sans-serif;
font-family: 'Figtree', sans-serif;
}
body {
@@ -35,6 +60,7 @@ body {
font-weight: 600;
margin-bottom: 1rem;
color: var(--accent-accent);
font-family: 'Montserrat', sans-serif;
}
.maintenance-message {
@@ -42,10 +68,22 @@ body {
line-height: 1.5;
margin-bottom: 1.5rem;
color: var(--text-primary);
font-family: 'Figtree', sans-serif;
}
.maintenance-footer {
font-size: 0.875rem;
color: var(--text-secondary);
margin-top: 2rem;
font-family: 'Figtree', sans-serif;
}
.maintenance-cactus {
position: fixed;
bottom: 0px;
right: 20px;
width: 120px;
height: 120px;
opacity: 1;
z-index: 1000;
}

View File

@@ -7,18 +7,46 @@ function loadMaintenanceCSS() {
function checkMaintenancePage() {
const maintenanceContent = document.querySelector('.login_content');
if (maintenanceContent && maintenanceContent.textContent.includes('frissítés alatt')) {
const bodyText = document.body ? document.body.textContent : '';
const specificMaintenanceMessage = 'Kedves Felhasználók! A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik. Köszönjük türelmüket és megértésüket! KRÉTA Csapat';
const hasSpecificMessage = bodyText.includes('Kedves Felhasználók!') &&
bodyText.includes('A KRÉTA rendszer jelenleg frissítés alatt van') &&
bodyText.includes('KRÉTA Csapat');
const hasGeneralMaintenance = maintenanceContent &&
(maintenanceContent.textContent.includes('frissítés alatt') ||
maintenanceContent.textContent.includes('under maintenance'));
if (hasSpecificMessage || hasGeneralMaintenance) {
const body = document.body;
const mainLogo = chrome.runtime.getURL('images/firka_logo_128.png');
const cactusImage = chrome.runtime.getURL('images/cactus.png');
const removeLoadingElements = () => {
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) loadingScreen.remove();
const kretaProgressBar = document.querySelector('#KretaProgressBar');
if (kretaProgressBar) kretaProgressBar.remove();
const modalBackground = document.querySelector('.modalBckgroundMain');
if (modalBackground) modalBackground.remove();
const overlays = document.querySelectorAll('.modalBckgroundMain, .loading-screen, #KretaProgressBar');
overlays.forEach(overlay => overlay.remove());
};
removeLoadingElements();
setTimeout(removeLoadingElements, 100);
const existingStyles = document.querySelectorAll('link[rel="stylesheet"], style');
existingStyles.forEach(style => style.remove());
body.innerHTML = '';
body.classList.add('maintenance-mode');
body.classList.add('theme-enabled');
body.classList.add('loaded');
loadMaintenanceCSS();
@@ -34,20 +62,25 @@ function checkMaintenancePage() {
const title = document.createElement('h1');
title.className = 'maintenance-title';
title.textContent = 'Karbantartás';
title.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.title') : 'Karbantartás';
const messageDiv = document.createElement('div');
messageDiv.className = 'maintenance-message';
const paragraph1 = document.createElement('p');
paragraph1.textContent = 'A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.';
paragraph1.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.message1') : 'A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.';
const paragraph2 = document.createElement('p');
paragraph2.textContent = 'Köszönjük türelmüket és megértésüket!';
paragraph2.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.message2') : 'Köszönjük türelmüket és megértésüket!';
const footer = document.createElement('div');
footer.className = 'maintenance-footer';
footer.textContent = 'KRÉTA Csapat';
footer.textContent = window.LanguageManager ? window.LanguageManager.t('maintenance.team') : 'KRÉTA Csapat';
const cactus = document.createElement('img');
cactus.src = cactusImage;
cactus.alt = 'Cactus';
cactus.className = 'maintenance-cactus';
messageDiv.appendChild(paragraph1);
@@ -59,6 +92,7 @@ function checkMaintenancePage() {
container.appendChild(footer);
body.appendChild(container);
body.appendChild(cactus);
}
}

View File

@@ -6,8 +6,8 @@ const COOKIE_KEYS = {
};
const DEFAULT_VALUES = {
SCHOOL: 'Iskola',
USER: 'Felhasználó',
SCHOOL: LanguageManager.t('navigation.school_default'),
USER: LanguageManager.t('navigation.user_default'),
TIMER: '45:00'
};

View File

@@ -1,31 +1,3 @@
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2) format('woff2');
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
box-sizing: border-box;
margin: 0;
@@ -53,14 +25,15 @@ body {
padding: 1rem;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow: hidden;
}
.overall-averages {
padding: 1.5rem;
background: var(--card-card);
border-radius: 24px;
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
width: calc(995px + 50px);
width: 100%;
max-width: calc(995px + 50px);
}
.average-details {
display: flex;
@@ -175,8 +148,38 @@ body {
display: flex;
flex-direction: column;
gap: 1rem;
overflow: auto;
max-height: calc(71.5px* 5 - 10px);
overflow: hidden;
max-height: calc(71.5px* 5 - 10px);
position: relative;
}
.grades-list.scrollable {
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.grades-list.scrollable::-webkit-scrollbar {
display: none;
}
.grades-list::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 30px;
height: 6px;
background: radial-gradient(circle, var(--text-secondary) 1px, transparent 1px);
background-size: 8px 6px;
background-repeat: repeat-x;
opacity: 0;
transition: opacity 0.3s ease;
}
.grades-list.has-more::after {
opacity: 1;
}
.grade-item {
display: grid;
@@ -615,16 +618,163 @@ body {
color: var(--grades-5);
}
@media (max-width: 1200px) {
.chart-header {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.chart-averages {
position: static;
align-self: flex-end;
}
.grade-distribution {
flex-wrap: wrap;
justify-content: center;
}
.grades-chart {
overflow-x: auto;
}
}
@media (max-width: 1024px) {
.grades-overview {
grid-template-columns: 1fr;
grid-template-columns: 1fr;
}
.semester-grades {
width: 100%;
width: 100%;
height: auto;
max-height: 400px;
}
.overall-averages {
width: 100%;
}
}
@media (max-width: 768px) {
.grades-chart {
height: 200px;
padding: 0.75rem;
margin-bottom: 1rem;
}
.chart-header {
padding: 0.75rem;
}
.chart-averages {
gap: 0.5rem;
}
.average-circle {
width: 40px;
height: 22px;
padding: 4px 6px;
}
.average-circle .average-value {
font-size: 12px;
}
.grade-distribution {
gap: 0.5rem;
padding: 0.75rem;
overflow-x: auto;
flex-wrap: nowrap;
}
.grade-count {
padding: 3px 6px 3px 3px;
flex-shrink: 0;
}
.grade-count .grade-value {
font-size: 16px;
}
.grade-count .grade-amount {
font-size: 12px;
}
.semester-grades {
padding: 1rem;
width: 100%;
min-width: 0;
}
.semester-grades h3 {
padding: 0.5rem;
font-size: 14px;
}
.semester-grade-item {
padding: 0.75rem;
gap: 0.75rem;
}
.semester-grade-value {
width: 28px;
height: 28px;
font-size: 18px;
}
.semester-grade-subject {
font-size: 14px;
}
.overall-averages {
padding: 1rem;
overflow-x: auto;
}
}
@media (max-width: 480px) {
.grades-chart {
height: 180px;
padding: 0.5rem;
}
.chart-header {
padding: 0.5rem;
flex-direction: column;
align-items: stretch;
}
.chart-averages {
align-self: center;
gap: 0.25rem;
}
.average-circle {
width: 36px;
height: 20px;
padding: 2px 4px;
}
.average-circle .average-value {
font-size: 11px;
}
.grade-distribution {
padding: 0.5rem;
gap: 0.25rem;
}
.semester-grades {
padding: 0.75rem;
}
.overall-averages {
padding: 0.75rem;
}
.grades-overview {
gap: 1rem;
margin-bottom: 1rem;
}
}

View File

@@ -23,10 +23,10 @@
};
setupEventListeners();
setupGradesListScrolling();
loadingScreen.hide();
} catch (error) {
console.error('Error transforming grades page:', error);
loadingScreen.hide();
}
}
@@ -41,7 +41,20 @@
const subjectName = cells[2].textContent.trim();
if (subjectName && subjectName !== 'Magatartás/Szorgalom') {
const grades = [];
const months = ['Szeptember', 'Oktober', 'November', 'December', 'JanuarI', 'JanuarII', 'Februar', 'Marcius', 'Aprilis', 'Majus', 'JuniusI', 'JuniusII'];
const months = [
LanguageManager.t('grades.september'),
LanguageManager.t('grades.october'),
LanguageManager.t('grades.november'),
LanguageManager.t('grades.december'),
LanguageManager.t('grades.january_1'),
LanguageManager.t('grades.january_2'),
LanguageManager.t('grades.february'),
LanguageManager.t('grades.march'),
LanguageManager.t('grades.april'),
LanguageManager.t('grades.may'),
LanguageManager.t('grades.june_1'),
LanguageManager.t('grades.june_2')
];
months.forEach((month, index) => {
const gradeElements = cells[index + 3].querySelectorAll('span[data-tanuloertekelesid]');
@@ -135,7 +148,20 @@
function generateGradeItem(grade) {
const semesterClass = grade.isSemesterGrade ? 'semester-grade' : '';
const dateObj = new Date(grade.date);
const monthNames = ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'];
const monthNames = [
LanguageManager.t('months.january'),
LanguageManager.t('months.february'),
LanguageManager.t('months.march'),
LanguageManager.t('months.april'),
LanguageManager.t('months.may'),
LanguageManager.t('months.june'),
LanguageManager.t('months.july'),
LanguageManager.t('months.august'),
LanguageManager.t('months.september'),
LanguageManager.t('months.october'),
LanguageManager.t('months.november'),
LanguageManager.t('months.december')
];
const formattedDate = `${monthNames[dateObj.getMonth()]} ${dateObj.getDate()}`;
const shortenedTheme = shortenEvaluationName(grade.theme);
return `
@@ -182,7 +208,7 @@
<div class="grades-overview">
<div class="overall-averages card">
<div class="chart-header">
<div class="chart-title">Jegyek (${totalGrades}db)</div>
<div class="chart-title">${LanguageManager.t('grades.chart_title')} (${totalGrades}db)</div>
<div class="chart-averages">
<div class="average-circle my-average" data-grade="${studentGradeLevel}">
<span class="average-value ${studentAverage < 2 && studentAverage > 0 ? 'warning' : ''}">${studentAverage > 0 ? studentAverage.toFixed(2) : '-'}</span>
@@ -209,7 +235,7 @@
</div>
${semesterGrades.length > 0 ? `
<div class="semester-grades card">
<h3>Félévi értékelések</h3>
<h3>${LanguageManager.t('grades.semester_evaluations')}</h3>
<div class="semester-grades-list">
${semesterGrades.map(grade => `
<div class="semester-grade-item grade-${grade.value}">
@@ -384,7 +410,7 @@
const sortedSubjects = [...subjects].sort((a, b) => a.grades.length - b.grades.length);
return sortedSubjects.map(subject => {
const regularGrades = subject.grades.filter(grade => !grade.isSemesterGrade);
const regularGrades = subject.grades.filter(grade => !grade.isSemesterGrade).reverse();
const myGrade = Math.floor(subject.average) || 0;
const classGrade = Math.floor(subject.classAverage) || 0;
@@ -423,19 +449,45 @@
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
timeLeft--;
if (timeLeft <= 0) {
window.location.href = '/Home/Logout';
} else {
timeLeft--;
if (timeLeft < 0) {
window.location.href = chrome.runtime.getURL('logout/logout.html');
}
};
updateTimer();
setInterval(updateTimer, 1000);
}
}
function setupGradesListScrolling() {
const gradesLists = document.querySelectorAll('.grades-list');
gradesLists.forEach(list => {
const checkScrollable = () => {
if (list.scrollHeight > list.clientHeight) {
list.classList.add('scrollable', 'has-more');
const handleScroll = () => {
const isAtBottom = list.scrollTop + list.clientHeight >= list.scrollHeight - 5;
if (isAtBottom) {
list.classList.remove('has-more');
} else {
list.classList.add('has-more');
}
};
list.addEventListener('scroll', handleScroll);
handleScroll();
} else {
list.classList.remove('scrollable', 'has-more');
}
};
checkScrollable();
});
}
if (window.location.href.includes('/TanuloErtekeles/Osztalyzatok')) {
transformGradesPage();
}

View File

@@ -1,28 +1,3 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
box-sizing: border-box;
margin: 0;
@@ -381,47 +356,6 @@ body {
font-style: italic;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-container {
background-color: var(--background);
padding: 2rem;
border-radius: 16px;
text-align: center;
max-width: 90%;
width: 300px;
}
.loading-logo {
width: 80px;
margin-bottom: 1rem;
}
.loading-text {
font-size: 18px;
font-weight: 600;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
.loading-text2 {
font-size: 14px;
color: var(--text-secondary);
}
.empty-state {
text-align: center;
padding: 2rem;

View File

@@ -1,7 +1,32 @@
async function collectHomeworkData() {
await helper.waitForElement('#TanulotHaziFeladatkGrid');
await new Promise(resolve => setTimeout(resolve, 1000));
async function fetchHomeworkData() {
try {
const currentDomain = window.location.hostname;
const apiUrl = `https://${currentDomain}/api/TanuloHaziFeladatApi/GetTanulotHaziFeladatGrid?sort=HaziFeladatHatarido-asc&page=1&pageSize=100&group=&filter=&data=%7B%22RegiHaziFeladatokElrejtese%22%3Afalse%7D&_=${Date.now()}`;
const response = await fetch(apiUrl, {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching homework data:', error);
return { Data: [], Total: 0 };
}
}
async function collectHomeworkData() {
const apiData = await fetchHomeworkData();
const basicData = {
schoolInfo: {
name: cookieManager.get('schoolName') || 'Iskola',
@@ -14,25 +39,25 @@ async function collectHomeworkData() {
};
const homeworkItems = [];
const rows = document.querySelectorAll('#TanulotHaziFeladatkGrid .k-grid-content tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 7) {
homeworkItems.push({
subject: cells[3]?.textContent?.trim() || '',
teacher: cells[4]?.textContent?.trim() || '',
description: cells[5]?.textContent?.trim() || '',
createdDate: cells[6]?.textContent?.trim() || '',
deadline: cells[7]?.textContent?.trim() || ''
});
}
});
if (apiData.Data && Array.isArray(apiData.Data)) {
apiData.Data.forEach(item => {
homeworkItems.push({
id: item.ID,
subject: item.TantargyNev || '',
teacher: item.TanarNeve || '',
description: item.HaziFeladatSzoveg || '',
createdDate: formatApiDate(item.HaziFeladatRogzitesDatuma),
deadline: formatApiDate(item.HaziFeladatHatarido),
completed: item.MegoldottHF_BOOL || false,
classGroup: item.OsztalyCsoport || ''
});
});
}
const groupedHomework = {};
homeworkItems.forEach(homework => {
const deadlineDate = homework.deadline.split(' ').slice(0, 3).join(' ');
const deadlineDate = homework.deadline.split(' ')[0];
if (!groupedHomework[deadlineDate]) {
groupedHomework[deadlineDate] = [];
}
@@ -42,6 +67,31 @@ async function collectHomeworkData() {
return { basicData, homeworkItems, groupedHomework };
}
function formatApiDate(dateString) {
if (!dateString) return '';
try {
const date = new Date(dateString);
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const dayNames = [
LanguageManager.t('common.sunday'),
LanguageManager.t('common.monday'),
LanguageManager.t('common.tuesday'),
LanguageManager.t('common.wednesday'),
LanguageManager.t('common.thursday'),
LanguageManager.t('common.friday'),
LanguageManager.t('common.saturday')
];
const dayName = dayNames[date.getDay()];
return `${month}.${day}. (${dayName})`;
} catch (error) {
return dateString;
}
}
function isTomorrow(dateStr) {
if (!dateStr) return false;
@@ -78,16 +128,16 @@ async function transformHomeworkPage() {
<main class="kreta-main">
<div class="filter-card">
<div class="filter-header">
<h2>Szűrés</h2>
<h2>${LanguageManager.t('homework.filter_title')}</h2>
</div>
<div class="filter-content">
<div class="filter-group">
<label>
<!--<span class="material-icons-round">subject</span>-->
Tantárgy
${LanguageManager.t('homework.subject')}
</label>
<select id="subjectFilter">
<option value="">Összes tantárgy</option>
<option value="">${LanguageManager.t('homework.all_subjects')}</option>
${[...new Set(homeworkItems.map(item => item.subject))]
.sort()
.map(subject => `<option value="${subject}">${subject}</option>`)
@@ -97,10 +147,10 @@ async function transformHomeworkPage() {
<div class="filter-group">
<label>
<!--<span class="material-icons-round">person</span>-->
Tanár
${LanguageManager.t('homework.teacher')}
</label>
<select id="teacherFilter">
<option value="">Összes tanár</option>
<option value="">${LanguageManager.t('homework.all_teachers')}</option>
${[...new Set(homeworkItems.map(item => item.teacher))]
.sort()
.map(teacher => `<option value="${teacher}">${teacher}</option>`)
@@ -110,13 +160,13 @@ async function transformHomeworkPage() {
<div class="filter-group">
<label>
<!--<span class="material-icons-round">date_range</span>-->
Határidő
${LanguageManager.t('homework.due_date')}
</label>
<select id="deadlineFilter">
<option value="">Összes határidő</option>
<option value="tomorrow">Holnapi határidő</option>
<option value="thisWeek">Ezen a héten</option>
<option value="nextWeek">Jövő héten</option>
<option value="">${LanguageManager.t('homework.all_deadlines')}</option>
<option value="tomorrow">${LanguageManager.t('homework.tomorrow_deadline')}</option>
<option value="thisWeek">${LanguageManager.t('homework.this_week')}</option>
<option value="nextWeek">${LanguageManager.t('homework.next_week')}</option>
</select>
</div>
</div>
@@ -136,17 +186,31 @@ async function transformHomeworkPage() {
}
function renderHomeworkList(groupedHomework) {
const sortedDates = Object.keys(groupedHomework).sort((a, b) => {
const dateA = new Date(a.replace(/\./g, ''));
const dateB = new Date(b.replace(/\./g, ''));
return dateA - dateB;
const partsA = a.split('.');
const partsB = b.split('.');
const monthA = parseInt(partsA[0]) - 1;
const dayA = parseInt(partsA[1]);
const monthB = parseInt(partsB[0]) - 1;
const dayB = parseInt(partsB[1]);
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
const yearA = monthA < currentMonth ? currentYear + 1 : currentYear;
const yearB = monthB < currentMonth ? currentYear + 1 : currentYear;
const dateA = new Date(yearA, monthA, dayA);
const dateB = new Date(yearB, monthB, dayB);
return dateB - dateA;
});
if (sortedDates.length === 0) {
return `
<div class="empty-state">
<p>Nincs megjeleníthető házi feladat.</p>
<p>${LanguageManager.t('homework.no_homework')}</p>
</div>
`;
}
@@ -166,7 +230,7 @@ function renderHomeworkList(groupedHomework) {
<div class="homework-item ${isTomorrowClass}" data-subject="${homework.subject}" data-teacher="${homework.teacher}">
<div class="homework-header">
<div class="homework-subject">${homework.subject}</div>
<div class="homework-deadline ${urgentClass}">${formatDeadline(homework.deadline)}</div>
<div class="homework-deadline ${urgentClass}">${homework.deadline}</div>
</div>
<div class="homework-content">${formatHomeworkDescription(homework.description)}</div>
<div class="homework-footer">
@@ -190,37 +254,32 @@ function formatDateHeader(dateStr) {
tomorrow.setDate(tomorrow.getDate() + 1);
const parts = dateStr.split('.');
if (parts.length < 3) return dateStr;
if (parts.length < 2) return dateStr;
const year = parseInt(parts[0].trim());
const month = parseInt(parts[1].trim()) - 1;
const day = parseInt(parts[2].trim());
const date = new Date(year, month, day);
const month = parseInt(parts[0].trim()) - 1;
const day = parseInt(parts[1].trim());
const currentYear = today.getFullYear();
const date = new Date(currentYear, month, day);
if (date.toDateString() === today.toDateString()) {
return 'Ma - ' + dateStr;
return LanguageManager.t('common.today') + ' - ' + dateStr;
} else if (date.toDateString() === tomorrow.toDateString()) {
return 'Holnap - ' + dateStr;
return LanguageManager.t('common.tomorrow') + ' - ' + dateStr;
}
const weekdays = ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'];
const weekdays = [
LanguageManager.t('common.sunday'),
LanguageManager.t('common.monday'),
LanguageManager.t('common.tuesday'),
LanguageManager.t('common.wednesday'),
LanguageManager.t('common.thursday'),
LanguageManager.t('common.friday'),
LanguageManager.t('common.saturday')
];
return `${weekdays[date.getDay()]} - ${dateStr}`;
}
function formatDeadline(dateStr) {
if (!dateStr) return '';
if (isTomorrow(dateStr)) {
return `Határidő: ${dateStr} (holnap!)`;
}
return `Határidő: ${dateStr}`;
}
function formatDate(dateStr) {
if (!dateStr) return '';
return dateStr;
@@ -229,14 +288,6 @@ function formatDate(dateStr) {
function formatHomeworkDescription(description) {
if (!description) return '';
description = description.replace(/(\d+\.)\s*(\w[^\n.]*)/g, '<strong>$1 $2</strong>');
description = description.replace(/(Határidő:)\s*([^\n]+)/g, '<div class="homework-requirement"><span class="requirement-label">$1</span> $2</div>');
description = description.replace(/(MS\s+[^\n.]+szerint\s+adható\s+be\.)/g, '<div class="homework-requirement"><span class="requirement-label">Beadás:</span> $1</div>');
description = description.replace(/\n/g, '<br>');
return description;
@@ -341,7 +392,7 @@ function setupFilters(homeworkItems, groupedHomework) {
if (!emptyState) {
emptyState = document.createElement('div');
emptyState.className = 'empty-state';
emptyState.innerHTML = '<p>Nincs a szűrési feltételeknek megfelelő házi feladat.</p>';
emptyState.innerHTML = `<p>${LanguageManager.t('homework.no_matching_homework')}</p>`;
homeworkList.appendChild(emptyState);
}

319
i18n/en.json Normal file
View File

@@ -0,0 +1,319 @@
{
"loading": {
"text": "Loading...",
"subtext": "Please wait!"
},
"settings": {
"title": "Settings",
"theme": "Theme",
"language": "Language",
"themes": {
"light_blue": "Light Blue",
"light_green": "Light Green",
"dark_blue": "Dark Blue",
"dark_green": "Dark Green",
"dark_red": "Dark Red",
"dark_purple": "Dark Purple",
"dark_orange": "Dark Orange",
"dark_pink": "Dark Pink",
"dark_yellow": "Dark Yellow",
"dark_cyan": "Dark Cyan",
"dark_lime": "Dark Lime",
"dark_indigo": "Dark Indigo"
},
"languages": {
"hu": "Magyar",
"en": "English"
},
"about": {
"title": "About",
"description": "Firka is an open-source project that creates a custom user interface for the KRÉTA system.",
"github": "GitHub"
},
"support": {
"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"
}
},
"navigation": {
"dashboard": "Home",
"timetable": "Timetable",
"grades": "Grades",
"homework": "Homework",
"absences": "Absences",
"other": "Other",
"profile": "Profile",
"settings": "Settings",
"logout": "Logout",
"nav_toggle": "Open navigation"
},
"dashboard": {
"welcome": "Welcome",
"recent_grades": "Recent grades",
"upcoming_lessons": "Upcoming lessons",
"homework_due": "Homework due",
"news": "News",
"grades": "Your grades",
"absences": "Absences",
"notes": "Notes",
"exams": "Announced tests",
"all_news": "All news",
"all_grades": "All your grades",
"all_absences": "All absences",
"all_messages": "All your messages",
"all_exams": "All tests",
"not_supported": "There is currently no data to show",
"evaluation": "Evaluation"
},
"grades": {
"title": "Grades",
"subject": "Subject",
"grade": "Grade",
"date": "Date",
"teacher": "Teacher",
"average": "Average",
"chart_title": "Grades",
"semester_evaluations": "Semester evaluations",
"semester_average": "Semester average",
"no_grades": "No grades",
"september": "September",
"october": "October",
"november": "November",
"december": "December",
"january_1": "January I",
"january_2": "January II",
"february": "February",
"march": "March",
"april": "April",
"may": "May",
"june_1": "June I",
"june_2": "June II"
},
"timetable": {
"title": "Timetable",
"lesson": "Lesson",
"time": "Time",
"subject": "Subject",
"teacher": "Teacher",
"classroom": "Classroom",
"homework_indicator": "Homework",
"test_indicator": "Test",
"teacher_label": "Teacher:",
"substitute_teacher_label": "Substitute teacher:",
"classroom_label": "Classroom:",
"time_label": "Time:",
"status_label": "Status:",
"substitution": "Substitution",
"cancelled": "Cancelled",
"has_homework": "Has homework",
"no_lessons_this_week": "No lessons this week or timeout occurred",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"found_current_week": "Found current week"
},
"homework": {
"title": "Homework",
"due_date": "Due date",
"subject": "Subject",
"description": "Description",
"filter_title": "Filter",
"all_subjects": "All subjects",
"all_teachers": "All teachers",
"all_deadlines": "All deadlines",
"tomorrow_deadline": "Tomorrow's deadline",
"this_week": "This week",
"next_week": "Next week",
"no_homework": "No homework to display.",
"no_filtered_homework": "No homework matching the filter criteria.",
"teacher": "Teacher",
"no_matching_homework": "No homework matching the filter criteria."
},
"absences": {
"title": "Absences",
"date": "Date",
"lesson": "Lesson",
"type": "Type",
"justified": "Justified",
"unjustified": "Unjustified",
"filter_title": "Filter",
"all_subjects": "All subjects",
"all_types": "All types",
"pending": "Pending justification",
"subject": "Subject",
"justification": "Justification",
"hours": "hours",
"page_transform_error": "An error occurred while transforming the page"
},
"profile": {
"title": "Profile",
"name": "Name",
"class": "Class",
"school": "School",
"student_id": "Student ID",
"settings_title": "Profile settings",
"tab_settings": "Settings",
"tab_password": "Change password",
"tab_security": "Security settings",
"tab_contacts": "Contact information",
"two_factor_description": "To use two-factor authentication, install a time-based one-time password (TOTP) application:",
"android": "Android",
"iphone": "iPhone",
"enable_2fa": "Enable two-factor authentication",
"security_key": "Security key:",
"verification_code_label": "Verification code",
"verification_code_help": "Enter the 6-digit code shown in your authenticator app.",
"verification_code_placeholder": "123456",
"verify_and_activate": "Verify and activate",
"backup_codes_description": "You can use the following backup codes to log in if you don't have access to your authenticator app. Each code can only be used once.",
"email_label": "Email address",
"email_help": "Email address is required for password recovery.",
"phone_label": "Phone number",
"phone_help": "Phone number is optional.",
"phone_placeholder": "+1 xxx xxx xxxx",
"current_password": "Current password",
"new_password": "New password",
"new_password_help": "Password must be at least 8 characters long.",
"confirm_password": "Confirm new password",
"change_password": "Change password",
"show_tips": "Show tips",
"show_tips_help": "Toggle display of tips on/off.",
"email_required": "Email address is required!",
"email_invalid": "Please enter a valid email address!",
"phone_invalid": "Please enter a valid phone number!",
"contacts_saved": "Contact information saved successfully!",
"contacts_save_error": "An error occurred while saving. Please try again later.",
"settings_saved": "Settings saved successfully! Please log in again for changes to take effect.",
"settings_save_error": "An error occurred while saving. Please try again later.",
"password_fields_required": "Please fill in all fields!",
"passwords_not_match": "New passwords do not match!",
"password_too_short": "New password must be at least 8 characters long!",
"password_changed": "Password changed successfully!",
"password_change_error": "An error occurred while changing password. Please try again later."
},
"login": {
"title": "Login",
"username": "Username",
"password": "Password",
"login_button": "Login",
"forgot_password": "Forgot password",
"two_factor_title": "Two-factor authentication",
"verification_code": "Verification code",
"username_placeholder": "Username",
"password_placeholder": "Password",
"username_required": "Please enter your username.",
"password_required": "Please enter your password.",
"help_login": "Can't log in?",
"help_link": "Help",
"system_message": "System message",
"privacy_policy": "Privacy policy",
"kreta_id": "KRÉTA ID",
"system_notification": "System notification"
},
"forgot_password": {
"title": "Forgot password",
"om_id": "OM ID",
"email": "Email address",
"om_id_placeholder": "Enter your OM ID",
"email_placeholder": "Enter your email address",
"om_id_required": "Please enter your OM ID.",
"email_required": "Please enter your email address."
},
"two_factor": {
"title": "Two-factor authentication",
"code_placeholder": "One-time password",
"code_required": "Please enter the one-time password.",
"verify_button": "Verify code",
"verifying": "Verifying...",
"trust_device": "Trust this device"
},
"logout": {
"title": "Logout",
"message": "Are you sure you want to logout?",
"confirm": "Yes",
"cancel": "Cancel",
"success": "Successfully logged out!",
"continue": "Continue"
},
"common": {
"save": "Save",
"cancel": "Cancel",
"close": "Close",
"loading": "Loading...",
"error": "Error",
"success": "Success",
"warning": "Warning",
"info": "Information",
"yes": "Yes",
"no": "No",
"continue": "Continue",
"back": "Back",
"next": "Next",
"previous": "Previous",
"all": "All",
"none": "None",
"filter": "Filter",
"search": "Search",
"select": "Select",
"required": "Required",
"optional": "Optional",
"api_error": "API error",
"api_load_error": "API load error",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"saturday": "Saturday",
"sunday": "Sunday",
"today": "Today",
"tomorrow": "Tomorrow"
},
"months": {
"january": "January",
"february": "February",
"march": "March",
"april": "April",
"may": "May",
"june": "June",
"july": "July",
"august": "August",
"september": "September",
"october": "October",
"november": "November",
"december": "December"
},
"search": {
"title": "Choose school",
"select_institution": "Please select an institution to continue!"
},
"roleselect": {
"student_book": "Student Book",
"student_description": "View grades, absences, timetable and other information.",
"dkt_title": "Digital Collaboration Space (DKT)",
"dkt_description": "Classroom communication and assignments.",
"logout_title": "Logout",
"logout_description": "Log out of the system",
"role_change_error": "An error occurred while changing roles."
},
"maintenance": {
"title": "Maintenance",
"message1": "The KRÉTA system is currently being updated and will be available again soon.",
"message2": "Thank you for your patience and understanding!",
"team": "KRÉTA Team"
},
"about": {
"title": "About",
"description": "Firka is an open source project that creates a custom user interface for the KRÉTA system.",
"support_title": "Support",
"support_description": "If you like our work and want to support development, you can do so in the following way:",
"version": "v1.1.0"
},
"app": {
"title": "Firka - KRÉTA",
"settings_title": "Firka - Settings"
}
}

319
i18n/hu.json Normal file
View File

@@ -0,0 +1,319 @@
{
"loading": {
"text": "Betöltés alatt...",
"subtext": "Kis türelmet!"
},
"settings": {
"title": "Beállítások",
"theme": "Téma",
"language": "Nyelv",
"themes": {
"light_blue": "Világos Kék",
"light_green": "Világos Zöld",
"dark_blue": "Sötét Kék",
"dark_green": "Sötét Zöld",
"dark_red": "Sötét Piros",
"dark_purple": "Sötét Lila",
"dark_orange": "Sötét Narancs",
"dark_pink": "Sötét Rózsaszín",
"dark_yellow": "Sötét Sárga",
"dark_cyan": "Sötét Cián",
"dark_lime": "Sötét Lime",
"dark_indigo": "Sötét Indigó"
},
"languages": {
"hu": "Magyar",
"en": "English"
},
"about": {
"title": "Névjegy",
"description": "A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.",
"github": "GitHub"
},
"support": {
"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"
}
},
"navigation": {
"dashboard": "Kezdőlap",
"timetable": "Órarend",
"grades": "Jegyek",
"homework": "Házi feladatok",
"absences": "Mulasztások",
"other": "Egyéb",
"profile": "Profil",
"settings": "Beállítások",
"logout": "Kijelentkezés",
"nav_toggle": "Navigáció megnyitása"
},
"dashboard": {
"welcome": "Üdvözöljük",
"recent_grades": "Legutóbbi jegyek",
"upcoming_lessons": "Következő órák",
"homework_due": "Esedékes házi feladatok",
"news": "Hírek",
"grades": "Értékeléseid",
"absences": "Mulasztások",
"notes": "Feljegyzések",
"exams": "Bejelentett dolgozatok",
"all_news": "Összes hír",
"all_grades": "Összes jegyed",
"all_absences": "Összes mulasztás",
"all_messages": "Összes üzeneted",
"all_exams": "Összes dolgozat",
"not_supported": "Jelenleg nincsen adat amivel fel lehetne tölteni",
"evaluation": "Értékelés"
},
"grades": {
"title": "Jegyek",
"subject": "Tantárgy",
"grade": "Jegy",
"date": "Dátum",
"teacher": "Tanár",
"average": "Átlag",
"chart_title": "Jegyek",
"semester_evaluations": "Félévi értékelések",
"semester_average": "Félévi átlag",
"no_grades": "Nincsenek jegyek",
"september": "Szeptember",
"october": "Oktober",
"november": "November",
"december": "December",
"january_1": "JanuarI",
"january_2": "JanuarII",
"february": "Februar",
"march": "Marcius",
"april": "Aprilis",
"may": "Majus",
"june_1": "JuniusI",
"june_2": "JuniusII"
},
"timetable": {
"title": "Órarend",
"lesson": "Óra",
"time": "Idő",
"subject": "Tantárgy",
"teacher": "Tanár",
"classroom": "Terem",
"homework_indicator": "Házi feladat",
"test_indicator": "Számonkérés",
"teacher_label": "Tanár:",
"substitute_teacher_label": "Helyettesítő tanár:",
"classroom_label": "Terem:",
"time_label": "Időpont:",
"status_label": "Állapot:",
"substitution": "Helyettesítés",
"cancelled": "Elmarad",
"has_homework": "Van házi feladat",
"no_lessons_this_week": "Nincsenek órák ezen a héten vagy időtúllépés történt",
"monday": "Hétfő",
"tuesday": "Kedd",
"wednesday": "Szerda",
"thursday": "Csütörtök",
"friday": "Péntek",
"found_current_week": "Megtalált jelenlegi hét"
},
"homework": {
"title": "Házi feladatok",
"due_date": "Határidő",
"subject": "Tantárgy",
"description": "Leírás",
"filter_title": "Szűrés",
"all_subjects": "Összes tantárgy",
"all_teachers": "Összes tanár",
"all_deadlines": "Összes határidő",
"tomorrow_deadline": "Holnapi határidő",
"this_week": "Ezen a héten",
"next_week": "Jövő héten",
"no_homework": "Nincs megjeleníthető házi feladat.",
"no_filtered_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat.",
"teacher": "Tanár",
"no_matching_homework": "Nincs a szűrési feltételeknek megfelelő házi feladat."
},
"absences": {
"title": "Hiányzások",
"date": "Dátum",
"lesson": "Óra",
"type": "Típus",
"justified": "Igazolt",
"unjustified": "Igazolatlan",
"filter_title": "Szűrés",
"all_subjects": "Minden tantárgy",
"all_types": "Mindegy",
"pending": "Igazolásra vár",
"subject": "Tantárgy",
"justification": "Igazolás",
"hours": "óra",
"page_transform_error": "Hiba történt az oldal átalakítása során"
},
"profile": {
"title": "Profil",
"name": "Név",
"class": "Osztály",
"school": "Iskola",
"student_id": "Diák azonosító",
"settings_title": "Profil beállítások",
"tab_settings": "Beállítások",
"tab_password": "Jelszó módosítása",
"tab_security": "Biztonsági beállítások",
"tab_contacts": "Elérhetőségek",
"two_factor_description": "A kétfaktoros hitelesítés használatához telepítsen egy időalapú, egyszer használatos jelszó (TOTP) alkalmazást:",
"android": "Android",
"iphone": "iPhone",
"enable_2fa": "Kétfaktoros azonosítás bekapcsolása",
"security_key": "Biztonsági kulcs:",
"verification_code_label": "Ellenőrző kód",
"verification_code_help": "Adja meg a hitelesítő alkalmazásban megjelenő 6 számjegyű kódot.",
"verification_code_placeholder": "123456",
"verify_and_activate": "Ellenőrzés és aktiválás",
"backup_codes_description": "Az alábbi biztonsági kódokat használhatja bejelentkezéshez, ha nem fér hozzá a hitelesítő alkalmazásához. Minden kód csak egyszer használható.",
"email_label": "E-mail cím",
"email_help": "Az e-mail cím megadása a jelszó emlékeztető miatt szükséges.",
"phone_label": "Telefonszám",
"phone_help": "A telefonszám megadása nem kötelező.",
"phone_placeholder": "+36 xx xxx xxxx",
"current_password": "Jelenlegi jelszó",
"new_password": "Új jelszó",
"new_password_help": "A jelszónak legalább 8 karakter hosszúnak kell lennie.",
"confirm_password": "Új jelszó megerősítése",
"change_password": "Jelszó módosítása",
"show_tips": "Tippek megjelenítése",
"show_tips_help": "A tippek megjelenítésének ki/be kapcsolása.",
"email_required": "Az e-mail cím megadása kötelező!",
"email_invalid": "Kérjük, adjon meg egy érvényes e-mail címet!",
"phone_invalid": "Kérjük, adjon meg egy érvényes telefonszámot!",
"contacts_saved": "Elérhetőségek sikeresen mentve!",
"contacts_save_error": "Hiba történt a mentés során. Kérjük, próbálja újra később.",
"settings_saved": "Beállítások sikeresen mentve! A változtatások érvényesítéséhez jelentkezzen be újra.",
"settings_save_error": "Hiba történt a mentés során. Kérjük, próbálja újra később.",
"password_fields_required": "Kérjük, töltse ki az összes mezőt!",
"passwords_not_match": "Az új jelszavak nem egyeznek!",
"password_too_short": "Az új jelszónak legalább 8 karakter hosszúnak kell lennie!",
"password_changed": "Jelszó sikeresen módosítva!",
"password_change_error": "Hiba történt a jelszó módosítása során. Kérjük, próbálja újra később."
},
"login": {
"title": "Bejelentkezés",
"username": "Felhasználónév",
"password": "Jelszó",
"login_button": "Bejelentkezés",
"forgot_password": "Elfelejtett jelszó",
"two_factor_title": "Kétfaktoros hitelesítés",
"verification_code": "Ellenőrző kód",
"username_placeholder": "Felhasználónév",
"password_placeholder": "Jelszó",
"username_required": "Kérjük, add meg a felhasználóneved.",
"password_required": "Kérjük, add meg a jelszavad.",
"help_login": "Nem tudsz bejelentkezni?",
"help_link": "Segítség",
"system_message": "Rendszerüzenet",
"privacy_policy": "Adatvédelmi szabályzat",
"kreta_id": "KRÉTA azonosító",
"system_notification": "Rendszerértesítés"
},
"forgot_password": {
"title": "Elfelejtett jelszó",
"om_id": "OM azonosítód",
"email": "E-mail cím",
"om_id_placeholder": "Add meg az OM azonosítód",
"email_placeholder": "Add meg az e-mail címed",
"om_id_required": "Kérjük, add meg az OM azonosítód.",
"email_required": "Kérjük, add meg az e-mail címed."
},
"two_factor": {
"title": "Kétfaktoros azonosítás",
"code_placeholder": "Egyszeri jelszó",
"code_required": "Kérjük, add meg az egyszeri jelszót.",
"verify_button": "Kód ellenőrzése",
"verifying": "Ellenőrzés...",
"trust_device": "Eszköz megbízhatónak jelölése"
},
"logout": {
"title": "Kijelentkezés",
"message": "Biztosan ki szeretne jelentkezni?",
"confirm": "Igen",
"cancel": "Mégse",
"success": "Sikeres kijelentkezés!",
"continue": "Tovább"
},
"common": {
"save": "Mentés",
"cancel": "Mégse",
"close": "Bezárás",
"loading": "Betöltés...",
"error": "Hiba",
"success": "Sikeres",
"warning": "Figyelmeztetés",
"info": "Információ",
"yes": "Igen",
"no": "Nem",
"continue": "Tovább",
"back": "Vissza",
"next": "Következő",
"previous": "Előző",
"all": "Összes",
"none": "Nincs",
"filter": "Szűrés",
"search": "Keresés",
"select": "Válassz",
"required": "Kötelező",
"optional": "Opcionális",
"api_error": "API hiba",
"api_load_error": "API betöltési hiba",
"monday": "hétfő",
"tuesday": "kedd",
"wednesday": "szerda",
"thursday": "csütörtök",
"friday": "péntek",
"saturday": "szombat",
"sunday": "vasárnap",
"today": "Ma",
"tomorrow": "Holnap"
},
"months": {
"january": "január",
"february": "február",
"march": "március",
"april": "április",
"may": "május",
"june": "június",
"july": "július",
"august": "augusztus",
"september": "szeptember",
"october": "október",
"november": "november",
"december": "december"
},
"search": {
"title": "Válassz iskolát",
"select_institution": "Kérjük, válasszon egy intézményt a folytatáshoz!"
},
"roleselect": {
"student_book": "Ellenőrzőkönyv",
"student_description": "Jegyek, hiányzások, órarended és egyéb információk megtekintése.",
"dkt_title": "Digitális Kollaborációs Tér (DKT)",
"dkt_description": "Osztálytermi kommunikáció és feladatok.",
"logout_title": "Kijelentkezés",
"logout_description": "Kilépés a rendszerből",
"role_change_error": "Hiba történt a szerepkör váltása közben."
},
"maintenance": {
"title": "Karbantartás",
"message1": "A KRÉTA rendszer jelenleg frissítés alatt van, hamarosan újra elérhetővé válik.",
"message2": "Köszönjük türelmüket és megértésüket!",
"team": "KRÉTA Csapat"
},
"about": {
"title": "Névjegy",
"description": "A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.",
"support_title": "Támogatás",
"support_description": "Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:",
"version": "v1.1.0"
},
"app": {
"title": "Firka - KRÉTA",
"settings_title": "Firxa - Beállítások"
}
}

BIN
images/cactus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
images/chrome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
images/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,28 +1,3 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
:root {
--icon-invert: 0.1;
--icon-sepia: 0.1;

View File

@@ -27,7 +27,7 @@ async function transformLoginPage() {
if (spanElement) {
const lines = spanElement.textContent?.split('\n').map(line => line.trim()) || [];
schoolInfo.kretaId = lines[0] || '';
schoolInfo.omCode = (lines[1] || '').replace('KRÉTA azonosító: ', '');
schoolInfo.omCode = (lines[1] || '').replace(`${LanguageManager.t('login.kreta_id')}: `, '');
}
const rawSystemMessage = document.querySelector('.alert-primary')?.textContent?.trim() || '';
@@ -44,7 +44,7 @@ async function transformLoginPage() {
<h1 class="school-name">${schoolInfo.name}</h1>
<div class="school-details">
${schoolInfo.kretaId ? `<div>${schoolInfo.kretaId}</div>` : ''}
${schoolInfo.omCode ? `<div>KRÉTA azonosító: ${schoolInfo.omCode}</div>` : ''}
${schoolInfo.omCode ? `<div>${LanguageManager.t('login.kreta_id')}: ${schoolInfo.omCode}</div>` : ''}
</div>
</div>
@@ -57,27 +57,27 @@ async function transformLoginPage() {
<div class="form-group">
<input class="form-control" type="text" id="UserName" name="UserName"
placeholder="Felhasználónév" maxlength="256" autocomplete="username" required value="${formData.userName}">
<div class="error-message">Kérjük, add meg a felhasználóneved.</div>
placeholder="${LanguageManager.t('login.username_placeholder')}" maxlength="256" autocomplete="username" required value="${formData.userName}">
<div class="error-message">${LanguageManager.t('login.username_required')}</div>
</div>
<div class="form-group password-group">
<input class="form-control" type="password" id="Password" name="Password"
placeholder="Jelszó" maxlength="256" autocomplete="current-password" required value="${formData.password}">
<button type="button" class="show-password" aria-label="Jelszó mutatása">
placeholder="${LanguageManager.t('login.password_placeholder')}" maxlength="256" autocomplete="current-password" required value="${formData.password}">
<button type="button" class="show-password" aria-label="${LanguageManager.t('login.show_password')}">
<img src="${chrome.runtime.getURL('icons/eye-off.svg')}" alt="Show password" class="icon-eye">
</button>
<div class="error-message">Kérjük, add meg a jelszavad.</div>
<div class="error-message">${LanguageManager.t('login.password_required')}</div>
</div>
<div class="form-actions">
<button type="submit" class="btn-login">
<span class="spinner"></span>
<span class="btn-text">Bejelentkezés</span>
<span class="btn-text">${LanguageManager.t('login.login_button')}</span>
</button>
<div class="help-links">
<a href="https://${schoolInfo.omCode ? `${schoolInfo.omCode}` : ''}.e-kreta.hu/Adminisztracio/ElfelejtettJelszo" class="help-link">Elfelejtettem a jelszavam</a>
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=2425086" target="_blank" class="help-link">Nem tudsz bejelentkezni?</a>
<a href="https://${schoolInfo.omCode ? `${schoolInfo.omCode}` : ''}.e-kreta.hu/Adminisztracio/ElfelejtettJelszo" class="help-link">${LanguageManager.t('login.forgot_password')}</a>
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=2425086" target="_blank" class="help-link">${LanguageManager.t('login.help_link')}</a>
</div>
</div>
</form>
@@ -85,14 +85,14 @@ async function transformLoginPage() {
${systemMessage ? `
<div class="system-message">
<h4>Rendszerértesítés</h4>
<h4>${LanguageManager.t('login.system_message')}</h4>
<p>${systemMessage}</p>
</div>
` : ''}
<footer class="login-footer">
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926"
target="_blank" class="privacy-link">Adatkezelési tájékoztató</a>
target="_blank" class="privacy-link">${LanguageManager.t('login.privacy_policy')}</a>
</footer>
</div>
`;

View File

@@ -1,28 +1,3 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
:root {
--icon-invert: 0.1;
--icon-sepia: 0.1;

View File

@@ -29,7 +29,7 @@ async function transformTwoFactorPage() {
<img src=${chrome.runtime.getURL('images/firka_logo.png')} alt="Firka" class="logo">
Firka
</p>
<h1 class="twofactor-title">Kétfaktoros azonosítás</h1>
<h1 class="twofactor-title">${LanguageManager.t('twofactor.title')}</h1>
</div>
<form class="twofactor-form" action="${formData.action}" method="post" id="twoFactorForm">
@@ -41,30 +41,30 @@ async function transformTwoFactorPage() {
<div class="form-group password-group">
<input class="form-control" type="password" id="VerificationCode" name="VerificationCode"
placeholder="Egyszeri jelszó" maxlength="256" autocomplete="off" required autofocus>
<button type="button" class="show-password" aria-label="Jelszó mutatása">
placeholder="${LanguageManager.t('twofactor.code_placeholder')}" maxlength="256" autocomplete="off" required autofocus>
<button type="button" class="show-password" aria-label="${LanguageManager.t('twofactor.show_code')}">
<img src="${chrome.runtime.getURL('icons/eye-off.svg')}" alt="Show password" class="icon-eye">
</button>
<div class="error-message">Kérjük, add meg az egyszeri jelszót.</div>
<div class="error-message">${LanguageManager.t('twofactor.code_required')}</div>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="trustDevice" name="TrustDevice" value="true">
<label class="form-check-label" for="trustDevice">
Eszköz megjelölése biztonságosként
${LanguageManager.t('twofactor.trust_device')}
</label>
<input name="TrustDevice" type="hidden" value="false">
</div>
<div class="d-flex justify-content-center mb-3 mt-4">
<button type="submit" class="btn-kreta">Kód ellenőrzése</button>
<button type="submit" class="btn-kreta">${LanguageManager.t('twofactor.verify_button')}</button>
</div>
<div class="d-flex justify-content-center mt-3">
<span class="subtext">
Nem fér hozzá eszközéhez? Lépjen be
${LanguageManager.t('twofactor.no_access')}
<button type="submit" class="btn-link" formaction="/account/loginwithrecoverycode">
helyreállító kóddal.
${LanguageManager.t('twofactor.recovery_code')}
</button>
</span>
</div>
@@ -73,7 +73,7 @@ async function transformTwoFactorPage() {
<footer class="login-footer">
<a href="https://tudasbazis.ekreta.hu/pages/viewpage.action?pageId=4064926"
target="_blank" class="privacy-link">Adatkezelési tájékoztató</a>
target="_blank" class="privacy-link">${LanguageManager.t('login.privacy_policy')}</a>
</footer>
</div>
`;
@@ -162,7 +162,7 @@ function handleSubmit(event) {
const submitButton = form.querySelector('.btn-kreta');
if (submitButton) {
submitButton.disabled = true;
submitButton.innerHTML = '<span class="spinner"></span><span class="btn-text">Ellenőrzés...</span>';
submitButton.innerHTML = `<span class="spinner"></span><span class="btn-text">${LanguageManager.t('twofactor.verifying')}</span>`;
}
form.submit();

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Firxa",
"version": "1.1.0",
"version": "1.2.2",
"description": "KRÉTA webes verziójának újraírása",
"icons": {
"128": "images/firka_logo_128.png"
@@ -15,10 +15,13 @@
"web_accessible_resources": [{
"resources": [
"settings/*",
"global/language.js",
"images/*",
"fonts/*.woff2",
"icons/*.svg",
"grades/chart.js"
"grades/chart.js",
"i18n/*.json",
"tools/cookieManager.js"
],
"matches": ["https://*.e-kreta.hu/*", "https://idp.e-kreta.hu/*"]
}],
@@ -28,7 +31,7 @@
"https://*.e-kreta.hu/*"
],
"js": ["tools/cookieManager.js", "tools/helper.js", "tools/loadingScreen.js", "tools/createTemplate.js",
"global/maintenance.js", "global/theme.js", "global/navigation.js"],
"global/language.js", "global/maintenance.js", "global/theme.js", "global/navigation.js"],
"css": ["tools/loadingScreen.css", "global/theme.css", "global/navigation.css"],
"run_at": "document_start"
},

View File

@@ -174,17 +174,17 @@
const phone = phoneInput.value.trim();
if (!email) {
alert('Az e-mail cím megadása kötelező!');
alert(LanguageManager.t('profile.email_required'));
return;
}
if (email && !isValidEmail(email)) {
alert('Kérjük, adjon meg egy érvényes e-mail címet!');
alert(LanguageManager.t('profile.invalid_email'));
return;
}
if (phone && !isValidPhone(phone)) {
alert('Kérjük, adjon meg egy érvényes telefonszámot!');
alert(LanguageManager.t('profile.invalid_phone'));
return;
}
@@ -199,13 +199,13 @@
});
if (response.ok) {
alert('Elérhetőségek sikeresen mentve!');
alert(LanguageManager.t('profile.contacts_saved'));
} else {
throw new Error('Hiba történt a mentés során.');
throw new Error(LanguageManager.t('profile.contacts_save_error'));
}
} catch (error) {
console.error('Error saving contacts:', error);
alert('Hiba történt a mentés során. Kérjük, próbálja újra később.');
alert(LanguageManager.t('profile.save_error'));
}
});
}
@@ -259,13 +259,13 @@
});
if (response.ok) {
alert('Beállítások sikeresen mentve! A változtatások érvényesítéséhez jelentkezzen be újra.');
alert(LanguageManager.t('profile.settings_saved'));
} else {
throw new Error('Hiba történt a mentés során.');
throw new Error(LanguageManager.t('profile.settings_save_error'));
}
} catch (error) {
console.error('Error saving settings:', error);
alert('Hiba történt a mentés során. Kérjük, próbálja újra később.');
alert(LanguageManager.t('profile.save_error'));
}
});
@@ -276,17 +276,17 @@
const confirmPassword = document.getElementById('confirmPassword').value;
if (!currentPassword || !newPassword || !confirmPassword) {
alert('Kérjük, töltse ki az összes mezőt!');
alert(LanguageManager.t('profile.fill_all_fields'));
return;
}
if (newPassword !== confirmPassword) {
alert('Az új jelszavak nem egyeznek!');
alert(LanguageManager.t('profile.passwords_not_match'));
return;
}
if (newPassword.length < 8) {
alert('Az új jelszónak legalább 8 karakter hosszúnak kell lennie!');
alert(LanguageManager.t('profile.password_min_length'));
return;
}
@@ -305,16 +305,16 @@
});
if (response.ok) {
alert('Jelszó sikeresen módosítva!');
alert(LanguageManager.t('profile.password_changed'));
document.getElementById('currentPassword').value = '';
document.getElementById('newPassword').value = '';
document.getElementById('confirmPassword').value = '';
} else {
throw new Error('Hiba történt a jelszó módosítása során.');
throw new Error(LanguageManager.t('profile.password_change_error'));
}
} catch (error) {
console.error('Error changing password:', error);
alert('Hiba történt a jelszó módosítása során. Kérjük, próbálja újra később.');
alert(LanguageManager.t('profile.password_change_error'));
}
});

View File

@@ -1,29 +1,3 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
box-sizing: border-box;
margin: 0;

View File

@@ -34,7 +34,7 @@
}
} catch (error) {
console.error('Error changing role:', error);
alert('Hiba történt a szerepkör váltása közben.');
alert(LanguageManager.t('roleselect.role_change_error'));
}
};
@@ -66,8 +66,8 @@
<img src="${chrome.runtime.getURL('icons/naplo.svg')}" alt="Napló ikon">
</div>
<div class="role-text">
Ellenőrzőkönyv
<div class="role-description">Jegyek, hiányzások, órarended és egyéb információk megtekintése.</div>
${LanguageManager.t('roleselect.student_book')}
<div class="role-description">${LanguageManager.t('roleselect.student_description')}</div>
</div>
</div>
</div>
@@ -78,8 +78,8 @@
<img src="${chrome.runtime.getURL('icons/dkt.svg')}" alt="DKT ikon">
</div>
<div class="role-text">
Digitális Kollaborációs Tér (DKT)
<div class="role-description">Osztálytermi kommunikáció és feladatok.</div>
${LanguageManager.t('roleselect.dkt_title')}
<div class="role-description">${LanguageManager.t('roleselect.dkt_description')}</div>
</div>
</div>
@@ -88,8 +88,8 @@
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés ikon">
</div>
<div class="role-text">
Kijelentkezés
<div class="role-description">Kilépés a rendszerből</div>
${LanguageManager.t('roleselect.logout_title')}
<div class="role-description">${LanguageManager.t('roleselect.logout_description')}</div>
</div>
</div>
</div>
@@ -113,7 +113,7 @@
const schoolSubdomain = window.location.hostname.split('.')[0];
const userNameEl = document.querySelector('.UserName');
const userName = userNameEl?.textContent.trim() || 'Felhasználónév';
const userName = userNameEl?.textContent.trim() || LanguageManager.t('common.username');
if (schoolCode && fullSchoolName) {

View File

@@ -1,28 +1,3 @@
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Montserrat';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Montserrat-SemiBold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
/* Hide original elements */
header, footer, .page-title, .card-kreta {
display: none !important;

View File

@@ -64,7 +64,7 @@ function applyFirkaStyling() {
redirectButton.addEventListener('click', function(event) {
if (!instituteCodeInput.value) {
event.preventDefault();
alert('Kérjük, válasszon egy intézményt a folytatáshoz!');
alert(LanguageManager.t('search.select_institution'));
}
});
}

View File

@@ -88,12 +88,14 @@ h2 {
}
.theme-grid {
.theme-grid,
.language-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.theme-option {
.theme-option,
.language-option {
background: none;
border: none;
padding: 0;
@@ -104,13 +106,18 @@ h2 {
gap: 8px;
transition: transform 0.2s ease;
}
.theme-option:hover {
.theme-option:hover,
.language-option:hover {
transform: translateY(-2px);
}
.theme-option.active .theme-preview {
outline: 2px solid var(--accent-accent);
outline-offset: 2px;
}
.language-option.active .language-preview {
outline: 2px solid var(--accent-accent);
outline-offset: 2px;
}
.theme-preview {
width: 100%;
height: 100px;
@@ -135,6 +142,31 @@ h2 {
border-radius: 8px;
}
.language-option {
background: var(--card-card);
border: 1px solid var(--border-border);
border-radius: 8px;
padding: 12px;
transition: all 0.2s ease;
}
.language-option:hover {
background: var(--card-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;
}
.theme-preview.light-blue {
background: #DAE4F7;

View File

@@ -23,12 +23,12 @@
</header>
<div class="settings-card">
<h2>Beállítások</h2>
<h2 data-i18n="settings.title">Beállítások</h2>
<div class="settings-group">
<div class="setting-section">
<div class="setting-header">
<span class="material-icons-round">palette</span>
Téma
<span data-i18n="settings.theme">Téma</span>
</div>
<div class="theme-grid">
<button class="theme-option" data-theme="default">
@@ -38,7 +38,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Világos Kék</span>
<span class="theme-name" data-i18n="settings.themes.light_blue">Világos Kék</span>
</button>
<button class="theme-option" data-theme="light-green">
<div class="theme-preview light-green">
@@ -47,7 +47,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Világos Zöld</span>
<span class="theme-name" data-i18n="settings.themes.light_green">Világos Zöld</span>
</button>
<button class="theme-option" data-theme="dark-blue">
<div class="theme-preview dark-blue">
@@ -56,7 +56,7 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Sötét Kék</span>
<span class="theme-name" data-i18n="settings.themes.dark_blue">Sötét Kék</span>
</button>
<button class="theme-option" data-theme="dark-green">
<div class="theme-preview dark-green">
@@ -65,7 +65,22 @@
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">Sötét Zöld</span>
<span class="theme-name" data-i18n="settings.themes.dark_green">Sötét Zöld</span>
</button>
</div>
</div>
<div class="setting-section">
<div class="setting-header">
<span class="material-icons-round">language</span>
<span data-i18n="settings.language">Nyelv</span>
</div>
<div class="language-grid">
<button class="language-option" data-language="hu">
<span class="language-name" data-i18n="settings.languages.hu">Magyar</span>
</button>
<button class="language-option" data-language="en">
<span class="language-name" data-i18n="settings.languages.en">English</span>
</button>
</div>
</div>
@@ -73,24 +88,24 @@
</div>
<div class="about-card">
<h2>Névjegy</h2>
<h2 data-i18n="settings.about.title">Névjegy</h2>
<div class="about-content">
<p>A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.</p>
<p data-i18n="settings.about.description">A Firka egy nyílt forráskódú projekt, amely a KRÉTA rendszerhez készít saját felhasználói felületet.</p>
<a href="https://github.com/QwIT-Development/" target="_blank" class="github-link">
<span class="material-icons-round">code</span>
GitHub
<span data-i18n="settings.about.github">GitHub</span>
</a>
</div>
</div>
<div class="support-card">
<h2>Támogatás</h2>
<h2 data-i18n="settings.support.title">Támogatás</h2>
<div class="support-content">
<p>Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:</p>
<p data-i18n="settings.support.description">Ha tetszik a munkánk és szeretnéd támogatni a fejlesztést, az alábbi módon teheted meg:</p>
<div class="support-buttons">
<a href="https://ko-fi.com/zan1456" target="_blank" class="support-button">
<span class="material-icons-round">coffee</span>
Ko-Fi
<span data-i18n="settings.support.kofi">Ko-Fi</span>
</a>
</div>
</div>
@@ -100,6 +115,8 @@
<div class="version-info" id="version">v1.1.0</div>
</footer>
</div>
<script src="index.js"></script>
<script src="../tools/cookieManager.js"></script>
<script src="../global/language.js"></script>
<script src="index.js"></script>
</body>
</html>

View File

@@ -1,4 +1,7 @@
document.addEventListener('DOMContentLoaded', async () => {
while (typeof window.LanguageManager === 'undefined') {
await new Promise(resolve => setTimeout(resolve, 10));
}
function isThemeDisabled(theme) {
const blueThemesUnlocked = localStorage.getItem('blueThemesUnlocked') === 'true';
@@ -59,6 +62,35 @@ document.addEventListener('DOMContentLoaded', async () => {
});
updateThemeAvailability();
}
function getCurrentLanguage() {
return localStorage.getItem('languagePreference') ||
getCookie('languagePreference') ||
'hu';
}
function updateLanguageButtons(currentLanguage) {
document.querySelectorAll('.language-option').forEach(button => {
const language = button.dataset.language;
button.classList.toggle('active', language === currentLanguage);
});
}
async function applyLanguage(language) {
setCookie('languagePreference', 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(() => {
});
});
}
async function applyTheme(theme) {
setCookie('themePreference', theme);
@@ -77,8 +109,6 @@ document.addEventListener('DOMContentLoaded', async () => {
action: 'changeTheme',
theme: theme
}).catch(() => {
console.log('Tab not ready for theme change:', tab.id);
});
});
}
@@ -91,7 +121,7 @@ document.addEventListener('DOMContentLoaded', async () => {
if (button.hasAttribute('disabled')) {
alert('Ez a téma jelenleg nem elérhető.');
alert(window.LanguageManager.t('common.warning') + ': ' + window.LanguageManager.t('settings.theme_not_available'));
return;
}
@@ -99,6 +129,14 @@ document.addEventListener('DOMContentLoaded', async () => {
});
});
const languageButtons = document.querySelectorAll('.language-option');
languageButtons.forEach(button => {
button.addEventListener('click', () => {
const language = button.dataset.language;
applyLanguage(language);
});
});
let initialTheme = getCurrentTheme();
@@ -111,6 +149,9 @@ document.addEventListener('DOMContentLoaded', async () => {
updateThemeAvailability();
await applyTheme(initialTheme);
const initialLanguage = getCurrentLanguage();
updateLanguageButtons(initialLanguage);
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'themeChanged') {
@@ -148,7 +189,7 @@ document.addEventListener('DOMContentLoaded', async () => {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
animation: slideIn 0.3s ease-out;
`;
notification.textContent = 'Kék témák feloldva! 🎉';
notification.textContent = window.LanguageManager.t('common.success') + ': ' + window.LanguageManager.t('settings.blue_themes_unlocked');
const style = document.createElement('style');
@@ -184,4 +225,18 @@ document.addEventListener('DOMContentLoaded', async () => {
button.style.transform = 'translateY(0)';
});
});
languageButtons.forEach(button => {
button.addEventListener('mouseover', () => {
button.style.transform = 'translateY(-2px)';
});
button.addEventListener('mouseout', () => {
button.style.transform = 'translateY(0)';
});
});
window.addEventListener('languageChanged', (event) => {
updateLanguageButtons(event.detail.language);
});
});

View File

@@ -1,32 +1,3 @@
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtZ6Hw5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: url(https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCu173w5aXp-p7K4KLg.woff2) format('woff2');
}
@font-face {
font-family: 'Figtree';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Figtree-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
box-sizing: border-box;
margin: 0;
@@ -55,7 +26,6 @@ body {
flex-direction: column;
}
/* Update header styles to match dashboard */
.kreta-header {
padding: clamp(1rem, 3vw, 2rem);
display: grid;
@@ -140,7 +110,6 @@ body {
}
}
/* User profile styles */
.user-profile {
position: relative;
justify-self: flex-end;
@@ -376,8 +345,8 @@ body {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--accent-15);
color: var(--accent-accent);
@@ -394,28 +363,57 @@ body {
}
.lesson-indicator .material-icons-round {
font-size: 14px;
font-size: 18px;
}
.week-controls {
display: flex;
gap: 16px;
flex-direction: column;
align-items: center;
margin: 16px;
justify-content: center;
margin: 16px auto;
background: var(--card-card);
border-radius: 24px;
max-width: 400px;
max-width: 800px;
padding: 20px;
}
.week-select {
flex: 1;
padding: 12px;
.week-selector-container {
width: 100%;
position: relative;
}
.expand-week-view-btn {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: none;
border-radius: 12px;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-family: inherit;
cursor: pointer;
transition: all 0.2s ease;
margin-left: 12px;
}
.expand-week-view-btn:hover {
background: var(--accent-15);
color: var(--accent-accent);
transform: scale(1.05);
}
.expand-week-view-btn .material-icons-round {
font-size: 18px;
}
.week-selector {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
max-width: 100%;
}
.week-nav-btn {
@@ -425,16 +423,336 @@ body {
width: 40px;
height: 40px;
border: none;
border-radius: 12px;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-secondary);
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s ease;
}
.week-nav-btn:hover {
.week-nav-btn:hover:not(:disabled) {
background: var(--accent-15);
color: var(--accent-accent);
transform: scale(1.05);
}
.week-nav-btn .material-icons-round {
font-size: 20px;
}
.week-display {
display: flex;
gap: 8px;
align-items: center;
}
.week-cell {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 60px;
height: 50px;
border: 2px solid var(--button-secondaryFill);
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
font-family: inherit;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
gap: 2px;
}
.week-cell:hover {
background: var(--accent-15);
border-color: var(--accent-accent);
color: var(--accent-accent);
transform: scale(1.05);
}
.week-cell.selected {
background: var(--accent-accent);
border-color: var(--accent-accent);
color: white;
font-weight: 600;
}
.week-cell.selected:hover {
background: var(--accent-accent);
transform: scale(1.05);
}
.week-cell.current-week {
border-color: var(--accent-accent);
box-shadow: 0 0 0 1px var(--accent-accent);
}
.week-cell.current-week.selected {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);
}
.week-number {
font-size: 14px;
font-weight: inherit;
}
.current-indicator {
font-size: 8px;
color: var(--accent-accent);
line-height: 1;
}
.week-cell.selected .current-indicator {
color: white;
}
.week-tooltip {
position: absolute;
background: var(--card-card);
border: 1px solid var(--border-border);
border-radius: 8px;
padding: 8px 12px;
font-size: 14px;
color: var(--text-primary);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease;
z-index: 1000;
white-space: nowrap;
}
.week-tooltip.show {
opacity: 1;
}
.week-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.week-modal-content {
background: var(--card-card);
border-radius: 16px;
max-width: 1000px;
max-height: 70vh;
width: 100%;
overflow: hidden;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}
.week-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid var(--border-border);
}
.week-modal-grid {
display: grid;
grid-template-columns: repeat(13, 1fr);
gap: 8px;
padding: 20px;
max-height: calc(70vh - 80px);
overflow-y: auto;
}
.modal-week-cell {
width: 40px;
height: 40px;
font-size: 12px;
}
@media (max-width: 768px) {
.week-modal-content {
max-width: 95vw;
max-height: 80vh;
}
.week-modal-grid {
grid-template-columns: repeat(10, 1fr);
gap: 6px;
padding: 16px;
max-height: calc(80vh - 80px);
}
.modal-week-cell {
width: 35px;
height: 35px;
font-size: 11px;
}
}
.week-modal-header h3 {
margin: 0;
color: var(--text-primary);
font-size: 20px;
font-weight: 600;
}
.week-modal-close {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: none;
border-radius: 8px;
background: var(--button-secondaryFill);
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s ease;
}
.week-modal-close:hover {
background: var(--accent-15);
color: var(--accent-accent);
}
.week-modal-close .material-icons-round {
font-size: 24px;
}
.week-modal-grid {
display: grid;
grid-template-columns: repeat(13, 1fr);
gap: 8px;
padding: 24px;
max-height: 70vh;
overflow-y: auto;
}
.week-modal-grid .week-cell {
width: 60px;
height: 50px;
font-size: 14px;
}
@media (max-width: 1200px) {
.week-modal-grid {
grid-template-columns: repeat(10, 1fr);
}
}
@media (max-width: 768px) {
.week-modal-grid {
grid-template-columns: repeat(7, 1fr);
gap: 6px;
}
.week-modal-grid .week-cell {
width: 50px;
height: 45px;
font-size: 12px;
}
.week-modal-content {
margin: 10px;
}
.week-modal-header {
padding: 16px 20px;
}
.week-modal-grid {
padding: 20px;
}
}
@media (max-width: 768px) {
.week-grid {
grid-template-columns: repeat(10, 1fr);
gap: 6px;
}
.week-cell {
width: 40px;
height: 35px;
font-size: 12px;
}
.week-controls {
max-width: 600px;
padding: 15px;
}
}
@media (max-width: 480px) {
.week-grid {
grid-template-columns: repeat(8, 1fr);
gap: 4px;
}
.week-cell {
width: 35px;
height: 30px;
font-size: 11px;
}
.week-controls {
max-width: 400px;
padding: 12px;
}
}
.day-navigation {
display: none;
align-items: center;
justify-content: space-between;
margin-bottom: 1rem;
padding: 0 1rem;
}
.day-nav-btn {
background: var(--card-card);
border: 1px solid var(--accent-15);
border-radius: 12px;
padding: 12px 16px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
.day-nav-btn:hover {
background: var(--accent-15);
color: var(--accent-accent);
}
.current-day-info {
text-align: center;
flex: 1;
margin: 0 1rem;
}
.current-day-name {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 4px;
}
.current-day-date {
font-size: 14px;
color: var(--text-secondary);
}
@media (max-width: 1024px) {
@@ -448,9 +766,33 @@ body {
}
@media (max-width: 768px) {
.day-navigation {
display: flex;
}
.timetable-container {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
overflow: hidden;
}
.timetable-grid {
grid-template-columns: 60px 1fr;
overflow: visible;
}
.grid-header:not(:first-child) {
display: none;
}
.grid-header.active {
display: flex !important;
}
.lesson-slot {
display: none;
}
.lesson-slot.active {
display: block;
}
.lesson-card {
@@ -601,7 +943,6 @@ body {
display: none;
}
/* Animations */
@keyframes fadeIn {
from {
opacity: 0;
@@ -635,7 +976,6 @@ body {
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.kreta-header {
flex-direction: column;
@@ -651,7 +991,6 @@ body {
}
}
/* Scrollbar styling */
::-webkit-scrollbar {
width: 8px;
height: 8px;
@@ -668,4 +1007,85 @@ body {
::-webkit-scrollbar-thumb:hover {
background: var(--text-primary);
}
.grid-header.special-day {
background: linear-gradient(135deg, #F99F50, #FF8C42);
color: white;
position: relative;
}
.special-day-indicator {
display: block;
font-size: 0.7rem;
font-weight: 500;
margin-top: 2px;
opacity: 0.9;
text-align: center;
}
.special-day-card {
background: #F99F50;
color: white;
padding: 12px;
border-radius: 8px;
margin: 4px;
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.special-day-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.special-day-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 4px;
}
.special-day-subtitle {
font-size: 0.9rem;
opacity: 0.9;
font-weight: 400;
}
.week-select {
min-width: 200px;
max-width: 300px;
}
@media (max-width: 768px) {
.special-day-indicator {
font-size: 0.6rem;
}
.special-day-card {
padding: 8px;
margin: 2px;
}
.special-day-title {
font-size: 0.8rem;
}
.special-day-subtitle {
font-size: 0.7rem;
}
}
.more-link {
margin-top: auto;
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--accent-accent);
text-decoration: none;
font-weight: 500;
padding-top: 16px;
transition: gap 0.2s ease;
font-size: clamp(0.875rem, 1.5vw, 1rem);
}

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ const createTemplate = {
</div>
</div>
<button class="nav-toggle" aria-label="Navigáció megnyitása">
<button class="nav-toggle" aria-label="${LanguageManager.t('navigation.nav_toggle')}">
<svg viewBox="0 0 24 24">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
</svg>
@@ -37,24 +37,24 @@ const createTemplate = {
<nav class="kreta-nav">
<div class="nav-links">
<a href="/Intezmeny/Faliujsag" data-page="dashboard" class="nav-item ${( location.pathname == '/Intezmeny/Faliujsag' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/dashboard-' + ( location.pathname == '/Intezmeny/Faliujsag' ? 'active' : 'inactive') + '.svg')}" alt="Kezdőlap">
Kezdőlap
<img src="${chrome.runtime.getURL('icons/dashboard-' + ( location.pathname == '/Intezmeny/Faliujsag' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.dashboard')}">
${LanguageManager.t('navigation.dashboard')}
</a>
<a href="/TanuloErtekeles/Osztalyzatok" data-page="grades" class="nav-item ${( location.pathname == '/TanuloErtekeles/Osztalyzatok' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/grades-' + ( location.pathname == '/TanuloErtekeles/Osztalyzatok' ? 'active' : 'inactive') + '.svg')}" alt="Jegyek">
Jegyek
<img src="${chrome.runtime.getURL('icons/grades-' + ( location.pathname == '/TanuloErtekeles/Osztalyzatok' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.grades')}">
${LanguageManager.t('navigation.grades')}
</a>
<a href="/Orarend/InformaciokOrarend" data-page="timetable" class="nav-item ${( location.pathname == '/Orarend/InformaciokOrarend' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/timetable-' + ( location.pathname == '/Orarend/InformaciokOrarend' ? 'active' : 'inactive') + '.svg')}" alt="Órarend">
Órarend
<img src="${chrome.runtime.getURL('icons/timetable-' + ( location.pathname == '/Orarend/InformaciokOrarend' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.timetable')}">
${LanguageManager.t('navigation.timetable')}
</a>
<a href="/Hianyzas/Hianyzasok" data-page="absences" class="nav-item ${( location.pathname == '/Hianyzas/Hianyzasok' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/absences-' + ( location.pathname == '/Hianyzas/Hianyzasok' ? 'active' : 'inactive') + '.svg')}" alt="Mulasztások">
Mulasztások
<img src="${chrome.runtime.getURL('icons/absences-' + ( location.pathname == '/Hianyzas/Hianyzasok' ? 'active' : 'inactive') + '.svg')}" alt="${LanguageManager.t('navigation.absences')}">
${LanguageManager.t('navigation.absences')}
</a>
<a href="/Tanulo/TanuloHaziFeladat" data-page="other" class="nav-item ${( location.pathname == '/Tanulo/TanuloHaziFeladat' ? 'active' : '')}">
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="Egyéb">
Egyéb
<img src="${chrome.runtime.getURL('icons/others.svg')}" alt="${LanguageManager.t('navigation.other')}">
${LanguageManager.t('navigation.other')}
</a>
</div>
</nav>
@@ -68,16 +68,16 @@ const createTemplate = {
</button>
<div class="user-dropdown">
<a href="/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="Profil">
Profil
<img src="${chrome.runtime.getURL('icons/profile.svg')}" alt="${LanguageManager.t('navigation.profile')}">
${LanguageManager.t('navigation.profile')}
</a>
<a href="#" class="dropdown-item" id="settingsBtn">
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="Beállítások">
Beállítások
<img src="${chrome.runtime.getURL('icons/settings.svg')}" alt="${LanguageManager.t('navigation.settings')}">
${LanguageManager.t('navigation.settings')}
</a>
<a href="/Home/Logout" data-page="logout" class="dropdown-item">
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="Kijelentkezés">
Kijelentkezés
<img src="${chrome.runtime.getURL('icons/logout.svg')}" alt="${LanguageManager.t('navigation.logout')}">
${LanguageManager.t('navigation.logout')}
</a>
</div>
</div>
@@ -111,6 +111,7 @@ const createTemplate = {
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/icon?family=Material+Icons+Round' }
];

View File

@@ -9,8 +9,8 @@ const loadingScreen = {
loadingScreen.innerHTML = `
<div class="loading-content">
<img src="${chrome.runtime.getURL('images/loading.gif')}" alt="Firka" class="loading-logo">
<div class="loading-text">Betöltés alatt...</div>
<div class="loading-text2">Kis türelmet!</div>
<div class="loading-text" data-i18n="loading.text">Betöltés alatt...</div>
<div class="loading-text2" data-i18n="loading.subtext">Kis türelmet!</div>
</div>
`;
document.body.appendChild(loadingScreen);
@@ -22,9 +22,15 @@ const loadingScreen = {
const loadingScreen = document.querySelector('.loading-screen');
if (loadingScreen) {
loadingScreen.style.opacity = '0';
loadingScreen.addEventListener('transitionend', () => {
loadingScreen.remove();
});
const removeLoadingScreen = () => {
if (loadingScreen && loadingScreen.parentNode) {
loadingScreen.remove();
}
};
loadingScreen.addEventListener('transitionend', removeLoadingScreen, { once: true });
setTimeout(removeLoadingScreen, 500);
}
}
}