Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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>;
}
10 changes: 3 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 @@ -35,6 +36,7 @@ export const useLocationContext = () => {

export function LocationProvider({ children }: ILocationProviderProps) {
const { metadata } = useContext(MetadataContext) as IMetadataContext;
console.log(metadata);
const [locationParams, setLocationParams] = useState<ILocationParams>();
const { urlGetters } = useContext(MetadataContext) as IMetadataContext;

Expand All @@ -57,13 +59,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
16 changes: 14 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,16 @@ function Notes() {
handleClearSelection();
}, [noteContent, pageNumber, selectedBlocks, handleAddNote, handleClearSelection, locationParams]);

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

const handelSelectNote = 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 +108,7 @@ function Notes() {
notes={notes}
onEditNote={handleUpdateNote}
onDeleteNote={handleDeleteNote}
onSelectNote={handelSelectNote}
/>
</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