Implement Task 16: Murphy Grammar Engine & Handwritten Journaling

This commit is contained in:
Antigravity committed 2026-10-06 15:42:10 +03:00
1 parent 3fae321322
commit 4d58002b48
11 files changed
+3267 -10

No files matched your search

+77
View File
@@ -9,6 +9,7 @@ import { initDictionary, loadInitialData } from './modules/dictionary.js';
import { initSrs, startSrsTrainingSession, openStatsDashboard } from './modules/srs.js';
import { initReader, loadBookshelf, openBook } from './modules/reader.js';
import { initCefr, loadCefrOverview, startCefrQuiz } from './modules/cefr.js';
import { initGrammar, loadGrammarUnits, openGrammarUnit } from './modules/grammar.js';
let currentUser = null;
let isRouting = false;
@@ -40,6 +41,8 @@ export function applyInitialViewPreflight() {
hash = '#srs';
} else if (lastView === 'cefr-view') {
hash = '#cefr';
} else if (lastView === 'grammar-view') {
hash = '#grammar';
}
} catch (e) {}
}
@@ -48,6 +51,7 @@ export function applyInitialViewPreflight() {
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
const bookshelfContainer = document.getElementById('bookshelf-container');
const readerInterface = document.getElementById('reader-interface');
const readerBookTitle = document.getElementById('reader-book-title');
@@ -56,6 +60,7 @@ export function applyInitialViewPreflight() {
if (dictionaryView) dictionaryView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (readerView) readerView.classList.remove('hidden');
updateMobileActiveTab('reader');
if (hash.includes('/book/')) {
@@ -67,14 +72,23 @@ export function applyInitialViewPreflight() {
if (dictionaryView) dictionaryView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (srsView) srsView.classList.remove('hidden');
updateMobileActiveTab('srs');
} else if (hash.startsWith('#cefr')) {
if (dictionaryView) dictionaryView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (cefrView) cefrView.classList.remove('hidden');
updateMobileActiveTab('');
} else if (hash.startsWith('#grammar')) {
if (dictionaryView) dictionaryView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.remove('hidden');
updateMobileActiveTab('');
}
}
@@ -90,10 +104,12 @@ export function openDictionaryView(updateHash = true) {
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
if (srsView) srsView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (dictionaryView) dictionaryView.classList.remove('hidden');
updateMobileActiveTab('dict');
try { localStorage.setItem('notes_active_view', 'dictionary-view'); } catch (e) {}
@@ -110,10 +126,12 @@ export function openSrsView(tagFilter = null, updateHash = true) {
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
if (dictionaryView) dictionaryView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (srsView) srsView.classList.remove('hidden');
updateMobileActiveTab('srs');
try { localStorage.setItem('notes_active_view', 'srs-view'); } catch (e) {}
@@ -133,12 +151,14 @@ export function openBookshelfView(updateHash = true) {
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
const bookshelfContainer = document.getElementById('bookshelf-container');
const readerInterface = document.getElementById('reader-interface');
if (dictionaryView) dictionaryView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (readerView) readerView.classList.remove('hidden');
if (bookshelfContainer) bookshelfContainer.classList.remove('hidden');
if (readerInterface) readerInterface.classList.add('hidden');
@@ -173,10 +193,12 @@ export function openCefrView(level = null, mode = 'all', updateHash = true) {
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
if (dictionaryView) dictionaryView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (grammarView) grammarView.classList.add('hidden');
if (cefrView) cefrView.classList.remove('hidden');
updateMobileActiveTab('');
@@ -189,6 +211,36 @@ export function openCefrView(level = null, mode = 'all', updateHash = true) {
}
}
export function openGrammarView(unitId = null, updateHash = true) {
const targetHash = unitId ? `#grammar/unit/${unitId}` : '#grammar';
if (updateHash && window.location.hash !== targetHash) {
window.location.hash = targetHash;
return;
}
const dictionaryView = document.getElementById('dictionary-view');
const srsView = document.getElementById('srs-view');
const readerView = document.getElementById('reader-view');
const cefrView = document.getElementById('cefr-view');
const grammarView = document.getElementById('grammar-view');
if (dictionaryView) dictionaryView.classList.add('hidden');
if (srsView) srsView.classList.add('hidden');
if (readerView) readerView.classList.add('hidden');
if (cefrView) cefrView.classList.add('hidden');
if (grammarView) grammarView.classList.remove('hidden');
updateMobileActiveTab('');
try { localStorage.setItem('notes_active_view', 'grammar-view'); } catch (e) {}
if (unitId) {
openGrammarUnit(unitId);
} else {
loadGrammarUnits();
}
}
// -----------------------------------------------------------------------
// Route Handler
// -----------------------------------------------------------------------
@@ -213,6 +265,10 @@ export async function handleRouting() {
hash = '#cefr';
window.location.hash = hash;
return;
} else if (lastView === 'grammar-view') {
hash = '#grammar';
window.location.hash = hash;
return;
} else {
hash = '#dictionary';
}
@@ -234,6 +290,14 @@ export async function handleRouting() {
const level = parts[1] || null;
const mode = parts[2] === 'mistakes' ? 'mistakes' : 'all';
openCefrView(level, mode, false);
} else if (cleanHash.startsWith('grammar')) {
const parts = cleanHash.split('/');
if (parts[1] === 'unit' && parts[2]) {
const unitId = parseInt(parts[2], 10);
openGrammarView(unitId, false);
} else {
openGrammarView(null, false);
}
} else if (cleanHash.startsWith('reader') || cleanHash === 'bookshelf') {
const parts = cleanHash.split('/');
if (parts[1] === 'book' && parts[2]) {
@@ -355,6 +419,14 @@ function initMobileNavigation() {
});
}
const mobileGrammarBtn = document.getElementById('mobile-grammar-btn');
if (mobileGrammarBtn) {
mobileGrammarBtn.addEventListener('click', () => {
closeMobileMenu();
openGrammarView(null, true);
});
}
const mobileCefrBtn = document.getElementById('mobile-cefr-btn');
if (mobileCefrBtn) {
mobileCefrBtn.addEventListener('click', () => {
@@ -499,11 +571,13 @@ document.addEventListener('DOMContentLoaded', () => {
initSrs();
initReader();
initCefr();
initGrammar();
// 5. Global Navigation & Header Actions
const navBrandHome = document.getElementById('nav-brand-home');
const navReaderBtn = document.getElementById('nav-reader-btn');
const navCefrBtn = document.getElementById('nav-cefr-btn');
const navGrammarBtn = document.getElementById('nav-grammar-btn');
const srsTrainerBtn = document.getElementById('srs-trainer-btn');
const srsJumpCefrBtn = document.getElementById('srs-jump-cefr-btn');
const loginForm = document.getElementById('login-form');
@@ -521,6 +595,9 @@ document.addEventListener('DOMContentLoaded', () => {
if (navCefrBtn) {
navCefrBtn.addEventListener('click', () => { window.location.hash = '#cefr'; });
}
if (navGrammarBtn) {
navGrammarBtn.addEventListener('click', () => { window.location.hash = '#grammar'; });
}
if (srsTrainerBtn) {
srsTrainerBtn.addEventListener('click', () => { window.location.hash = '#srs'; });
}