Skip to content
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"build:docs": "next build",
"clean": "rimraf dist",
"coverage": "vitest --ui --coverage",
"dev": "next dev",
"dev": "next dev -p 4001",
"dev:vite": "vite",
"lint": "prettier . --check && next lint",
"prepublishOnly": "npm run build",
Expand Down
2 changes: 1 addition & 1 deletion pages/docs/viewer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A UI component that renders a multicanvas IIIF item viewer with pan-zoom support
---

<Viewer
iiifContent="https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif"
iiifContent="https://iiif.io/api/cookbook/recipe/0026-toc-opera/manifest.json"
options={{
showIIIFBadge: false,
informationPanel: {
Expand Down
6 changes: 5 additions & 1 deletion public/web-component/clover-viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
<body>
<script src="https://www.unpkg.com/@samvera/clover-iiif@latest/dist/web-components/index.umd.js"></script>

<clover-viewer
<!-- <clover-viewer
id="https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif"
/> -->
<clover-viewer
id="https://iiif.io/api/cookbook/recipe/0024-book-4-toc/manifest.json"
/>

</body>
</html>
15 changes: 15 additions & 0 deletions src/components/Viewer/InformationPanel/InformationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import AnnotationPage from "src/components/Viewer/InformationPanel/Annotation/Pa
import ContentSearch from "src/components/Viewer/InformationPanel/ContentSearch/ContentSearch";
import { AnnotationResources, AnnotationResource } from "src/types/annotations";
import Information from "src/components/Viewer/InformationPanel/About/About";
import Structure from "src/components/Viewer/InformationPanel/Structure/Structure";
import {
InternationalString,
AnnotationPageNormalized,
Expand Down Expand Up @@ -58,6 +59,7 @@ export const InformationPanel: React.FC<NavigatorProps> = ({
const [activeResource, setActiveResource] = useState<string>();

const renderAbout = informationPanel?.renderAbout;
const renderStructure = informationPanel?.renderStructure;
const renderAnnotation = informationPanel?.renderAnnotation;
const canvas = vault.get({
id: activeCanvas,
Expand Down Expand Up @@ -106,6 +108,8 @@ export const InformationPanel: React.FC<NavigatorProps> = ({
} else {
setActiveResource("manifest-about");
}
} else if (renderStructure) {
setActiveResource("manifest-structure");
} else if (renderAbout) {
setActiveResource("manifest-about");
} else if (renderContentSearch) {
Expand All @@ -120,6 +124,7 @@ export const InformationPanel: React.FC<NavigatorProps> = ({
activeCanvas,
activeResource,
renderAbout,
renderStructure,
renderContentSearch,
annotationResources,
contentSearchResource,
Expand Down Expand Up @@ -166,6 +171,11 @@ export const InformationPanel: React.FC<NavigatorProps> = ({
{t("informationPanelTabsAbout")}
</Trigger>
)}
{renderStructure && (
<Trigger value="manifest-structure">
{t("informationPanelTabsStructure")}
</Trigger>
)}
{renderContentSearch && contentSearchResource && (
<Trigger value="manifest-content-search">
<Label label={contentSearchResource.label as InternationalString} />
Expand Down Expand Up @@ -194,6 +204,11 @@ export const InformationPanel: React.FC<NavigatorProps> = ({
<Information />
</Content>
)}
{renderStructure && (
<Content value="manifest-structure">
<Structure />
</Content>
)}
{renderContentSearch && contentSearchResource && (
<Content value="manifest-content-search">
<ContentSearch
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { styled } from "src/styles/stitches.config";

const StructureContent = styled("div", {
padding: " 0 1.618rem 2rem",
display: "flex",
flexDirection: "column",
overflow: "scroll",
position: "absolute",
fontWeight: "400",
fontSize: "1rem",
zIndex: "0",

".manifest-property-title": {
fontWeight: "700",
margin: "1rem 0 0.25rem",
},

"a": {
color: "Blue",
textDecoration: "underline",
},

"ul, ol": {
padding: "0",
marginLeft: "1rem",
listStyleType: "disc",

li: {
fontSize: "1rem",
lineHeight: "1.45em",
margin: "0.25rem 0 0.25rem",
},
},
});

const StructureStyled = styled("div", {
position: "relative",
width: "100%",
height: "100%",
zIndex: "0",
});

export { StructureContent, StructureStyled };
56 changes: 56 additions & 0 deletions src/components/Viewer/InformationPanel/Structure/Structure.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
StructureContent,
StructureStyled,
} from "src/components/Viewer/InformationPanel/Structure/Structure.styled";
import {
ContentResource,
IIIFExternalWebResource,
ManifestNormalized,
} from "@iiif/presentation-3";
import {
Id,
Range,
} from "src/components/Viewer/Properties";
import React, { useEffect, useState } from "react";
import { ViewerContextStore, useViewerState } from "src/context/viewer-context";
import {
getValue,
rangeToTableOfContentsTree,
rangesToTableOfContentsTree,
RangeTableOfContentsNode,
} from "@iiif/helpers"

function renderRangeList(range: RangeTableOfContentsNode | null, skipCanvases = false, indent = 0) {
if (!range) {
return '';
}
return range.items;
}

const Structure: React.FC = () => {
const viewerState: ViewerContextStore = useViewerState();
const { activeManifest, vault } = viewerState;

const [manifest, setManifest] = useState<ManifestNormalized>();

useEffect(() => {
const data: ManifestNormalized = vault.get(activeManifest);
setManifest(data);
}, [activeManifest, vault]);

if (!manifest) return <></>;

// ToDo: Loop through structures to build ToC instead of grabbing the first one
const tree = rangeToTableOfContentsTree(vault, manifest.structures[0] as any);
const items = renderRangeList(tree);

return (
<StructureStyled>
<StructureContent>
<Range items={items} />
</StructureContent>
</StructureStyled>
);
};

export default Structure;
9 changes: 6 additions & 3 deletions src/components/Viewer/Player/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ const Player: React.FC<PlayerProps> = ({
}) => {
const [currentTime, setCurrentTime] = React.useState<number>(0);
const [poster, setPoster] = React.useState<string | undefined>();
const playerRef = React.useRef<HTMLVideoElement>(null);
// const playerRef = React.useRef<HTMLVideoElement>(null);
const isAudio = painting?.type === "Sound";

const viewerState: ViewerContextStore = useViewerState();
const { playerRef } = viewerState;
const { activeCanvas, configOptions, vault } = viewerState;

/**
Expand All @@ -41,12 +42,14 @@ const Player: React.FC<PlayerProps> = ({
* Check that IIIF content resource ID exists and
* we have a reffed <video> for attaching HLS
*/
if (!painting.id || !playerRef.current) return;
// if (!painting.id || !playerRef.current) return;
if (!painting.id) return;

if (playerRef?.current) {
const video: HTMLVideoElement = playerRef.current;
video.src = painting.id as string;
video.load();
console.log(playerRef)
}

/**
Expand Down Expand Up @@ -109,7 +112,7 @@ const Player: React.FC<PlayerProps> = ({
video.currentTime = 0;
}
};
}, [configOptions.withCredentials, painting.id]);
}, [configOptions.withCredentials, playerRef, painting.id]);

useEffect(() => {
const canvas: CanvasNormalized = vault.get(activeCanvas);
Expand Down
Loading