Skip to content

Commit

Permalink
feat: support load ydoc from url
Browse files Browse the repository at this point in the history
  • Loading branch information
lawvs committed Apr 10, 2024
1 parent 99f8715 commit a5ac029
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 25 deletions.
26 changes: 1 addition & 25 deletions src/components/config-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as Y from "yjs";
import { Button } from "./ui/button";
import { useToast } from "./ui/use-toast";
import { Config, useConfig, useYDoc } from "../state";
import { ExportButton } from "./export-button";
Expand All @@ -24,29 +22,7 @@ export function ConfigPanel() {
return (
<div className="flex w-64 flex-col gap-4">
<h2 className="text-xl">Configure</h2>
<Button
onClick={async () => {
yDoc.destroy();
setYDoc(new Y.Doc());
const handles = await window.showOpenFilePicker({
startIn: "downloads",
});
const file = await handles[0].getFile();
try {
const newYDoc = await fileToYDoc(file);
setYDoc(newYDoc);
} catch (error) {
console.error(error);
toast({
variant: "destructive",
title: "Error",
description: "Failed to load YDoc",
});
}
}}
>
Load YDoc
</Button>
<LoadButton />

<Select
value={config.view}
Expand Down
148 changes: 148 additions & 0 deletions src/components/load-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { File, Link, RotateCw, Upload } from "lucide-react";
import { useState } from "react";
import * as Y from "yjs";
import { useYDoc } from "../state";
import { fileToYDoc } from "../utils";
import { toast } from "./ui/use-toast";

function LoadFromUrlDialog({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [url, setUrl] = useState("");
const [, setYDoc] = useYDoc();

const handleLoadYDoc = () => {
setLoading(true);
fetch(url)
.then((res) => res.arrayBuffer())
.then((buffer) => {
const uint8 = new Uint8Array(buffer);
const yDoc = new Y.Doc();
Y.applyUpdate(yDoc, uint8);
setYDoc(yDoc);
setOpen(false);
})
.catch((error) => {
console.error(error);
toast({
variant: "destructive",
title: "Error",
description: "Failed to load YDoc",
});
})
.finally(() => {
setLoading(false);
});
};

return (
<Dialog open={open} onOpenChange={setOpen}>
{children}
<DialogContent>
<DialogHeader>
<DialogTitle>Load from URL</DialogTitle>
<DialogDescription>
Paste the URL of the YDoc you want to load
</DialogDescription>
</DialogHeader>
<div className="flex items-center space-x-2">
<div className="grid flex-1 gap-2">
<Label htmlFor="load-from-url-input" className="sr-only">
URL
</Label>
<Input
id="load-from-url-input"
type="url"
placeholder="https://example.com/ydoc"
onKeyDown={(e) => {
if (e.key === "Enter") {
// Cancel the default action, if needed
e.preventDefault();
handleLoadYDoc();
}
}}
onChange={(e) => {
setUrl(e.target.value);
}}
/>
</div>
</div>
<DialogFooter>
<Button disabled={loading} onClick={handleLoadYDoc}>
{loading && <RotateCw className="mr-2 h-4 w-4 animate-spin" />}
Load
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
LoadFromUrlDialog.Trigger = DialogTrigger;

export function LoadButton() {
const [yDoc, setYDoc] = useYDoc();

return (
<LoadFromUrlDialog>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button>
<Upload className="mr-2 h-4 w-4" />
Load YDoc
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={async () => {
yDoc.destroy();
setYDoc(new Y.Doc());
const handles = await window.showOpenFilePicker({
startIn: "downloads",
});
const file = await handles[0].getFile();
try {
const newYDoc = await fileToYDoc(file);
setYDoc(newYDoc);
} catch (error) {
console.error(error);
toast({
variant: "destructive",
title: "Error",
description: "Failed to load YDoc",
});
}
}}
>
<File className="mr-2 h-4 w-4" />
Load from file
</DropdownMenuItem>

<LoadFromUrlDialog.Trigger asChild>
<DropdownMenuItem>
<Link className="mr-2 h-4 w-4" />
Load from URL
</DropdownMenuItem>
</LoadFromUrlDialog.Trigger>
</DropdownMenuContent>
</DropdownMenu>
</LoadFromUrlDialog>
);
}

0 comments on commit a5ac029

Please sign in to comment.