Created
April 20, 2021 21:09
-
-
Save zmitry/673a2d8bddaced99c825d4174e0d82b3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| import React, { useRef, useMemo, Suspense } from "react"; | |
| import { last } from "lodash"; | |
| import { stringify } from "./url"; | |
| import { Trie, dfs } from "./trie"; | |
| function stringifyQueryHash(hash) { | |
| return "?" + stringify(hash); | |
| } | |
| function isUpperCase(str) { | |
| return str[0] === str[0].toUpperCase(); | |
| } | |
| function StoryCase({ componentName, component, config, params }) { | |
| const getFullscreenLink = async (addProps) => { | |
| return ( | |
| window.location.origin + | |
| stringifyQueryHash({ | |
| ...params, | |
| fullscreen: true, | |
| story: params.story, | |
| }) | |
| ); | |
| }; | |
| return ( | |
| <div | |
| style={{ | |
| height: "100%", | |
| }} | |
| > | |
| <div | |
| className="card-title hstack" | |
| style={ | |
| { | |
| "--space": "0.5ch", | |
| } as any | |
| } | |
| > | |
| <a | |
| title="fullscreen" | |
| className="size1 icon-button" | |
| onClick={async (e) => { | |
| e.preventDefault(); | |
| const url = await getFullscreenLink(false); | |
| window.open(url); | |
| }} | |
| target="_blank" | |
| > | |
| <div>{componentName} ⧉</div> | |
| </a> | |
| </div> | |
| {config.decorator(component)} | |
| </div> | |
| ); | |
| } | |
| function IframeControllerWrapper({ children }) { | |
| return ( | |
| <div className="stack"> | |
| <Suspense | |
| fallback={<div style={{ margin: "auto" }} className="storyui-loader" />} | |
| > | |
| {children} | |
| </Suspense> | |
| </div> | |
| ); | |
| } | |
| //#endregion | |
| //#region controller app | |
| const SidePanel = React.memo(function SidePanel({ | |
| stories, | |
| story, | |
| navigate, | |
| }: any) { | |
| let res = []; | |
| dfs(stories, (node, depth, parentKey) => { | |
| // do not render top level folder which is "."" | |
| if (!parentKey) { | |
| return; | |
| } | |
| let key = node.key; | |
| const label = key.replace(parentKey, "").replace("/", ""); | |
| let className = story === key ? "selected" : ""; | |
| if (node.end) { | |
| className += " side-label-item"; | |
| } else { | |
| className += " side-label-group"; | |
| } | |
| res.push( | |
| <a | |
| style={{ | |
| marginLeft: depth - 1 + "ch", | |
| }} | |
| title={label} | |
| className={className} | |
| key={key + "group"} | |
| onClick={(e) => { | |
| e.preventDefault(); | |
| navigate({ story: key }, { preserveParams: false }); | |
| return false; | |
| }} | |
| > | |
| {label} | |
| </a> | |
| ); | |
| }); | |
| return ( | |
| <div style={{ overflow: "auto" }}> | |
| <nav className="side stack" style={{ "--space": "2px" } as any}> | |
| {res} | |
| </nav> | |
| </div> | |
| ); | |
| }); | |
| function AppIframe({ story, ...params }) { | |
| return useMemo(() => { | |
| return ( | |
| <object | |
| aria-label="story" | |
| key={story} | |
| className="embed" | |
| data={stringifyQueryHash({ story, ...params, iframe: true })} | |
| /> | |
| ); | |
| }, [story]); | |
| } | |
| //#endregion | |
| export function isStory(key) { | |
| return isUpperCase(key); | |
| } | |
| export function LightApp({ stories, params, navigate }) { | |
| const { story, iframe } = params; | |
| const root = new Trie(stories); | |
| if (iframe) { | |
| let items = root.find(story || "")?.map((el) => [el.key, el.value]); | |
| return ( | |
| <IframeControllerWrapper> | |
| {items.map(([key, C]: any) => { | |
| return ( | |
| <StoryCase | |
| params={params} | |
| key={key} | |
| config={C.config} | |
| componentName={last(key.split("/"))} | |
| component={C} | |
| /> | |
| ); | |
| })} | |
| </IframeControllerWrapper> | |
| ); | |
| } | |
| return ( | |
| <div className="storyRoot"> | |
| <SidePanel stories={stories} {...params} navigate={navigate} /> | |
| <AppIframe {...params} /> | |
| </div> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment