mirror of
https://github.com/QwIT-Development/firka-extension.git
synced 2026-06-12 11:51:39 +02:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b36adf8ebf | ||
|
|
6d9a45941b | ||
|
|
581c8ba1d5 | ||
|
|
56182279f3 | ||
|
|
33da0de509 | ||
|
|
486f33efcf | ||
|
|
b35154f906 | ||
|
|
f984f9e7a2 | ||
|
|
92e0397c61 | ||
|
|
a26163f41d | ||
|
|
bf1ad731fb | ||
|
|
4ded1cce20 |
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,7 @@ async function collectAbsencesData() {
|
||||
|
||||
absences.push({
|
||||
date: formattedDate,
|
||||
rawDate: date,
|
||||
lesson: item.Oraszam?.toString() || "",
|
||||
subject: item.Targy || "",
|
||||
topic: item.Tema || "",
|
||||
@@ -59,12 +60,19 @@ async function collectAbsencesData() {
|
||||
});
|
||||
}
|
||||
|
||||
const groupedAbsences = {};
|
||||
absences.forEach((absence) => {
|
||||
if (!groupedAbsences[absence.date]) {
|
||||
groupedAbsences[absence.date] = [];
|
||||
|
||||
const groupedAbsences = absences.reduce((groups, absence) => {
|
||||
const date = absence.date;
|
||||
if (!groups[date]) {
|
||||
groups[date] = [];
|
||||
}
|
||||
groupedAbsences[absence.date].push(absence);
|
||||
groups[date].push(absence);
|
||||
return groups;
|
||||
}, {});
|
||||
|
||||
|
||||
Object.keys(groupedAbsences).forEach(date => {
|
||||
groupedAbsences[date].sort((a, b) => parseInt(a.lesson) - parseInt(b.lesson));
|
||||
});
|
||||
|
||||
return { basicData, absences, groupedAbsences };
|
||||
@@ -86,20 +94,87 @@ function createFilterCard(absences) {
|
||||
|
||||
const filterContent = document.createElement('div');
|
||||
filterContent.className = 'filter-content';
|
||||
|
||||
const dateGroup = document.createElement('div');
|
||||
dateGroup.className = 'filter-group';
|
||||
|
||||
const dateGroup = createFilterGroup(
|
||||
'Calendar.svg',
|
||||
'Dátum',
|
||||
LanguageManager.t('absences.date'),
|
||||
'input',
|
||||
{ type: 'date', id: 'dateFilter', className: 'filter-input' }
|
||||
);
|
||||
const dateLabel = document.createElement('label');
|
||||
const dateImg = document.createElement('img');
|
||||
dateImg.src = chrome.runtime.getURL('icons/Calendar.svg');
|
||||
dateImg.alt = 'Dátum';
|
||||
dateLabel.appendChild(dateImg);
|
||||
dateLabel.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.date')));
|
||||
|
||||
const dateInput = document.createElement('input');
|
||||
dateInput.type = 'date';
|
||||
dateInput.id = 'dateFilter';
|
||||
dateInput.className = 'filter-input';
|
||||
|
||||
dateGroup.appendChild(dateLabel);
|
||||
dateGroup.appendChild(dateInput);
|
||||
filterContent.appendChild(dateGroup);
|
||||
|
||||
const subjectGroup = createSubjectFilterGroup(absences);
|
||||
const subjectGroup = document.createElement('div');
|
||||
subjectGroup.className = 'filter-group';
|
||||
|
||||
const subjectLabel = document.createElement('label');
|
||||
const subjectImg = document.createElement('img');
|
||||
subjectImg.src = chrome.runtime.getURL('icons/Subject.svg');
|
||||
subjectImg.alt = 'Tantárgy';
|
||||
subjectLabel.appendChild(subjectImg);
|
||||
subjectLabel.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.subject')));
|
||||
|
||||
const subjectSelect = document.createElement('select');
|
||||
subjectSelect.id = 'subjectFilter';
|
||||
subjectSelect.className = 'filter-input';
|
||||
|
||||
const defaultSubjectOption = document.createElement('option');
|
||||
defaultSubjectOption.value = '';
|
||||
defaultSubjectOption.textContent = LanguageManager.t('absences.all_subjects');
|
||||
subjectSelect.appendChild(defaultSubjectOption);
|
||||
|
||||
const subjects = [...new Set(absences.map(a => a.subject))].sort();
|
||||
subjects.forEach(subject => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subject;
|
||||
option.textContent = subject;
|
||||
subjectSelect.appendChild(option);
|
||||
});
|
||||
|
||||
subjectGroup.appendChild(subjectLabel);
|
||||
subjectGroup.appendChild(subjectSelect);
|
||||
filterContent.appendChild(subjectGroup);
|
||||
|
||||
const justificationGroup = createJustificationFilterGroup();
|
||||
const justificationGroup = document.createElement('div');
|
||||
justificationGroup.className = 'filter-group';
|
||||
|
||||
const justificationLabel = document.createElement('label');
|
||||
const justificationImg = document.createElement('img');
|
||||
justificationImg.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
|
||||
justificationImg.alt = 'Igazolás';
|
||||
justificationLabel.appendChild(justificationImg);
|
||||
justificationLabel.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justification')));
|
||||
|
||||
const justificationSelect = document.createElement('select');
|
||||
justificationSelect.id = 'justificationFilter';
|
||||
justificationSelect.className = 'filter-input';
|
||||
|
||||
const justificationOptions = [
|
||||
{ value: '', text: LanguageManager.t('absences.all_types') },
|
||||
{ value: 'justified', text: LanguageManager.t('absences.justified') },
|
||||
{ value: 'unjustified', text: LanguageManager.t('absences.unjustified') },
|
||||
{ value: 'pending', text: LanguageManager.t('absences.pending') }
|
||||
];
|
||||
|
||||
justificationOptions.forEach(optionData => {
|
||||
const option = document.createElement('option');
|
||||
option.value = optionData.value;
|
||||
option.textContent = optionData.text;
|
||||
justificationSelect.appendChild(option);
|
||||
});
|
||||
|
||||
justificationGroup.appendChild(justificationLabel);
|
||||
justificationGroup.appendChild(justificationSelect);
|
||||
filterContent.appendChild(justificationGroup);
|
||||
|
||||
filterCard.appendChild(filterHeader);
|
||||
@@ -108,118 +183,40 @@ function createFilterCard(absences) {
|
||||
return filterCard;
|
||||
}
|
||||
|
||||
function createFilterGroup(iconName, altText, labelText, elementType, attributes) {
|
||||
const group = document.createElement('div');
|
||||
group.className = 'filter-group';
|
||||
function createStatsSection(absences) {
|
||||
const statsSection = document.createElement('div');
|
||||
statsSection.className = 'stats-section';
|
||||
|
||||
const label = document.createElement('label');
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL(`icons/${iconName}`);
|
||||
img.alt = altText;
|
||||
img.style.width = '24px';
|
||||
img.style.height = '24px';
|
||||
|
||||
label.appendChild(img);
|
||||
label.appendChild(document.createTextNode(' ' + labelText));
|
||||
|
||||
const element = document.createElement(elementType);
|
||||
Object.assign(element, attributes);
|
||||
|
||||
group.appendChild(label);
|
||||
group.appendChild(element);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
function createSubjectFilterGroup(absences) {
|
||||
const group = document.createElement('div');
|
||||
group.className = 'filter-group';
|
||||
|
||||
const label = document.createElement('label');
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL('icons/Subject.svg');
|
||||
img.alt = 'Tantárgy';
|
||||
img.style.width = '24px';
|
||||
img.style.height = '24px';
|
||||
|
||||
label.appendChild(img);
|
||||
label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.subject')));
|
||||
|
||||
const select = document.createElement('select');
|
||||
select.id = 'subjectFilter';
|
||||
select.className = 'filter-input';
|
||||
|
||||
const defaultOption = document.createElement('option');
|
||||
defaultOption.value = '';
|
||||
defaultOption.textContent = LanguageManager.t('absences.all_subjects');
|
||||
select.appendChild(defaultOption);
|
||||
|
||||
const subjects = [...new Set(absences.map(a => a.subject))].sort();
|
||||
subjects.forEach(subject => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subject;
|
||||
option.textContent = subject;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
group.appendChild(label);
|
||||
group.appendChild(select);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
function createJustificationFilterGroup() {
|
||||
const group = document.createElement('div');
|
||||
group.className = 'filter-group';
|
||||
|
||||
const label = document.createElement('label');
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
|
||||
img.alt = 'Igazolás';
|
||||
img.style.width = '24px';
|
||||
img.style.height = '24px';
|
||||
|
||||
label.appendChild(img);
|
||||
label.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justification')));
|
||||
|
||||
const select = document.createElement('select');
|
||||
select.id = 'justificationFilter';
|
||||
select.className = 'filter-input';
|
||||
|
||||
const options = [
|
||||
{ value: '', text: LanguageManager.t('absences.all_types') },
|
||||
{ value: 'justified', text: LanguageManager.t('absences.justified') },
|
||||
{ value: 'unjustified', text: LanguageManager.t('absences.unjustified') },
|
||||
{ value: 'pending', text: LanguageManager.t('absences.pending') }
|
||||
];
|
||||
|
||||
options.forEach(optionData => {
|
||||
const option = document.createElement('option');
|
||||
option.value = optionData.value;
|
||||
option.textContent = optionData.text;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
group.appendChild(label);
|
||||
group.appendChild(select);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
function createStatsOverview(absences) {
|
||||
const statsOverview = document.createElement('div');
|
||||
statsOverview.className = 'stats-overview';
|
||||
const statsGrid = document.createElement('div');
|
||||
statsGrid.className = 'stats-grid';
|
||||
|
||||
const stats = [
|
||||
{ number: absences.length, label: LanguageManager.t('absences.total_absences') },
|
||||
{ number: absences.filter(a => a.justificationStatus === 'justified').length, label: LanguageManager.t('absences.justified') },
|
||||
{ number: absences.filter(a => a.justificationStatus === 'unjustified').length, label: LanguageManager.t('absences.unjustified') },
|
||||
{ number: absences.filter(a => a.justificationStatus === 'pending').length, label: LanguageManager.t('absences.pending') }
|
||||
{
|
||||
type: 'total',
|
||||
number: absences.length,
|
||||
label: LanguageManager.t('absences.total_absences')
|
||||
},
|
||||
{
|
||||
type: 'justified',
|
||||
number: absences.filter(a => a.justificationStatus === 'justified').length,
|
||||
label: LanguageManager.t('absences.justified')
|
||||
},
|
||||
{
|
||||
type: 'unjustified',
|
||||
number: absences.filter(a => a.justificationStatus === 'unjustified').length,
|
||||
label: LanguageManager.t('absences.unjustified')
|
||||
},
|
||||
{
|
||||
type: 'pending',
|
||||
number: absences.filter(a => a.justificationStatus === 'pending').length,
|
||||
label: LanguageManager.t('absences.pending')
|
||||
}
|
||||
];
|
||||
|
||||
stats.forEach(stat => {
|
||||
const statCard = document.createElement('div');
|
||||
statCard.className = 'stat-card';
|
||||
statCard.className = `stat-card ${stat.type}`;
|
||||
statCard.dataset.type = stat.type;
|
||||
|
||||
const statNumber = document.createElement('div');
|
||||
statNumber.className = 'stat-number';
|
||||
@@ -231,54 +228,179 @@ function createStatsOverview(absences) {
|
||||
|
||||
statCard.appendChild(statNumber);
|
||||
statCard.appendChild(statLabel);
|
||||
statsOverview.appendChild(statCard);
|
||||
statsGrid.appendChild(statCard);
|
||||
});
|
||||
|
||||
return statsOverview;
|
||||
statsSection.appendChild(statsGrid);
|
||||
return statsSection;
|
||||
}
|
||||
|
||||
function createAbsencesContainer(absences) {
|
||||
const container = document.createElement('div');
|
||||
container.className = 'absences-container';
|
||||
function createDayGroup(date, dayAbsences) {
|
||||
const dayGroup = document.createElement('div');
|
||||
dayGroup.className = 'day-group';
|
||||
dayGroup.dataset.date = date;
|
||||
|
||||
const table = document.createElement('table');
|
||||
table.className = 'absences-table';
|
||||
|
||||
const thead = document.createElement('thead');
|
||||
thead.className = 'table-header';
|
||||
const dayHeader = document.createElement('div');
|
||||
dayHeader.className = 'day-header';
|
||||
|
||||
const headerRow = document.createElement('tr');
|
||||
const headers = [
|
||||
LanguageManager.t('absences.date'),
|
||||
LanguageManager.t('absences.lesson'),
|
||||
LanguageManager.t('absences.subject'),
|
||||
LanguageManager.t('absences.topic'),
|
||||
LanguageManager.t('absences.status')
|
||||
];
|
||||
const dayDate = document.createElement('div');
|
||||
dayDate.className = 'day-date';
|
||||
|
||||
headers.forEach(headerText => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = headerText;
|
||||
headerRow.appendChild(th);
|
||||
const calendarIcon = document.createElement('img');
|
||||
calendarIcon.src = chrome.runtime.getURL('icons/Calendar.svg');
|
||||
calendarIcon.alt = 'Dátum';
|
||||
|
||||
const dateText = document.createElement('span');
|
||||
dateText.textContent = formatDateWithDay(date);
|
||||
|
||||
dayDate.appendChild(calendarIcon);
|
||||
dayDate.appendChild(dateText);
|
||||
|
||||
const dayCount = document.createElement('div');
|
||||
dayCount.className = 'day-count';
|
||||
dayCount.textContent = `${dayAbsences.length} ${LanguageManager.t('absences.hours')}`;
|
||||
|
||||
dayHeader.appendChild(dayDate);
|
||||
dayHeader.appendChild(dayCount);
|
||||
|
||||
const dayAbsencesContainer = document.createElement('div');
|
||||
dayAbsencesContainer.className = 'day-absences';
|
||||
|
||||
dayAbsences.forEach(absence => {
|
||||
const absenceCard = createAbsenceCard(absence);
|
||||
dayAbsencesContainer.appendChild(absenceCard);
|
||||
});
|
||||
|
||||
thead.appendChild(headerRow);
|
||||
dayGroup.appendChild(dayHeader);
|
||||
dayGroup.appendChild(dayAbsencesContainer);
|
||||
|
||||
const tbody = document.createElement('tbody');
|
||||
generateAbsencesRows(absences, tbody);
|
||||
return dayGroup;
|
||||
}
|
||||
|
||||
function formatDateWithDay(dateStr) {
|
||||
const parts = dateStr.split('.');
|
||||
const year = parseInt(parts[0]);
|
||||
const month = parseInt(parts[1]) - 1;
|
||||
const day = parseInt(parts[2]);
|
||||
|
||||
table.appendChild(thead);
|
||||
table.appendChild(tbody);
|
||||
container.appendChild(table);
|
||||
const date = new Date(year, month, day);
|
||||
const days = [
|
||||
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 container;
|
||||
const dayName = days[date.getDay()];
|
||||
return `${dateStr} - ${dayName.charAt(0).toUpperCase() + dayName.slice(1)}`;
|
||||
}
|
||||
|
||||
function createAbsenceCard(absence) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'absence-card';
|
||||
card.dataset.subject = absence.subject;
|
||||
card.dataset.status = absence.justificationStatus;
|
||||
card.dataset.date = absence.date;
|
||||
|
||||
const lessonDiv = document.createElement('div');
|
||||
lessonDiv.className = 'absence-lesson';
|
||||
lessonDiv.textContent = absence.lesson + '.';
|
||||
|
||||
const subjectDiv = document.createElement('div');
|
||||
subjectDiv.className = 'absence-subject';
|
||||
subjectDiv.textContent = absence.subject;
|
||||
|
||||
const topicDiv = document.createElement('div');
|
||||
topicDiv.className = 'absence-topic';
|
||||
topicDiv.textContent = absence.topic || '-';
|
||||
topicDiv.title = absence.topic;
|
||||
|
||||
const statusDiv = document.createElement('div');
|
||||
statusDiv.className = 'absence-status';
|
||||
|
||||
const statusBadge = document.createElement('span');
|
||||
statusBadge.className = `status-badge ${absence.justificationStatus}`;
|
||||
|
||||
if (absence.justificationStatus === 'justified') {
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
|
||||
img.alt = 'Igazolt';
|
||||
statusBadge.appendChild(img);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justified')));
|
||||
} else if (absence.justificationStatus === 'unjustified') {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'material-icons-round';
|
||||
span.textContent = 'cancel';
|
||||
statusBadge.appendChild(span);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.unjustified')));
|
||||
} else {
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL('icons/pending.svg');
|
||||
img.alt = 'Függőben';
|
||||
statusBadge.appendChild(img);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.pending')));
|
||||
}
|
||||
|
||||
statusDiv.appendChild(statusBadge);
|
||||
|
||||
card.appendChild(lessonDiv);
|
||||
card.appendChild(subjectDiv);
|
||||
card.appendChild(topicDiv);
|
||||
card.appendChild(statusDiv);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
function createAbsencesContent(groupedAbsences) {
|
||||
const content = document.createElement('div');
|
||||
content.className = 'absences-content';
|
||||
|
||||
const sortedDates = Object.keys(groupedAbsences).sort((a, b) => {
|
||||
const dateA = new Date(a.replace(/\./g, '-').slice(0, -1));
|
||||
const dateB = new Date(b.replace(/\./g, '-').slice(0, -1));
|
||||
return dateB - dateA;
|
||||
});
|
||||
|
||||
if (sortedDates.length === 0) {
|
||||
const emptyState = document.createElement('div');
|
||||
emptyState.className = 'empty-state';
|
||||
|
||||
const emptyIcon = document.createElement('img');
|
||||
emptyIcon.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
|
||||
emptyIcon.alt = 'Nincs hiányzás';
|
||||
|
||||
const emptyTitle = document.createElement('h3');
|
||||
emptyTitle.textContent = LanguageManager.t('absences.title');
|
||||
|
||||
const emptyText = document.createElement('p');
|
||||
emptyText.textContent = LanguageManager.t('dashboard.not_supported');
|
||||
|
||||
emptyState.appendChild(emptyIcon);
|
||||
emptyState.appendChild(emptyTitle);
|
||||
emptyState.appendChild(emptyText);
|
||||
content.appendChild(emptyState);
|
||||
} else {
|
||||
sortedDates.forEach(date => {
|
||||
const dayGroup = createDayGroup(date, groupedAbsences[date]);
|
||||
content.appendChild(dayGroup);
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
async function transformAbsencesPage() {
|
||||
const { basicData, absences, groupedAbsences } = await collectAbsencesData();
|
||||
|
||||
document.body.textContent = '';
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.className = 'kreta-container';
|
||||
|
||||
const headerDiv = document.createElement('div');
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(await createTemplate.header(), 'text/html');
|
||||
@@ -287,244 +409,59 @@ async function transformAbsencesPage() {
|
||||
headerDiv.appendChild(tempDiv.firstChild);
|
||||
}
|
||||
container.appendChild(headerDiv);
|
||||
|
||||
const main = document.createElement('main');
|
||||
main.className = 'kreta-main';
|
||||
const filterCard = createFilterCard(absences);
|
||||
main.appendChild(filterCard);
|
||||
const statsOverview = createStatsOverview(absences);
|
||||
main.appendChild(statsOverview);
|
||||
const absencesContainer = createAbsencesContainer(absences);
|
||||
main.appendChild(absencesContainer);
|
||||
|
||||
const pageGrid = document.createElement('div');
|
||||
pageGrid.className = 'absences-page';
|
||||
|
||||
const sidebar = document.createElement('div');
|
||||
sidebar.className = 'absences-sidebar';
|
||||
const filterCard = createFilterCard(absences);
|
||||
sidebar.appendChild(filterCard);
|
||||
|
||||
const statsSection = createStatsSection(absences);
|
||||
sidebar.appendChild(statsSection);
|
||||
|
||||
const absencesContent = createAbsencesContent(groupedAbsences);
|
||||
|
||||
pageGrid.appendChild(sidebar);
|
||||
pageGrid.appendChild(absencesContent);
|
||||
|
||||
main.appendChild(pageGrid);
|
||||
container.appendChild(main);
|
||||
document.body.appendChild(container);
|
||||
|
||||
|
||||
setupUserDropdown();
|
||||
setupMobileNavigation();
|
||||
|
||||
setupEventListeners();
|
||||
setupFilters();
|
||||
setupFilters(groupedAbsences);
|
||||
|
||||
loadingScreen.hide();
|
||||
}
|
||||
|
||||
function generateAbsencesRows(absences, tbody) {
|
||||
const groupedByDate = absences.reduce((groups, absence) => {
|
||||
const date = absence.date;
|
||||
if (!groups[date]) {
|
||||
groups[date] = [];
|
||||
}
|
||||
groups[date].push(absence);
|
||||
return groups;
|
||||
}, {});
|
||||
|
||||
const sortedDates = Object.keys(groupedByDate).sort(
|
||||
(a, b) => new Date(b) - new Date(a),
|
||||
);
|
||||
|
||||
sortedDates.forEach((date) => {
|
||||
const dateAbsences = groupedByDate[date];
|
||||
const divider = document.createElement('tr');
|
||||
divider.className = 'date-group-divider';
|
||||
divider.style.display = 'none';
|
||||
tbody.appendChild(divider);
|
||||
|
||||
dateAbsences.forEach((absence) => {
|
||||
const row = document.createElement('tr');
|
||||
row.className = 'table-row';
|
||||
row.dataset.subject = absence.subject;
|
||||
row.dataset.justified = absence.justified;
|
||||
row.dataset.date = absence.date;
|
||||
row.dataset.dateGroup = date;
|
||||
|
||||
const dateCell = document.createElement('td');
|
||||
dateCell.className = 'table-cell date-cell';
|
||||
dateCell.dataset.label = LanguageManager.t('absences.date');
|
||||
dateCell.textContent = absence.date;
|
||||
row.appendChild(dateCell);
|
||||
|
||||
const lessonCell = document.createElement('td');
|
||||
lessonCell.className = 'table-cell lesson-cell';
|
||||
lessonCell.dataset.label = LanguageManager.t('absences.lesson');
|
||||
lessonCell.textContent = absence.lesson + '.';
|
||||
row.appendChild(lessonCell);
|
||||
|
||||
const subjectCell = document.createElement('td');
|
||||
subjectCell.className = 'table-cell subject-cell';
|
||||
subjectCell.dataset.label = LanguageManager.t('absences.subject');
|
||||
subjectCell.textContent = absence.subject;
|
||||
row.appendChild(subjectCell);
|
||||
|
||||
const topicCell = document.createElement('td');
|
||||
topicCell.className = 'table-cell topic-cell';
|
||||
topicCell.dataset.label = LanguageManager.t('absences.topic');
|
||||
topicCell.title = absence.topic;
|
||||
topicCell.textContent = absence.topic;
|
||||
row.appendChild(topicCell);
|
||||
|
||||
const statusCell = document.createElement('td');
|
||||
statusCell.className = 'table-cell status-cell';
|
||||
statusCell.dataset.label = LanguageManager.t('absences.status');
|
||||
|
||||
const statusBadge = document.createElement('span');
|
||||
statusBadge.className = `status-badge ${absence.justificationStatus}`;
|
||||
|
||||
if (absence.justificationStatus === 'justified') {
|
||||
const img = document.createElement('img');
|
||||
img.src = chrome.runtime.getURL('icons/BadgeCheck.svg');
|
||||
img.alt = 'Igazolt';
|
||||
img.style.width = '16px';
|
||||
img.style.height = '16px';
|
||||
statusBadge.appendChild(img);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.justified')));
|
||||
} else if (absence.justificationStatus === 'unjustified') {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'material-icons-round';
|
||||
span.textContent = 'cancel';
|
||||
statusBadge.appendChild(span);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.unjustified')));
|
||||
} else {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'material-icons-round';
|
||||
span.textContent = 'pending';
|
||||
statusBadge.appendChild(span);
|
||||
statusBadge.appendChild(document.createTextNode(' ' + LanguageManager.t('absences.pending')));
|
||||
}
|
||||
|
||||
statusCell.appendChild(statusBadge);
|
||||
row.appendChild(statusCell);
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
function setupMobileGrouping() {
|
||||
if (window.innerWidth <= 480) {
|
||||
createMobileGroups();
|
||||
} else {
|
||||
removeMobileGroups();
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("resize", setupMobileGrouping);
|
||||
|
||||
setupMobileGrouping();
|
||||
}
|
||||
|
||||
function createMobileGroups() {
|
||||
const tbody = document.querySelector(".absences-table tbody");
|
||||
if (!tbody) return;
|
||||
|
||||
removeMobileGroups();
|
||||
|
||||
const rows = Array.from(tbody.querySelectorAll(".table-row"));
|
||||
const groupedRows = {};
|
||||
|
||||
rows.forEach((row) => {
|
||||
const date = row.dataset.date;
|
||||
if (!groupedRows[date]) {
|
||||
groupedRows[date] = [];
|
||||
}
|
||||
groupedRows[date].push(row);
|
||||
});
|
||||
|
||||
const sortedDates = Object.keys(groupedRows).sort(
|
||||
(a, b) => new Date(b) - new Date(a),
|
||||
);
|
||||
|
||||
while (tbody.firstChild) {
|
||||
tbody.removeChild(tbody.firstChild);
|
||||
}
|
||||
|
||||
sortedDates.forEach((date) => {
|
||||
const dateRows = groupedRows[date];
|
||||
|
||||
const dateGroup = document.createElement("div");
|
||||
dateGroup.className = "date-group";
|
||||
|
||||
const dateHeader = document.createElement("div");
|
||||
dateHeader.className = "date-group-header";
|
||||
dateHeader.textContent = date;
|
||||
|
||||
const dateContent = document.createElement("div");
|
||||
dateContent.className = "date-group-content";
|
||||
|
||||
dateRows.forEach((row) => {
|
||||
dateContent.appendChild(row);
|
||||
});
|
||||
|
||||
dateGroup.appendChild(dateHeader);
|
||||
dateGroup.appendChild(dateContent);
|
||||
tbody.appendChild(dateGroup);
|
||||
});
|
||||
}
|
||||
|
||||
function removeMobileGroups() {
|
||||
const tbody = document.querySelector(".absences-table tbody");
|
||||
if (!tbody) return;
|
||||
|
||||
const dateGroups = tbody.querySelectorAll(".date-group");
|
||||
if (dateGroups.length === 0) return;
|
||||
|
||||
const allRows = [];
|
||||
dateGroups.forEach((group) => {
|
||||
const rows = group.querySelectorAll(".table-row");
|
||||
rows.forEach((row) => allRows.push(row));
|
||||
});
|
||||
|
||||
while (tbody.firstChild) {
|
||||
tbody.removeChild(tbody.firstChild);
|
||||
}
|
||||
allRows.forEach((row) => tbody.appendChild(row));
|
||||
}
|
||||
|
||||
function updateDateGroupsVisibility() {
|
||||
if (window.innerWidth > 480) return;
|
||||
|
||||
const dateGroups = document.querySelectorAll(".date-group");
|
||||
|
||||
dateGroups.forEach((group) => {
|
||||
const visibleRows = group.querySelectorAll(
|
||||
'.table-row[style=""], .table-row:not([style])',
|
||||
);
|
||||
|
||||
if (visibleRows.length > 0) {
|
||||
group.style.display = "";
|
||||
} else {
|
||||
group.style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupFilters() {
|
||||
function setupFilters(originalGroupedAbsences) {
|
||||
try {
|
||||
const filters = {
|
||||
dateFilter: document.getElementById("dateFilter"),
|
||||
subject: document.getElementById("subjectFilter"),
|
||||
justified: document.getElementById("justificationFilter"),
|
||||
};
|
||||
const dateFilter = document.getElementById("dateFilter");
|
||||
const subjectFilter = document.getElementById("subjectFilter");
|
||||
const justificationFilter = document.getElementById("justificationFilter");
|
||||
|
||||
if (!filters.dateFilter || !filters.subject || !filters.justified) {
|
||||
if (!dateFilter || !subjectFilter || !justificationFilter) {
|
||||
console.warn("Some filter elements were not found in the DOM");
|
||||
return;
|
||||
}
|
||||
|
||||
const filterAbsences = () => {
|
||||
try {
|
||||
const dateFilterValue = filters.dateFilter.value;
|
||||
const subject = filters.subject.value;
|
||||
const justified = filters.justified.value;
|
||||
const dateFilterValue = dateFilter.value;
|
||||
const subject = subjectFilter.value;
|
||||
const justified = justificationFilter.value;
|
||||
const selectedDate = dateFilterValue ? new Date(dateFilterValue) : null;
|
||||
|
||||
document.querySelectorAll(".table-row").forEach((row) => {
|
||||
const dateStr = row.dataset.date;
|
||||
document.querySelectorAll(".absence-card").forEach((card) => {
|
||||
const dateStr = card.dataset.date;
|
||||
const dateParts = dateStr.split(".");
|
||||
|
||||
if (dateParts.length < 3) {
|
||||
console.error(`Invalid date format: ${dateStr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -532,100 +469,101 @@ function setupFilters() {
|
||||
const parsedMonth = parseInt(dateParts[1].trim(), 10) - 1;
|
||||
const parsedDay = parseInt(dateParts[2].trim(), 10);
|
||||
|
||||
if (isNaN(parsedDay) || isNaN(parsedMonth) || isNaN(parsedYear)) {
|
||||
console.error(`Invalid date components: ${dateStr}`);
|
||||
return;
|
||||
}
|
||||
const cardDate = new Date(parsedYear, parsedMonth, parsedDay);
|
||||
|
||||
const rowDate = new Date(parsedYear, parsedMonth, parsedDay);
|
||||
|
||||
let showRow = true;
|
||||
let showCard = true;
|
||||
|
||||
if (selectedDate) {
|
||||
if (
|
||||
rowDate.getFullYear() !== selectedDate.getFullYear() ||
|
||||
rowDate.getMonth() !== selectedDate.getMonth() ||
|
||||
rowDate.getDate() !== selectedDate.getDate()
|
||||
cardDate.getFullYear() !== selectedDate.getFullYear() ||
|
||||
cardDate.getMonth() !== selectedDate.getMonth() ||
|
||||
cardDate.getDate() !== selectedDate.getDate()
|
||||
) {
|
||||
showRow = false;
|
||||
showCard = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (subject && row.dataset.subject !== subject) {
|
||||
showRow = false;
|
||||
if (subject && card.dataset.subject !== subject) {
|
||||
showCard = false;
|
||||
}
|
||||
|
||||
if (justified) {
|
||||
const statusElement = row.querySelector(".status-badge");
|
||||
const hasStatus = statusElement.classList.contains(justified);
|
||||
if (!hasStatus) showRow = false;
|
||||
if (justified && card.dataset.status !== justified) {
|
||||
showCard = false;
|
||||
}
|
||||
|
||||
row.style.display = showRow ? "" : "none";
|
||||
card.style.display = showCard ? "" : "none";
|
||||
});
|
||||
|
||||
updateDateGroupsVisibility();
|
||||
updateDayGroupsVisibility();
|
||||
|
||||
updateStatistics();
|
||||
} catch (err) {
|
||||
console.error("Error during filtering absences:", err);
|
||||
}
|
||||
};
|
||||
|
||||
Object.values(filters).forEach((filter) => {
|
||||
try {
|
||||
if (filter) {
|
||||
filter.addEventListener("change", filterAbsences);
|
||||
}
|
||||
} catch (err) {
|
||||
if (
|
||||
err.message &&
|
||||
err.message.includes("Extension context invalidated")
|
||||
) {
|
||||
console.warn(
|
||||
"Extension context invalidated during event listener setup",
|
||||
);
|
||||
} else {
|
||||
console.error("Error setting up filter event listener:", err);
|
||||
}
|
||||
[dateFilter, subjectFilter, justificationFilter].forEach((filter) => {
|
||||
if (filter) {
|
||||
filter.addEventListener("change", filterAbsences);
|
||||
}
|
||||
});
|
||||
|
||||
filterAbsences();
|
||||
} catch (err) {
|
||||
if (err.message && err.message.includes("Extension context invalidated")) {
|
||||
console.warn("Extension context invalidated during filter setup");
|
||||
} else {
|
||||
console.error("Error setting up filters:", err);
|
||||
}
|
||||
console.error("Error setting up filters:", err);
|
||||
}
|
||||
}
|
||||
|
||||
function updateDayGroupsVisibility() {
|
||||
document.querySelectorAll(".day-group").forEach((group) => {
|
||||
const visibleCards = group.querySelectorAll('.absence-card:not([style*="display: none"])');
|
||||
const dayCount = group.querySelector('.day-count');
|
||||
|
||||
if (visibleCards.length > 0) {
|
||||
group.style.display = "";
|
||||
if (dayCount) {
|
||||
dayCount.textContent = `${visibleCards.length} ${LanguageManager.t('absences.hours')}`;
|
||||
}
|
||||
} else {
|
||||
group.style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
try {
|
||||
const visibleRows = document.querySelectorAll(
|
||||
'.table-row:not([style*="display: none"])',
|
||||
);
|
||||
const totalVisible = visibleRows.length;
|
||||
const justifiedVisible = Array.from(visibleRows).filter((row) =>
|
||||
row.querySelector(".status-badge.justified"),
|
||||
const visibleCards = document.querySelectorAll('.absence-card:not([style*="display: none"])');
|
||||
const totalVisible = visibleCards.length;
|
||||
const justifiedVisible = Array.from(visibleCards).filter(
|
||||
card => card.dataset.status === 'justified'
|
||||
).length;
|
||||
const unjustifiedVisible = Array.from(visibleRows).filter((row) =>
|
||||
row.querySelector(".status-badge.unjustified"),
|
||||
const unjustifiedVisible = Array.from(visibleCards).filter(
|
||||
card => card.dataset.status === 'unjustified'
|
||||
).length;
|
||||
const pendingVisible = Array.from(visibleRows).filter((row) =>
|
||||
row.querySelector(".status-badge.pending"),
|
||||
const pendingVisible = Array.from(visibleCards).filter(
|
||||
card => card.dataset.status === 'pending'
|
||||
).length;
|
||||
|
||||
const statCards = document.querySelectorAll(".stat-card");
|
||||
if (statCards[0])
|
||||
statCards[0].querySelector(".stat-number").textContent = totalVisible;
|
||||
if (statCards[1])
|
||||
statCards[1].querySelector(".stat-number").textContent = justifiedVisible;
|
||||
if (statCards[2])
|
||||
statCards[2].querySelector(".stat-number").textContent =
|
||||
unjustifiedVisible;
|
||||
if (statCards[3])
|
||||
statCards[3].querySelector(".stat-number").textContent = pendingVisible;
|
||||
statCards.forEach(card => {
|
||||
const type = card.dataset.type;
|
||||
const numberEl = card.querySelector('.stat-number');
|
||||
if (numberEl) {
|
||||
switch(type) {
|
||||
case 'total':
|
||||
numberEl.textContent = totalVisible;
|
||||
break;
|
||||
case 'justified':
|
||||
numberEl.textContent = justifiedVisible;
|
||||
break;
|
||||
case 'unjustified':
|
||||
numberEl.textContent = unjustifiedVisible;
|
||||
break;
|
||||
case 'pending':
|
||||
numberEl.textContent = pendingVisible;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error updating statistics:", err);
|
||||
}
|
||||
|
||||
@@ -354,13 +354,15 @@ h2 {
|
||||
}
|
||||
|
||||
.user-dropdown-btn {
|
||||
background: none;
|
||||
background: var(--button-secondaryFill);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-primary);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.user-dropdown {
|
||||
|
||||
@@ -505,7 +505,6 @@ class DashboardRenderer {
|
||||
document.body.appendChild(kretaContainer);
|
||||
|
||||
setupUserDropdown();
|
||||
setupMobileNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,335 +1,491 @@
|
||||
.kreta-header {
|
||||
padding:clamp(1rem,3vw,2rem);
|
||||
display:grid;
|
||||
grid-template-columns:minmax(300px,400px) 1fr minmax(200px,300px);
|
||||
align-items:center;
|
||||
gap:1rem;
|
||||
background-color:var(--background);
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: var(--background);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.school-info {
|
||||
margin:0;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 200px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
color:var(--text-primary);
|
||||
font-size:24px;
|
||||
font-weight:600;
|
||||
margin:0 0 0.5rem;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
color: var(--text-primary);
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width:24px;
|
||||
height:24px;
|
||||
border-radius:8px;
|
||||
margin-right:0.5rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.school-details {
|
||||
color:var(--text-secondary);
|
||||
font-size:14px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 300px;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.kreta-nav {
|
||||
padding:0 clamp(0.5rem,3vw,1.5rem);
|
||||
position:sticky;
|
||||
top:0;
|
||||
z-index:100;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display:flex;
|
||||
gap:clamp(0.5rem,2vw,1rem);
|
||||
padding:0.25rem;
|
||||
align-items:center;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
padding:8px 14px 8px 12px;
|
||||
color:var(--text-secondary);
|
||||
text-decoration:none;
|
||||
font-weight:500;
|
||||
white-space:nowrap;
|
||||
border-radius:20px;
|
||||
transition:all 0.2s ease;
|
||||
gap:0.5rem;
|
||||
text-decoration:none;
|
||||
background:var(--button-secondaryFill);
|
||||
box-shadow:0px 1px var(--shadow-blur,2px) 0px var(--accent-shadow);
|
||||
}
|
||||
.nav-item.active {
|
||||
display:flex;
|
||||
padding:8px 14px 8px 12px;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
border-radius:20px;
|
||||
background:var(--button-secondaryFill);
|
||||
box-shadow:0px 1px var(--shadow-blur,2px) 0px var(--accent-shadow);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 16px;
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
gap: 0.5rem;
|
||||
background: var(--button-secondaryFill);
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
color:var(--text-primary);
|
||||
background-color:var(--accent-15);
|
||||
border-radius:8px;
|
||||
text-decoration:none;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--accent-15);
|
||||
text-decoration: none;
|
||||
}
|
||||
.nav-item.active:hover {
|
||||
color:var(--accent-accent);
|
||||
background-color:var(--accent-15);
|
||||
text-decoration:none;
|
||||
|
||||
.nav-item.active {
|
||||
color: var(--accent-accent);
|
||||
background: var(--accent-15);
|
||||
}
|
||||
.nav-item img,.nav-item svg {
|
||||
width:24px;
|
||||
height:24px;
|
||||
|
||||
.nav-item img,
|
||||
.nav-item svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.nav-item.active img {
|
||||
filter: var(--icon-filter) !important;
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-dropdown-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
background: var(--button-secondaryFill);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.user-dropdown-btn:hover {
|
||||
background: var(--accent-15);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
display: block;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-logout-timer {
|
||||
display: block;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.user-avatar-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.user-avatar-icon svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: var(--accent-accent);
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: var(--text-secondary);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.user-dropdown-btn.open .dropdown-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.user-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
background: var(--card-card);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||||
min-width: 180px;
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-dropdown.show {
|
||||
display: block;
|
||||
animation: dropdownShow 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 12px 16px;
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
transition: background-color 0.2s;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background: var(--hover);
|
||||
color: var(--accent-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown-item img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
filter: var(--icon-filter);
|
||||
}
|
||||
.nav-item.active svg path {
|
||||
fill:var(--accent-accent);
|
||||
}
|
||||
.user-profile {
|
||||
position:relative;
|
||||
justify-self:flex-end;
|
||||
}
|
||||
.user-dropdown-btn {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:1rem;
|
||||
background:none;
|
||||
border:none;
|
||||
cursor:pointer;
|
||||
padding:0.5rem;
|
||||
border-radius:8px;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
.user-dropdown-btn:hover {
|
||||
background:var(--hover);
|
||||
}
|
||||
.user-info {
|
||||
text-align:right;
|
||||
}
|
||||
.user-name {
|
||||
display:block;
|
||||
color:var(--text-primary);
|
||||
font-size:16px;
|
||||
}
|
||||
.nav-logout-timer {
|
||||
display:block;
|
||||
color:var(--text-secondary);
|
||||
font-size:14px;
|
||||
}
|
||||
.user-dropdown {
|
||||
position:absolute;
|
||||
top:100%;
|
||||
right:0;
|
||||
margin-top:0.5rem;
|
||||
background:var(--card-card);
|
||||
border-radius:12px;
|
||||
box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);
|
||||
width:200px;
|
||||
display:none;
|
||||
z-index:1000;
|
||||
}
|
||||
.user-dropdown.show {
|
||||
display:block;
|
||||
animation:dropdownShow 0.2s ease;
|
||||
}
|
||||
.dropdown-item {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:0.75rem;
|
||||
padding:0.75rem 1rem;
|
||||
color:var(--text-primary);
|
||||
text-decoration:none;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
.dropdown-item:hover {
|
||||
background:var(--hover);
|
||||
color:var(--accent-accent);
|
||||
border-radius:8px;
|
||||
text-decoration:none;
|
||||
|
||||
.dropdown-item:hover img {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
@keyframes dropdownShow {
|
||||
from {
|
||||
opacity:0;
|
||||
transform:translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity:1;
|
||||
transform:translateY(0);
|
||||
}
|
||||
}@media (max-width:1200px) {
|
||||
.kreta-header {
|
||||
grid-template-columns:minmax(250px,350px) 1fr minmax(180px,250px);
|
||||
}
|
||||
}/* Hamburger menu styles */
|
||||
.nav-toggle {
|
||||
display:none;
|
||||
background:none;
|
||||
border:none;
|
||||
cursor:pointer;
|
||||
padding:0.5rem;
|
||||
border-radius:8px;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
.nav-toggle:hover {
|
||||
background:var(--hover);
|
||||
}
|
||||
.nav-toggle svg {
|
||||
width:24px;
|
||||
height:24px;
|
||||
fill:var(--text-primary);
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
.kreta-header {
|
||||
grid-template-columns:1fr auto auto;
|
||||
grid-template-areas:"school toggle user"
|
||||
"nav nav nav";
|
||||
padding:1rem;
|
||||
gap:0.5rem;
|
||||
}
|
||||
.nav-toggle {
|
||||
display:block;
|
||||
grid-area:toggle;
|
||||
}
|
||||
.school-info {
|
||||
grid-area:school;
|
||||
max-width:none;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:0.5rem;
|
||||
}
|
||||
.logo-text {
|
||||
margin:0;
|
||||
font-size:18px;
|
||||
}
|
||||
.school-details {
|
||||
font-size:11px;
|
||||
max-width:200px;
|
||||
}
|
||||
.kreta-nav {
|
||||
grid-area:nav;
|
||||
padding:0;
|
||||
margin-top:0.5rem;
|
||||
display:none;
|
||||
}
|
||||
.kreta-nav.show {
|
||||
display:flex;
|
||||
animation:slideDown 0.3s ease;
|
||||
}
|
||||
.kreta-nav::-webkit-scrollbar {
|
||||
display:none;
|
||||
}
|
||||
.nav-links {
|
||||
flex-direction:column;
|
||||
width:100%;
|
||||
gap:0.5rem;
|
||||
background:var(--card-card);
|
||||
border-radius:12px;
|
||||
padding:1rem;
|
||||
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
|
||||
}
|
||||
.nav-item {
|
||||
width:100%;
|
||||
justify-content:flex-start;
|
||||
padding:0.75rem;
|
||||
font-size:14px;
|
||||
}
|
||||
.user-profile {
|
||||
grid-area:user;
|
||||
}
|
||||
.user-info {
|
||||
text-align:right;
|
||||
max-width:120px;
|
||||
}
|
||||
.user-name {
|
||||
font-size:13px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
.nav-logout-timer {
|
||||
font-size:11px;
|
||||
}
|
||||
}@media (max-width:480px) {
|
||||
.kreta-header {
|
||||
grid-template-columns:1fr auto auto;
|
||||
grid-template-areas:"school toggle user"
|
||||
"nav nav nav";
|
||||
padding:0.75rem;
|
||||
gap:0.25rem;
|
||||
}
|
||||
.school-info {
|
||||
min-width:0;
|
||||
flex:1;
|
||||
}
|
||||
.logo-text {
|
||||
font-size:16px;
|
||||
}
|
||||
.school-details {
|
||||
font-size:10px;
|
||||
max-width:150px;
|
||||
}
|
||||
.kreta-nav {
|
||||
display:none;
|
||||
}
|
||||
.kreta-nav.show {
|
||||
display:flex;
|
||||
animation:slideDown 0.3s ease;
|
||||
}
|
||||
.nav-links {
|
||||
flex-direction:column;
|
||||
width:100%;
|
||||
gap:0.5rem;
|
||||
background:var(--card-card);
|
||||
border-radius:12px;
|
||||
padding:1rem;
|
||||
box-shadow:0px 1px var(--shadow-blur) 0px var(--accent-shadow);
|
||||
}
|
||||
.nav-item {
|
||||
width:100%;
|
||||
justify-content:flex-start;
|
||||
padding:0.75rem;
|
||||
font-size:14px;
|
||||
}
|
||||
.user-info {
|
||||
max-width:100px;
|
||||
}
|
||||
.user-name {
|
||||
font-size:12px;
|
||||
}
|
||||
.nav-logout-timer {
|
||||
font-size:10px;
|
||||
}
|
||||
}@media (max-width:360px) {
|
||||
.kreta-header {
|
||||
padding:0.5rem;
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.logo-text {
|
||||
font-size:14px;
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
.school-details {
|
||||
font-size:9px;
|
||||
max-width:120px;
|
||||
}
|
||||
.user-info {
|
||||
max-width:80px;
|
||||
}
|
||||
.user-name {
|
||||
font-size:11px;
|
||||
}
|
||||
.nav-logout-timer {
|
||||
font-size:9px;
|
||||
}
|
||||
}@keyframes slideDown {
|
||||
|
||||
@keyframes dropdownShowUp {
|
||||
from {
|
||||
opacity:0;
|
||||
transform:translateY(-10px);
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
to {
|
||||
opacity:1;
|
||||
transform:translateY(0);
|
||||
|
||||
.mobile-header,
|
||||
.mobile-bottom-nav,
|
||||
.mobile-user-dropdown {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.kreta-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
background-color: var(--background);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.mobile-header .school-info {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.mobile-header .logo-text {
|
||||
font-size: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mobile-header .school-details {
|
||||
max-width: 280px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mobile-bottom-nav {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--background);
|
||||
padding: 8px 16px;
|
||||
padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
|
||||
z-index: 1000;
|
||||
box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.1);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-radius: 20px 20px 0 0;
|
||||
}
|
||||
|
||||
.mobile-nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding: 8px 4px;
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
gap: 4px;
|
||||
background: var(--card-card);
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.mobile-nav-item:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--accent-15);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mobile-nav-item.active {
|
||||
color: var(--accent-accent);
|
||||
background: var(--accent-15);
|
||||
}
|
||||
|
||||
.mobile-nav-item img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
transition: filter 0.2s ease;
|
||||
}
|
||||
|
||||
.mobile-nav-item.active img {
|
||||
filter: var(--icon-filter) !important;
|
||||
}
|
||||
|
||||
.mobile-nav-item.active {
|
||||
color: var(--accent-accent) !important;
|
||||
background: var(--accent-15);
|
||||
}
|
||||
|
||||
.mobile-user-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding: 8px 4px;
|
||||
color: var(--text-secondary);
|
||||
background: var(--card-card);
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
border: none;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile-user-btn:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--accent-15);
|
||||
}
|
||||
|
||||
.mobile-user-btn.active {
|
||||
color: var(--accent-accent);
|
||||
background: var(--accent-15);
|
||||
}
|
||||
|
||||
.mobile-user-btn .user-avatar-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.mobile-user-btn .user-avatar-icon svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.mobile-user-dropdown {
|
||||
position: fixed;
|
||||
bottom: calc(70px + env(safe-area-inset-bottom, 0px));
|
||||
right: 12px;
|
||||
background: var(--card-card);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
|
||||
min-width: 200px;
|
||||
display: none;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mobile-user-dropdown.show {
|
||||
display: block;
|
||||
animation: dropdownShowUp 0.2s ease;
|
||||
}
|
||||
|
||||
.mobile-dropdown-header {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--hover);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mobile-dropdown-header .user-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.mobile-dropdown-header .nav-logout-timer {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.mobile-dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 12px 16px;
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
transition: background-color 0.2s;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-dropdown-item:hover {
|
||||
background: var(--hover);
|
||||
color: var(--accent-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mobile-dropdown-item img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
filter: var(--icon-filter);
|
||||
}
|
||||
|
||||
.mobile-dropdown-item:hover img {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
body {
|
||||
padding-bottom: calc(70px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.mobile-header {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.mobile-header .logo-text {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.mobile-header .school-details {
|
||||
font-size: 11px;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.mobile-nav-item {
|
||||
padding: 6px 4px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.mobile-nav-item img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mobile-user-btn {
|
||||
padding: 6px 4px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.mobile-user-btn .user-avatar-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.mobile-header .logo-text {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mobile-header .school-details {
|
||||
font-size: 10px;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.mobile-nav-item span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-user-btn span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-nav-item img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.mobile-user-btn .user-avatar-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
@@ -42,12 +42,17 @@ async function updateHeaderInfo() {
|
||||
function startLogoutTimer(timeString) {
|
||||
const startTime = parseInt(timeString?.match(/\d+/)?.[0] || "45");
|
||||
let timeLeft = startTime * 60;
|
||||
const timerElement = document.querySelector(".nav-logout-timer");
|
||||
|
||||
|
||||
const updateTimer = () => {
|
||||
const minutes = Math.floor(timeLeft / 60);
|
||||
const seconds = timeLeft % 60;
|
||||
timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
||||
const timeText = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
||||
|
||||
const desktopTimer = document.querySelector("#logoutTimer");
|
||||
const mobileTimer = document.querySelector("#mobileLogoutTimer");
|
||||
|
||||
if (desktopTimer) desktopTimer.textContent = timeText;
|
||||
if (mobileTimer) mobileTimer.textContent = timeText;
|
||||
|
||||
if (timeLeft <= 0) {
|
||||
window.location.href = "/Home/Logout";
|
||||
@@ -59,10 +64,6 @@ function startLogoutTimer(timeString) {
|
||||
setInterval(updateTimer, 1000);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
await updateHeaderInfo();
|
||||
});
|
||||
|
||||
function setupUserDropdown() {
|
||||
const userBtn = document.querySelector(".user-dropdown-btn");
|
||||
const userDropdown = document.querySelector(".user-dropdown");
|
||||
@@ -70,10 +71,36 @@ function setupUserDropdown() {
|
||||
userBtn?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
userDropdown?.classList.toggle("show");
|
||||
userBtn?.classList.toggle("open");
|
||||
});
|
||||
|
||||
document.addEventListener("click", () => {
|
||||
userDropdown?.classList.remove("show");
|
||||
const mobileUserBtn = document.querySelector("#mobileUserBtn");
|
||||
const mobileUserDropdown = document.querySelector("#mobileUserDropdown");
|
||||
|
||||
mobileUserBtn?.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
mobileUserDropdown?.classList.toggle("show");
|
||||
mobileUserBtn?.classList.toggle("active");
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!userBtn?.contains(e.target) && !userDropdown?.contains(e.target)) {
|
||||
userDropdown?.classList.remove("show");
|
||||
userBtn?.classList.remove("open");
|
||||
}
|
||||
|
||||
if (!mobileUserBtn?.contains(e.target) && !mobileUserDropdown?.contains(e.target)) {
|
||||
mobileUserDropdown?.classList.remove("show");
|
||||
mobileUserBtn?.classList.remove("active");
|
||||
}
|
||||
});
|
||||
|
||||
const mobileDropdownItems = document.querySelectorAll(".mobile-dropdown-item");
|
||||
mobileDropdownItems.forEach(item => {
|
||||
item.addEventListener("click", () => {
|
||||
mobileUserDropdown?.classList.remove("show");
|
||||
mobileUserBtn?.classList.remove("active");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,94 +111,17 @@ function setupSettingsButton() {
|
||||
const url = chrome.runtime.getURL("settings/index.html");
|
||||
window.open(url, "_blank", "width=400,height=600");
|
||||
});
|
||||
}
|
||||
|
||||
function setupMobileNavigation() {
|
||||
setTimeout(() => {
|
||||
const navToggle = document.querySelector(".nav-toggle");
|
||||
const nav = document.querySelector(".kreta-nav");
|
||||
|
||||
if (!navToggle || !nav) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
|
||||
if (isFirefox) {
|
||||
let isNavOpen = false;
|
||||
|
||||
navToggle.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (isNavOpen) {
|
||||
nav.style.display = "none";
|
||||
nav.classList.remove("show");
|
||||
isNavOpen = false;
|
||||
} else {
|
||||
nav.style.display = "flex";
|
||||
nav.classList.add("show");
|
||||
isNavOpen = true;
|
||||
}
|
||||
});
|
||||
|
||||
navToggle.addEventListener("touchend", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (isNavOpen) {
|
||||
nav.style.display = "none";
|
||||
nav.classList.remove("show");
|
||||
isNavOpen = false;
|
||||
} else {
|
||||
nav.style.display = "flex";
|
||||
nav.classList.add("show");
|
||||
isNavOpen = true;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!nav.contains(e.target) && !navToggle.contains(e.target) && isNavOpen) {
|
||||
nav.style.display = "none";
|
||||
nav.classList.remove("show");
|
||||
isNavOpen = false;
|
||||
}
|
||||
});
|
||||
|
||||
const navItems = document.querySelectorAll(".nav-item");
|
||||
navItems.forEach((item) => {
|
||||
item.addEventListener("click", () => {
|
||||
nav.style.display = "none";
|
||||
nav.classList.remove("show");
|
||||
isNavOpen = false;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
navToggle.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
nav.classList.toggle("show");
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!nav.contains(e.target) && !navToggle.contains(e.target)) {
|
||||
nav.classList.remove("show");
|
||||
}
|
||||
});
|
||||
|
||||
const navItems = document.querySelectorAll(".nav-item");
|
||||
navItems.forEach((item) => {
|
||||
item.addEventListener("click", () => {
|
||||
nav.classList.remove("show");
|
||||
});
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
document.getElementById("mobileSettingsBtn")?.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const url = chrome.runtime.getURL("settings/index.html");
|
||||
window.open(url, "_blank", "width=400,height=600");
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
await updateHeaderInfo();
|
||||
setupUserDropdown();
|
||||
setupSettingsButton();
|
||||
setupMobileNavigation();
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -276,16 +276,17 @@ body {
|
||||
.user-dropdown-btn {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:1rem;
|
||||
background:none;
|
||||
gap:0.75rem;
|
||||
background:var(--button-secondaryFill);
|
||||
border:none;
|
||||
cursor:pointer;
|
||||
padding:0.5rem;
|
||||
border-radius:8px;
|
||||
transition:background-color 0.2s;
|
||||
padding:8px 12px;
|
||||
border-radius:12px;
|
||||
transition:all 0.2s ease;
|
||||
box-shadow:0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
}
|
||||
.user-dropdown-btn:hover {
|
||||
background:var(--card-card);
|
||||
background:var(--accent-15);
|
||||
}
|
||||
.user-info {
|
||||
text-align:right;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
|
||||
setupUserDropdown();
|
||||
setupMobileNavigation();
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = chrome.runtime.getURL("grades/chart.js");
|
||||
@@ -533,6 +532,9 @@
|
||||
if (!ctx) return;
|
||||
|
||||
const gradePoints = calculateGradePoints(subjects);
|
||||
const accentColor = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--accent-accent")
|
||||
.trim();
|
||||
|
||||
new Chart(ctx, {
|
||||
type: "line",
|
||||
@@ -543,28 +545,8 @@
|
||||
label: "Átlag",
|
||||
data: gradePoints.map((p) => p.average),
|
||||
borderWidth: 5,
|
||||
borderColor: accentColor,
|
||||
tension: 0.5,
|
||||
segment: {
|
||||
borderColor: (ctx) => {
|
||||
const curr = ctx.p1.parsed.y;
|
||||
if (!curr) return "transparent";
|
||||
const color =
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue(
|
||||
curr < 2
|
||||
? "--grades-1"
|
||||
: curr < 2.5
|
||||
? "--grades-2"
|
||||
: curr < 3.5
|
||||
? "--grades-3"
|
||||
: curr < 4.5
|
||||
? "--grades-4"
|
||||
: "--grades-5",
|
||||
)
|
||||
.trim() + "80";
|
||||
return color;
|
||||
},
|
||||
},
|
||||
fill: true,
|
||||
backgroundColor: function (context) {
|
||||
const chart = context.chart;
|
||||
@@ -578,55 +560,12 @@
|
||||
chartArea.top,
|
||||
);
|
||||
|
||||
gradientBg.addColorStop(
|
||||
0,
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--grades-1")
|
||||
.trim() + "30",
|
||||
);
|
||||
gradientBg.addColorStop(
|
||||
0.2,
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--grades-2")
|
||||
.trim() + "30",
|
||||
);
|
||||
gradientBg.addColorStop(
|
||||
0.4,
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--grades-3")
|
||||
.trim() + "30",
|
||||
);
|
||||
gradientBg.addColorStop(
|
||||
0.6,
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--grades-4")
|
||||
.trim() + "30",
|
||||
);
|
||||
gradientBg.addColorStop(
|
||||
0.8,
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--grades-5")
|
||||
.trim() + "30",
|
||||
);
|
||||
gradientBg.addColorStop(0, accentColor + "30");
|
||||
gradientBg.addColorStop(1, accentColor + "10");
|
||||
|
||||
return gradientBg;
|
||||
},
|
||||
pointBackgroundColor: (context) => {
|
||||
const value = context.raw;
|
||||
return getComputedStyle(document.documentElement)
|
||||
.getPropertyValue(
|
||||
value < 2
|
||||
? "--grades-1"
|
||||
: value < 2.5
|
||||
? "--grades-2"
|
||||
: value < 3.5
|
||||
? "--grades-3"
|
||||
: value < 4.5
|
||||
? "--grades-4"
|
||||
: "--grades-5",
|
||||
)
|
||||
.trim();
|
||||
},
|
||||
pointBackgroundColor: accentColor,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
},
|
||||
@@ -641,15 +580,10 @@
|
||||
max: 5,
|
||||
ticks: {
|
||||
stepSize: 1,
|
||||
color: getComputedStyle(
|
||||
document.documentElement,
|
||||
).getPropertyValue("--text-secondary"),
|
||||
color: accentColor,
|
||||
},
|
||||
grid: {
|
||||
color:
|
||||
getComputedStyle(document.documentElement).getPropertyValue(
|
||||
"--text-teritary",
|
||||
) + "20",
|
||||
color: accentColor + "20",
|
||||
lineWidth: 1,
|
||||
borderDash: [5, 5],
|
||||
},
|
||||
|
||||
1
icons/pending.svg
Normal file
1
icons/pending.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12m11-5a1 1 0 1 0-2 0v3.764a3 3 0 0 0 1.658 2.683l2.895 1.447a1 1 0 1 0 .894-1.788l-2.894-1.448a1 1 0 0 1-.553-.894z" clip-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 348 B |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Firxa",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"description": "KRÉTA webes verziójának újraírása",
|
||||
"icons": {
|
||||
"128": "images/firka_logo_128.png"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Firxa",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"description": "KRÉTA webes verziójának újraírása",
|
||||
"icons": {
|
||||
"128": "images/firka_logo_128.png"
|
||||
|
||||
@@ -128,16 +128,23 @@ body {
|
||||
padding: 10px 12px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.bulk-actions-left,
|
||||
.bulk-actions-left {
|
||||
justify-content: space-between;
|
||||
flex-wrap: nowrap;
|
||||
gap: 6px;
|
||||
order: 1;
|
||||
}
|
||||
.bulk-actions-right {
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
order: 2;
|
||||
}
|
||||
.bulk-btn,
|
||||
.view-toggle button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
}
|
||||
.bulk-btn img,
|
||||
.view-toggle button img {
|
||||
@@ -151,12 +158,19 @@ body {
|
||||
.view-toggle button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 1;
|
||||
}
|
||||
.bulk-btn img,
|
||||
.view-toggle button img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.bulk-actions-left {
|
||||
order: 1;
|
||||
}
|
||||
.bulk-actions-right {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.messages-grid {
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
modalContent.innerHTML = `
|
||||
<div class="modal-header">
|
||||
<h2>Üzenet részletei</h2>
|
||||
<button class="modal-close" onclick="closeMessageModal()">×</button>
|
||||
<button class="modal-close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="loading-content">
|
||||
@@ -173,6 +173,9 @@
|
||||
`;
|
||||
modalOverlay.appendChild(modalContent);
|
||||
document.body.appendChild(modalOverlay);
|
||||
|
||||
const closeBtn = modalContent.querySelector('.modal-close');
|
||||
closeBtn.addEventListener('click', closeMessageModal);
|
||||
|
||||
if (!isRead) {
|
||||
try {
|
||||
@@ -594,9 +597,6 @@ async function switchView(view) {
|
||||
if (typeof setupUserDropdown === 'function') {
|
||||
setupUserDropdown();
|
||||
}
|
||||
if (typeof setupMobileNavigation === 'function') {
|
||||
setupMobileNavigation();
|
||||
}
|
||||
|
||||
await loadMessages(messagesContainer);
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ to {
|
||||
}
|
||||
}@media (max-width:900px) {
|
||||
.role-grid {
|
||||
gap:0.5rem;
|
||||
grid-template-columns:1fr;
|
||||
}
|
||||
.side-roles {
|
||||
|
||||
@@ -248,8 +248,6 @@ h2 {
|
||||
|
||||
.custom-themes-section {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--border-border, var(--text-teritary));
|
||||
}
|
||||
|
||||
.custom-themes-header {
|
||||
@@ -262,7 +260,13 @@ h2 {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.add-theme-btn {
|
||||
.custom-themes-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.theme-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -276,7 +280,7 @@ h2 {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.add-theme-btn:hover {
|
||||
.theme-btn:hover {
|
||||
background: var(--accent-accent);
|
||||
color: var(--button-secondaryFill);
|
||||
}
|
||||
@@ -523,7 +527,7 @@ h2 {
|
||||
}
|
||||
|
||||
.theme-form input[type="text"] {
|
||||
width: 100%;
|
||||
width: 150px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-border, var(--text-teritary));
|
||||
border-radius: 8px;
|
||||
@@ -587,12 +591,15 @@ h2 {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.color-group label {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.color-input-wrapper {
|
||||
@@ -602,13 +609,15 @@ h2 {
|
||||
}
|
||||
|
||||
.color-input-wrapper input[type="color"] {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--border-border, var(--text-teritary));
|
||||
}
|
||||
|
||||
.color-input-wrapper input[type="color"]::-webkit-color-swatch-wrapper {
|
||||
@@ -621,15 +630,16 @@ h2 {
|
||||
}
|
||||
|
||||
.color-hex {
|
||||
width: 80px;
|
||||
width: 72px;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid var(--border-border, var(--text-teritary));
|
||||
border-radius: 6px;
|
||||
background: var(--button-secondaryFill);
|
||||
color: var(--text-primary);
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-family: monospace;
|
||||
text-transform: uppercase;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-preview-section {
|
||||
|
||||
@@ -55,9 +55,14 @@
|
||||
<div class="custom-themes-section">
|
||||
<div class="custom-themes-header">
|
||||
<span data-i18n="settings.custom_themes.title">Egyéni témák</span>
|
||||
<button class="add-theme-btn" id="addCustomTheme">
|
||||
<span class="material-icons-round">add</span>
|
||||
</button>
|
||||
<div class="custom-themes-buttons">
|
||||
<button class="theme-btn" id="addCustomTheme" title="Új téma">
|
||||
<span class="material-icons-round">add</span>
|
||||
</button>
|
||||
<button class="theme-btn" id="importCustomTheme" title="Téma importálása">
|
||||
<span class="material-icons-round">download</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="theme-grid custom-themes-grid" id="customThemesGrid">
|
||||
</div>
|
||||
@@ -225,7 +230,7 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p data-i18n="settings.custom_themes.import_description">Illeszd be a téma kódot:</p>
|
||||
<textarea id="importCode" placeholder="Illessze be a téma kódot ide..."></textarea>
|
||||
<textarea id="importCode" placeholder="Illeszd be a téma kódját ide..."></textarea>
|
||||
<p class="error-message" id="importError"></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
@@ -503,6 +503,10 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
document.getElementById("cancelThemeEditor")?.addEventListener("click", closeThemeEditor);
|
||||
document.getElementById("saveTheme")?.addEventListener("click", saveThemeFromEditor);
|
||||
|
||||
document.getElementById("importCustomTheme")?.addEventListener("click", () => {
|
||||
document.getElementById("importThemeModal").classList.add("active");
|
||||
});
|
||||
|
||||
document.querySelectorAll(".mode-option").forEach(btn => {
|
||||
btn.addEventListener("click", () => {
|
||||
document.querySelectorAll(".mode-option").forEach(b => b.classList.remove("active"));
|
||||
@@ -550,16 +554,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
document.getElementById("closeShareModalBtn")?.addEventListener("click", closeShareModal);
|
||||
document.getElementById("copyShareCode")?.addEventListener("click", copyShareCode);
|
||||
|
||||
let pressTimer;
|
||||
const addBtn = document.getElementById("addCustomTheme");
|
||||
addBtn?.addEventListener("mousedown", () => {
|
||||
pressTimer = setTimeout(() => {
|
||||
document.getElementById("importThemeModal").classList.add("active");
|
||||
}, 500);
|
||||
});
|
||||
addBtn?.addEventListener("mouseup", () => clearTimeout(pressTimer));
|
||||
addBtn?.addEventListener("mouseleave", () => clearTimeout(pressTimer));
|
||||
|
||||
document.getElementById("closeImportModal")?.addEventListener("click", closeImportModal);
|
||||
document.getElementById("cancelImport")?.addEventListener("click", closeImportModal);
|
||||
document.getElementById("confirmImport")?.addEventListener("click", importTheme);
|
||||
|
||||
@@ -21,128 +21,6 @@ body {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
}
|
||||
.kreta-header {
|
||||
padding:clamp(1rem,3vw,2rem);
|
||||
display:grid;
|
||||
grid-template-columns:minmax(300px,400px) 1fr minmax(200px,300px);
|
||||
align-items:center;
|
||||
gap:1rem;
|
||||
}
|
||||
@media (max-width:1200px) {
|
||||
.kreta-header {
|
||||
grid-template-columns:minmax(250px,350px) 1fr minmax(180px,250px);
|
||||
}
|
||||
}@media (max-width:768px) {
|
||||
.kreta-header {
|
||||
grid-template-columns:1fr auto auto;
|
||||
grid-template-areas:"school toggle user"
|
||||
"nav nav nav";
|
||||
padding:1rem;
|
||||
gap:0.5rem;
|
||||
}
|
||||
}.school-info {
|
||||
margin:0;
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
.school-info {
|
||||
grid-area:school;
|
||||
max-width:none;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:0.5rem;
|
||||
}
|
||||
}.logo-text {
|
||||
color:var(--text-primary);
|
||||
font-size:24px;
|
||||
font-weight:600;
|
||||
margin:0 0 0.5rem;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
.logo-text {
|
||||
margin:0;
|
||||
font-size:20px;
|
||||
}
|
||||
}.logo {
|
||||
width:24px;
|
||||
border-radius:8px;
|
||||
margin-right:0.5rem;
|
||||
}
|
||||
.school-details {
|
||||
color:var(--text-secondary);
|
||||
font-size:14px;
|
||||
}
|
||||
.school-details span {
|
||||
display:block;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
max-width:300px;
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
.school-details span {
|
||||
max-width:200px;
|
||||
}
|
||||
.school-details {
|
||||
font-size:12px;
|
||||
}
|
||||
}.user-profile {
|
||||
position:relative;
|
||||
justify-self:flex-end;
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
.user-profile {
|
||||
grid-area:user;
|
||||
}
|
||||
}.user-dropdown-btn {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:1rem;
|
||||
background:none;
|
||||
border:none;
|
||||
cursor:pointer;
|
||||
padding:0.5rem;
|
||||
border-radius:8px;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
.user-dropdown-btn:hover {
|
||||
background:var(--hover);
|
||||
}
|
||||
.user-info {
|
||||
text-align:right;
|
||||
}
|
||||
.user-dropdown {
|
||||
position:absolute;
|
||||
top:100%;
|
||||
right:0;
|
||||
margin-top:0.5rem;
|
||||
background:var(--card-card);
|
||||
border-radius:12px;
|
||||
box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);
|
||||
width:200px;
|
||||
display:none;
|
||||
z-index:1000;
|
||||
}
|
||||
.user-dropdown.show {
|
||||
display:block;
|
||||
animation:dropdownShow 0.2s ease;
|
||||
}
|
||||
.dropdown-item {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:0.75rem;
|
||||
padding:0.75rem 1rem;
|
||||
color:var(--text-primary);
|
||||
text-decoration:none;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
.dropdown-item:hover {
|
||||
background:var(--hover);
|
||||
color:var(--accent-accent);
|
||||
border-radius:8px;
|
||||
text-decoration:none;
|
||||
}
|
||||
.kreta-main {
|
||||
flex:1;
|
||||
padding:clamp(1rem,3vw,2rem);
|
||||
@@ -431,8 +309,8 @@ body {
|
||||
flex-direction:column;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
width:60px;
|
||||
height:50px;
|
||||
width:40px;
|
||||
height:40px;
|
||||
border:2px solid var(--button-secondaryFill);
|
||||
border-radius:8px;
|
||||
background:var(--button-secondaryFill);
|
||||
@@ -513,7 +391,7 @@ body {
|
||||
.week-modal-content {
|
||||
background:var(--card-card);
|
||||
border-radius:16px;
|
||||
max-width:1000px;
|
||||
max-width:700px;
|
||||
max-height:70vh;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
@@ -531,12 +409,11 @@ body {
|
||||
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;
|
||||
width:60px;
|
||||
height:60px;
|
||||
font-size:12px;
|
||||
}
|
||||
@media (max-width:768px) {
|
||||
@@ -583,29 +460,26 @@ body {
|
||||
}
|
||||
.week-modal-grid {
|
||||
display:grid;
|
||||
grid-template-columns:repeat(13,1fr);
|
||||
gap:8px;
|
||||
grid-template-columns:repeat(auto-fill, 60px);
|
||||
gap:4px;
|
||||
padding:24px;
|
||||
max-height:70vh;
|
||||
overflow-y:auto;
|
||||
justify-content:center;
|
||||
}
|
||||
.week-modal-grid .week-cell {
|
||||
width:60px;
|
||||
height:50px;
|
||||
height:60px;
|
||||
font-size:14px;
|
||||
}
|
||||
@media (max-width:1200px) {
|
||||
@media (max-width:768px) {
|
||||
.week-modal-grid {
|
||||
grid-template-columns:repeat(10,1fr);
|
||||
}
|
||||
}@media (max-width:768px) {
|
||||
.week-modal-grid {
|
||||
grid-template-columns:repeat(7,1fr);
|
||||
gap:6px;
|
||||
grid-template-columns:repeat(auto-fill, 40px);
|
||||
gap:4px;
|
||||
}
|
||||
.week-modal-grid .week-cell {
|
||||
width:50px;
|
||||
height:45px;
|
||||
width:40px;
|
||||
height:40px;
|
||||
font-size:12px;
|
||||
}
|
||||
.week-modal-content {
|
||||
@@ -615,7 +489,7 @@ body {
|
||||
padding:16px 20px;
|
||||
}
|
||||
.week-modal-grid {
|
||||
padding:20px;
|
||||
padding:16px;
|
||||
}
|
||||
}@media (max-width:768px) {
|
||||
.week-grid {
|
||||
@@ -637,8 +511,8 @@ body {
|
||||
gap:4px;
|
||||
}
|
||||
.week-cell {
|
||||
width:35px;
|
||||
height:30px;
|
||||
width:40px;
|
||||
height:40px;
|
||||
font-size:11px;
|
||||
}
|
||||
.week-controls {
|
||||
@@ -654,7 +528,7 @@ body {
|
||||
}
|
||||
.day-nav-btn {
|
||||
background:var(--card-card);
|
||||
border:1px solid var(--accent-15);
|
||||
box-shadow: 0px 1px var(--shadow-blur, 2px) 0px var(--accent-shadow);
|
||||
border-radius:12px;
|
||||
padding:12px 16px;
|
||||
color:var(--text-secondary);
|
||||
@@ -663,6 +537,7 @@ body {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
border: #00000000 0px solid;
|
||||
}
|
||||
.day-nav-btn:hover {
|
||||
background:var(--accent-15);
|
||||
|
||||
@@ -711,19 +711,21 @@
|
||||
const lessonDetails = document.createElement('div');
|
||||
lessonDetails.className = 'lesson-details';
|
||||
|
||||
const teacherItem = document.createElement('div');
|
||||
teacherItem.className = 'detail-item';
|
||||
const teacherLabel = document.createElement('span');
|
||||
teacherLabel.className = 'detail-label';
|
||||
teacherLabel.textContent = LanguageManager.t('timetable.teacher_label');
|
||||
const teacherValue = document.createElement('span');
|
||||
teacherValue.className = `detail-value ${lesson.originalTeacher != '' ? 'line-through' : ''}`;
|
||||
teacherValue.textContent = lesson.originalTeacher != '' ? lesson.originalTeacher : lesson.teacher;
|
||||
teacherItem.appendChild(teacherLabel);
|
||||
teacherItem.appendChild(teacherValue);
|
||||
lessonDetails.appendChild(teacherItem);
|
||||
if (!lesson.isSubstituted) {
|
||||
const teacherItem = document.createElement('div');
|
||||
teacherItem.className = 'detail-item';
|
||||
const teacherLabel = document.createElement('span');
|
||||
teacherLabel.className = 'detail-label';
|
||||
teacherLabel.textContent = LanguageManager.t('timetable.teacher_label');
|
||||
const teacherValue = document.createElement('span');
|
||||
teacherValue.className = 'detail-value';
|
||||
teacherValue.textContent = lesson.teacher;
|
||||
teacherItem.appendChild(teacherLabel);
|
||||
teacherItem.appendChild(teacherValue);
|
||||
lessonDetails.appendChild(teacherItem);
|
||||
}
|
||||
|
||||
if (lesson.originalTeacher != '') {
|
||||
if (lesson.isSubstituted) {
|
||||
const substituteItem = document.createElement('div');
|
||||
substituteItem.className = 'detail-item';
|
||||
const substituteLabel = document.createElement('span');
|
||||
@@ -1700,7 +1702,7 @@
|
||||
const timetableGrid = document.querySelector(".timetable-grid");
|
||||
if (timetableGrid) {
|
||||
|
||||
const newContent = await generateTimeGrid(lessons, weekDates);
|
||||
const newContent = await generateTimeGrid(allLessons, weekDates);
|
||||
timetableGrid.innerHTML = '';
|
||||
|
||||
const parser1 = new DOMParser();
|
||||
@@ -1982,8 +1984,10 @@
|
||||
|
||||
dayNavigationState.currentDayIndex = currentDayIndex;
|
||||
} else {
|
||||
const preservedDayIndex = dayNavigationState.currentDayIndex;
|
||||
dayNavigationState.currentDayIndex = preservedDayIndex;
|
||||
if (dayNavigationState.currentDayIndex >= 0 && dayNavigationState.currentDayIndex < 5) {
|
||||
} else {
|
||||
dayNavigationState.currentDayIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function updateDayDisplay() {
|
||||
@@ -2501,9 +2505,6 @@
|
||||
if (typeof setupUserDropdown === 'function') {
|
||||
setupUserDropdown();
|
||||
}
|
||||
if (typeof setupMobileNavigation === 'function') {
|
||||
setupMobileNavigation();
|
||||
}
|
||||
setupEventListeners(data);
|
||||
initializeWeekSelector();
|
||||
|
||||
@@ -2646,6 +2647,7 @@
|
||||
timetableContainer.appendChild(tempDiv.firstChild);
|
||||
}
|
||||
setupLessonCardListeners();
|
||||
setupDayNavigation(weekDates);
|
||||
|
||||
setTimeout(async () => {
|
||||
await updateHomeworkIconsFromCookie();
|
||||
|
||||
@@ -17,72 +17,115 @@ const createTemplate = {
|
||||
const baseUrl = schoolSubdomain ? `https://${schoolSubdomain}.e-kreta.hu` : "";
|
||||
const schoolNameFull = `${data.schoolInfo.id} - ${data.schoolInfo.name}`;
|
||||
const shortenedSchoolName = helper.shortenSchoolName(schoolNameFull);
|
||||
const navItems = [
|
||||
{ href: `${baseUrl}/Intezmeny/Faliujsag`, page: "dashboard", path: "/Intezmeny/Faliujsag", icon: "dashboard", label: LanguageManager.t("navigation.dashboard") },
|
||||
{ href: `${baseUrl}/TanuloErtekeles/Osztalyzatok`, page: "grades", path: "/TanuloErtekeles/Osztalyzatok", icon: "grades", label: LanguageManager.t("navigation.grades") },
|
||||
{ href: `${baseUrl}/Orarend/InformaciokOrarend`, page: "timetable", path: "/Orarend/InformaciokOrarend", icon: "timetable", label: LanguageManager.t("navigation.timetable") },
|
||||
{ href: `${baseUrl}/Hianyzas/Hianyzasok`, page: "absences", path: "/Hianyzas/Hianyzasok", icon: "absences", label: LanguageManager.t("navigation.absences") },
|
||||
{ href: "https://eugyintezes.e-kreta.hu/api/bff/login", page: "messages", path: "/" || "/uzenetek", icon: "messages", label: LanguageManager.t("navigation.messages") }
|
||||
];
|
||||
const desktopNavItems = navItems.map(item => {
|
||||
const isActive = location.pathname === item.path;
|
||||
return `<a href="${item.href}" data-page="${item.page}" class="nav-item ${isActive ? "active" : ""}">
|
||||
<img src="${chrome.runtime.getURL("icons/" + item.icon + "-" + (isActive ? "active" : "inactive") + ".svg")}" alt="${item.label}">
|
||||
${item.label}
|
||||
</a>`;
|
||||
}).join("");
|
||||
const mobileNavItems = navItems.map(item => {
|
||||
const isActive = location.pathname === item.path;
|
||||
return `<a href="${item.href}" data-page="${item.page}" class="mobile-nav-item ${isActive ? "active" : ""}">
|
||||
<img src="${chrome.runtime.getURL("icons/" + item.icon + "-" + (isActive ? "active" : "inactive") + ".svg")}" alt="${item.label}">
|
||||
<span>${item.label}</span>
|
||||
</a>`;
|
||||
}).join("");
|
||||
const userAvatarSvg = `<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>`;
|
||||
|
||||
const element = `<header class="kreta-header">
|
||||
<div class="school-info">
|
||||
<p class="logo-text">
|
||||
<img src="${chrome.runtime.getURL("images/firka_logo.png")}" alt="Firka" class="logo">
|
||||
Firka
|
||||
</p>
|
||||
<div class="school-details" title="${schoolNameFull}">
|
||||
${shortenedSchoolName}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</button>
|
||||
|
||||
<nav class="kreta-nav">
|
||||
<div class="nav-links">
|
||||
<a href="${baseUrl}/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="${LanguageManager.t("navigation.dashboard")}">
|
||||
${LanguageManager.t("navigation.dashboard")}
|
||||
</a>
|
||||
<a href="${baseUrl}/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="${LanguageManager.t("navigation.grades")}">
|
||||
${LanguageManager.t("navigation.grades")}
|
||||
</a>
|
||||
<a href="${baseUrl}/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="${LanguageManager.t("navigation.timetable")}">
|
||||
${LanguageManager.t("navigation.timetable")}
|
||||
</a>
|
||||
<a href="${baseUrl}/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="${LanguageManager.t("navigation.absences")}">
|
||||
${LanguageManager.t("navigation.absences")}
|
||||
</a>
|
||||
<a href="https://eugyintezes.e-kreta.hu/api/bff/login" data-page="messages" class="nav-item ${location.pathname == "/" ? "active" : ""}">
|
||||
<img src="${chrome.runtime.getURL("icons/messages-" + (location.pathname == "/uzenetek" ? "active" : "inactive") + ".svg")}" alt="${LanguageManager.t("navigation.messages")}">
|
||||
${LanguageManager.t("navigation.messages")}
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
const element = `
|
||||
<header class="kreta-header">
|
||||
<div class="school-info">
|
||||
<p class="logo-text">
|
||||
<img src="${chrome.runtime.getURL("images/firka_logo.png")}" alt="Firka" class="logo">
|
||||
Firka
|
||||
</p>
|
||||
<div class="school-details" title="${schoolNameFull}">
|
||||
${shortenedSchoolName}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="kreta-nav">
|
||||
<div class="nav-links">
|
||||
${desktopNavItems}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="user-profile">
|
||||
<button class="user-dropdown-btn">
|
||||
<div class="user-info">
|
||||
<span class="user-name">${data.userData.name}</span>
|
||||
<span class="nav-logout-timer" id="logoutTimer">${data.userData.time}</span>
|
||||
</div>
|
||||
</button>
|
||||
<div class="user-dropdown">
|
||||
<a href="${baseUrl}/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
|
||||
<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="${LanguageManager.t("navigation.settings")}">
|
||||
${LanguageManager.t("navigation.settings")}
|
||||
</a>
|
||||
<a href="${baseUrl}/Home/Logout" data-page="logout" class="dropdown-item">
|
||||
<img src="${chrome.runtime.getURL("icons/logout.svg")}" alt="${LanguageManager.t("navigation.logout")}">
|
||||
${LanguageManager.t("navigation.logout")}
|
||||
</a>
|
||||
<div class="user-profile">
|
||||
<button class="user-dropdown-btn">
|
||||
<div class="user-info">
|
||||
<span class="user-name">${data.userData.name}</span>
|
||||
<span class="nav-logout-timer" id="logoutTimer">${data.userData.time}</span>
|
||||
</div>
|
||||
<div class="user-avatar-icon">
|
||||
${userAvatarSvg}
|
||||
</div>
|
||||
</header>`;
|
||||
</button>
|
||||
<div class="user-dropdown">
|
||||
<a href="${baseUrl}/Adminisztracio/Profil" data-page="profile" class="dropdown-item">
|
||||
<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="${LanguageManager.t("navigation.settings")}">
|
||||
${LanguageManager.t("navigation.settings")}
|
||||
</a>
|
||||
<a href="${baseUrl}/Home/Logout" data-page="logout" class="dropdown-item">
|
||||
<img src="${chrome.runtime.getURL("icons/logout.svg")}" alt="${LanguageManager.t("navigation.logout")}">
|
||||
${LanguageManager.t("navigation.logout")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<header class="mobile-header">
|
||||
<div class="school-info">
|
||||
<p class="logo-text">
|
||||
<img src="${chrome.runtime.getURL("images/firka_logo.png")}" alt="Firka" class="logo">
|
||||
Firka
|
||||
</p>
|
||||
<div class="school-details" title="${schoolNameFull}">
|
||||
${shortenedSchoolName}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="mobile-bottom-nav">
|
||||
${mobileNavItems}
|
||||
<button class="mobile-user-btn" id="mobileUserBtn">
|
||||
<div class="user-avatar-icon">
|
||||
${userAvatarSvg}
|
||||
</div>
|
||||
<span>${LanguageManager.t("navigation.profile")}</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="mobile-user-dropdown" id="mobileUserDropdown">
|
||||
<div class="mobile-dropdown-header">
|
||||
<span class="user-name">${data.userData.name}</span>
|
||||
<span class="nav-logout-timer" id="mobileLogoutTimer">${data.userData.time}</span>
|
||||
</div>
|
||||
<a href="${baseUrl}/Adminisztracio/Profil" data-page="profile" class="mobile-dropdown-item">
|
||||
<img src="${chrome.runtime.getURL("icons/profile.svg")}" alt="${LanguageManager.t("navigation.profile")}">
|
||||
${LanguageManager.t("navigation.profile")}
|
||||
</a>
|
||||
<a href="#" class="mobile-dropdown-item" id="mobileSettingsBtn">
|
||||
<img src="${chrome.runtime.getURL("icons/settings.svg")}" alt="${LanguageManager.t("navigation.settings")}">
|
||||
${LanguageManager.t("navigation.settings")}
|
||||
</a>
|
||||
<a href="${baseUrl}/Home/Logout" data-page="logout" class="mobile-dropdown-item">
|
||||
<img src="${chrome.runtime.getURL("icons/logout.svg")}" alt="${LanguageManager.t("navigation.logout")}">
|
||||
${LanguageManager.t("navigation.logout")}
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const startTime = parseInt(data.userData.time?.match(/\d+/)?.[0] || "45");
|
||||
let timeLeft = startTime * 60;
|
||||
@@ -90,11 +133,12 @@ const createTemplate = {
|
||||
const updateTimer = () => {
|
||||
const minutes = Math.floor(timeLeft / 60);
|
||||
const seconds = timeLeft % 60;
|
||||
const timerEl = document.getElementById("logoutTimer");
|
||||
if (timerEl) {
|
||||
timerEl.textContent = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
const timeText = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
||||
const desktopTimer = document.getElementById("logoutTimer");
|
||||
const mobileTimer = document.getElementById("mobileLogoutTimer");
|
||||
|
||||
if (desktopTimer) desktopTimer.textContent = timeText;
|
||||
if (mobileTimer) mobileTimer.textContent = timeText;
|
||||
if (timeLeft <= 0) {
|
||||
window.location.href = "/Home/Logout";
|
||||
} else {
|
||||
@@ -110,7 +154,15 @@ const createTemplate = {
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
await helper.waitForElement("#settingsBtn");
|
||||
document.querySelector("#settingsBtn").addEventListener("click", (e) => {
|
||||
|
||||
document.querySelector("#settingsBtn")?.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const url = chrome.runtime.getURL("settings/index.html");
|
||||
window.open(url, "_blank", "width=400,height=600");
|
||||
});
|
||||
|
||||
document.querySelector("#mobileSettingsBtn")?.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const url = chrome.runtime.getURL("settings/index.html");
|
||||
|
||||
Reference in New Issue
Block a user