* chore: update deps * feat: use jsonc/x language * chore: update eslint 10.0 * fix: no-useless-assignment * feat: add CLAUDE.md * chore: ignore * feat: claude * fix: lint * chore: suppot eslint v10 * fix: lint * fix: lint * fix: type check * fix: unit test * fix: Suggested fix * fix: unit test * chore: update stylelint v17 * chore: update all major deps * fix: echarts console warn * chore: update vitest v4 * feat: add skills ignores * chore: update deps * chore: update deps * fix: cspell * chore: update deps * chore: update tailwindcss v4 * chore: remove postcss config * fix: no use catalog * chore: tailwind v4 config * fix: tailwindcss v4 sort * feat: use eslint-plugin-better-tailwindcss * fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier * fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier * fix(lint): resolve prettier and better-tailwindcss formatting conflicts * fix(tailwind): update theme references and lint sources * style(format): normalize apps docs and playground vue files * style(format): normalize core ui-kit components * style(format): normalize effects ui and layout components
87 lines
2.1 KiB
Vue
87 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import type { PointSelectionCaptchaCardProps } from '../types';
|
|
|
|
import { computed } from 'vue';
|
|
|
|
import { $t } from '@vben/locales';
|
|
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardFooter,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@vben-core/shadcn-ui';
|
|
|
|
const props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), {
|
|
height: '220px',
|
|
paddingX: '12px',
|
|
paddingY: '16px',
|
|
title: '',
|
|
width: '300px',
|
|
});
|
|
|
|
const emit = defineEmits<{
|
|
click: [MouseEvent];
|
|
}>();
|
|
|
|
const parseValue = (value: number | string) => {
|
|
if (typeof value === 'number') {
|
|
return value;
|
|
}
|
|
const parsed = Number.parseFloat(value);
|
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
};
|
|
|
|
const rootStyles = computed(() => ({
|
|
padding: `${parseValue(props.paddingY)}px ${parseValue(props.paddingX)}px`,
|
|
width: `${parseValue(props.width) + parseValue(props.paddingX) * 2}px`,
|
|
}));
|
|
|
|
const captchaStyles = computed(() => {
|
|
return {
|
|
height: `${parseValue(props.height)}px`,
|
|
width: `${parseValue(props.width)}px`,
|
|
};
|
|
});
|
|
|
|
function handleClick(e: MouseEvent) {
|
|
emit('click', e);
|
|
}
|
|
</script>
|
|
<template>
|
|
<Card :style="rootStyles" aria-labelledby="captcha-title" role="region">
|
|
<CardHeader class="p-0">
|
|
<CardTitle id="captcha-title" class="flex items-center justify-between">
|
|
<template v-if="$slots.title">
|
|
<slot name="title">{{ $t('ui.captcha.title') }}</slot>
|
|
</template>
|
|
<template v-else>
|
|
<span>{{ title }}</span>
|
|
</template>
|
|
<div class="flex items-center justify-end">
|
|
<slot name="extra"></slot>
|
|
</div>
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent
|
|
class="relative mt-2 flex w-full overflow-hidden rounded-sm p-0"
|
|
>
|
|
<img
|
|
v-show="captchaImage"
|
|
:alt="$t('ui.captcha.alt')"
|
|
:src="captchaImage"
|
|
:style="captchaStyles"
|
|
class="relative z-10"
|
|
@click="handleClick"
|
|
/>
|
|
<div class="absolute inset-0">
|
|
<slot></slot>
|
|
</div>
|
|
</CardContent>
|
|
<CardFooter class="mt-2 flex justify-between p-0">
|
|
<slot name="footer"></slot>
|
|
</CardFooter>
|
|
</Card>
|
|
</template>
|