Skip to content

Commit

Permalink
expandable sections working for arcade
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxwell Yinger committed Jul 27, 2023
1 parent 3f7106f commit 50c1468
Show file tree
Hide file tree
Showing 4 changed files with 375 additions and 7 deletions.
76 changes: 74 additions & 2 deletions website/src/arcade/Arcade.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import { ArcadeEditor } from "@site/src/arcade/ArcadeEditor";
import datasets from "@site/src/datasets.json";
import { ARCADE_STORAGE_KEYS } from "@site/src/arcade/consts";
import { ExamplePayload, EXAMPLES } from "@site/src/arcade/examples";
import { ArcadeSection } from "@site/src/arcade/ArcadeSection";
import {
ArcadeSection,
ArcadeSectionResizer,
} from "@site/src/arcade/ArcadeSection";
import { ArcadeDatasetEditor } from "@site/src/arcade/ArcadeDatasetEditor";
import { ArcadeResponseView } from "@site/src/arcade/ArcadeResponseView";
import lzstring from "lz-string";
Expand All @@ -22,6 +25,7 @@ import { DefaultToastOptions, Toaster } from "react-hot-toast";
import { HiPlay } from "react-icons/hi";
import clsx from "clsx";
import { ArcadeActionList } from "@site/src/arcade/ArcadeActionList";
import Abacus from "@site/src/arcade/abacus";

export function Arcade() {
const [
Expand Down Expand Up @@ -89,12 +93,49 @@ export function Arcade() {
}
}, []);

const abacus = React.useMemo(() => {
return new Abacus({
dividers: 2,
dividerWidth: 18,
});
}, []);

React.useEffect(
() =>
abacus.onBoundChange(() => {
abacus.container.style.setProperty(
"--w-data",
`${abacus.getNormalizedSectionWidth(0) * 100}%`
);
abacus.container.style.setProperty(
"--w-query",
`${abacus.getNormalizedSectionWidth(1) * 100}%`
);
abacus.container.style.setProperty(
"--w-result",
`${abacus.getNormalizedSectionWidth(2) * 100}%`
);
}),
[]
);

