create-nuxt-base 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/nuxt-base-template/.env.example +0 -1
- package/nuxt-base-template/package-lock.json +287 -269
- package/nuxt-base-template/package.json +7 -7
- package/nuxt-base-template/src/app.vue +6 -7
- package/nuxt-base-template/src/pages/index.vue +0 -30
- package/package.json +1 -1
- package/nuxt-base-template/src/components/SocialMediaBubble.vue +0 -16
- package/nuxt-base-template/src/components/base/BaseAccordion.vue +0 -55
- package/nuxt-base-template/src/components/base/BaseButton.vue +0 -103
- package/nuxt-base-template/src/components/base/BaseContainer.vue +0 -5
- package/nuxt-base-template/src/components/base/BaseContextMenuContainer.vue +0 -61
- package/nuxt-base-template/src/components/base/BaseInfinityList.vue +0 -34
- package/nuxt-base-template/src/components/base/BaseProgressbar.vue +0 -64
- package/nuxt-base-template/src/components/base/BaseToggle.vue +0 -27
- package/nuxt-base-template/src/components/form/FormInput.vue +0 -34
- package/nuxt-base-template/src/components/form/FormPassword.vue +0 -47
- package/nuxt-base-template/src/components/form/FormSelect.vue +0 -40
- package/nuxt-base-template/src/components/form/FormSubmit.vue +0 -18
- package/nuxt-base-template/src/components/form/FormTextarea.vue +0 -36
- package/nuxt-base-template/src/components/form/FormToggle.vue +0 -27
- package/nuxt-base-template/src/components/modal/Modal.vue +0 -48
- package/nuxt-base-template/src/components/modal/ModalConfirm.vue +0 -38
- package/nuxt-base-template/src/components/modal/ModalContainer.vue +0 -7
- package/nuxt-base-template/src/components/modal/ModalInfo.vue +0 -22
- package/nuxt-base-template/src/components/modal/ModalShare.vue +0 -63
- package/nuxt-base-template/src/components/notification/Notification.vue +0 -82
- package/nuxt-base-template/src/components/notification/NotificationContainer.vue +0 -40
- package/nuxt-base-template/src/components/pwa/pwa-install-banner.vue +0 -224
- /package/nuxt-base-template/src/components/{transition → Transition}/TransitionFade.vue +0 -0
- /package/nuxt-base-template/src/components/{transition → Transition}/TransitionFadeScale.vue +0 -0
- /package/nuxt-base-template/src/components/{transition → Transition}/TransitionSlide.vue +0 -0
- /package/nuxt-base-template/src/components/{transition → Transition}/TransitionSlideBottom.vue +0 -0
- /package/nuxt-base-template/src/components/{transition → Transition}/TransitionSlideRevert.vue +0 -0
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"init": "npm install",
|
|
6
6
|
"reinit": "rm -rf node_modules && rm -rf package-lock.json && yes | npx nuxt cleanup && npm cache clean --force && npm i",
|
|
7
7
|
"build": "nuxt build",
|
|
8
|
-
"build:develop": "
|
|
9
|
-
"build:test": "
|
|
8
|
+
"build:develop": "nuxt build",
|
|
9
|
+
"build:test": "nuxt build",
|
|
10
10
|
"start": "nuxt dev",
|
|
11
11
|
"start:develop": "node .output/server/index.mjs",
|
|
12
12
|
"start:test": "node .output/server/index.mjs",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@egoist/tailwindcss-icons": "1.7.4",
|
|
29
29
|
"@iconify-json/bi": "1.1.23",
|
|
30
|
-
"@lenne.tech/nuxt-base": "3.
|
|
30
|
+
"@lenne.tech/nuxt-base": "3.7.0",
|
|
31
31
|
"@nuxt/image": "1.3.0",
|
|
32
32
|
"@vee-validate/yup": "4.12.5",
|
|
33
33
|
"@vueuse/core": "10.7.2",
|
|
@@ -46,16 +46,16 @@
|
|
|
46
46
|
"@nuxtjs/google-fonts": "3.1.3",
|
|
47
47
|
"@nuxtjs/plausible": "0.2.4",
|
|
48
48
|
"@nuxtjs/sitemap": "5.1.0",
|
|
49
|
-
"@nuxtjs/tailwindcss": "6.11.
|
|
49
|
+
"@nuxtjs/tailwindcss": "6.11.4",
|
|
50
50
|
"@playwright/test": "1.41.2",
|
|
51
51
|
"@tailwindcss/forms": "0.5.7",
|
|
52
52
|
"@tailwindcss/typography": "0.5.10",
|
|
53
|
-
"@types/node": "20.11.
|
|
54
|
-
"@vitejs/plugin-vue": "5.0.
|
|
53
|
+
"@types/node": "20.11.19",
|
|
54
|
+
"@vitejs/plugin-vue": "5.0.4",
|
|
55
55
|
"@vue/test-utils": "2.4.4",
|
|
56
56
|
"eslint": "8.56.0",
|
|
57
57
|
"jsdom": "24.0.0",
|
|
58
|
-
"nuxt": "3.10.
|
|
58
|
+
"nuxt": "3.10.2",
|
|
59
59
|
"nuxt-simple-robots": "4.0.0-rc.14",
|
|
60
60
|
"ts-loader": "9.5.1",
|
|
61
61
|
"typescript": "5.3.3",
|
|
@@ -1,35 +1,5 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import FormTextarea from '~/components/form/FormTextarea.vue';
|
|
3
|
-
|
|
4
|
-
const isSubmitting = ref(false);
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
1
|
<template>
|
|
8
2
|
<div class="flex h-screen items-center justify-center flex-col">
|
|
9
3
|
<h1 class="font-extrabold text-transparent text-8xl bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">Lenne Nuxt Starter</h1>
|
|
10
|
-
|
|
11
|
-
<h2 class="mt-5">DEMO</h2>
|
|
12
|
-
<FormInput name="email" type="email" label="E-Mail" placeholder="max.mustermann@test.de" />
|
|
13
|
-
<FormTextarea name="description" label="Description" placeholder="..." />
|
|
14
|
-
<FormPassword name="password" label="Password" placeholder="Password" />
|
|
15
|
-
<FormSelect
|
|
16
|
-
name="select"
|
|
17
|
-
label="Select"
|
|
18
|
-
placeholder="placeholder"
|
|
19
|
-
:options="[
|
|
20
|
-
{ label: 'Option 1', value: 1 },
|
|
21
|
-
{ label: 'Option 2', value: 2 },
|
|
22
|
-
{ label: 'Option 3', value: 3 },
|
|
23
|
-
]"
|
|
24
|
-
/>
|
|
25
|
-
<FormToggle name="toggle" label="Toggle" />
|
|
26
|
-
<div class="flex items-center gap-3">
|
|
27
|
-
<FormSubmit label="Save" :is-submitting="isSubmitting" @click="isSubmitting = true" />
|
|
28
|
-
<BaseButton size="sm" :loading="isSubmitting" @click="isSubmitting = true">Submit</BaseButton>
|
|
29
|
-
<BaseButton size="lg" :loading="isSubmitting" @click="isSubmitting = true">Submit</BaseButton>
|
|
30
|
-
<BaseButton size="md" :loading="isSubmitting" appearance="outline" @click="isSubmitting = true">Submit</BaseButton>
|
|
31
|
-
<BaseButton size="md" :loading="isSubmitting" appearance="none" @click="isSubmitting = true">Submit</BaseButton>
|
|
32
|
-
<BaseButton size="md" color="danger" @click="isSubmitting = false">Reset</BaseButton>
|
|
33
|
-
</div>
|
|
34
4
|
</div>
|
|
35
5
|
</template>
|
package/package.json
CHANGED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = defineProps<{
|
|
3
|
-
icon: string;
|
|
4
|
-
title: string;
|
|
5
|
-
bgColor: string;
|
|
6
|
-
}>();
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<template>
|
|
10
|
-
<button class="flex flex-col items-center group">
|
|
11
|
-
<span class="rounded-full w-14 h-14 flex items-center justify-center transition-all duration-300 group-hover:-translate-y-1" :style="{ 'background-color': bgColor }">
|
|
12
|
-
<span class="text-2xl text-white" :class="icon"></span>
|
|
13
|
-
</span>
|
|
14
|
-
<small class="text-sm font-light mt-2">{{ title }}</small>
|
|
15
|
-
</button>
|
|
16
|
-
</template>
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, ref } from 'vue';
|
|
3
|
-
import { useElementSize } from '@vueuse/core';
|
|
4
|
-
|
|
5
|
-
const props = withDefaults(
|
|
6
|
-
defineProps<{
|
|
7
|
-
expanded?: boolean;
|
|
8
|
-
}>(),
|
|
9
|
-
{
|
|
10
|
-
expanded: false,
|
|
11
|
-
}
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const show = ref(false);
|
|
15
|
-
const contents = ref<HTMLElement>();
|
|
16
|
-
|
|
17
|
-
watch(
|
|
18
|
-
() => props.expanded,
|
|
19
|
-
() => {
|
|
20
|
-
show.value = props.expanded;
|
|
21
|
-
},
|
|
22
|
-
{ immediate: true }
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
const { height: targetHeight } = useElementSize(contents, undefined, {
|
|
26
|
-
box: 'border-box',
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const height = computed(() => (show.value ? targetHeight.value : 0));
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<template>
|
|
33
|
-
<div class="group border-b border-gray-800 bg-white dark:bg-gray-950 dark:border-gray-500 transition duration-500 hover:bg-gray-50">
|
|
34
|
-
<div class="flex cursor-pointer items-center justify-center p-5 md:p-6">
|
|
35
|
-
<div class="text-base text-gray-900 transition group-hover:text-gray-950 md:text-lg">
|
|
36
|
-
<slot name="title"></slot>
|
|
37
|
-
</div>
|
|
38
|
-
|
|
39
|
-
<div class="relative ml-auto flex items-center justify-center">
|
|
40
|
-
<span :class="{ 'rotate-180': show, 'rotate-45': !show }" class="i-bi-x h-5 w-5 text-gray-900 transition-transform duration-500 md:h-6 md:w-6 dark:bg-white"></span>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<div
|
|
45
|
-
:style="{
|
|
46
|
-
height: `${height}px`,
|
|
47
|
-
}"
|
|
48
|
-
class="overflow-hidden px-5 transition-[height] duration-500 will-change-[height] md:px-6"
|
|
49
|
-
>
|
|
50
|
-
<div ref="contents" class="space-y-4 pb-5 font-light leading-relaxed tracking-wide text-gray-900 md:pb-6">
|
|
51
|
-
<slot></slot>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</template>
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { twMerge } from 'tailwind-merge';
|
|
3
|
-
import { NuxtLink } from '#components';
|
|
4
|
-
import type { RouteLocationRaw } from 'vue-router';
|
|
5
|
-
|
|
6
|
-
const props = withDefaults(
|
|
7
|
-
defineProps<{
|
|
8
|
-
href?: string;
|
|
9
|
-
to?: RouteLocationRaw;
|
|
10
|
-
appearance?: 'regular' | 'outline' | 'none';
|
|
11
|
-
size?: 'sm' | 'md' | 'lg' | 'auto';
|
|
12
|
-
color?: 'primary' | 'secondary' | 'green' | 'yellow' | 'lightprimary' | 'danger';
|
|
13
|
-
textColor?: 'white' | 'black' | 'primary' | 'gray' | '';
|
|
14
|
-
type?: 'submit' | 'button';
|
|
15
|
-
loading?: boolean;
|
|
16
|
-
loadingText?: string;
|
|
17
|
-
block?: boolean; // or width full
|
|
18
|
-
}>(),
|
|
19
|
-
{
|
|
20
|
-
appearance: 'regular',
|
|
21
|
-
size: 'md',
|
|
22
|
-
type: 'button',
|
|
23
|
-
color: 'primary',
|
|
24
|
-
textColor: '',
|
|
25
|
-
loading: false,
|
|
26
|
-
loadingText: 'Loading',
|
|
27
|
-
block: false,
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const appearanceClasses: Record<typeof props.appearance, string> = {
|
|
32
|
-
regular: 'rounded-md text-white',
|
|
33
|
-
outline:
|
|
34
|
-
'rounded-md border border-primary bg-background hover:bg-primary-500 text-primary hover:text-white disabled:bg-transparent disabled:text-gray-400 disabled:border-gray-200',
|
|
35
|
-
none: 'bg-transparent border-transparent hover:text-primary-500 text-foreground hover:bg-transparent',
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const sizeClasses: Record<typeof props.size, string> = {
|
|
39
|
-
sm: 'min-w-[100px] py-1.5 px-1.5 text-sm',
|
|
40
|
-
md: 'min-w-[100px] py-1.5 px-2 text-base',
|
|
41
|
-
lg: 'min-w-[240px] py-3 px-4 text-lg',
|
|
42
|
-
auto: 'text-sm lg:text-lg',
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const colorClasses: Record<typeof props.color, string> = {
|
|
46
|
-
primary: 'bg-primary-500 hover:bg-primary-400 text-primary-50',
|
|
47
|
-
secondary: 'bg-orange-500 hover:bg-orange-400 text-orange-50',
|
|
48
|
-
green: 'bg-green-500 hover:bg-green-400 text-green-50',
|
|
49
|
-
yellow: 'bg-yellow-500 hover:bg-yellow-400 text-yellow-950',
|
|
50
|
-
danger: 'bg-red-500 hover:bg-red-400 text-red-950',
|
|
51
|
-
lightprimary: 'bg-primary-300 text-primary-50',
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const textColorClasses: Record<typeof props.textColor, string> = {
|
|
55
|
-
white: 'text-white',
|
|
56
|
-
black: 'text-black',
|
|
57
|
-
primary: 'text-primary',
|
|
58
|
-
gray: 'text-gray-400',
|
|
59
|
-
'': '',
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const LoadingIcon = defineComponent({
|
|
63
|
-
render: () =>
|
|
64
|
-
h('svg', { fill: 'none', viewBox: '0 0 24 24', class: 'animate-spin h-5 w-5 text-white' }, [
|
|
65
|
-
h('circle', {
|
|
66
|
-
class: 'opacity-25',
|
|
67
|
-
cx: '12',
|
|
68
|
-
cy: '12',
|
|
69
|
-
r: '10',
|
|
70
|
-
stroke: 'currentColor',
|
|
71
|
-
'stroke-width': '4',
|
|
72
|
-
}),
|
|
73
|
-
h('path', {
|
|
74
|
-
class: 'opacity-75',
|
|
75
|
-
fill: 'currentColor',
|
|
76
|
-
d: 'M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z',
|
|
77
|
-
}),
|
|
78
|
-
]),
|
|
79
|
-
});
|
|
80
|
-
const defaultClasses = 'duration-200 flex gap-2 justify-center items-center whitespace-nowrap text-center disabled:bg-gray-200 disabled:cursor-not-allowed disabled:text-gray-400';
|
|
81
|
-
const classes = twMerge(defaultClasses, sizeClasses[props.size], colorClasses[props.color], appearanceClasses[props.appearance], textColorClasses[props.textColor]);
|
|
82
|
-
</script>
|
|
83
|
-
|
|
84
|
-
<template>
|
|
85
|
-
<component
|
|
86
|
-
:is="props.href ? 'a' : props.to ? NuxtLink : 'button'"
|
|
87
|
-
:class="[
|
|
88
|
-
classes,
|
|
89
|
-
{
|
|
90
|
-
'w-full': props.block,
|
|
91
|
-
'cursor-wait': props.loading,
|
|
92
|
-
},
|
|
93
|
-
]"
|
|
94
|
-
:to="props.to"
|
|
95
|
-
:active-class="props.appearance === 'none' ? '!text-primary-500' : ''"
|
|
96
|
-
:href="props.href"
|
|
97
|
-
:type="props.type"
|
|
98
|
-
>
|
|
99
|
-
<LoadingIcon v-if="props.loading" />
|
|
100
|
-
<p v-if="props.loadingText && props.loading" v-text="props.loadingText"></p>
|
|
101
|
-
<slot v-else></slot>
|
|
102
|
-
</component>
|
|
103
|
-
</template>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { useMouse } from '@vueuse/core';
|
|
3
|
-
|
|
4
|
-
import { useContextMenu } from '~/composables/use-context-menu';
|
|
5
|
-
|
|
6
|
-
const { activeMenu, close } = useContextMenu();
|
|
7
|
-
const target = ref();
|
|
8
|
-
const isLeft = usePageLeave();
|
|
9
|
-
|
|
10
|
-
onClickOutside(target, () => close());
|
|
11
|
-
|
|
12
|
-
const { x, y } = useMouse();
|
|
13
|
-
const left = ref(0);
|
|
14
|
-
const top = ref(0);
|
|
15
|
-
|
|
16
|
-
watch(
|
|
17
|
-
() => isLeft.value,
|
|
18
|
-
() => {
|
|
19
|
-
close();
|
|
20
|
-
}
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
watch(
|
|
24
|
-
() => activeMenu.value,
|
|
25
|
-
() => {
|
|
26
|
-
if (activeMenu.value?.show) {
|
|
27
|
-
left.value = unref(x.value);
|
|
28
|
-
top.value = unref(y.value);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
</script>
|
|
33
|
-
|
|
34
|
-
<template>
|
|
35
|
-
<ClientOnly>
|
|
36
|
-
<Teleport to="body">
|
|
37
|
-
<TransitionFade leave-duration="150" start-duration="150">
|
|
38
|
-
<div
|
|
39
|
-
v-show="activeMenu"
|
|
40
|
-
@mouseleave="close()"
|
|
41
|
-
ref="target"
|
|
42
|
-
class="absolute w-56 right-0 origin-top-right border border-border bg-background overflow-hidden shadow-lg rounded-md focus:outline-none"
|
|
43
|
-
:style="`top: ${top}px; left: ${left}px`"
|
|
44
|
-
>
|
|
45
|
-
<button
|
|
46
|
-
v-for="item of activeMenu?.items"
|
|
47
|
-
:key="item"
|
|
48
|
-
type="button"
|
|
49
|
-
class="w-full text-left text-foreground px-4 py-2 text-sm hover:bg-hover hover:text-foreground flex justify-between items-center"
|
|
50
|
-
@click="
|
|
51
|
-
item.click();
|
|
52
|
-
close();
|
|
53
|
-
"
|
|
54
|
-
>
|
|
55
|
-
{{ item.label }}
|
|
56
|
-
</button>
|
|
57
|
-
</div>
|
|
58
|
-
</TransitionFade>
|
|
59
|
-
</Teleport>
|
|
60
|
-
</ClientOnly>
|
|
61
|
-
</template>
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const emit = defineEmits<{
|
|
3
|
-
(event: 'loadMore'): void;
|
|
4
|
-
}>();
|
|
5
|
-
const scrollContainer = ref<HTMLElement | null>(null);
|
|
6
|
-
let infinityScrollInProgress = false;
|
|
7
|
-
|
|
8
|
-
const handleScroll = async () => {
|
|
9
|
-
let element = scrollContainer.value;
|
|
10
|
-
if (!infinityScrollInProgress && element && element.getBoundingClientRect().bottom < window.innerHeight) {
|
|
11
|
-
infinityScrollInProgress = true;
|
|
12
|
-
|
|
13
|
-
emit('loadMore');
|
|
14
|
-
|
|
15
|
-
setTimeout(() => {
|
|
16
|
-
infinityScrollInProgress = false;
|
|
17
|
-
}, 1000);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
onMounted(() => {
|
|
22
|
-
window.addEventListener('scroll', handleScroll);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
onUnmounted(() => {
|
|
26
|
-
window.removeEventListener('scroll', handleScroll);
|
|
27
|
-
});
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<template>
|
|
31
|
-
<div ref="scrollContainer">
|
|
32
|
-
<slot></slot>
|
|
33
|
-
</div>
|
|
34
|
-
</template>
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = withDefaults(
|
|
3
|
-
defineProps<{
|
|
4
|
-
percent: number | `${number}`;
|
|
5
|
-
duration?: number | `${number}`;
|
|
6
|
-
label?: string;
|
|
7
|
-
color?: 'primary' | 'red' | 'green' | 'blue';
|
|
8
|
-
}>(),
|
|
9
|
-
{
|
|
10
|
-
duration: 400,
|
|
11
|
-
color: 'primary',
|
|
12
|
-
}
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
type RecordFromUnion<T extends string> = {
|
|
16
|
-
[K in T]: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type ColorTypes = 'text' | 'background' | 'background-light';
|
|
20
|
-
|
|
21
|
-
const colorClass: Record<typeof props.color, RecordFromUnion<ColorTypes>> = {
|
|
22
|
-
primary: {
|
|
23
|
-
text: 'text-primary-600',
|
|
24
|
-
background: 'bg-primary-500',
|
|
25
|
-
'background-light': 'bg-gray-200',
|
|
26
|
-
},
|
|
27
|
-
red: {
|
|
28
|
-
text: 'text-red-600',
|
|
29
|
-
background: 'bg-red-500',
|
|
30
|
-
'background-light': 'bg-red-200',
|
|
31
|
-
},
|
|
32
|
-
green: {
|
|
33
|
-
text: 'text-green-600',
|
|
34
|
-
background: 'bg-green-500',
|
|
35
|
-
'background-light': 'bg-green-200',
|
|
36
|
-
},
|
|
37
|
-
blue: {
|
|
38
|
-
text: 'text-blue-600',
|
|
39
|
-
background: 'bg-blue-500',
|
|
40
|
-
'background-light': 'bg-blue-200',
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
</script>
|
|
44
|
-
|
|
45
|
-
<template>
|
|
46
|
-
<div :style="`--percent: ${props.percent}%; --duration: ${props.duration}ms;`" class="relative pt-1 w-full">
|
|
47
|
-
<div v-if="props.label" class="flex mb-2 items-center justify-between">
|
|
48
|
-
<div>
|
|
49
|
-
<span :class="[colorClass[props.color].text, colorClass[props.color]['background-light']]" class="text-xs font-semibold inline-block py-1 px-2 uppercase rounded-full">
|
|
50
|
-
{{ props.label }}
|
|
51
|
-
</span>
|
|
52
|
-
</div>
|
|
53
|
-
<div class="text-right">
|
|
54
|
-
<span :class="[colorClass[props.color].text]" class="text-xs font-semibold inline-block"> {{ (+props.percent).toFixed(0) }}% </span>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
<div :class="colorClass[props.color]['background-light']" class="overflow-hidden h-1 mb-4 text-xs flex rounded bg-[--color-light]">
|
|
58
|
-
<div
|
|
59
|
-
:class="colorClass[props.color].background"
|
|
60
|
-
class="transform ease-in-out w-[--percent] duration-[--duration] shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center"
|
|
61
|
-
></div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</template>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = withDefaults(
|
|
3
|
-
defineProps<{
|
|
4
|
-
active?: boolean;
|
|
5
|
-
}>(),
|
|
6
|
-
{
|
|
7
|
-
active: false,
|
|
8
|
-
}
|
|
9
|
-
);
|
|
10
|
-
const toggleActive = ref(false);
|
|
11
|
-
|
|
12
|
-
watch(
|
|
13
|
-
() => props.active,
|
|
14
|
-
() => {
|
|
15
|
-
toggleActive.value = props.active;
|
|
16
|
-
},
|
|
17
|
-
{ immediate: true }
|
|
18
|
-
);
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<template>
|
|
22
|
-
<div class="flex justify-between items-center cursor-pointer" @click="toggleActive = !toggleActive">
|
|
23
|
-
<div class="w-8 h-5 flex items-center bg-gray-300 rounded-full p-1 duration-300 ease-in-out" :class="{ 'bg-green-400': toggleActive }">
|
|
24
|
-
<div class="bg-white w-4 h-4 rounded-full shadow-md transform duration-300 ease-in-out" :class="{ 'translate-x-2': toggleActive }"></div>
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
</template>
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ErrorMessage, useField } from 'vee-validate';
|
|
3
|
-
|
|
4
|
-
const props = defineProps<{
|
|
5
|
-
disabled?: boolean;
|
|
6
|
-
label?: string;
|
|
7
|
-
name: string;
|
|
8
|
-
placeholder?: string;
|
|
9
|
-
type: string;
|
|
10
|
-
}>();
|
|
11
|
-
|
|
12
|
-
const { handleBlur, handleChange, value, meta, setTouched } = useField(() => props.name);
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<template>
|
|
16
|
-
<div class="mt-3">
|
|
17
|
-
<label v-if="label" :for="name" class="block text-sm font-medium leading-6 text-foreground">{{ label }}{{ meta.required ? '*' : '' }}</label>
|
|
18
|
-
<div class="relative mt-2 pb-2">
|
|
19
|
-
<input
|
|
20
|
-
:id="name"
|
|
21
|
-
:type="type"
|
|
22
|
-
:name="name"
|
|
23
|
-
v-model="value"
|
|
24
|
-
:disabled="disabled"
|
|
25
|
-
@blur="handleBlur"
|
|
26
|
-
@focus="setTouched(true)"
|
|
27
|
-
@change="handleChange"
|
|
28
|
-
class="bg-background block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-border placeholder:text-foreground/50 focus:ring-1 focus:ring-inset focus:ring-primary-500 sm:text-sm sm:leading-6"
|
|
29
|
-
:placeholder="placeholder"
|
|
30
|
-
/>
|
|
31
|
-
<ErrorMessage class="absolute -bottom-2.5 text-xs font-light text-red-600" :name="name" />
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</template>
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ErrorMessage, useField } from 'vee-validate';
|
|
3
|
-
|
|
4
|
-
enum InputType {
|
|
5
|
-
Password = 'password',
|
|
6
|
-
Text = 'text',
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const props = defineProps<{
|
|
10
|
-
label: string;
|
|
11
|
-
name: string;
|
|
12
|
-
placeholder: string;
|
|
13
|
-
}>();
|
|
14
|
-
|
|
15
|
-
const type = ref<InputType>(InputType.Password);
|
|
16
|
-
const { handleBlur, handleChange, meta, value, setTouched } = useField(() => props.name);
|
|
17
|
-
|
|
18
|
-
function changeType() {
|
|
19
|
-
type.value = type.value === InputType.Password ? InputType.Text : InputType.Password;
|
|
20
|
-
}
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<template>
|
|
24
|
-
<div class="mt-3">
|
|
25
|
-
<label v-if="label" :for="name" class="block text-sm font-medium leading-6 text-foreground">{{ label }}{{ meta.required ? '*' : '' }}</label>
|
|
26
|
-
<div class="relative mt-2 pb-2">
|
|
27
|
-
<div class="relative">
|
|
28
|
-
<input
|
|
29
|
-
:id="name"
|
|
30
|
-
v-model="value"
|
|
31
|
-
:type="type"
|
|
32
|
-
:name="name"
|
|
33
|
-
@blur="handleBlur"
|
|
34
|
-
@focus="setTouched(true)"
|
|
35
|
-
@change="handleChange"
|
|
36
|
-
class="bg-background block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-border placeholder:text-foreground/50 focus:ring-1 focus:ring-inset focus:ring-primary-500 sm:text-sm sm:leading-6"
|
|
37
|
-
:placeholder="placeholder"
|
|
38
|
-
/>
|
|
39
|
-
<button type="button" class="absolute right-2 bottom-1/2 transform translate-y-1/2 text-secondary-100 flex items-center hover:text-primary-500" @click="changeType()">
|
|
40
|
-
<span v-if="type === 'password'" class="i-bi-eye"></span>
|
|
41
|
-
<span v-else class="i-bi-eye-slash"></span>
|
|
42
|
-
</button>
|
|
43
|
-
</div>
|
|
44
|
-
<ErrorMessage class="absolute -bottom-2.5 text-xs font-light text-red-600" :name="name" />
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
</template>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ErrorMessage, useField } from 'vee-validate';
|
|
3
|
-
|
|
4
|
-
interface Option {
|
|
5
|
-
label: string;
|
|
6
|
-
value: any;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const props = defineProps<{
|
|
10
|
-
disabled?: boolean;
|
|
11
|
-
label?: string;
|
|
12
|
-
multiple?: boolean;
|
|
13
|
-
name: string;
|
|
14
|
-
options: Option[];
|
|
15
|
-
placeholder?: string;
|
|
16
|
-
}>();
|
|
17
|
-
|
|
18
|
-
const { handleBlur, handleChange, meta, value, setTouched } = useField(() => props.name);
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<template>
|
|
22
|
-
<div class="relative mt-3 pb-2">
|
|
23
|
-
<label v-if="label" :for="name" class="block text-sm font-medium leading-6 text-foreground">{{ label }}{{ meta.required ? '*' : '' }}</label>
|
|
24
|
-
<select
|
|
25
|
-
:id="name"
|
|
26
|
-
v-model="value"
|
|
27
|
-
@focus="setTouched(true)"
|
|
28
|
-
:name="name"
|
|
29
|
-
:multiple="multiple ?? false"
|
|
30
|
-
:disabled="disabled"
|
|
31
|
-
class="bg-background mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-foreground ring-1 ring-inset ring-border focus:ring-1 focus:ring-primary-500 sm:text-sm sm:leading-6"
|
|
32
|
-
@blur="handleBlur"
|
|
33
|
-
@change="handleChange"
|
|
34
|
-
>
|
|
35
|
-
<option class="text-foreground/50" :value="null" disabled selected>{{ placeholder }}</option>
|
|
36
|
-
<option v-for="option of options" :value="option.value">{{ option.label }}</option>
|
|
37
|
-
</select>
|
|
38
|
-
<ErrorMessage class="absolute -bottom-2.5 text-xs font-light text-red-600" :name="name" />
|
|
39
|
-
</div>
|
|
40
|
-
</template>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = defineProps<{
|
|
3
|
-
isSubmitting?: boolean;
|
|
4
|
-
label: string;
|
|
5
|
-
}>();
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<div>
|
|
10
|
-
<BaseButton v-if="isSubmitting" type="button" disabled>
|
|
11
|
-
<span class="animate-bounce">.</span>
|
|
12
|
-
<span class="animate-bounce delay-150">.</span>
|
|
13
|
-
<span class="animate-bounce delay-300 me-1">.</span>
|
|
14
|
-
Loading
|
|
15
|
-
</BaseButton>
|
|
16
|
-
<BaseButton v-else type="submit"> {{ label }} </BaseButton>
|
|
17
|
-
</div>
|
|
18
|
-
</template>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ErrorMessage, useField } from 'vee-validate';
|
|
3
|
-
|
|
4
|
-
const props = defineProps<{
|
|
5
|
-
disabled?: boolean;
|
|
6
|
-
label?: string;
|
|
7
|
-
name: string;
|
|
8
|
-
placeholder?: string;
|
|
9
|
-
cols?: number;
|
|
10
|
-
maxlength?: number;
|
|
11
|
-
}>();
|
|
12
|
-
|
|
13
|
-
const { handleBlur, handleChange, value, meta, setTouched } = useField(() => props.name);
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<div class="mt-3">
|
|
18
|
-
<label v-if="label" :for="name" class="block text-sm font-medium leading-6 text-foreground">{{ label }}{{ meta.required ? '*' : '' }}</label>
|
|
19
|
-
<div class="relative mt-2 pb-2">
|
|
20
|
-
<textarea
|
|
21
|
-
:id="name"
|
|
22
|
-
:cols="cols"
|
|
23
|
-
:maxlength="maxlength"
|
|
24
|
-
:name="name"
|
|
25
|
-
v-model="value"
|
|
26
|
-
:disabled="disabled"
|
|
27
|
-
@blur="handleBlur"
|
|
28
|
-
@focus="setTouched(true)"
|
|
29
|
-
@change="handleChange"
|
|
30
|
-
class="bg-background block resize-none w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-border placeholder:text-foreground/50 focus:ring-1 focus:ring-inset focus:ring-primary-500 sm:text-sm sm:leading-6"
|
|
31
|
-
:placeholder="placeholder"
|
|
32
|
-
/>
|
|
33
|
-
<ErrorMessage class="absolute -bottom-2.5 text-xs font-light text-red-600" :name="name" />
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</template>
|