Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/catto-labs/drive
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexcited committed Aug 13, 2023
2 parents f6d6c22 + b5b52c9 commit fb6d8ed
Show file tree
Hide file tree
Showing 4 changed files with 629 additions and 78 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ netlify

# Temp
gitignore
vite.config.ts.*

# System Files
.DS_Store
Expand Down
223 changes: 145 additions & 78 deletions src/routes/dashboard/[workspace_id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,32 @@ import {
Match,
} from "solid-js";
import { A, Title, useNavigate } from "solid-start";
import { auth, logOutUser } from "@/stores/auth";
import { logOutUser } from "@/stores/auth";

import IconPower from "~icons/mdi/power";
import IconDotsHorizontalCircleOutline from "~icons/mdi/dots-horizontal-circle-outline";
import IconStarOutline from "~icons/mdi/star-outline";
import IconShareVariantOutline from "~icons/mdi/share-variant-outline";
import IconChevronRight from "~icons/mdi/chevron-right";
import IconCheck from "~icons/mdi/check";
import IconFileUploadOutline from "~icons/mdi/file-upload-outline";
import IconPlus from "~icons/mdi/plus";
import IconFolderAccountOutline from "~icons/mdi/folder-account-outline";
import IconAccountMultipleOutline from "~icons/mdi/account-multiple-outline";
import IconTrashCanOutline from "~icons/mdi/trash-can-outline";
import IconAccount from "~icons/mdi/account";
import IconMenuDown from "~icons/mdi/menu-down";
import IconFileOutline from "~icons/mdi/file-outline"
import IconFileImageOutline from "~icons/mdi/file-image-outline"
import IconFileDownloadOutline from "~icons/mdi/file-download-outline"
import IconDeleteOutline from "~icons/mdi/delete-outline"
import IconHomeExportOutline from "~icons/mdi/home-export-outline"
import IconDotsHorizontal from "~icons/mdi/dots-horizontal"
import IconDownload from "~icons/mdi/download";
import IconDeleteOutline from "~icons/mdi/delete-outline";
import IconDotsHorizontal from "~icons/mdi/dots-horizontal";
import IconClose from "~icons/mdi/close";
import IconFolderOutline from "~icons/mdi/folder-outline";

import cattoDriveLogo from "@/assets/icon/logo.png";

import FullscreenLoader from "@/components/FullscreenLoader";

import { DropdownMenu } from "@kobalte/core";
import { getFileIcon } from "@/utils/getFileIcons";

import { DropdownMenu, Dialog } from "@kobalte/core";

import { useParams } from "solid-start";

Expand All @@ -47,10 +46,7 @@ import {
removePermanentlyFile,
} from "@/utils/files";

import {
getContentOfWorkspace,
createWorkspace
} from "@/utils/workspaces";
import { getContentOfWorkspace, createWorkspace } from "@/utils/workspaces";

import type { WorkspaceContent } from "@/types/api";
import { Switch } from "solid-js";
Expand All @@ -59,48 +55,47 @@ const Page: Component = () => {
const [view, setView] = createSignal<string>("name");
const params = useParams();

const [workspaceContent, setWorkspaceContent] = createSignal<WorkspaceContent[] | null>(null);
const [workspaceContent, setWorkspaceContent] = createSignal<
WorkspaceContent[] | null
>(null);
const navigate = useNavigate();

createEffect(on(() => params.workspace_id, async (workspaceId: string) => {
const workspace_content = await getContentOfWorkspace(workspaceId);
setWorkspaceContent(workspace_content);
}));
createEffect(
on(
() => params.workspace_id,
async (workspaceId: string) => {
const workspace_content = await getContentOfWorkspace(workspaceId);
setWorkspaceContent(workspace_content);
}
)
);

const fileUploadHandler = async (files: FileList) => {
try {
const uploaded = await makeFileUpload(files, {
workspace_id: params.workspace_id,
private: true
private: true,
});

const new_content: WorkspaceContent[] = uploaded.map(file => ({
const new_content: WorkspaceContent[] = uploaded.map((file) => ({
type: "file",
data: file
}))
data: file,
}));

setWorkspaceContent((files) => (files ? [...files, ...new_content] : new_content));
setWorkspaceContent((files) =>
files ? [...files, ...new_content] : new_content
);
} catch (error) {
console.error(error);
}
};

const getFileIcon = (file: any) => {
const fileExtension = file.name.split(".").pop().toLowerCase();
const imageFileExtensions = ["png", "jpg", "jpeg", "gif", "webp"];

if (imageFileExtensions.indexOf(fileExtension) !== -1) {
return <IconFileImageOutline class="text-xl" />
}
else {
return <IconFileOutline class="text-xl" />
}
}

createEffect(() => {
window.scrollTo(0, 0);
});

const [openDeletion, setOpenDeletion] = createSignal(false);

return (
<>
<Title>Dashboard - Drive</Title>
Expand All @@ -112,7 +107,7 @@ const Page: Component = () => {
}
>
<div class="backdrop-blur-xl w-screen h-screen relative flex overflow-hidden">
<div class="text-text bg-surface0/65 min-w-64 w-1/5 shrink-0">
<div class="text-text bg-surface0/80 min-w-64 w-1/5 shrink-0">
<header class="px-4 pt-6 pb-2 shrink-0 sticky top-0 w-full h-14 flex flex-row flex flex-row gap-[10px] items-center w-full">
<img src={cattoDriveLogo} class="w-10 h-10 -ml-1 mt-1" />
<span class="text-lg">
Expand Down Expand Up @@ -181,15 +176,20 @@ const Page: Component = () => {
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content class="overview-dropdown-content bg-surface0 border border-surface2 p-2 flex flex-col w-68 bg-opacity-50 gap-y-1 backdrop-blur-md rounded-lg text-sm">
<DropdownMenu.Item class="px-4 py-1 hover:bg-lavender text-text hover:text-[rgb(46,48,66)] rounded-md w-full flex justify-between"
<DropdownMenu.Item
class="px-4 py-1 hover:bg-lavender text-text hover:text-[rgb(46,48,66)] rounded-md w-full flex justify-between"
onSelect={async () => {
const workspace = await createWorkspace(params.workspace_id);
const workspace = await createWorkspace(
params.workspace_id
);
const item: WorkspaceContent = {
type: "workspace",
data: workspace
data: workspace,
};

setWorkspaceContent(prev => prev ? [...prev, item] : [item]);
setWorkspaceContent((prev) =>
prev ? [...prev, item] : [item]
);
}}
>
New Folder <span class="text-subtext1">⌘ N</span>
Expand Down Expand Up @@ -284,16 +284,30 @@ const Page: Component = () => {
</header>

<main class="overflow-auto">
<section class="block p-4">
<section class="block p-4 pt-3">
<div class="w-full h-auto pl-10 pb-1 px-2 flex flex-row justify-between items-center gap-1 text-sm text-subtext0">
<div class="flex flex-row">
<span class="w-142">Name</span>
<span>Date added</span>
</div>
<span>Actions</span>
</div>
<For each={workspaceContent()!}>
{(content) => (
<Switch>
<Match when={content.type === "file" && content.data}>
{file => (
<div class="w-full h-auto p-2 flex flex-row justify-between items-center gap-1 border-b border-surface2 hover:bg-surface0">
<div class="flex flex-row gap-2">
{getFileIcon(file())}
<p class="text-sm mt-0.5">{file().name}</p>
{(file) => (
<div class="w-full h-auto p-2 flex flex-row justify-between items-center gap-1 border-b border-surface2 hover:bg-surface0/50">
<div class="flex flex-row">
<div class="flex flex-row gap-2 text-text w-150">
{getFileIcon(file())}
<p class="text-sm mt-0.5">{file().name}</p>
</div>
<div class="flex flex-row gap-2 text-text">
<p class="text-sm mt-0.5">
{file().created_at}
</p>
</div>
</div>
<div class="flex flex-row gap-1">
<button
Expand All @@ -309,54 +323,108 @@ const Page: Component = () => {
</button>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<button
type="button"
title="Actions"
class="p-1 hover:bg-surface1 rounded-md"
>
<IconDotsHorizontal class="text-lg text-text" />
</button>
<button
type="button"
title="Actions"
class="p-1 hover:bg-surface1 rounded-md"
>
<IconDotsHorizontal class="text-lg text-text" />
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content class="overview-dropdown-content min-w-[120px] bg-surface0/50 border border-surface2 p-2 flex flex-col gap-y-1 backdrop-blur-md rounded-lg text-sm">
<DropdownMenu.Item
onClick={() => downloadUploadedFile(file())}
class="flex flex-row items-center gap-6 pl-2 pr-4 py-1 hover:bg-lavender/30 text-text hover:text-[rgb(46,48,66)] rounded-md"
<DropdownMenu.Content class="overview-dropdown-content min-w-[120px] bg-base/50 border border-surface2 p-2 flex flex-col gap-y-1 backdrop-blur-md rounded-lg text-sm">
<DropdownMenu.Item
onClick={() =>
downloadUploadedFile(file())
}
class="flex flex-row items-center gap-2 pl-2 pr-4 py-1 hover:bg-lavender/30 text-text hover:text-[rgb(46,48,66)] rounded-md"
>
<IconFileDownloadOutline class="text-lg" />
<IconDownload class="text-lg" />
Download
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex flex-row items-center gap-6 pl-2 pr-4 px-4 py-1 hover:bg-lavender/30 text-text hover:text-[rgb(46,48,66)] rounded-md"
>
<DropdownMenu.Item class="flex flex-row items-center gap-2 pl-2 pr-4 px-4 py-1 hover:bg-lavender/30 text-text hover:text-[rgb(46,48,66)] rounded-md">
<IconStarOutline class="text-lg" />
Favorite
</DropdownMenu.Item>
<DropdownMenu.Item
class="cursor-pointer flex flex-row items-center gap-6 pl-2 pr-4 py-1 hover:bg-lavender/30 text-text hover:text-[rgb(46,48,66)] rounded-md"
onSelect={async () => {
await removePermanentlyFile(file().id)
setWorkspaceContent(prev => prev ?
prev.filter(item => item.type === "workspace" || (item.type === "file" && item.data.id !== file().id))
: [])
}}
<Dialog.Root
open={openDeletion()}
onOpenChange={setOpenDeletion}
>
<IconDeleteOutline class="text-lg" />
Delete permanently
</DropdownMenu.Item>
<Dialog.Trigger class="flex flex-row items-center gap-2 pl-2 pr-4 py-1 hover:bg-maroon/20 text-maroon rounded-md">
<IconDeleteOutline class="text-lg" />
Delete permanently
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay class="fixed inset-0 z-50 bg-text/75 dialog-overlay-animation" />
<div class="fixed inset-0 z-50 flex items-center justify-center">
<Dialog.Content class="dialog-content-animation z-50 flex flex-col gap-y-2 border rounded-lg bg-surface0 border-surface1 p-4 max-w-128">
<div class="text-text flex justify-between">
<h1 class="text-xl font-semibold my-auto">
Delete file
</h1>
<Dialog.CloseButton class="p-2 hover:bg-maroon/20 my-auto rounded-lg">
<IconClose class="text-lg" />
</Dialog.CloseButton>
</div>
<Dialog.Description class="text-subtext0">
Are you sure you want to
permanently delete this file? You
won't be able to restore this from
the trash bin later on.
</Dialog.Description>
<div class="flex w-full justify-end gap-x-4 mt-2">
<Dialog.CloseButton>
<button
onClick={async () => {
await removePermanentlyFile(
file().id
);
setWorkspaceContent(
(prev) =>
prev
? prev.filter(
(item) =>
item.type ===
"workspace" ||
(item.type ===
"file" &&
item.data
.id !==
file().id)
)
: []
);
}}
class="py-2 px-4 border-surface1 bg-base/50 hover:bg-base border transition-all hover:border-lavender my-auto rounded-lg"
>
Yes
</button>
</Dialog.CloseButton>
<Dialog.CloseButton class="py-2 px-4 border-surface1 bg-base/50 hover:bg-base border transition-all hover:border-lavender my-auto rounded-lg">
No
</Dialog.CloseButton>
</div>
</Dialog.Content>
</div>
</Dialog.Portal>
</Dialog.Root>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
</div>
</div>
)}
</Match>
<Match when={content.type === "workspace" && content.data}>
{workspace => (
<A class="w-full h-auto p-2 flex flex-row justify-between items-center gap-1 border-b border-text hover:bg-surface0"
<Match
when={content.type === "workspace" && content.data}
>
{(workspace) => (
<A
class="w-full h-auto py-3 px-2 flex flex-row justify-between items-center gap-1 border-b border-surface2 hover:bg-surface0"
href={`/dashboard/${workspace().id}`}
>
<div class="flex flex-row gap-2">
<div class="flex flex-row gap-2 pl-0.5">
<IconFolderOutline class="text-lg" />
<p class="text-sm mt-0.5">{workspace().name}</p>
</div>
</A>
Expand All @@ -375,4 +443,3 @@ const Page: Component = () => {
};

export default Page;

34 changes: 34 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ blockquote:before {
background-color: rgba(114, 135, 253, 0.5);
}

.dialog-overlay-animation {
animation: overlayHide 150ms ease-in 100ms forwards;
}

.dialog-overlay-animation[data-expanded] {
animation: overlayShow 150ms ease-out;
}

.dialog-content-animation {
animation: contentHide 150ms ease-in forwards;
}

.dialog-content-animation[data-expanded] {
animation: contentShow 150ms ease-out;
}

@keyframes contentShow {
from {
opacity: 0;
Expand All @@ -40,3 +56,21 @@ blockquote:before {
transform: scale(0.96);
}
}

@keyframes overlayShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes overlayHide {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Loading

0 comments on commit fb6d8ed

Please sign in to comment.