Skip to content

Commit

Permalink
Drag and drop workspaces
Browse files Browse the repository at this point in the history
  • Loading branch information
spaaaacccee committed Oct 26, 2023
1 parent 8e22e2e commit 97e48f2
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 34 deletions.
19 changes: 14 additions & 5 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"react-beautiful-dnd": "^13.1.1",
"react-d3-tree": "^3.6.1",
"react-dom": "^18.2.0",
"react-file-drop": "^3.1.6",
"react-slot-component": "^2.0.3",
"react-use": "^17.4.0",
"react-virtualized-auto-sizer": "^1.0.20",
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/app-bar/Playback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export function PlaybackService({
children,
value,
}: EditorSetterProps<Layer<PlaybackLayerData>>) {
const { step, tick, end, playing, pause } = usePlaybackState(value?.key);
useRaf();
const { step, tick, end, playing, pause } = usePlaybackState(value?.key);

const notify = useSnackbar();
const [{ playbackRate = 1 }] = useSettings();
Expand Down
2 changes: 0 additions & 2 deletions client/src/components/inspector/FullscreenProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ export function FullscreenProgress() {
WebkitAppRegion: "drag",
}}
open={!!messages.length}
unmountOnExit
mountOnEnter
>
<Stack alignItems="center" spacing={4}>
<CircularProgress />
Expand Down
39 changes: 39 additions & 0 deletions client/src/components/inspector/WorkspaceDropZone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { WorkspacesOutlined } from "@mui/icons-material";
import { Backdrop, Stack, Typography as Type } from "@mui/material";
import { useWorkspace } from "hooks/useWorkspace";
import { head } from "lodash";
import { useState } from "react";
import { FileDrop } from "react-file-drop";
import { useAcrylic } from "theme";

export function WorkspaceDropZone() {
const acrylic = useAcrylic() as any;
const { load } = useWorkspace();
const [open, setOpen] = useState(false);
return (
<>
<FileDrop
onFrameDragLeave={() => setOpen(false)}
onFrameDragEnter={() => setOpen(true)}
onFrameDrop={() => setOpen(false)}
onDragLeave={() => setOpen(false)}
onDrop={(f) => f?.length && load(head(f))}
>
<Backdrop
sx={{
...acrylic,
zIndex: (t) => t.zIndex.tooltip + 1,
}}
open={open}
>
<Stack alignItems="center" spacing={4}>
<WorkspacesOutlined />
<Type variant="body2" color="textSecondary">
Open workspace
</Type>
</Stack>
</Backdrop>
</FileDrop>
</>
);
}
2 changes: 2 additions & 0 deletions client/src/components/inspector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useAnyLoading } from "slices/loading";
import { PanelState, useView } from "slices/view";
import { ViewTree } from "./ViewTree";
import { FullscreenProgress } from "./FullscreenProgress";
import { WorkspaceDropZone } from "./WorkspaceDropZone";

type SpecimenInspectorProps = Record<string, any> & FlexProps;

Expand Down Expand Up @@ -39,6 +40,7 @@ export function Inspector(props: SpecimenInspectorProps) {
/>
</Fade>
<FullscreenProgress />
<WorkspaceDropZone />
</>
);
}
50 changes: 30 additions & 20 deletions client/src/hooks/useWorkspace.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
import { useSnackbar } from "components/generic/Snackbar";
import download from "downloadjs";
import { fileDialog as file } from "file-select-dialog";
import { find } from "lodash";
import { UIState, useUIState } from "slices/UIState";
import { formatByte, useBusyState } from "slices/busy";
import { Layers, useLayers } from "slices/layers";
import { generateUsername as id } from "unique-username-generator";
import { parseYamlAsync } from "workers/async";

function ext(s: string) {
return s.split(".").pop();
}
const FORMATS = ["json", "yaml"];
const acceptedFormats = [`.workspace.yaml`, `.workspace.json`];

type Workspace = {
UIState: UIState;
layers: Layers;
};

export function useWorkspace() {
const notify = useSnackbar();
const [layers, setLayers] = useLayers();
const [UIState, setUIState] = useUIState();
const usingBusyState = useBusyState("workspace");
return {
load: async () => {
const f = await file({
accept: FORMATS.map((c) => `.workspace.${c}`),
strict: true,
});
if (f && FORMATS.includes(ext(f.name)!)) {
await usingBusyState(async () => {
const content = await f.text();
const parsed = (await parseYamlAsync(content)) as
| Workspace
| undefined;
if (parsed) {
setLayers(() => parsed.layers);
setUIState(() => parsed.UIState);
}
}, `Opening workspace (${formatByte(f.size)})`);
load: async (selectedFile?: File) => {
const f =
selectedFile ??
(await file({
accept: acceptedFormats,
strict: true,
}));
if (f) {
if (isWorkspaceFile(f)) {
await usingBusyState(async () => {
const content = await f.text();
const parsed = (await parseYamlAsync(content)) as
| Workspace
| undefined;
if (parsed) {
setLayers(() => parsed.layers);
setUIState(() => parsed.UIState);
}
}, `Opening workspace (${formatByte(f.size)})`);
} else {
notify(`${f?.name} is not a workspace file.`);
}
}
},
save: () => {
Expand All @@ -48,3 +54,7 @@ export function useWorkspace() {
},
};
}

export function isWorkspaceFile(f: File) {
return find(acceptedFormats, (format) => f.name.endsWith(format));
}
12 changes: 6 additions & 6 deletions internal-renderers/src/d2-renderer/D2RendererWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,20 +206,20 @@ export class D2RendererWorker extends EventEmitter<
ctx.fillStyle = this.#options.backgroundColor;
ctx.fillRect(0, 0, tile.width, tile.height);

const x = 16;
const length = 16;
const thickness = 1;
ctx.fillStyle = `rgba(127,127,127,0.25)`;
ctx.fillStyle = `rgba(127,127,127,0.36)`;
ctx.fillRect(
(tile.width - x) / 2,
(tile.width - length) / 2,
(tile.height - thickness) / 2,
x,
length,
thickness
);
ctx.fillRect(
(tile.width - thickness) / 2,
(tile.height - x) / 2,
(tile.height - length) / 2,
thickness,
x
length
);

for (const { component } of sortBy(
Expand Down

0 comments on commit 97e48f2

Please sign in to comment.