5.6.8 • Published 5 months ago

@cimom/vben-core-shadcn-ui v5.6.8

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

Shadcn UI 组件

Shadcn UI 组件是一个基于 Vue 3 的 UI 组件库,提供了丰富的基础组件和高级组件,采用了现代化的设计风格,支持主题定制和响应式设计。

安装

npm install @cimom/vben-core-ui-kit-shadcn-ui

组件列表

Shadcn UI 组件库包含以下组件:

基础组件

  • Avatar: 头像组件
  • Button: 按钮组件
  • Checkbox: 复选框组件
  • Icon: 图标组件
  • Input: 输入框组件
  • InputPassword: 密码输入框组件
  • PinInput: PIN 码输入组件
  • Select: 选择器组件
  • Spinner: 加载中组件
  • Tooltip: 文字提示组件

导航组件

  • BackTop: 回到顶部组件
  • Breadcrumb: 面包屑导航组件
  • ContextMenu: 上下文菜单组件
  • DropdownMenu: 下拉菜单组件
  • HoverCard: 悬停卡片组件
  • Popover: 弹出框组件
  • Scrollbar: 滚动条组件
  • Segmented: 分段控制器组件

其他组件

  • CountToAnimator: 数字动画组件
  • ExpandableArrow: 可展开箭头组件
  • FullScreen: 全屏组件
  • Logo: Logo 组件
  • RenderContent: 内容渲染组件
  • SpineText: 脊柱文本组件

基础组件使用

Button 按钮

<script setup lang="ts">
import { VbenButton } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div class="space-x-2">
    <VbenButton>默认按钮</VbenButton>
    <VbenButton variant="primary">主要按钮</VbenButton>
    <VbenButton variant="destructive">危险按钮</VbenButton>
    <VbenButton variant="outline">轮廓按钮</VbenButton>
    <VbenButton variant="ghost">幽灵按钮</VbenButton>
    <VbenButton variant="link">链接按钮</VbenButton>
  </div>

  <div class="mt-4 space-x-2">
    <VbenButton size="sm">小型按钮</VbenButton>
    <VbenButton>默认大小</VbenButton>
    <VbenButton size="lg">大型按钮</VbenButton>
  </div>

  <div class="mt-4 space-x-2">
    <VbenButton loading>加载中</VbenButton>
    <VbenButton disabled>禁用按钮</VbenButton>
    <VbenButton icon="Search">带图标</VbenButton>
  </div>
</template>

Avatar 头像

<script setup lang="ts">
import { VbenAvatar } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div class="flex space-x-4">
    <VbenAvatar src="/path/to/avatar.jpg" alt="用户头像" />
    <VbenAvatar>JD</VbenAvatar>
    <VbenAvatar icon="User" />
  </div>

  <div class="mt-4 flex space-x-4">
    <VbenAvatar size="sm" src="/path/to/avatar.jpg" />
    <VbenAvatar src="/path/to/avatar.jpg" />
    <VbenAvatar size="lg" src="/path/to/avatar.jpg" />
  </div>
</template>

Input 输入框

