-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
537 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,64 @@ | ||
import { DocumentStatusBar, Separator, Skeleton } from "@prismicio/editor-ui"; | ||
import { useMemo } from "react"; | ||
import { AnimatedElement, DocumentStatusBar, Tab } from "@prismicio/editor-ui"; | ||
import { useEffect, useState } from "react"; | ||
|
||
import { AppFooter } from "./components/AppFooter"; | ||
import { AppHeader } from "./components/AppHeader"; | ||
import { CustomTypeList } from "./components/CustomTypeList"; | ||
import { SharedSliceList } from "./components/SharedSliceList"; | ||
import { useRepository } from "./store/useRepository"; | ||
import { useSliceMachineConfig } from "./store/useSliceMachineConfig"; | ||
import { useUser } from "./store/useUser"; | ||
|
||
function Header(): JSX.Element { | ||
const { config } = useSliceMachineConfig(); | ||
const { profile } = useUser(); | ||
|
||
const apiEndpoint = useMemo(() => { | ||
if (!config) { | ||
return null; | ||
} | ||
export function App(): JSX.Element { | ||
const repository = useRepository(); | ||
const sliceMachineConfig = useSliceMachineConfig(); | ||
const user = useUser(); | ||
|
||
return config.apiEndpoint | ||
? config.apiEndpoint.replace(/^https?:\/\//i, "") | ||
: `${config.repositoryName}.prismic.io`; | ||
}, [config]); | ||
const tabs = ["Slices", "Custom Types", "Upgrade Summary"] as const; | ||
const [activeTab, setActiveTab] = | ||
useState<(typeof tabs)[number]>("Custom Types"); | ||
|
||
return ( | ||
<header className="p-4 container max-w-screen-lg mx-auto flex justify-between items-center"> | ||
{config ? ( | ||
<div> | ||
<h1 className="font-medium text-xl">{config.repositoryName}</h1> | ||
<a | ||
href={config.apiEndpoint || `https://${apiEndpoint}`} | ||
className="text-gray-600 text-sm underline" | ||
target="_blank" | ||
> | ||
{apiEndpoint} | ||
</a> | ||
</div> | ||
) : ( | ||
<div className="leading-[0] opacity-40"> | ||
<Skeleton width={256} height={52} /> | ||
</div> | ||
)} | ||
{profile ? ( | ||
<h2 className="text-sm"> | ||
Logged in as <em>{profile.email}</em> | ||
</h2> | ||
) : ( | ||
<div className="leading-[0] opacity-40"> | ||
<Skeleton width={256} height={20} /> | ||
</div> | ||
)} | ||
</header> | ||
); | ||
} | ||
|
||
export function App(): JSX.Element { | ||
useSliceMachineConfig((state) => state.fetch)(); | ||
useUser((state) => state.fetch)(); | ||
useEffect(() => { | ||
repository.fetch(); | ||
sliceMachineConfig.fetch(); | ||
user.fetch(); | ||
}, []); | ||
Check warning on line 25 in gui/src/App.tsx GitHub Actions / Suite (ubuntu-latest, Node 16)
Check warning on line 25 in gui/src/App.tsx GitHub Actions / Suite (ubuntu-latest, Node 18)
|
||
|
||
return ( | ||
<> | ||
<DocumentStatusBar status="release" /> | ||
<Header /> | ||
<div className="px-4 container max-w-screen-lg mx-auto"> | ||
<Separator decorative={true} /> | ||
<AppHeader /> | ||
<div className="container space-y-4"> | ||
<hr className="border-stone-300" /> | ||
<nav className="flex gap-2"> | ||
{tabs.map((tab) => ( | ||
<Tab | ||
key={tab} | ||
title={tab} | ||
selected={activeTab === tab} | ||
onSelect={() => setActiveTab(tab)} | ||
/> | ||
))} | ||
</nav> | ||
<AnimatedElement> | ||
{activeTab === "Slices" ? ( | ||
<main key="Slices" className="space-y-4"> | ||
TODO: Slices | ||
</main> | ||
) : activeTab === "Custom Types" ? ( | ||
<main key="Custom Types" className="space-y-4"> | ||
<CustomTypeList key="Custom Types" /> | ||
<SharedSliceList key="Slices" /> | ||
</main> | ||
) : ( | ||
<main key="Upgrade Summary" className="space-y-4"> | ||
TODO: Upgrade Summary | ||
</main> | ||
)} | ||
</AnimatedElement> | ||
<hr className="border-stone-300" /> | ||
</div> | ||
<main className="p-4"></main> | ||
<AppFooter /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export function AppFooter(): JSX.Element { | ||
return ( | ||
<footer className="container py-4 flex justify-between items-center"> | ||
<div className="text-stone-600 text-sm"> | ||
<a | ||
href="https://prismic.io/docs/help-center" | ||
className="underline" | ||
target="_blank" | ||
> | ||
Help Center | ||
</a> | ||
</div> | ||
</footer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Icon, Skeleton } from "@prismicio/editor-ui"; | ||
|
||
import { useSliceMachineConfig } from "../store/useSliceMachineConfig"; | ||
import { useUser } from "../store/useUser"; | ||
|
||
export function AppHeader(): JSX.Element { | ||
const [config, dashboard] = useSliceMachineConfig((state) => [ | ||
state.config, | ||
state.dashboard, | ||
]); | ||
const profile = useUser((state) => state.profile); | ||
|
||
return ( | ||
<header className="container py-4 flex justify-between items-center"> | ||
{config ? ( | ||
<div> | ||
<h1 className="heading-1">{config.repositoryName}</h1> | ||
<div className="text-stone-600 text-sm"> | ||
Dashboard:{" "} | ||
<a href={dashboard ?? ""} className="underline" target="_blank"> | ||
{dashboard?.replace(/^https?:\/\//i, "")} | ||
</a> | ||
</div> | ||
</div> | ||
) : ( | ||
<div className="leading-[0]"> | ||
<Skeleton width={256} height={56} /> | ||
</div> | ||
)} | ||
{profile ? ( | ||
<em className="badge badge--medium"> | ||
<Icon name="public" size="small" /> | ||
Logged in as {profile.email} | ||
</em> | ||
) : ( | ||
<div className="leading-[0]"> | ||
<Skeleton width={256} height={28} /> | ||
</div> | ||
)} | ||
</header> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import { Button, Icon, Tooltip } from "@prismicio/editor-ui"; | ||
import { useMemo } from "react"; | ||
|
||
import { useSliceConflicts } from "../store/useSliceConflicts"; | ||
import { useSliceMachineConfig } from "../store/useSliceMachineConfig"; | ||
|
||
import { StatusDot } from "./StatusDot"; | ||
|
||
import { CompositeSlice } from "../../../src/models/CompositeSlice"; | ||
import { CustomType } from "../../../src/models/CustomType"; | ||
|
||
export function CustomTypeCard({ | ||
customType, | ||
}: { | ||
customType: CustomType; | ||
}): JSX.Element { | ||
const dashboard = useSliceMachineConfig((state) => state.dashboard); | ||
const conflicts = useSliceConflicts((state) => state.conflicts); | ||
|
||
const sliceZones = useMemo(() => { | ||
const sliceZoneMap: Record< | ||
string, | ||
{ id: string; tabID: string; compositeSlices: CompositeSlice[] } | ||
> = {}; | ||
const compositeSlices = customType.getAllCompositeSlices(); | ||
|
||
for (const compositeSlice of compositeSlices) { | ||
sliceZoneMap[compositeSlice.meta.path.sliceZoneID] ||= { | ||
id: compositeSlice.meta.path.sliceZoneID, | ||
tabID: compositeSlice.meta.path.tabID, | ||
compositeSlices: [], | ||
}; | ||
sliceZoneMap[compositeSlice.meta.path.sliceZoneID].compositeSlices.push( | ||
compositeSlice, | ||
); | ||
} | ||
|
||
return Object.values(sliceZoneMap); | ||
}, [customType]); | ||
|
||
const hasConflicts = useMemo(() => { | ||
return Object.values(conflicts ?? {}).some((slices) => { | ||
return slices.some((slice) => { | ||
return ( | ||
slice instanceof CompositeSlice && | ||
slice.meta.parent.id === customType.id | ||
); | ||
}); | ||
}); | ||
}, [conflicts, customType]); | ||
|
||
return ( | ||
<article className="rounded border-stone-300 border"> | ||
<header className="p-4 flex justify-between items-center"> | ||
<div className="space-x-2 flex items-end"> | ||
<h3 className="heading-3 flex gap-2 items-center"> | ||
<StatusDot type={hasConflicts ? "error" : "success"} /> | ||
{customType.definition.label} | ||
</h3> | ||
<em className="badge"> | ||
<Icon name="description" size="extraSmall" /> ID: {customType.id} | ||
</em> | ||
</div> | ||
<div> | ||
<a | ||
href={`${dashboard}/masks/${customType.id}.json`} | ||
target="_blank" | ||
tabIndex={-1} | ||
> | ||
<Button size="small" variant="secondary" startIcon="link"> | ||
View on Prismic | ||
</Button> | ||
</a> | ||
</div> | ||
</header> | ||
<hr /> | ||
<section className="px-4 py-3"> | ||
<ul className="space-y-3"> | ||
{sliceZones.length ? ( | ||
sliceZones.map((sliceZone) => ( | ||
<li key={sliceZone.id} className="space-y-2"> | ||
<header> | ||
<h4 className="heading-4 flex gap-1 items-center"> | ||
<Icon name="viewDay" size="extraSmall" /> | ||
{sliceZone.id} | ||
</h4> | ||
<small className="italic"> | ||
{sliceZone.compositeSlices.length} legacy slice | ||
{sliceZone.compositeSlices.length > 1 ? "s" : ""} in this | ||
slice zone. | ||
</small> | ||
</header> | ||
<ul className="grid grid-cols-3 gap-2"> | ||
{sliceZone.compositeSlices.map((compositeSlice) => ( | ||
<li | ||
key={compositeSlice.id} | ||
className="text-sm p-2 rounded border-stone-300 border hover:bg-stone-100" | ||
> | ||
<header className="space-y-2"> | ||
<h5 className="heading-5"> | ||
<Tooltip | ||
title={`${compositeSlice.definition.fieldset} has a conflicting ID`} | ||
content={`The ID of this slice is also present in other slice zones or among your shared slices. Head over to the "Slices" tab to resolve them!`} | ||
open={ | ||
compositeSlice.id in (conflicts ?? {}) | ||
? undefined | ||
: false | ||
} | ||
> | ||
<span className="inline-flex gap-2 items-center"> | ||
<StatusDot | ||
type={ | ||
conflicts | ||
? compositeSlice.id in conflicts | ||
? "error" | ||
: "success" | ||
: "unknown" | ||
} | ||
/> | ||
{compositeSlice.definition.fieldset} | ||
</span> | ||
</Tooltip> | ||
</h5> | ||
<em className="badge"> | ||
<Icon name="tag" size="extraSmall" /> ID:{" "} | ||
{compositeSlice.id} | ||
</em> | ||
</header> | ||
</li> | ||
))} | ||
</ul> | ||
</li> | ||
)) | ||
) : ( | ||
<li> | ||
<small className="italic"> | ||
No slice zone in this custom type. | ||
</small> | ||
</li> | ||
)} | ||
</ul> | ||
</section> | ||
</article> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { useRepository } from "../store/useRepository"; | ||
|
||
import { CustomTypeCard } from "./CustomTypeCard"; | ||
|
||
export function CustomTypeList(): JSX.Element { | ||
const customTypes = useRepository((state) => state.customTypes); | ||
|
||
return ( | ||
<section className="space-y-4"> | ||
<h2 className="heading-2">Custom Types ({customTypes?.length})</h2> | ||
<ul className="space-y-2"> | ||
{customTypes?.map((customType) => ( | ||
<li key={customType.id}> | ||
<CustomTypeCard customType={customType} /> | ||
</li> | ||
))} | ||
{customTypes?.length === 0 ? ( | ||
<li className="italic p-4">No Shared Slices found.</li> | ||
) : null} | ||
</ul> | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useRepository } from "../store/useRepository"; | ||
|
||
// TODO: Rendering | ||
export function SharedSliceList(): JSX.Element { | ||
const sharedSlices = useRepository((state) => state.sharedSlices); | ||
|
||
return ( | ||
<section className="space-y-4"> | ||
<h2 className="heading-2">Shared Slices ({sharedSlices?.length})</h2> | ||
<ul> | ||
{sharedSlices?.map((sharedSlice) => ( | ||
<li key={sharedSlice.id}>{sharedSlice.id}</li> | ||
))} | ||
{sharedSlices?.length === 0 ? ( | ||
<li className="italic p-4">No Shared Slices found.</li> | ||
) : null} | ||
</ul> | ||
</section> | ||
); | ||
} |
Oops, something went wrong.