database reading
This commit is contained in:
1 parent
68c24dcec5
commit
fc8455e353
418 files changed
+674410
-1561
No files matched your search
+83
-29
@@ -1,38 +1,92 @@
|
||||
import './style.css';
|
||||
import { renderHomePage } from './home-page.ts';
|
||||
import { renderSyncPage } from './sync-page.ts';
|
||||
|
||||
import * as sqlite from 'wa-sqlite';
|
||||
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs';
|
||||
import { SyncPanel } from './sync-panel';
|
||||
export const worker = new Worker(new URL('./db-worker.ts', import.meta.url), {
|
||||
type: 'module',
|
||||
});
|
||||
|
||||
// Смоук-тест: запускаем SQLite (сборка wa-sqlite) в памяти.
|
||||
// Запись и чтение БД идут через OPFS (src/storage.ts); подключение
|
||||
// SQLite к файлу из OPFS сделаем при работе с самими карточками.
|
||||
const sqliteStatus = document.querySelector<HTMLParagraphElement>('#sqlite-status');
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.type === 'success') {
|
||||
const app = document.getElementById('app');
|
||||
if (app) {
|
||||
console.log(e.data.rows)
|
||||
}
|
||||
} else if (e.data.type === 'error') {
|
||||
console.error(e.data.message);
|
||||
}
|
||||
};
|
||||
|
||||
async function initSqlite(): Promise<void> {
|
||||
try {
|
||||
// 1. Загрузчик сам скачивает wa-sqlite.wasm (рядом с wa-sqlite.mjs).
|
||||
const module = await SQLiteESMFactory();
|
||||
// 2. Оборачиваем Emscripten-модуль в JS API.
|
||||
const sqlite3 = sqlite.Factory(module);
|
||||
// 3. Открываем базу в памяти и выполняем запрос.
|
||||
const db = await sqlite3.open_v2(':memory:');
|
||||
let result = 'нет данных';
|
||||
await sqlite3.exec(db, "SELECT 'Привет, мир!'", (row) => {
|
||||
result = String(row[0]);
|
||||
});
|
||||
await sqlite3.close(db);
|
||||
|
||||
if (sqliteStatus) sqliteStatus.textContent = `SQLite работает: ${result}`;
|
||||
} catch (error) {
|
||||
if (sqliteStatus) sqliteStatus.textContent = `SQLite: ошибка инициализации — ${error}`;
|
||||
console.error(error);
|
||||
// Каркас приложения: топ-бар + бургер-меню + две страницы (Главная / Синхронизация).
|
||||
|
||||
type Page = 'home' | 'sync';
|
||||
|
||||
const PAGE_TITLES: Record<Page, string> = {
|
||||
home: 'Главная',
|
||||
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): void {
|
||||
pageTitle.textContent = PAGE_TITLES[page];
|
||||
setActiveButton(page);
|
||||
if (page === 'home') {
|
||||
renderHomePage(pageRoot, { goSync: () => renderPage('sync') });
|
||||
} else {
|
||||
renderSyncPage(pageRoot);
|
||||
}
|
||||
}
|
||||
|
||||
// Главный экран: токен сохранения + кнопки «Скачать» / «Выгрузить».
|
||||
// HTTP-обвязка появится на следующем шаге.
|
||||
const syncPanel = new SyncPanel(document);
|
||||
syncPanel.init();
|
||||
burgerBtn.addEventListener('click', () => {
|
||||
setDrawer(!drawerOpen);
|
||||
});
|
||||
|
||||
void initSqlite();
|
||||
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 === 'sync') renderPage(page);
|
||||
setDrawer(false);
|
||||
});
|
||||
});
|
||||
|
||||
// Старт: главная страница, меню закрыто
|
||||
setDrawer(false);
|
||||
renderPage('home');
|
||||
console.log('[JapLearn] crossOriginIsolated =', window.crossOriginIsolated);
|
||||
Reference in new issue
Block a user