return (
<div className="w-full h-screen overflow-hidden flex flex-col bg-white dark:bg-zinc-900">
<ArcadeHeader selectExample={loadExample} />

<div className="flex-1 flex items-center">
<div className="w-full grid grid-cols-3 gap-5 max-h-[1200px] h-full container max-w-[2400px] pb-5">
<div
ref={abacus.setContainer}
className="relative w-full flex max-h-[1200px] h-full container max-w-[2400px] pb-5"
style={
{
"--w-resizer": `${abacus.dividerWidth}px`,
"--w-data": abacus.initialSectionCssWidth,
"--w-query": abacus.initialSectionCssWidth,
"--w-result": abacus.initialSectionCssWidth,
} as React.CSSProperties
}
>
<ArcadeSection
title="Dataset"
subtitle="The data your query will run against."
Expand All @@ -105,14 +146,32 @@ export function Arcade() {
onSelectItem={setDatasetPreset}
/>
}
onExpandSection={() => abacus.expand(0)}
onContractSection={abacus.reset}
style={{
width: "var(--w-data)",
}}
>
<div className="h-full relative">
<ArcadeDatasetEditor />
</div>
</ArcadeSection>
<ArcadeSectionResizer
onMouseDrag={(x) => {
abacus.updateDivider(0, x);
}}
style={{
width: "var(--w-resizer)",
}}
/>
<ArcadeSection
title="Query Code"
subtitle="Your code to run a GROQD query."
onExpandSection={() => abacus.expand(1)}
onContractSection={abacus.reset}
style={{
width: "var(--w-query)",
}}
headerRightContent={
<button
className={clsx(
Expand All @@ -134,9 +193,22 @@ export function Arcade() {
<ArcadeQueryDisplay query={query.query} />
</div>
</ArcadeSection>
<ArcadeSectionResizer
onMouseDrag={(x) => {
abacus.updateDivider(1, x);
}}
style={{
width: "var(--w-resizer)",
}}
/>
<ArcadeSection
title="Query Result"
subtitle="The result of your GROQD query."
onExpandSection={() => abacus.expand(2)}
onContractSection={abacus.reset}
style={{
width: "var(--w-result)",
}}
>
<ArcadeResponseView
isExecutingQuery={isExecutingQuery}
Expand Down
2 changes: 1 addition & 1 deletion website/src/arcade/ArcadeQueryDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function ArcadeQueryDisplay({ query }: ArcadeQueryDisplayProps) {
Query
</div>
<div className="relative group">
<pre className="p-4 bg-transparent rounded-none w-full overflow-auto pretty-scrollbar text-gray-700 dark:text-gray-200 mb-0">
<pre className="p-4 bg-transparent rounded-none w-full overflow-scroll pretty-scrollbar text-gray-700 dark:text-gray-200 mb-0">
{query || "..."}
</pre>
<div className="absolute right-0 inset-y-0 flex items-center pr-4">
Expand Down
95 changes: 91 additions & 4 deletions website/src/arcade/ArcadeSection.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,62 @@
import * as React from "react";
import { RiExpandLeftRightFill, RiContractLeftRightFill } from "react-icons/ri";

import clsx from "clsx";

type ArcadeSectionProps = {
title: string;
subtitle?: string;
headerRightContent?: JSX.Element;
style?: React.CSSProperties;
onContractSection?: () => void;
onExpandSection?: () => void;
};

export function ArcadeSection({
title,
subtitle,
headerRightContent,
style,
onContractSection,
onExpandSection,
children,
}: React.PropsWithChildren<ArcadeSectionProps>) {
return (
<div className="w-full border border-solid border-gray-200 dark:border-zinc-700 rounded overflow-hidden flex flex-col h-full">
<div className="p-4 flex items-center justify-between">
<div
className="group border border-solid border-gray-200 dark:border-zinc-700 rounded flex flex-col h-full overflow-hidden"
style={style}
>
<div className="flex ml-2 mt-2">
<button
className={clsx(
"h-3.5 w-3.5 self-start flex items-center justify-center p-0",
"rounded-full cursor-pointer border-none transition-opacity duration-150",
"text-transparent bg-zinc-400 dark:bg-zinc-700",
"hover:bg-green-500 focus-visible:bg-green-500 hover:text-zinc-900 focus-visible:text-zinc-900"
)}
onClick={onExpandSection}
>
<RiExpandLeftRightFill className="h-3.5 w-3.5" />
</button>
<button
className={clsx(
"ml-2 h-3.5 w-3.5 self-start flex items-center justify-center p-0",
"rounded-full cursor-pointer border-none transition-opacity duration-150",
"text-transparent bg-zinc-400 dark:bg-zinc-700",
"hover:bg-yellow-500 focus-visible:bg-yellow-500 hover:text-zinc-900 focus-visible:text-zinc-900"
)}
onClick={onContractSection}
>
<RiContractLeftRightFill className="h-3.5 w-3.5" />
</button>
</div>
<div className="pt-3 pl-4 pr-4 pb-4 flex items-center justify-between">
<div>
<div className="text-base font-bold leading-none text-gray-700 dark:text-gray-200 mb-0.5">
<div className="text-base font-bold leading-none text-gray-700 dark:text-gray-200 mb-0.5 whitespace-nowrap">
{title}
</div>
{subtitle && (
<div className="text-gray-800 dark:text-gray-100 text-sm">
<div className="text-gray-800 dark:text-gray-100 text-sm whitespace-nowrap">
{subtitle}
</div>
)}
Expand All @@ -31,3 +67,54 @@ export function ArcadeSection({
</div>
);
}

export function ArcadeSectionResizer({
onMouseDrag,
style,
}: {
onMouseDrag?: (x: number) => void;
style?: React.CSSProperties;
}) {
const isDragging = React.useRef(false);
const offset = React.useRef(0);
const mouseDragHandler = React.useRef(onMouseDrag);
mouseDragHandler.current = onMouseDrag;

React.useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!isDragging.current) return;
mouseDragHandler.current?.(e.clientX - offset.current);
};
const handleMouseUp = () => {
if (!isDragging.current) return;
offset.current = 0;
isDragging.current = false;
document.body.style.userSelect = "auto";
};

document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);

return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, []);

return (
<div
style={{
// backgroundColor: "tomato ",
width: 18,
cursor: "col-resize",
...style,
}}
onMouseDown={(e) => {
offset.current =
e.clientX - e.currentTarget.getBoundingClientRect().left;
isDragging.current = true;
document.body.style.userSelect = "none";
}}
/>
);
}
Loading

0 comments on commit 50c1468

Please sign in to comment.