init frontend

This commit is contained in:
Yuzhong Zhang
2025-07-05 23:22:48 +08:00
parent 94953a5eac
commit 602f4629ff
771 changed files with 194268 additions and 1 deletions
@@ -0,0 +1,123 @@
import React from "react";
import { useAtom, useSetAtom } from "jotai";
import {
userAtom,
createCanvasDialogAtom,
renameCanvasDialogAtom,
} from "../app-jotai";
import { CanvasMetadata } from "../data/storage";
import { FilledButton } from "../../packages/excalidraw/components/FilledButton";
import {
FreedrawIcon,
LoadIcon,
TrashIcon,
} from "../../packages/excalidraw/components/icons";
import "./MyCreationsTab.scss";
import clsx from "clsx";
import { timeAgo } from "../utils/time";
interface MyCreationsTabProps {
canvases: readonly CanvasMetadata[];
onCanvasSelect: (id: string) => void;
onCanvasDelete: (id: string) => void;
currentCanvasId: string | null;
}
export const MyCreationsTab: React.FC<MyCreationsTabProps> = ({
canvases,
onCanvasSelect,
onCanvasDelete,
currentCanvasId,
}) => {
const [user] = useAtom(userAtom);
const setCreateCanvasDialog = useSetAtom(createCanvasDialogAtom);
const setRenameCanvasDialog = useSetAtom(renameCanvasDialogAtom);
const sortedCanvases = [...canvases].sort(
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
);
return (
<div className="my-creations-tab">
<div style={{ marginBottom: "1rem" }}>
<FilledButton
label="Create New Canvas"
onClick={() => setCreateCanvasDialog({ isOpen: true })}
fullWidth
>
Create New Canvas
</FilledButton>
</div>
<div className="my-creations-tab__grid">
{canvases.length === 0 ? (
<div className="my-creations-tab__empty">
{LoadIcon}
<p>You have no saved canvases yet.</p>
<p>
Create a new canvas to get started. It will be saved{" "}
{user ? "to your account" : "in your browser"}.
</p>
</div>
) : (
sortedCanvases.map((canvas) => (
<div
key={canvas.id}
className={clsx("my-creations-tab__card", {
"my-creations-tab__card--active": canvas.id === currentCanvasId,
})}
onClick={() => onCanvasSelect(canvas.id)}
>
{canvas.thumbnail ? (
<img
src={canvas.thumbnail}
alt={canvas.name}
className="my-creations-tab__card-thumbnail"
/>
) : (
<div className="my-creations-tab__card-thumbnail--placeholder">
</div>
)}
<div className="my-creations-tab__card-info">
<div className="my-creations-tab__card-details">
<span className="my-creations-tab__card-name">
{canvas.name}
</span>
<span className="my-creations-tab__card-date">
{timeAgo(canvas.updatedAt)}
</span>
</div>
<div className="my-creations-tab__card-actions">
<button
className="my-creations-tab__card-rename"
title="Rename canvas"
onClick={(e) => {
e.stopPropagation();
setRenameCanvasDialog({
isOpen: true,
canvasId: canvas.id,
currentName: canvas.name,
});
}}
>
{FreedrawIcon}
</button>
<button
className="my-creations-tab__card-delete"
title="Delete canvas"
onClick={(e) => {
e.stopPropagation();
onCanvasDelete(canvas.id);
}}
>
{TrashIcon}
</button>
</div>
</div>
</div>
))
)}
</div>
</div>
);
};