Skip to content

Commit

Permalink
Adding manifests from explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenwf committed Jul 21, 2023
1 parent 87d353e commit 201fdad
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CreatorDefinition } from "@/creator-api";
import textFormatIcon from "@/icons/TextFormatIcon.svg";
import React from "react";
import ManifestBrowserCreatorForm from "@/_creators/Manifest/ManifestBrowserCreator/manifest-browser-form.lazy";
import { createFromManifestBrowserOutput } from "@/_creators/Manifest/ManifestBrowserCreator/manifest-browser-creator";

export const manifestBrowserCreator: CreatorDefinition = {
id: "@manifest-editor/manifest-browser-creator",
create: createFromManifestBrowserOutput,
label: "IIIF Browser",
summary: "Find a resource within a IIIF Collection",
icon: <img src={textFormatIcon} alt="" />,
render(ctx: any) {
return <ManifestBrowserCreatorForm {...ctx} />;
},
resourceType: "Manifest",
resourceFields: ["id", "label"],
additionalTypes: ["Collection"],
supports: {
parentTypes: ["Collection"],
parentFieldMap: {
Collection: ["items"],
},
},
sideEffects: [],
staticFields: {},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { CreatorFunctionContext } from "@/creator-api";
import { ContentState, normaliseContentState, parseContentState } from "@iiif/vault-helpers";
import { lazy } from "react";
import invariant from "tiny-invariant";

interface ManifestBrowserCreatorPayload {
// This is the output (JSON) from the IIIF Browser.
// We could have gone with "IIIF Content State" here and may do in the future, but this
// will simplify parsing and importing resources.
output: string | ContentState | ContentState[];
}

export async function createFromManifestBrowserOutput(
data: ManifestBrowserCreatorPayload,
ctx: CreatorFunctionContext
) {
const targetType = ctx.options.targetType as "Manifest" | "Collection";

// For now..
if (Array.isArray(data.output)) {
throw new Error("Multiple items not yet supported");
}

const contentState = normaliseContentState(
typeof data.output === "string" ? parseContentState(data.output) : data.output
);

const target = contentState.target[0];
const previewVault = ctx.getPreviewVault();

if (targetType === "Manifest") {
const manifestId = target.source.id;
invariant(manifestId, "Could not find Manifest ID");
const manifest = await previewVault.get(manifestId);
return ctx.embed({
id: target.source.id,
type: "Manifest",
label: manifest.label,
});
}

if (targetType === "Collection") {
const collectionId = target.source.id;
invariant(collectionId, "Could not find Manifest ID");
const collection = await previewVault.get(collectionId);
return ctx.embed({
id: target.source.id,
type: "Collection",
label: collection.label,
});
}

throw new Error("Not yet supported.");
}
export const ManifestBrowserCreatorForm = lazy(() => import("./manifest-browser-form.lazy"));
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { CreatorContext } from "@/creator-api";
import {
HOMEPAGE_COLLECTION,
PreviewVaultBoundary,
usePreviewHistory,
usePreviewVault,
} from "@/shell/PreviewVault/PreviewVault";
import { IIIFExplorer } from "@/components/widgets/IIIFExplorer/IIIFExplorer";

export default function ManifestBrowserCreatorForm(props: CreatorContext) {
const vault = usePreviewVault();
const { addHistory, clearHistory } = usePreviewHistory();

return (
<>
<PreviewVaultBoundary>
<IIIFExplorer
window={false}
hideHeader={true}
outputTypes={["Manifest", "Collection"]}
vault={vault}
output={{ type: "content-state" }}
homepageCollection={HOMEPAGE_COLLECTION}
clearHomepageCollection={clearHistory}
onHistory={addHistory}
outputTargets={[
{
type: "callback",
label: "Select",
cb: (resource) => props.runCreate({ output: resource }),
},
]}
allowRemoveEntry
/>
</PreviewVaultBoundary>
</>
);
}
2 changes: 2 additions & 0 deletions manifest-editor/src/_creators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { internalCanvas } from "@/_creators/Canvas/InternalCanvas";
import { imageUrlAnnotation } from "@/_creators/Annotation/ImageUrlAnnotation";
import { audioAnnotation } from "@/_creators/Annotation/AudioAnnotation";
import { videoAnnotation } from "@/_creators/Annotation/VideoAnnotation";
import { manifestBrowserCreator } from "@/_creators/Manifest/ManifestBrowserCreator";

export const allCreators = [
emptyCanvas,
Expand All @@ -33,4 +34,5 @@ export const allCreators = [
imageUrlAnnotation,
audioAnnotation,
videoAnnotation,
manifestBrowserCreator,
];
112 changes: 61 additions & 51 deletions manifest-editor/src/_panels/center-panels/ExportPanel/ExportPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useManifest } from "@/hooks/useManifest";
import { useVault } from "react-iiif-vault";
import { useLayoutActions } from "@/shell";
import { useCollection, useVault } from "react-iiif-vault";
import { useApps, useEditingResource, useLayoutActions } from "@/shell";
import { Button } from "@/atoms/Button";
import { CenterPanelContainer } from "@/_components/ui/CenterPanelContainer/CenterPanelContainer";
import { Accordion } from "@/components/layout/Accordion/Accordion";
Expand All @@ -17,7 +17,13 @@ export interface ExportPanelProps {
}

export function ExportPanel(props: ExportPanelProps) {
const manifest = useManifest();
const { apps, currentApp } = useApps();
const selectedApp = currentApp ? apps[currentApp.id] : null;

const isCollection = selectedApp?.metadata.projectType === "Collection";

// eslint-disable-next-line react-hooks/rules-of-hooks
const manifest = isCollection ? useCollection({} as any) : useManifest();
const vault = useVault();
const actions = useLayoutActions();

Expand All @@ -33,54 +39,58 @@ export function ExportPanel(props: ExportPanelProps) {
<CenterPanelContainer title="Export manifest" close={actions.centerPanel.popStack}>
<div style={{ flex: 1, overflowY: "auto" }}>
<Accordion
items={[
{
label: "Presentation 3",
description: 'Download this version by clicking the "Download" button.',
maxHeight: 400,
large: true,
initialOpen: true,
overflow: true,
icon: (
<Button onClick={() => createDownload(version3, "manifest.json")}>
<img width={24} alt="" src={downloadIcon} />
</Button>
),
children: (
<div style={{ maxWidth: "100%" }}>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(vault.toPresentation3(manifest as any), null, 2)}
</pre>
<ButtonRow data-sticky="true">
<Button onClick={() => copyToClipboard(version3)}>Copy to clipboard</Button>
<Button onClick={() => createDownload(version3, "manifest.json")}>Download</Button>
</ButtonRow>
</div>
),
},
{
label: "Presentation 2",
description: 'Download this version by clicking the "Download" button.',
maxHeight: 400,
large: true,
icon: (
<Button onClick={() => createDownload(version2, "manifest.json")}>
<img width={24} alt="" src={downloadIcon} />
</Button>
),
children: (
<div style={{ maxWidth: "100%" }}>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(vault.toPresentation2(manifest as any), null, 2)}
</pre>
<ButtonRow data-sticky="true">
<Button onClick={() => copyToClipboard(version2)}>Copy to clipboard</Button>
<Button onClick={() => createDownload(version2, "manifest.json")}>Download</Button>
</ButtonRow>
</div>
),
},
]}
items={
[
{
label: "Presentation 3",
description: 'Download this version by clicking the "Download" button.',
maxHeight: 400,
large: true,
initialOpen: true,
overflow: true,
icon: (
<Button onClick={() => createDownload(version3, "manifest.json")}>
<img width={24} alt="" src={downloadIcon} />
</Button>
),
children: (
<div style={{ maxWidth: "100%" }}>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(vault.toPresentation3(manifest as any), null, 2)}
</pre>
<ButtonRow data-sticky="true">
<Button onClick={() => copyToClipboard(version3)}>Copy to clipboard</Button>
<Button onClick={() => createDownload(version3, "manifest.json")}>Download</Button>
</ButtonRow>
</div>
),
},
!isCollection
? {
label: "Presentation 2",
description: 'Download this version by clicking the "Download" button.',
maxHeight: 400,
large: true,
icon: (
<Button onClick={() => createDownload(version2, "manifest.json")}>
<img width={24} alt="" src={downloadIcon} />
</Button>
),
children: (
<div style={{ maxWidth: "100%" }}>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(vault.toPresentation2(manifest as any), null, 2)}
</pre>
<ButtonRow data-sticky="true">
<Button onClick={() => copyToClipboard(version2)}>Copy to clipboard</Button>
<Button onClick={() => createDownload(version2, "manifest.json")}>Download</Button>
</ButtonRow>
</div>
),
}
: null,
].filter(Boolean) as any
}
/>
</div>
</CenterPanelContainer>
Expand Down
18 changes: 18 additions & 0 deletions manifest-editor/src/apps/CollectionEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { useInStack } from "@/_components/ui/CanvasPanelEditor/CanvasPanelEditor
import { PreviewVaultBoundary } from "@/shell/PreviewVault/PreviewVault";
import { IIIFExplorer } from "@/components/widgets/IIIFExplorer/IIIFExplorer";
import { PaddedSidebarContainer } from "@/atoms/PaddedSidebarContainer";
import { manifestBrowserCreator } from "@/_creators/Manifest/ManifestBrowserCreator";
import { ExportPanel } from "@/_panels/center-panels/ExportPanel/ExportPanel";
import React from "react";

export default { id: "collection-editor", title: "Collection Editor", project: true, projectType: "Collection" };

Expand All @@ -30,6 +33,12 @@ export const centerPanels: LayoutPanel[] = [
icon: "",
render: () => <ViewManifest />,
},
{
id: "export",
label: "Export",
icon: "",
render: () => <ExportPanel />,
},
];
export const leftPanels: LayoutPanel[] = [
{
Expand Down Expand Up @@ -58,6 +67,9 @@ export const editors = [
technicalProperties,
linkingProperties,
];

export const creators = [manifestBrowserCreator];

export const resources = ["Collection", "Manifest"];

function ViewManifest() {
Expand Down Expand Up @@ -106,6 +118,12 @@ function CollectionLeftPanel() {
}
createActions={createAppActions(items)}
/>

{canCreateManifest ? (
<Button {...manifestActions.buttonProps} onClick={() => manifestActions.create()}>
Add Manifest
</Button>
) : null}
</PaddedSidebarContainer>
);
}

0 comments on commit 201fdad

Please sign in to comment.