added card component and workspace display
This commit is contained in:
20
src/lib/components/ui/card/card-action.svelte
Normal file
20
src/lib/components/ui/card/card-action.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card-action"
|
||||||
|
class={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
15
src/lib/components/ui/card/card-content.svelte
Normal file
15
src/lib/components/ui/card/card-content.svelte
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={ref} data-slot="card-content" class={cn("px-6", className)} {...restProps}>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
20
src/lib/components/ui/card/card-description.svelte
Normal file
20
src/lib/components/ui/card/card-description.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card-description"
|
||||||
|
class={cn("text-muted-foreground text-sm", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</p>
|
||||||
20
src/lib/components/ui/card/card-footer.svelte
Normal file
20
src/lib/components/ui/card/card-footer.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card-footer"
|
||||||
|
class={cn("[.border-t]:pt-6 flex items-center px-6", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
23
src/lib/components/ui/card/card-header.svelte
Normal file
23
src/lib/components/ui/card/card-header.svelte
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card-header"
|
||||||
|
class={cn(
|
||||||
|
"@container/card-header has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6 grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
20
src/lib/components/ui/card/card-title.svelte
Normal file
20
src/lib/components/ui/card/card-title.svelte
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card-title"
|
||||||
|
class={cn("font-semibold leading-none", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
23
src/lib/components/ui/card/card.svelte
Normal file
23
src/lib/components/ui/card/card.svelte
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="card"
|
||||||
|
class={cn(
|
||||||
|
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
25
src/lib/components/ui/card/index.ts
Normal file
25
src/lib/components/ui/card/index.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import Root from "./card.svelte";
|
||||||
|
import Content from "./card-content.svelte";
|
||||||
|
import Description from "./card-description.svelte";
|
||||||
|
import Footer from "./card-footer.svelte";
|
||||||
|
import Header from "./card-header.svelte";
|
||||||
|
import Title from "./card-title.svelte";
|
||||||
|
import Action from "./card-action.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Description,
|
||||||
|
Footer,
|
||||||
|
Header,
|
||||||
|
Title,
|
||||||
|
Action,
|
||||||
|
//
|
||||||
|
Root as Card,
|
||||||
|
Content as CardContent,
|
||||||
|
Description as CardDescription,
|
||||||
|
Footer as CardFooter,
|
||||||
|
Header as CardHeader,
|
||||||
|
Title as CardTitle,
|
||||||
|
Action as CardAction,
|
||||||
|
};
|
||||||
@@ -1,5 +1,33 @@
|
|||||||
import type { Workspace } from "$lib/types/workspace";
|
import type { Workspace } from "$lib/types/workspace";
|
||||||
|
|
||||||
|
let ws: Workspace[] = [
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Name: "Test 1",
|
||||||
|
Description: "This is a test description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "2",
|
||||||
|
Name: "Test 2",
|
||||||
|
Description: "This is a longer test description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "3",
|
||||||
|
Name: "Test 3",
|
||||||
|
Description: "This is a slightly longer test description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "4",
|
||||||
|
Name: "Test 4",
|
||||||
|
Description: "This is an even slightly longer test description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "5",
|
||||||
|
Name: "Test 5",
|
||||||
|
Description: "This is a veryyyyyyyyyyyyyyyyyyyyyyyyyyy longggggggggggggggggggggggggggg test descriptionnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export async function get_workspaces(): Promise<Workspace[]> {
|
export async function get_workspaces(): Promise<Workspace[]> {
|
||||||
return []
|
return ws
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
Id: string,
|
Id: string;
|
||||||
Name: string,
|
Name: string;
|
||||||
}
|
Description: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,24 +3,65 @@
|
|||||||
import { Button } from "$lib/components/ui/button/index.js";
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
import FolderCodeIcon from "@lucide/svelte/icons/folder-code";
|
import FolderCodeIcon from "@lucide/svelte/icons/folder-code";
|
||||||
import { get_workspaces } from "$lib/services/workspaces";
|
import { get_workspaces } from "$lib/services/workspaces";
|
||||||
|
import type { Workspace } from "$lib/types/workspace";
|
||||||
|
import * as Card from "$lib/components/ui/card/index";
|
||||||
|
|
||||||
get_workspaces;
|
let showPrompt = false;
|
||||||
|
let workspaces: Workspace[] = [];
|
||||||
|
|
||||||
|
get_workspaces().then((ws) => {
|
||||||
|
if (ws.length == 0) {
|
||||||
|
showPrompt = true;
|
||||||
|
} else {
|
||||||
|
workspaces = ws;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Empty.Root class="flex min-h-[calc(100vh-4rem)] items-center justify-center">
|
{#if showPrompt}
|
||||||
<Empty.Header>
|
<Empty.Root class="flex min-h-[calc(100vh-4rem)] items-center justify-center">
|
||||||
<Empty.Media variant="icon">
|
<Empty.Header>
|
||||||
<FolderCodeIcon />
|
<Empty.Media variant="icon">
|
||||||
</Empty.Media>
|
<FolderCodeIcon />
|
||||||
<Empty.Title>No Workspaces Yet</Empty.Title>
|
</Empty.Media>
|
||||||
<Empty.Description>
|
<Empty.Title>No Workspaces Yet</Empty.Title>
|
||||||
You haven't created any Workspaces yet. Get started by creating your first
|
<Empty.Description>
|
||||||
project.
|
You haven't created any Workspaces yet. Get started by creating your
|
||||||
</Empty.Description>
|
first project.
|
||||||
</Empty.Header>
|
</Empty.Description>
|
||||||
<Empty.Content>
|
</Empty.Header>
|
||||||
<div class="flex gap-2">
|
<Empty.Content>
|
||||||
<Button>Create Workspace</Button>
|
<div class="flex gap-2">
|
||||||
|
<Button>Create Workspace</Button>
|
||||||
|
</div>
|
||||||
|
</Empty.Content>
|
||||||
|
</Empty.Root>
|
||||||
|
{:else}
|
||||||
|
<div class="min-h-[calc(100vh-4rem)] p-6">
|
||||||
|
<div
|
||||||
|
class="grid gap-6
|
||||||
|
grid-cols-1
|
||||||
|
sm:grid-cols-2
|
||||||
|
md:grid-cols-3
|
||||||
|
xl:grid-cols-4
|
||||||
|
2xl:grid-cols-5"
|
||||||
|
>
|
||||||
|
{#each workspaces as workspace (workspace.Id)}
|
||||||
|
<Card.Root
|
||||||
|
class="min-h-40 w-full max-w-xs mx-auto flex flex-col justify-between cursor-pointer hover:shadow-md transition-shadow"
|
||||||
|
>
|
||||||
|
<Card.Header>
|
||||||
|
<Card.Title class="truncate">{workspace.Name}</Card.Title>
|
||||||
|
<Card.Description class="text-xs text-muted-foreground">
|
||||||
|
{workspace.Description}
|
||||||
|
</Card.Description>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Footer class="flex items-center justify-center gap-2">
|
||||||
|
<Button size="sm" class="justify-center">Open</Button>
|
||||||
|
<Button size="sm" class="justify-center">Edit</Button>
|
||||||
|
</Card.Footer>
|
||||||
|
</Card.Root>
|
||||||
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Empty.Content>
|
</div>
|
||||||
</Empty.Root>
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user