<script setup lang="ts">
import {
  VbenInput,
  VbenInputPassword,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const username = ref('');
const password = ref('');
</script>

<template>
  <div class="space-y-4">
    <div>
      <label class="mb-1 block">用户名</label>
      <VbenInput v-model="username" placeholder="请输入用户名" />
    </div>

    <div>
      <label class="mb-1 block">密码</label>
      <VbenInputPassword v-model="password" placeholder="请输入密码" />
    </div>
  </div>
</template>

PinInput 验证码输入

<script setup lang="ts">
import { VbenPinInput } from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const pinValue = ref('');
</script>

<template>
  <div>
    <label class="mb-2 block">验证码</label>
    <VbenPinInput
      v-model="pinValue"
      :length="6"
      @complete="(value) => console.log('验证码输入完成:', value)"
    />
  </div>
</template>

Select 选择器

<script setup lang="ts">
import { VbenSelect } from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const selectedValue = ref('');
const options = [
  { label: '选项1', value: '1' },
  { label: '选项2', value: '2' },
  { label: '选项3', value: '3' },
];
</script>

<template>
  <div>
    <label class="mb-1 block">选择项</label>
    <VbenSelect
      v-model="selectedValue"
      :options="options"
      placeholder="请选择"
    />
  </div>
</template>

导航组件使用

Breadcrumb 面包屑

<script setup lang="ts">
import {
  VbenBreadcrumb,
  VbenBreadcrumbItem,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <VbenBreadcrumb>
    <VbenBreadcrumbItem>首页</VbenBreadcrumbItem>
    <VbenBreadcrumbItem>用户管理</VbenBreadcrumbItem>
    <VbenBreadcrumbItem>用户详情</VbenBreadcrumbItem>
  </VbenBreadcrumb>
</template>

DropdownMenu 下拉菜单

<script setup lang="ts">
import {
  VbenDropdownMenu,
  VbenDropdownMenuTrigger,
  VbenDropdownMenuContent,
  VbenDropdownMenuItem,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <VbenDropdownMenu>
    <VbenDropdownMenuTrigger>
      <button class="rounded border px-4 py-2">点击打开菜单</button>
    </VbenDropdownMenuTrigger>

    <VbenDropdownMenuContent>
      <VbenDropdownMenuItem @select="() => console.log('选项1')">
        选项1
      </VbenDropdownMenuItem>
      <VbenDropdownMenuItem @select="() => console.log('选项2')">
        选项2
      </VbenDropdownMenuItem>
      <VbenDropdownMenuItem @select="() => console.log('选项3')">
        选项3
      </VbenDropdownMenuItem>
    </VbenDropdownMenuContent>
  </VbenDropdownMenu>
</template>

Scrollbar 滚动条

<script setup lang="ts">
import { VbenScrollbar } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div class="h-60 w-full">
    <VbenScrollbar>
      <div class="p-4">
        <p v-for="i in 20" :key="i" class="mb-4">
          这是一段示例文本,用于演示滚动条组件。 {{ i }}
        </p>
      </div>
    </VbenScrollbar>
  </div>
</template>

BackTop 回到顶部

<script setup lang="ts">
import { VbenBackTop } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div>
    <!-- 页面内容 -->

    <VbenBackTop :visibilityHeight="100" />
  </div>
</template>

其他组件使用

CountToAnimator 数字动画

<script setup lang="ts">
import { VbenCountToAnimator } from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const value = ref(0);

// 模拟数据变化
setTimeout(() => {
  value.value = 1000;
}, 1000);
</script>

<template>
  <div>
    <h3>数字动画:</h3>
    <VbenCountToAnimator
      :value="value"
      :duration="1000"
      :decimals="0"
      prefix="¥"
    />
  </div>
</template>

FullScreen 全屏

<script setup lang="ts">
import { VbenFullScreen } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div>
    <VbenFullScreen>
      <template #default="{ toggle, isFullscreen }">
        <button @click="toggle">
          {{ isFullscreen ? '退出全屏' : '进入全屏' }}
        </button>
      </template>
    </VbenFullScreen>
  </div>
</template>

Tooltip 文字提示

<script setup lang="ts">
import { VbenTooltip } from '@cimom/vben-core-ui-kit-shadcn-ui';
</script>

<template>
  <div class="p-10">
    <VbenTooltip content="这是一个提示文本">
      <button class="rounded border px-4 py-2">鼠标悬停查看提示</button>
    </VbenTooltip>
  </div>
</template>

组件属性

Button 属性

属性名类型默认值说明
variant'default' \| 'primary' \| 'destructive' \| 'outline' \| 'ghost' \| 'link''default'按钮样式变体
size'sm' \| 'default' \| 'lg''default'按钮大小
loadingbooleanfalse是否显示加载状态
disabledbooleanfalse是否禁用
iconstring \| Component-按钮图标
iconPlacement'left' \| 'right''left'图标位置

Avatar 属性

属性名类型默认值说明
srcstring-头像图片地址
altstring-头像图片替代文本
size'sm' \| 'default' \| 'lg''default'头像大小
iconstring \| Component-头像图标
shape'circle' \| 'square''circle'头像形状

Input 属性

属性名类型默认值说明
modelValuestring''输入框值
placeholderstring-占位文本
disabledbooleanfalse是否禁用
readonlybooleanfalse是否只读
clearablebooleanfalse是否可清空
size'sm' \| 'default' \| 'lg''default'输入框大小
prefixstring-前缀内容
suffixstring-后缀内容

Select 属性

属性名类型默认值说明
modelValuestring \| number \| Array-选择器值
optionsArray[]选项数据
placeholderstring-占位文本
disabledbooleanfalse是否禁用
clearablebooleanfalse是否可清空
multiplebooleanfalse是否多选
filterablebooleanfalse是否可搜索

示例

登录表单

<template>
  <div class="mx-auto w-96 rounded border p-6 shadow-md">
    <h2 class="mb-6 text-center text-2xl font-bold">用户登录</h2>

    <form @submit.prevent="handleSubmit">
      <div class="mb-4">
        <label class="mb-1 block">用户名</label>
        <VbenInput
          v-model="form.username"
          placeholder="请输入用户名"
          :disabled="loading"
        />
      </div>

      <div class="mb-6">
        <label class="mb-1 block">密码</label>
        <VbenInputPassword
          v-model="form.password"
          placeholder="请输入密码"
          :disabled="loading"
        />
      </div>

      <div class="mb-6 flex items-center">
        <VbenCheckbox v-model="form.remember" :disabled="loading">
          记住我
        </VbenCheckbox>

        <a href="#" class="ml-auto text-sm text-blue-500">忘记密码?</a>
      </div>

      <VbenButton
        variant="primary"
        class="w-full"
        :loading="loading"
        @click="handleSubmit"
      >
        登录
      </VbenButton>
    </form>
  </div>
</template>

<script setup lang="ts">
import {
  VbenButton,
  VbenInput,
  VbenInputPassword,
  VbenCheckbox,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const form = ref({
  username: '',
  password: '',
  remember: false,
});

const loading = ref(false);

const handleSubmit = async () => {
  if (!form.value.username || !form.value.password) {
    alert('请输入用户名和密码');
    return;
  }

  loading.value = true;

  try {
    // 模拟登录请求
    await new Promise((resolve) => setTimeout(resolve, 1500));
    console.log('登录成功', form.value);
    // 登录成功后的处理...
  } catch (error) {
    console.error('登录失败', error);
  } finally {
    loading.value = false;
  }
};
</script>

数据展示卡片

<template>
  <div class="grid grid-cols-1 gap-6 md:grid-cols-3">
    <div
      v-for="(card, index) in cards"
      :key="index"
      class="rounded-lg border p-6 shadow-sm"
    >
      <div class="mb-4 flex items-center justify-between">
        <h3 class="text-lg font-medium">{{ card.title }}</h3>
        <VbenIcon :name="card.icon" class="text-gray-400" />
      </div>

      <div class="mb-2">
        <VbenCountToAnimator
          :value="card.value"
          :duration="1500"
          :decimals="card.decimals"
          :prefix="card.prefix"
          class="text-2xl font-bold"
        />
      </div>

      <div class="flex items-center text-sm">
        <span
          :class="[card.trend > 0 ? 'text-green-500' : 'text-red-500', 'mr-1']"
        >
          {{ card.trend > 0 ? '+' : '' }}{{ card.trend }}%
        </span>
        <span class="text-gray-500">较上周</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  VbenIcon,
  VbenCountToAnimator,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref } from 'vue';

const cards = ref([
  {
    title: '总销售额',
    value: 126500,
    decimals: 2,
    prefix: '¥',
    trend: 12.5,
    icon: 'TrendingUp',
  },
  {
    title: '访问量',
    value: 8846,
    decimals: 0,
    prefix: '',
    trend: -2.3,
    icon: 'Users',
  },
  {
    title: '订单数',
    value: 1293,
    decimals: 0,
    prefix: '',
    trend: 8.7,
    icon: 'ShoppingCart',
  },
]);
</script>

交互式表格

<template>
  <div class="rounded-lg border p-6 shadow-sm">
    <div class="mb-4 flex items-center justify-between">
      <h2 class="text-xl font-bold">用户列表</h2>

      <div class="flex space-x-2">
        <VbenInput
          v-model="searchQuery"
          placeholder="搜索用户"
          suffix="Search"
          class="w-64"
        />

        <VbenButton variant="primary" icon="Plus"> 添加用户 </VbenButton>
      </div>
    </div>

    <div class="overflow-x-auto">
      <table class="w-full border-collapse">
        <thead>
          <tr class="bg-gray-50">
            <th class="p-3 text-left">用户名</th>
            <th class="p-3 text-left">邮箱</th>
            <th class="p-3 text-left">角色</th>
            <th class="p-3 text-left">状态</th>
            <th class="p-3 text-left">操作</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="(user, index) in filteredUsers"
            :key="index"
            class="border-t hover:bg-gray-50"
          >
            <td class="p-3">
              <div class="flex items-center">
                <VbenAvatar :src="user.avatar" size="sm" class="mr-2" />
                {{ user.username }}
              </div>
            </td>
            <td class="p-3">{{ user.email }}</td>
            <td class="p-3">{{ user.role }}</td>
            <td class="p-3">
              <span
                :class="[
                  user.status === 'active'
                    ? 'bg-green-100 text-green-800'
                    : 'bg-gray-100 text-gray-800',
                  'rounded px-2 py-1 text-xs',
                ]"
              >
                {{ user.status === 'active' ? '活跃' : '禁用' }}
              </span>
            </td>
            <td class="p-3">
              <div class="flex space-x-2">
                <VbenTooltip content="编辑">
                  <button class="text-blue-500 hover:text-blue-700">
                    <VbenIcon name="Edit" size="sm" />
                  </button>
                </VbenTooltip>

                <VbenTooltip content="删除">
                  <button class="text-red-500 hover:text-red-700">
                    <VbenIcon name="Trash" size="sm" />
                  </button>
                </VbenTooltip>
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  VbenButton,
  VbenInput,
  VbenAvatar,
  VbenIcon,
  VbenTooltip,
} from '@cimom/vben-core-ui-kit-shadcn-ui';
import { ref, computed } from 'vue';

const searchQuery = ref('');

const users = ref([
  {
    username: 'admin',
    email: 'admin@example.com',
    role: '管理员',
    status: 'active',
    avatar: 'https://via.placeholder.com/40',
  },
  {
    username: 'user1',
    email: 'user1@example.com',
    role: '编辑',
    status: 'active',
    avatar: 'https://via.placeholder.com/40',
  },
  {
    username: 'user2',
    email: 'user2@example.com',
    role: '访客',
    status: 'inactive',
    avatar: 'https://via.placeholder.com/40',
  },
]);

const filteredUsers = computed(() => {
  if (!searchQuery.value) return users.value;

  const query = searchQuery.value.toLowerCase();
  return users.value.filter(
    (user) =>
      user.username.toLowerCase().includes(query) ||
      user.email.toLowerCase().includes(query) ||
      user.role.toLowerCase().includes(query),
  );
});
</script>