Archived
- Backend: Django REST Framework API with Bookmark and Note models - ViewSets with user-scoped querysets and select_related for N+1 prevention - Create/List/Detail/Update/Delete endpoints - Batch delete operations - Unique constraint on user+book+page for bookmarks - IsOwner permission class for object-level access control - Full serializer validation (page > 0, non-empty content, duplicate check) - 30+ pytest-django tests covering CRUD, auth, filtering, edge cases - Frontend: React TypeScript components - AnnotationsContext with useReducer for state management - BookmarkList, NoteList, AddAnnotationForm, AnnotationsDashboard - Inline note editing with immediate save - Batch delete support - API client with JWT auto-refresh interceptors - Paginated query hook for infinite scroll support - Responsive CSS with loading/empty states - Infrastructure: Django project with custom User model, JWT auth, CORS - PostgreSQL database models with proper FK and indexes - Django admin configuration for all models
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import React from "react";
|
|
import ReactDOM from "react-dom/client";
|
|
import { Layout } from "@/components/layout";
|
|
import { BookmarksNotesPage } from "@/components/annotations/BookmarksNotesPage";
|
|
import "./styles.css";
|
|
|
|
function App(): React.ReactElement {
|
|
const path = window.location.pathname;
|
|
|
|
// Simple client-side routing
|
|
if (path.startsWith("/books/") && path.includes("bookmarks-notes")) {
|
|
// /books/:id/bookmarks-notes
|
|
const bookId = path.split("/")[2];
|
|
return (
|
|
<Layout title="Cloud Reader">
|
|
<BookmarksNotesPage bookId={bookId} />
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
if (path === "/bookmarks-notes" || path === "/bookmarks-notes/") {
|
|
return (
|
|
<Layout title="Cloud Reader">
|
|
<BookmarksNotesPage />
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
// Default: landing page
|
|
return (
|
|
<Layout title="Cloud Reader">
|
|
<div className="page">
|
|
<h2>Welcome to Cloud Reader</h2>
|
|
<p>Your personal e-book reader with cross-device sync.</p>
|
|
<div className="quick-links">
|
|
<a href="/bookmarks-notes" className="card-link">
|
|
<h3>Bookmarks & Notes</h3>
|
|
<p>View and manage all your annotations</p>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
const rootElement = document.getElementById("root");
|
|
if (rootElement) {
|
|
ReactDOM.createRoot(rootElement).render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>
|
|
);
|
|
} |