107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import './style.css';
|
|
import { renderHomePage } from './home-page.ts';
|
|
import { renderDecksPage } from './decks-page.ts';
|
|
import { renderDeckPage } from './deck-page.ts';
|
|
import { renderHistoryPage } from './history-page.ts';
|
|
import { renderReviewPage } from './review-page.ts';
|
|
import { renderSyncPage } from './sync-page.ts';
|
|
import { initWorker } from './sqlite-api.ts';
|
|
import { setupPwa } from './pwa.ts';
|
|
|
|
// Каркас приложения: топ-бар + бургер-меню + страницы (Главная / Колоды / Колода / Повторение / История / Синхронизация).
|
|
|
|
type Page = 'home' | 'decks' | 'deck' | 'review' | 'history' | 'sync';
|
|
|
|
const PAGE_TITLES: Record<Page, string> = {
|
|
home: 'Главная',
|
|
decks: 'Колоды',
|
|
deck: 'Колода',
|
|
review: 'Повторение',
|
|
history: 'История',
|
|
sync: 'Синхронизация',
|
|
};
|
|
|
|
function requireEl<T extends HTMLElement>(id: string): T {
|
|
const el = document.getElementById(id);
|
|
if (!el) throw new Error(`[JapLearn] Не найден элемент #${id}`);
|
|
return el as T;
|
|
}
|
|
|
|
const burgerBtn = requireEl<HTMLButtonElement>('burger-btn');
|
|
const drawer = requireEl<HTMLElement>('drawer');
|
|
const overlay = requireEl<HTMLElement>('drawer-overlay');
|
|
const pageTitle = requireEl<HTMLElement>('page-title');
|
|
const pageRoot = requireEl<HTMLElement>('page');
|
|
|
|
let drawerOpen = false;
|
|
|
|
function setDrawer(open: boolean): void {
|
|
drawerOpen = open;
|
|
drawer.classList.toggle('open', open);
|
|
overlay.hidden = !open;
|
|
burgerBtn.setAttribute('aria-expanded', String(open));
|
|
drawer.setAttribute('aria-hidden', String(!open));
|
|
document.body.classList.toggle('drawer-open', open);
|
|
}
|
|
|
|
function setActiveButton(page: Page): void {
|
|
drawer.querySelectorAll<HTMLButtonElement>('.drawer-btn').forEach((btn) => {
|
|
btn.classList.toggle('active', btn.dataset.page === page);
|
|
});
|
|
}
|
|
|
|
function renderPage(page: Page, deckId?: number): void {
|
|
pageTitle.textContent = PAGE_TITLES[page];
|
|
// Колода / повторение / история — подразделы «Колод»: в меню подсвечиваем «Колоды».
|
|
setActiveButton(page === 'deck' || page === 'review' || page === 'history' ? 'decks' : page);
|
|
if (page === 'home') {
|
|
renderHomePage(pageRoot, {});
|
|
} else if (page === 'decks') {
|
|
renderDecksPage(pageRoot, {
|
|
goDeck: (id) => renderPage('deck', id),
|
|
goReview: (id) => renderPage('review', id),
|
|
});
|
|
} else if (page === 'deck') {
|
|
renderDeckPage(pageRoot, deckId ?? 0, {
|
|
goDecks: () => renderPage('decks'),
|
|
goReview: (id) => renderPage('review', id),
|
|
goHistory: (id) => renderPage('history', id),
|
|
});
|
|
} else if (page === 'review') {
|
|
renderReviewPage(pageRoot, deckId ?? 0, { goDecks: () => renderPage('decks') });
|
|
} else if (page === 'history') {
|
|
renderHistoryPage(pageRoot, deckId ?? 0, { goDeck: (id) => renderPage('deck', id) });
|
|
} else {
|
|
renderSyncPage(pageRoot);
|
|
}
|
|
}
|
|
|
|
burgerBtn.addEventListener('click', () => {
|
|
setDrawer(!drawerOpen);
|
|
});
|
|
|
|
overlay.addEventListener('click', () => {
|
|
setDrawer(false);
|
|
});
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape' && drawerOpen) setDrawer(false);
|
|
});
|
|
|
|
drawer.querySelectorAll<HTMLButtonElement>('.drawer-btn').forEach((btn) => {
|
|
btn.addEventListener('click', () => {
|
|
const page = btn.dataset.page as Page | undefined;
|
|
if (page === 'home' || page === 'decks' || page === 'sync') renderPage(page);
|
|
setDrawer(false);
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// Старт: главная страница, меню закрыто
|
|
await initWorker();
|
|
setDrawer(false);
|
|
renderPage('home');
|
|
setupPwa();
|
|
console.log('[JapLearn] crossOriginIsolated =', window.crossOriginIsolated);
|