first commit
This commit is contained in:
39
src/components/feedback/EmptyState.vue
Normal file
39
src/components/feedback/EmptyState.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<script setup lang="ts">
|
||||
import type { LucideIcon } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
|
||||
defineProps<{
|
||||
actionLabel?: string
|
||||
description: string
|
||||
icon: LucideIcon
|
||||
title: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(e: 'action'): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card
|
||||
class="border-dashed border-border/70 bg-card/88 shadow-sm backdrop-blur-sm"
|
||||
>
|
||||
<CardContent
|
||||
class="flex flex-col items-center justify-center gap-4 px-6 py-12 text-center"
|
||||
>
|
||||
<div class="rounded-2xl border border-border/70 bg-muted/60 p-3">
|
||||
<component :is="icon" class="size-6 text-muted-foreground" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-lg font-semibold">{{ title }}</h3>
|
||||
<p class="max-w-md text-sm leading-6 text-muted-foreground">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<Button v-if="actionLabel" variant="outline" @click="$emit('action')">
|
||||
{{ actionLabel }}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
38
src/components/feedback/ErrorState.vue
Normal file
38
src/components/feedback/ErrorState.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import { AlertTriangleIcon } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
|
||||
defineProps<{
|
||||
actionLabel?: string
|
||||
description: string
|
||||
title: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(e: 'action'): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card class="border-destructive/25 bg-card/88 shadow-sm backdrop-blur-sm">
|
||||
<CardContent
|
||||
class="flex flex-col items-center justify-center gap-4 px-6 py-12 text-center"
|
||||
>
|
||||
<div
|
||||
class="rounded-2xl border border-destructive/30 bg-destructive/10 p-3"
|
||||
>
|
||||
<AlertTriangleIcon class="size-6 text-destructive" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-lg font-semibold">{{ title }}</h3>
|
||||
<p class="max-w-md text-sm leading-6 text-muted-foreground">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<Button v-if="actionLabel" variant="outline" @click="$emit('action')">
|
||||
{{ actionLabel }}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
30
src/components/feedback/PermissionGate.vue
Normal file
30
src/components/feedback/PermissionGate.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { ShieldXIcon } from 'lucide-vue-next'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
|
||||
defineProps<{
|
||||
allowed: boolean
|
||||
description: string
|
||||
title: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot v-if="allowed" />
|
||||
|
||||
<Card v-else class="border-border/70 bg-card/88 shadow-sm backdrop-blur-sm">
|
||||
<CardContent
|
||||
class="flex flex-col items-center justify-center gap-4 px-6 py-12 text-center"
|
||||
>
|
||||
<div class="rounded-2xl border border-border/70 bg-muted/60 p-3">
|
||||
<ShieldXIcon class="size-6 text-muted-foreground" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-lg font-semibold">{{ title }}</h3>
|
||||
<p class="max-w-md text-sm leading-6 text-muted-foreground">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
Reference in New Issue
Block a user