feat: uv config other feats

- add uv configuration for the backend
- update frontend to make auth work
- add new auth endpoints
- add bookmars feat
- add reader feat
This commit is contained in:
2026-06-03 22:06:01 -05:00
parent 730c748f5f
commit 6b4c0c43f8
137 changed files with 20319 additions and 2340 deletions
@@ -0,0 +1,86 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18n-lite";
import { useAnnotations } from "@/context/AnnotationsContext";
import type { MarkerEntry } from "@/types";
import {
CollapsibleMarkerPassage,
CollapsibleMarkerThought,
} from "@/components/annotations/CollapsibleMarkerText";
interface BookMarkersPanelProps {
ebookId: number;
isOpen: boolean;
onClose: () => void;
onGoToPassage: (marker: MarkerEntry) => void;
}
export function BookMarkersPanel({
ebookId,
isOpen,
onClose,
onGoToPassage,
}: BookMarkersPanelProps) {
const { t } = useTranslation();
const { markers, loadBookmarks, removeBookmark, state } = useAnnotations();
useEffect(() => {
if (isOpen) void loadBookmarks(ebookId);
}, [isOpen, ebookId, loadBookmarks]);
if (!isOpen) return null;
return (
<>
<div className="reader-panel-backdrop" onClick={onClose} aria-hidden />
<aside className="reader-side-panel reader-markers-panel" role="dialog" aria-label={t("annotations.inBookPanel")}>
<header className="reader-panel-header">
<h2>{t("annotations.inBookPanel")}</h2>
<button type="button" className="reader-panel-close" onClick={onClose} aria-label={t("annotations.close")}>
×
</button>
</header>
<div className="reader-panel-body">
{state.bookmarksLoading ? (
<p className="annotations-loading">{t("annotations.loading")}</p>
) : markers.length === 0 ? (
<p className="annotations-empty">{t("annotations.selectTextHint")}</p>
) : (
<ul className="marker-thread-list">
{markers.map((m) => (
<li key={m.id} className="marker-thread">
{m.chapter_title && (
<span className="marker-thread-chapter">{m.chapter_title}</span>
)}
{m.location_text && (
<CollapsibleMarkerPassage
text={m.location_text}
highlightColor={m.highlight_color}
className="annotation-quote"
/>
)}
{m.content ? (
<CollapsibleMarkerThought text={m.content} />
) : (
<span className="annotation-kind-badge bookmark-badge">{t("annotations.bookmarkOnly")}</span>
)}
<div className="annotation-actions">
<button type="button" className="btn btn-sm" onClick={() => onGoToPassage(m)}>
{t("annotations.goToPassage")}
</button>
<button
type="button"
className="btn btn-sm btn-danger"
onClick={() => removeBookmark(m.id)}
>
{t("common.delete")}
</button>
</div>
</li>
))}
</ul>
)}
</div>
</aside>
</>
);
}