This commit is contained in:
dap
2024-11-09 16:45:50 +08:00
58 changed files with 1512 additions and 111 deletions

View File

@@ -32,6 +32,7 @@
"@vben-core/shadcn-ui": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben/constants": "workspace:*",
"@vben/hooks": "workspace:*",
"@vben/icons": "workspace:*",
"@vben/locales": "workspace:*",
"@vben/preferences": "workspace:*",

View File

@@ -1,3 +1,5 @@
import type { ClassType } from '@vben/types';
import type { CSSProperties } from 'vue';
export interface CaptchaData {
@@ -72,7 +74,7 @@ export interface PointSelectionCaptchaProps
}
export interface SliderCaptchaProps {
class?: any;
class?: ClassType;
/**
* @description 滑块的样式
* @default {}

View File

@@ -0,0 +1,166 @@
<script setup lang="ts">
import { ref, useTemplateRef, watch, watchEffect } from 'vue';
import { usePagination } from '@vben/hooks';
import { EmptyIcon, Grip } from '@vben/icons';
import {
Button,
Pagination,
PaginationEllipsis,
PaginationFirst,
PaginationLast,
PaginationList,
PaginationListItem,
PaginationNext,
PaginationPrev,
VbenIcon,
VbenIconButton,
VbenPopover,
} from '@vben-core/shadcn-ui';
interface Props {
value?: string;
pageSize?: number;
/**
* 图标列表
*/
icons?: string[];
}
const props = withDefaults(defineProps<Props>(), {
value: '',
pageSize: 36,
icons: () => [],
});
const emit = defineEmits<{
change: [string];
'update:value': [string];
}>();
const refTrigger = useTemplateRef<HTMLElement>('refTrigger');
const currentSelect = ref('');
const currentList = ref(props.icons);
watch(
() => props.icons,
(newIcons) => {
currentList.value = newIcons;
},
{ immediate: true },
);
const { paginationList, total, setCurrentPage } = usePagination(
currentList,
props.pageSize,
);
watchEffect(() => {
currentSelect.value = props.value;
});
watch(
() => currentSelect.value,
(v) => {
emit('update:value', v);
emit('change', v);
},
);
const handleClick = (icon: string) => {
currentSelect.value = icon;
};
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
function changeOpenState() {
refTrigger.value?.click?.();
}
defineExpose({ changeOpenState });
</script>
<template>
<VbenPopover
:content-props="{ align: 'end', alignOffset: -11, sideOffset: 8 }"
content-class="p-0 pt-3"
>
<template #trigger>
<div ref="refTrigger">
<VbenIcon :icon="currentSelect || Grip" class="size-5" />
</div>
</template>
<template v-if="paginationList.length > 0">
<div class="grid max-h-[360px] w-full grid-cols-6 justify-items-center">
<VbenIconButton
v-for="(item, index) in paginationList"
:key="index"
:tooltip="item"
tooltip-side="top"
@click="handleClick(item)"
>
<VbenIcon
:class="{
'text-primary transition-all': currentSelect === item,
}"
:icon="item"
/>
</VbenIconButton>
</div>
<div
v-if="total >= pageSize"
class="flex-center flex justify-end overflow-hidden border-t py-2 pr-3"
>
<Pagination
v-slot="{ page }"
:items-per-page="36"
:sibling-count="1"
:total="total"
show-edges
size="small"
@update:page="handlePageChange"
>
<PaginationList
v-slot="{ items }"
class="flex w-full items-center gap-1"
>
<PaginationFirst class="size-5" />
<PaginationPrev class="size-5" />
<template v-for="(item, index) in items">
<PaginationListItem
v-if="item.type === 'page'"
:key="index"
:value="item.value"
as-child
>
<Button
:variant="item.value === page ? 'default' : 'outline'"
class="size-5 p-0 text-sm"
>
{{ item.value }}
</Button>
</PaginationListItem>
<PaginationEllipsis
v-else
:key="item.type"
:index="index"
class="size-5"
/>
</template>
<PaginationNext class="size-5" />
<PaginationLast class="size-5" />
</PaginationList>
</Pagination>
</div>
</template>
<template v-else>
<div class="flex-col-center text-muted-foreground min-h-[150px] w-full">
<EmptyIcon class="size-10" />
<div class="mt-1 text-sm">{{ $t('common.noData') }}</div>
</div>
</template>
</VbenPopover>
</template>

View File

@@ -0,0 +1 @@
export { default as IconPicker } from './icon-picker.vue';

View File

@@ -1,6 +1,7 @@
export * from './captcha';
export * from './code-mirror';
export * from './ellipsis-text';
export * from './icon-picker';
export * from './json-preview';
export * from './markdown';
export * from './page';

View File

@@ -15,6 +15,7 @@ interface WorkbenchProjectItem {
group: string;
icon: Component | string;
title: string;
url?: string;
}
interface WorkbenchTrendItem {
@@ -35,6 +36,7 @@ interface WorkbenchQuickNavItem {
color?: string;
icon: Component | string;
title: string;
url?: string;
}
export type {

View File

@@ -21,6 +21,8 @@ defineOptions({
withDefaults(defineProps<Props>(), {
items: () => [],
});
defineEmits(['click']);
</script>
<template>
@@ -43,6 +45,7 @@ withDefaults(defineProps<Props>(), {
:color="item.color"
:icon="item.icon"
class="size-8 transition-all duration-300 group-hover:scale-110"
@click="$emit('click', item)"
/>
<span class="ml-4 text-lg font-medium">{{ item.title }}</span>
</div>

View File

@@ -21,6 +21,8 @@ defineOptions({
withDefaults(defineProps<Props>(), {
items: () => [],
});
defineEmits(['click']);
</script>
<template>
@@ -37,6 +39,7 @@ withDefaults(defineProps<Props>(), {
'border-b-0': index < 3,
}"
class="flex-col-center border-border group w-1/3 cursor-pointer border-b border-r border-t py-8 hover:shadow-xl"
@click="$emit('click', item)"
>
<VbenIcon
:color="item.color"