-
Notifications
You must be signed in to change notification settings - Fork 130
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
13 changed files
with
575 additions
and
8 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 |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!DOCTYPE html> | ||
<html lang="en" class="h-full bg-white"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/src/assets/kanaries.ico" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Graphic Walker Gallery</title> | ||
<meta name="description" content="An easy to use Exploratory Data Analysis tool"> | ||
</head> | ||
<body class="h-full"> | ||
<div id="root"></div> | ||
<script type="module" src="/src/gallery/index.tsx"></script> | ||
</body> | ||
</html> |
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 @@ | ||
export { default } from "../../examples/components/errorPage"; |
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,151 @@ | ||
import React, { useContext, useState, Fragment } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import { Menu, Transition } from '@headlessui/react' | ||
import { ChevronDownIcon } from '@heroicons/react/20/solid' | ||
import { ArrowUturnLeftIcon } from '@heroicons/react/24/outline'; | ||
import { IChart, PureRenderer, GraphicWalker } from '@kanaries/graphic-walker'; | ||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; | ||
import { a11yDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; | ||
import { themeContext } from '../context'; | ||
import { GalleryItemOption } from './GalleryGroup'; | ||
import { specDict } from '../resources'; | ||
import { IDataSource, useFetch } from '../util'; | ||
|
||
function getResourceURL(type: "datasets" | "specs", name: string): string { | ||
if (type === "specs") { | ||
return specDict[name]; | ||
} else if (type === "datasets") { | ||
return `https://pub-2422ed4100b443659f588f2382cfc7b1.r2.dev/datasets/${name}.json`; | ||
} else { | ||
throw new Error(`Unknown fetch type: "${type}".`); | ||
} | ||
} | ||
|
||
interface ExampleProps { | ||
title: string, | ||
specName: string, | ||
datasetName: string, | ||
} | ||
|
||
function classNames(...classes: string[]) { | ||
return classes.filter(Boolean).join(' ') | ||
} | ||
|
||
function Dropdown({ showMode, setShowMode }: { | ||
showMode: 'preview' | 'editor', | ||
setShowMode: (mode: 'preview' | 'editor') => void | ||
}) { | ||
return ( | ||
<div className="absolute top-4 right-4 w-56 text-right z-10"> | ||
<Menu as="div" className="relative inline-block text-left"> | ||
<div> | ||
<Menu.Button className="inline-flex w-full justify-center rounded-md bg-gray-950 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75"> | ||
{showMode === 'preview' ? 'Preview' : 'Editor'} | ||
<ChevronDownIcon className="-mr-1 ml-2 h-5 w-5" aria-hidden="true"/> | ||
</Menu.Button> | ||
</div> | ||
<Transition | ||
as={Fragment} | ||
enter="transition ease-out duration-100" | ||
enterFrom="transform opacity-0 scale-95" | ||
enterTo="transform opacity-100 scale-100" | ||
leave="transition ease-in duration-75" | ||
leaveFrom="transform opacity-100 scale-100" | ||
leaveTo="transform opacity-0 scale-95" | ||
> | ||
<Menu.Items className="absolute right-0 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none"> | ||
<div className="px-1 py-1 "> | ||
<Menu.Item> | ||
{({ active }) => ( | ||
<button | ||
onClick={() => setShowMode("preview")} | ||
className={`${active ? 'bg-gray-100 text-gray-900' : 'text-gray-700' | ||
} group flex w-full items-center rounded-md px-2 py-2 text-sm`} | ||
> | ||
Preview | ||
</button> | ||
)} | ||
</Menu.Item> | ||
<Menu.Item> | ||
{({ active }) => ( | ||
<button | ||
onClick={() => setShowMode("editor")} | ||
className={`${active ? 'bg-gray-100 text-gray-900' : 'text-gray-700' | ||
} group flex w-full items-center rounded-md px-2 py-2 text-sm`} | ||
> | ||
Editor | ||
</button> | ||
)} | ||
</Menu.Item> | ||
</div> | ||
</Menu.Items> | ||
</Transition> | ||
</Menu> | ||
</div> | ||
) | ||
} | ||
|
||
function Example(props: ExampleProps) { | ||
const { | ||
title, | ||
specName, | ||
datasetName, | ||
} = props; | ||
const { theme } = useContext(themeContext); | ||
const [showMode, setShowMode] = useState<'preview' | 'editor'>('preview'); | ||
const datasetURL = getResourceURL("datasets", datasetName); | ||
const specsURL = getResourceURL("specs", specName); | ||
const { dataSource, fields } = useFetch<IDataSource>(datasetURL); | ||
const spec = useFetch<IChart[]>(specsURL); | ||
const chart = spec[0] as IChart; | ||
|
||
return ( | ||
<div> | ||
<div className="flex gap-2 items-center"> | ||
<Link to={".."}> | ||
<button type="button" className="flex items-center justify-center rounded-md px-1 py-1 transition hover:bg-zinc-900/5 dark:text-white dark:hover:bg-white/5"> | ||
<ArrowUturnLeftIcon className="h-5 w-5" /> | ||
</button> | ||
</Link> | ||
<h2 className="text-2xl font-bold tracking-tight text-gray-900">{title}</h2> | ||
</div> | ||
|
||
<div className={classNames("relative", showMode === 'editor' ? "mt-6 border rounded-md overflow-hidden" : "")}> | ||
<Dropdown showMode={showMode} setShowMode={setShowMode} /> | ||
{showMode === 'preview' && <> | ||
<PureRenderer | ||
className="mt-6 border rounded-md overflow-hidden" | ||
rawData={dataSource} | ||
visualConfig={chart.config} | ||
visualState={chart.encodings} | ||
visualLayout={chart.layout} | ||
appearance={theme} | ||
/> | ||
<h2 className="mt-16 mb-6 text-2xl font-bold tracking-tight text-gray-900">Graphic Walker JSON Specification</h2> | ||
<SyntaxHighlighter language="tsx" style={a11yDark}> | ||
{JSON.stringify(spec, null, 2)} | ||
</SyntaxHighlighter> | ||
</>} | ||
|
||
{showMode === "editor" && | ||
<GraphicWalker fields={fields} data={dataSource} chart={spec} appearance={theme} /> | ||
} | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default function ExampleWrapper(props: { | ||
options: GalleryItemOption, | ||
}) { | ||
const { options } = props; | ||
return ( | ||
<React.Suspense fallback={<p>Loading component...</p>}> | ||
<Example | ||
title={options.title} | ||
specName={options.id} | ||
datasetName={options.datasetName} | ||
/> | ||
</React.Suspense> | ||
); | ||
} |
56 changes: 56 additions & 0 deletions
56
packages/playground/src/gallery/components/GalleryGroup.tsx
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,56 @@ | ||
import { useMemo } from 'react'; | ||
import { Link, Outlet, useLocation } from 'react-router-dom'; | ||
import { imageDict } from '../resources'; | ||
|
||
interface GalleryItemProps { | ||
id: string, | ||
title: string, | ||
} | ||
export type GalleryItemOption = GalleryItemProps & { datasetName: string }; | ||
|
||
function GalleryItem(props: GalleryItemProps) { | ||
const { id, title } = props; | ||
const imageURL = imageDict[id]; | ||
|
||
return ( | ||
<Link to={id}> | ||
<div className="divide-y divide-gray-200 h-full overflow-hidden rounded-lg bg-white shadow group"> | ||
<div | ||
className="w-full h-36 bg-cover bg-no-repeat overflow-hidden hover:bg-right-bottom" | ||
style={{ | ||
backgroundImage: `url(${imageURL})`, | ||
transition: "background-position 2s", | ||
}} | ||
></div> | ||
<div className="px-4 pt-2 pb-4 sm:px-6 text-sm text-gray-700 group-hover:underline">{title}</div> | ||
</div> | ||
</Link> | ||
); | ||
} | ||
|
||
export default function GalleryGroup(props: { | ||
title: string, | ||
path: string, | ||
items: GalleryItemProps[], | ||
}) { | ||
const { title, path, items } = props; | ||
const location = useLocation(); | ||
const isActive = useMemo(() => { | ||
return location.pathname.endsWith(path) || location.pathname.endsWith(path + '/'); | ||
}, [location.pathname, path]); | ||
|
||
return ( | ||
<> | ||
{isActive && <> | ||
<h2 className="mb-6 text-2xl font-bold tracking-tight text-gray-900">{title}</h2> | ||
<div className="grid justify-between gap-y-5 gap-x-4 grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] my-7"> | ||
{ | ||
items.map(({ id, title }, index) => | ||
<GalleryItem key={index} id={id} title={title} />) | ||
} | ||
</div> | ||
</>} | ||
<Outlet /> | ||
</> | ||
) | ||
} |
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 @@ | ||
export { themeContext, useTheme } from '../examples/context'; |
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,3 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
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,26 @@ | ||
import React from 'react'; | ||
import { createRoot } from 'react-dom/client'; | ||
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; | ||
import Layout from './layout'; | ||
import { pages } from './pages'; | ||
import ErrorPage from './components/ErrorPage'; | ||
import './index.css'; | ||
|
||
export const homeRoute = "/gallery" | ||
|
||
const root = createRoot(document.getElementById("root") as HTMLElement); | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: homeRoute, | ||
element: <Layout />, | ||
errorElement: <ErrorPage />, | ||
children: pages, | ||
}, | ||
]); | ||
|
||
root.render( | ||
<React.StrictMode> | ||
<RouterProvider router={router} /> | ||
</React.StrictMode> | ||
); |
Oops, something went wrong.