
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
carduiBordered container with an opinionated header / content / footer layout. Use it as the wrapper around any self-contained block of content — settings panels, dashboard tiles, list cells.
Also available for React ->$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/card.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/card.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/card.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/card.jsonnpx shadcn-vue@latest add @uipkge/cardInstalls to:app/components/ui/card/| Name | Type / Values | Default | Required |
|---|---|---|---|
variant | 'default''elevated''outline''ghost' | — | optional |
class | HTMLAttributes['class'] | — | optional |
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { cardVariants } from './card.variants'
// Inlined union: SFC compiler can't extract runtime props from
// `CardVariants['variant']`.
const props = defineProps<{
variant?: 'default' | 'elevated' | 'outline' | 'ghost'
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div data-uipkge data-slot="card" :class="cn(cardVariants({ variant }), 'overflow-hidden', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div
data-uipkge
data-slot="card-action"
:class="cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', props.class)"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div data-uipkge data-slot="card-content" :class="cn('p-6 pt-0', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<p data-uipkge data-slot="card-description" :class="cn('text-muted-foreground text-sm', props.class)">
<slot />
</p>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div data-uipkge data-slot="card-footer" :class="cn('flex items-center p-6 pt-0', props.class)">
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div
data-uipkge
data-slot="card-header"
:class="
cn(
'grid auto-rows-min grid-cols-[minmax(0,1fr)] grid-rows-[auto_auto] items-start gap-1.5 p-6 has-data-[slot=card-action]:grid-cols-[minmax(0,1fr)_auto]',
props.class,
)
"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div'
class?: HTMLAttributes['class']
}>()
</script>
<template>
<component
:is="props.as ?? 'h3'"
data-uipkge
data-slot="card-title"
:class="cn('leading-none font-semibold tracking-tight', props.class)"
>
<slot />
</component>
</template>
import type { VariantProps } from 'class-variance-authority'
import { cva } from 'class-variance-authority'
/**
* Variant definitions live in their own file (rather than the package
* `index.ts`) so `Card.vue` can `import { cardVariants } from './card.variants'`
* without creating a circular dependency back through the index. The circular
* form caused intermittent `$setup.cardVariants is not a function` errors
* during dev SSR when several `<Card>` instances rendered in a v-for before
* the module graph had fully resolved.
*/
export const cardVariants = cva(
'bg-card text-card-foreground rounded-xl border shadow-sm transition-colors duration-150',
{
variants: {
variant: {
default: 'border-border',
elevated: 'border-transparent shadow-md hover:shadow-md',
outline: 'border-2',
ghost: 'border-transparent shadow-none hover:bg-muted/50',
},
},
defaultVariants: {
variant: 'default',
},
},
)
export type CardVariants = VariantProps<typeof cardVariants>
export { default as Card } from './Card.vue'
export { default as CardAction } from './CardAction.vue'
export { default as CardContent } from './CardContent.vue'
export { default as CardDescription } from './CardDescription.vue'
export { default as CardFooter } from './CardFooter.vue'
export { default as CardHeader } from './CardHeader.vue'
export { default as CardTitle } from './CardTitle.vue'
// Re-export variant API from the sibling file (kept separate to avoid the
// Card.vue <-> index.ts circular import that broke dev SSR).
export { cardVariants, type CardVariants } from './card.variants'
Raw manifest:https://uipkge.dev/r/vue/card.json