Artifact Stack
A group of artifact cards with a Download all action.
import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle,} from "@/components/ai/artifact-card";import { ArtifactStack, ArtifactStackDownloadAll,} from "@/components/ai/artifact-stack";import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
export default function Demo() { return ( <ArtifactStack className="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /> </ArtifactStack> );}<script setup lang="ts">import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle,} from "@/components/ai/artifact-card";import { ArtifactStack, ArtifactStackDownloadAll } from "@/components/ai/artifact-stack";import { DropdownMenuItem } from "@/components/ui/dropdown-menu";</script>
<template> <ArtifactStack class="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /> </ArtifactStack></template><script lang="ts"> import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle, } from "$lib/components/ai/artifact-card"; import { ArtifactStack, ArtifactStackDownloadAll } from "$lib/components/ai/artifact-stack"; import { DropdownMenuItem } from "$lib/components/ui/dropdown-menu";</script>
<ArtifactStack class="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /></ArtifactStack>Edmi ✦ addition. Built on button and ai-artifact-card.
Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/ai-artifact-stackpnpm dlx shadcn@latest add @edmi-ui/ai-artifact-stackyarn dlx shadcn@latest add @edmi-ui/ai-artifact-stackbunx shadcn@latest add @edmi-ui/ai-artifact-stackPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Add the Edmi components this one builds on:
button,ai-artifact-card.Copy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/ai-artifact-stackpnpm dlx shadcn-vue@latest add @edmi-ui/ai-artifact-stackyarn dlx shadcn-vue@latest add @edmi-ui/ai-artifact-stackbunx shadcn-vue@latest add @edmi-ui/ai-artifact-stackPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @lucide/vueTerminal window pnpm add @lucide/vueTerminal window yarn add @lucide/vueTerminal window bun add @lucide/vueAdd the Edmi components this one builds on:
button,ai-artifact-card.Copy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-artifact-stack.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-artifact-stack.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-artifact-stack.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-artifact-stack.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Add the Edmi components this one builds on:
button,ai-artifact-card.Copy the code from Component source into your project and update the import paths to match your aliases.
import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle,} from "@/components/ai/artifact-card";import { ArtifactStack, ArtifactStackDownloadAll,} from "@/components/ai/artifact-stack";import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
<ArtifactStack className="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /></ArtifactStack><script setup lang="ts">import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle,} from "@/components/ai/artifact-card";import { ArtifactStack, ArtifactStackDownloadAll,} from "@/components/ai/artifact-stack";import { DropdownMenuItem } from "@/components/ui/dropdown-menu";</script>
<template> <ArtifactStack class="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /> </ArtifactStack></template><script lang="ts"> import { ArtifactCard, ArtifactCardActions, ArtifactCardBody, ArtifactCardIcon, ArtifactCardMeta, ArtifactCardThumbnail, ArtifactCardTitle, } from "$lib/components/ai/artifact-card"; import { ArtifactStack, ArtifactStackDownloadAll, } from "$lib/components/ai/artifact-stack"; import { DropdownMenuItem } from "$lib/components/ui/dropdown-menu";</script>
<ArtifactStack class="max-w-lg"> <ArtifactCard> <ArtifactCardThumbnail /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · PDF</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactCard> <ArtifactCardIcon kind="document" /> <ArtifactCardBody> <ArtifactCardTitle>Rebalance report</ArtifactCardTitle> <ArtifactCardMeta>Document · MD</ArtifactCardMeta> </ArtifactCardBody> <ArtifactCardActions> <DropdownMenuItem>Copy link</DropdownMenuItem> </ArtifactCardActions> </ArtifactCard> <ArtifactStackDownloadAll /></ArtifactStack>Component source
Section titled “Component source”import { cn } from "cn";import type { ComponentProps } from "react";import { DownloadIcon } from "@phosphor-icons/react";import { Button } from "@/registry/edmi/ui/button";
export type ArtifactStackProps = ComponentProps<"div">;
/** Several outputs from one answer: artifact cards with a Download all action. */export const ArtifactStack = ({ className, ...props }: ArtifactStackProps) => ( <div data-slot="ai-artifact-stack" className={cn("flex w-full flex-col items-start gap-2", className)} {...props} />);
export type ArtifactStackDownloadAllProps = ComponentProps<typeof Button>;
export const ArtifactStackDownloadAll = ({ className, children = "Download all", ...props}: ArtifactStackDownloadAllProps) => ( <Button data-slot="ai-artifact-stack-download-all" variant="secondary" size="sm" type="button" className={cn(className)} {...props} > <DownloadIcon className="size-3.5" /> {children} </Button>);<script setup lang="ts">import type { HTMLAttributes } from "vue"import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"]}>()</script>
<template> <div data-slot="ai-artifact-stack" :class="cn('flex w-full flex-col items-start gap-2', props.class)"> <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from "vue"import { DownloadIcon } from "@lucide/vue"import { cn } from "@/registry/edmi/lib/utils"import { Button } from "@/registry/edmi/ui/button"
const props = defineProps<{ class?: HTMLAttributes["class"]}>()</script>
<template> <Button data-slot="ai-artifact-stack-download-all" variant="secondary" size="sm" type="button" :class="cn(props.class)" > <DownloadIcon class="size-3.5" /> <slot>Download all</slot> </Button></template>export { default as ArtifactStack } from "./ArtifactStack.vue";export { default as ArtifactStackDownloadAll } from "./ArtifactStackDownloadAll.vue";<script lang="ts"> import DownloadIcon from "phosphor-svelte/lib/Download"; import { Button, type ButtonProps } from "$lib/registry/ui/button/index.js";
let { ref = $bindable(null), class: className, children, ...restProps }: Omit<ButtonProps, "href"> = $props();</script>
<Button bind:ref data-slot="ai-artifact-stack-download-all" variant="secondary" size="sm" type="button" class={className} {...restProps}> <DownloadIcon class="size-3.5" /> {#if children} {@render children()} {:else} Download all {/if}</Button><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>, HTMLDivElement> = $props();</script>
<div bind:this={ref} data-slot="ai-artifact-stack" class={cn("flex w-full flex-col items-start gap-2", className)} {...restProps}> {@render children?.()}</div>import ArtifactStack from "./artifact-stack.svelte";import ArtifactStackDownloadAll from "./artifact-stack-download-all.svelte";
export { ArtifactStack, ArtifactStackDownloadAll };| Part | Prop | Type | Default |
|---|---|---|---|
| ArtifactStack | div props |
||
| ArtifactStackDownloadAll | children, Button props |
ReactNode (Vue: default slot, Svelte: children snippet) |
Download all |
Elevation ✦
Section titled “Elevation ✦”Flat only. The stack is a layout wrapper; each ArtifactCard inside takes its own elevation.
✦ Edmi additions
Section titled “✦ Edmi additions”- Documents show a paper thumbnail and other files an icon tile; the meta line reads kind · format.