Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CodeSyncProvider } from "./components/CodeSyncProvider/CodeSyncProvider
import { DownloadPdfWithTheme } from "./components/DownloadThemedPdf/DownloadThemedPdf";
import { Header } from "./components/Header/Header";
import { LightThemeToggle } from "./components/LightThemeToggle/LightThemeToggle";
import { type ILocationContext, LocationContext } from "./components/LocationProvider/LocationProvider";
import { useVersionContext } from "./components/LocationProvider/VersionProvider";
import { type IMetadataContext, MetadataContext } from "./components/MetadataProvider/MetadataProvider";
import { NotesProvider } from "./components/NotesProvider/NotesProvider";
import { PdfProvider } from "./components/PdfProvider/PdfProvider";
Expand All @@ -17,9 +17,7 @@ import { Sidebar } from "./components/Sidebar/Sidebar";
import { ZoomControls } from "./components/ZoomControls/ZoomControls";

export function App() {
const {
locationParams: { version },
} = useContext(LocationContext) as ILocationContext;
const { version } = useVersionContext();

const { urlGetters } = useContext(MetadataContext) as IMetadataContext;

Expand Down
28 changes: 19 additions & 9 deletions src/components/CodeSyncProvider/CodeSyncProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { migrateSelection as migrateSelectionRaw } from "@fluffylabs/links-metadata";
import type { ISelectionParams, ISynctexBlock, ISynctexBlockId, ISynctexData } from "@fluffylabs/links-metadata";
import { createContext, useCallback, useContext, useEffect, useState } from "react";
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import type { PropsWithChildren } from "react";
import { isFeatureEnabled } from "../../devtools";
import { type ILocationContext, LocationContext } from "../LocationProvider/LocationProvider";
Expand Down Expand Up @@ -196,14 +196,24 @@ export function CodeSyncProvider({ children }: PropsWithChildren) {
[synctexStore, texStore],
);

const context = {
getSynctexBlockAtLocation,
getSynctexBlockById,
getSynctexBlockRange,
getSectionTitleAtSynctexBlock,
getSubsectionTitleAtSynctexBlock,
migrateSelection,
};
const context = useMemo(
() => ({
getSynctexBlockAtLocation,
getSynctexBlockById,
getSynctexBlockRange,
getSectionTitleAtSynctexBlock,
getSubsectionTitleAtSynctexBlock,
migrateSelection,
}),
[
getSynctexBlockAtLocation,
getSynctexBlockById,
getSynctexBlockRange,
getSectionTitleAtSynctexBlock,
getSubsectionTitleAtSynctexBlock,
migrateSelection,
],
);

return <CodeSyncContext.Provider value={context}>{children}</CodeSyncContext.Provider>;
}
9 changes: 2 additions & 7 deletions src/components/LocationProvider/LocationProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type ISelectionParams, type ISynctexBlock, isSameBlock } from "@fluffyl
import { type ReactNode, createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { deserializeLegacyLocation } from "../../utils/deserializeLegacyLocation";
import { type IMetadataContext, MetadataContext } from "../MetadataProvider/MetadataProvider";
import { useGetLocationParamsToHash } from "./hooks/useGetLocationParamsToHash";
import type { ILocationParams, SearchParams } from "./types";
import {
BASE64_VALIDATION_REGEX,
Expand Down Expand Up @@ -57,13 +58,7 @@ export function LocationProvider({ children }: ILocationProviderProps) {
[metadata],
);

const getHashFromLocationParams = useCallback(
(params: ILocationParams) => {
const hash = locationParamsToHash(params, metadata);
return hash;
},
[metadata],
);
const { getHashFromLocationParams } = useGetLocationParamsToHash();

const handleHashChange = useCallback(() => {
const { rest: newHash, search, section } = extractSearchParams(window.location.hash);
Expand Down
27 changes: 27 additions & 0 deletions src/components/LocationProvider/VersionProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createContext, useContext, useMemo } from "react";
import { useLocationContext } from "./LocationProvider";

const versionContext = createContext<{ version: string } | undefined>(undefined);

export const useVersionContext = () => {
const context = useContext(versionContext);

if (!context) {
throw new Error("useVersionContext must be used within a VersionProvider");
}

return context;
};

export const VersionProvider = ({ children }: { children: React.ReactNode }) => {
const locationContext = useLocationContext();

const context = useMemo(
() => ({
version: locationContext.locationParams.version,
}),
[locationContext.locationParams.version],
);

return <versionContext.Provider value={context}>{children}</versionContext.Provider>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useCallback } from "react";
import { useMetadataContext } from "../../MetadataProvider/MetadataProvider";
import type { ILocationParams } from "../types";
import { locationParamsToHash } from "../utils/locationParamsToHash";

export const useGetLocationParamsToHash = () => {
const metaDataContext = useMetadataContext();
const { metadata } = metaDataContext;
const getHashFromLocationParams = useCallback(
(params: ILocationParams) => {
const hash = locationParamsToHash(params, metadata);
return hash;
},
[metadata],
);

return { getHashFromLocationParams };
};
10 changes: 9 additions & 1 deletion src/components/MetadataProvider/MetadataProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ReactNode, createContext, useEffect, useMemo, useState } from "react";
import { type ReactNode, createContext, useContext, useEffect, useMemo, useState } from "react";

const METADATA_HOST = "";
const METADATA_JSON = `${METADATA_HOST}/metadata.json`;
Expand Down Expand Up @@ -34,6 +34,14 @@ interface IMetadataProviderProps {

export const MetadataContext = createContext<IMetadataContext | null>(null);

export const useMetadataContext = () => {
const context = useContext(MetadataContext);
if (!context) {
throw new Error("useMetadataContext must be used within a MetadataProvider");
}
return context;
};

export function MetadataProvider({ children }: IMetadataProviderProps) {
const [metadata, setMetadata] = useState<IMetadata>();

Expand Down
17 changes: 15 additions & 2 deletions src/components/NoteManager/NoteManager.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { memo, useCallback, useContext, useEffect, useState } from "react";
import { memo, useCallback, useContext, useEffect, useRef, useState } from "react";
import "./NoteManager.css";
import { Button, Textarea } from "@fluffylabs/shared-ui";
import { twMerge } from "tailwind-merge";
import { validateMath } from "../../utils/validateMath";
import { type ILocationContext, LocationContext } from "../LocationProvider/LocationProvider";
import { type INotesContext, NotesContext } from "../NotesProvider/NotesProvider";
import { LABEL_LOCAL } from "../NotesProvider/consts/labels";
import type { IDecoratedNote } from "../NotesProvider/types/DecoratedNote";
import type { IStorageNote } from "../NotesProvider/types/StorageNote";
import { Selection } from "../Selection/Selection";
import { type ISelectionContext, SelectionContext } from "../SelectionProvider/SelectionProvider";
Expand All @@ -27,7 +28,7 @@ const MemoizedNotesList = memo(NotesList);
function Notes() {
const [noteContent, setNoteContent] = useState("");
const [noteContentError, setNoteContentError] = useState("");
const { locationParams } = useContext(LocationContext) as ILocationContext;
const { locationParams, setLocationParams } = useContext(LocationContext) as ILocationContext;
const { notesReady, activeNotes, notes, handleAddNote, handleDeleteNote, handleUpdateNote } = useContext(
NotesContext,
) as INotesContext;
Expand Down Expand Up @@ -67,6 +68,17 @@ function Notes() {
handleClearSelection();
}, [noteContent, pageNumber, selectedBlocks, handleAddNote, handleClearSelection, locationParams]);

const locationRef = useRef({ locationParams, setLocationParams });
locationRef.current = { locationParams, setLocationParams };

const handleSelectNote = useCallback((note: IDecoratedNote) => {
locationRef.current.setLocationParams({
selectionStart: note.current.selectionStart,
selectionEnd: note.current.selectionEnd,
version: locationRef.current.locationParams.version,
});
}, []);

useEffect(() => {
if (selectedBlocks.length === 0) {
setNoteContent("");
Expand Down Expand Up @@ -97,6 +109,7 @@ function Notes() {
notes={notes}
onEditNote={handleUpdateNote}
onDeleteNote={handleDeleteNote}
onSelectNote={handleSelectNote}
/>
</div>
);
Expand Down
20 changes: 5 additions & 15 deletions src/components/NoteManager/components/Note.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Button, cn } from "@fluffylabs/shared-ui";
import { type ChangeEvent, useCallback, useEffect, useMemo, useState } from "react";
import { validateMath } from "../../../utils/validateMath";
import { useLocationContext } from "../../LocationProvider/LocationProvider";
import type { INotesContext } from "../../NotesProvider/NotesProvider";
import { type IDecoratedNote, NoteSource } from "../../NotesProvider/types/DecoratedNote";
import type { IStorageNote } from "../../NotesProvider/types/StorageNote";
Expand All @@ -19,17 +18,16 @@ type NoteProps = {
active: boolean;
onEditNote: INotesContext["handleUpdateNote"];
onDeleteNote: INotesContext["handleDeleteNote"];
onSelectNote: (note: IDecoratedNote) => void;
};

export function Note({ note, active = false, onEditNote, onDeleteNote }: NoteProps) {
export function Note({ note, active = false, onEditNote, onDeleteNote, onSelectNote }: NoteProps) {
const [isEditing, setIsEditing] = useState(false);
const [noteDirty, setNoteDirty] = useState<IStorageNote>({
...note.original,
});
const [noteContentError, setNoteContentError] = useState("");

const { setLocationParams, locationParams } = useLocationContext();

const isEditable = note.source !== NoteSource.Remote;

const handleSaveClick = useCallback(() => {
Expand Down Expand Up @@ -83,11 +81,7 @@ export function Note({ note, active = false, onEditNote, onDeleteNote }: NotePro
return;
}

setLocationParams({
version: locationParams.version,
selectionStart: note.original.selectionStart,
selectionEnd: note.original.selectionEnd,
});
onSelectNote(note);
};

const handleNoteEnter = (e: React.KeyboardEvent<HTMLDivElement>) => {
Expand All @@ -104,11 +98,7 @@ export function Note({ note, active = false, onEditNote, onDeleteNote }: NotePro
return;
}

setLocationParams({
version: note.original.version,
selectionStart: note.original.selectionStart,
selectionEnd: note.original.selectionEnd,
});
onSelectNote(note);
};

useEffect(() => {
Expand Down Expand Up @@ -161,7 +151,7 @@ export function Note({ note, active = false, onEditNote, onDeleteNote }: NotePro
>
{!active && (
<>
<NoteLink note={note} onEditNote={onEditNote} />
<NoteLink note={note} active={false} />
<NoteLayout.Text />
</>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/NoteManager/components/NoteLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ export const NoteText = () => {

export const SelectedText = () => {
const { selectionString } = useContext(SelectionContext) as ISelectionContext;
const { note, onEditNote } = useNoteContext();
const { note } = useNoteContext();

return (
<div className="px-6 py-3 bg-sidebar rounded-md border-brand-primary border flex flex-col gap-1">
<div className="flex justify-between gap-1">
<NoteLink note={note} onEditNote={onEditNote} />
<NoteLink note={note} active={true} />
</div>
<blockquote className="italic" data-testid="selected-text">
{selectionString}
Expand Down
Loading