Files
gitlab-instance-0a899031_di…/app/lib/learning.ts
2026-03-11 22:26:12 -05:00

142 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 学习进度、继续学习、收藏、笔记 - localStorage来自 nomadlms
*/
const PREFIX = "lms-";
const KEY_LAST = `${PREFIX}last`;
const KEY_COMPLETED = `${PREFIX}completed`;
const KEY_BOOKMARKS = `${PREFIX}bookmarks`;
const KEY_NOTES = `${PREFIX}notes`;
const KEY_RATING = `${PREFIX}rating`;
export type LastWatched = { moduleIndex: number; lessonIndex: number; name: string };
export function getLastWatched(): LastWatched | null {
if (typeof window === "undefined") return null;
try {
const raw = localStorage.getItem(KEY_LAST);
if (!raw) return null;
const d = JSON.parse(raw);
if (typeof d?.moduleIndex !== "number" || typeof d?.lessonIndex !== "number") return null;
return { moduleIndex: d.moduleIndex, lessonIndex: d.lessonIndex, name: d.name || "" };
} catch {
return null;
}
}
export function setLastWatched(m: number, l: number, name: string): void {
if (typeof window === "undefined") return;
try {
localStorage.setItem(KEY_LAST, JSON.stringify({ moduleIndex: m, lessonIndex: l, name }));
} catch {
/* ignore */
}
}
export function getCompletedLessons(): Set<string> {
if (typeof window === "undefined") return new Set();
try {
const raw = localStorage.getItem(KEY_COMPLETED);
if (!raw) return new Set();
const arr = JSON.parse(raw);
return new Set(Array.isArray(arr) ? arr : []);
} catch {
return new Set();
}
}
export function markCompleted(moduleIndex: number, lessonIndex: number): void {
if (typeof window === "undefined") return;
try {
const set = getCompletedLessons();
set.add(`${moduleIndex}-${lessonIndex}`);
localStorage.setItem(KEY_COMPLETED, JSON.stringify([...set]));
window.dispatchEvent(new CustomEvent("learning:progress"));
} catch {
/* ignore */
}
}
export function getProgress(totalLessons: number): { completed: number; percent: number } {
const set = getCompletedLessons();
const completed = set.size;
return { completed, percent: totalLessons > 0 ? Math.round((completed / totalLessons) * 100) : 0 };
}
export function getBookmarks(): Set<string> {
if (typeof window === "undefined") return new Set();
try {
const raw = localStorage.getItem(KEY_BOOKMARKS);
if (!raw) return new Set();
const arr = JSON.parse(raw);
return new Set(Array.isArray(arr) ? arr : []);
} catch {
return new Set();
}
}
export function toggleBookmark(moduleIndex: number, lessonIndex: number): boolean {
if (typeof window === "undefined") return false;
try {
const set = getBookmarks();
const key = `${moduleIndex}-${lessonIndex}`;
if (set.has(key)) set.delete(key);
else set.add(key);
localStorage.setItem(KEY_BOOKMARKS, JSON.stringify([...set]));
window.dispatchEvent(new CustomEvent("learning:bookmarks"));
return set.has(key);
} catch {
return false;
}
}
export function isBookmarked(moduleIndex: number, lessonIndex: number): boolean {
return getBookmarks().has(`${moduleIndex}-${lessonIndex}`);
}
export function getNote(moduleIndex: number, lessonIndex: number): string {
if (typeof window === "undefined") return "";
try {
const raw = localStorage.getItem(KEY_NOTES);
if (!raw) return "";
const map = JSON.parse(raw);
return map[`${moduleIndex}-${lessonIndex}`] ?? "";
} catch {
return "";
}
}
export function setNote(moduleIndex: number, lessonIndex: number, text: string): void {
if (typeof window === "undefined") return;
try {
const raw = localStorage.getItem(KEY_NOTES);
const map = raw ? JSON.parse(raw) : {};
map[`${moduleIndex}-${lessonIndex}`] = text;
localStorage.setItem(KEY_NOTES, JSON.stringify(map));
} catch {
/* ignore */
}
}
export function getRating(): { stars: number; comment: string } | null {
if (typeof window === "undefined") return null;
try {
const raw = localStorage.getItem(KEY_RATING);
if (!raw) return null;
const d = JSON.parse(raw);
return { stars: d?.stars ?? 0, comment: d?.comment ?? "" };
} catch {
return null;
}
}
export function setRating(stars: number, comment: string): void {
if (typeof window === "undefined") return;
try {
localStorage.setItem(KEY_RATING, JSON.stringify({ stars, comment }));
window.dispatchEvent(new CustomEvent("learning:rating"));
} catch {
/* ignore */
}
}