Skip to content

Commit de0a02a

Browse files
authored
Merge pull request #34 from formsible/long/form-style
Long/form style
2 parents 19ac730 + 271ea23 commit de0a02a

File tree

15 files changed

+198
-30
lines changed

15 files changed

+198
-30
lines changed

src/components/address/index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ const isRequired = computed(() =>
3939
<div :class="props.theme.container">
4040
<label :class="props.theme.label" :for="props.input.key">
4141
{{ props.input.label }}
42-
<span v-if="isRequired" class="text-red-600 dark:text-red-400"
42+
<span
43+
v-if="isRequired"
44+
class="text-red-600 dark:text-red-400 -ml-0.5"
4345
>*</span
4446
>
4547
</label>

src/components/appointment/index.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ const isRequired = computed(() =>
5252
<div :class="theme.container">
5353
<label :class="theme.label" :for="input.key">
5454
{{ input.label }}
55-
<span v-if="isRequired" class="text-red-600">*</span>
55+
<span
56+
v-if="isRequired"
57+
class="text-red-600 dark:text-red-400 -ml-0.5"
58+
>*</span
59+
>
5660
</label>
5761
<p :class="theme.description">{{ input.description }}</p>
5862

@@ -84,7 +88,12 @@ const isRequired = computed(() =>
8488
</div>
8589

8690
<!-- if error -->
87-
<small v-if="error" :id="`${input.key}-help`" class="text-sm mt-0.5" :class="theme.error">
91+
<small
92+
v-if="error"
93+
:id="`${input.key}-help`"
94+
class="text-sm mt-0.5"
95+
:class="theme.error"
96+
>
8897
{{ error }}
8998
</small>
9099
</div>

src/components/audio_recorder/index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ onBeforeUnmount(() => {
210210
<div :class="theme.container">
211211
<label :class="theme.label" :for="input.key" class="font-semibold">
212212
{{ input.label }}
213-
<span v-if="isRequired" class="text-red-600 dark:text-red-400"
213+
<span
214+
v-if="isRequired"
215+
class="text-red-600 dark:text-red-400 -ml-0.5"
214216
>*</span
215217
>
216218
</label>

src/components/color_picker/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ const isRequired = computed(() =>
3838
<div :class="theme.container">
3939
<label :class="theme.label" :for="input.key">
4040
{{ input.label }}
41-
<span v-if="isRequired" class="text-red-600">*</span>
41+
<span
42+
v-if="isRequired"
43+
class="text-red-600 dark:text-red-400 -ml-0.5"
44+
>*</span
45+
>
4246
</label>
4347
<p :class="theme.description">{{ input.description }}</p>
4448
<!-- Color Picker -->

src/components/consent_checkbox/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ const isRequired = computed(() =>
4141
v-bind="{ ...$attrs, ...props.input.props }"
4242
/>
4343
<span>{{ input.label }}</span>
44-
<span v-if="isRequired" class="text-red-600">*</span>
44+
<span
45+
v-if="isRequired"
46+
class="text-red-600 dark:text-red-400 -ml-0.5"
47+
>*</span
48+
>
4549
</label>
4650
<p :class="theme.description">{{ input.description }}</p>
4751
<!-- if error -->

src/components/email/index.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ const isRequired = computed(() =>
3434
<div :class="theme.container">
3535
<label :class="theme.label" :for="input.key">
3636
{{ input.label }}
37-
<span v-if="isRequired" class="text-red-600">*</span>
37+
<span
38+
v-if="isRequired"
39+
class="text-red-600 dark:text-red-400 -ml-0.5"
40+
>*</span
41+
>
3842
</label>
3943
<p :class="theme.description">{{ input.description }}</p>
4044
<!-- input section -->
@@ -47,8 +51,12 @@ const isRequired = computed(() =>
4751
v-bind="input.props"
4852
/>
4953
<!-- if error -->
50-
<small v-if="error" :id="`${input.key}-help`" :class="theme.error" class="text-sm mt-0.5">{{
51-
error
52-
}}</small>
54+
<small
55+
v-if="error"
56+
:id="`${input.key}-help`"
57+
:class="theme.error"
58+
class="text-sm mt-0.5"
59+
>{{ error }}</small
60+
>
5361
</div>
5462
</template>

src/components/file_upload/file-card.vue

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ watch(
6464
<div class="text-sm text-gray-500 flex gap-2 items-center">
6565
<span>{{ file.file.type }}</span>
6666
<div class="h-1 w-1 rounded-full bg-gray-300"></div>
67-
<div>
67+
<div class="flex items-center">
6868
<span class="mr-2">{{
6969
formatFileSize(file.file.size)
7070
}}</span>
@@ -80,12 +80,30 @@ watch(
8080
v-else-if="file.status === 'pending'"
8181
class="pi pi-spinner text-blue-600 dark:text-blue-400 pi-spin"
8282
></i>
83-
<i
83+
<!-- Thay thế icon đồng hồ cát bằng dots loader -->
84+
<div
8485
v-else-if="file.status === 'queued'"
85-
class="pi pi-hourglass text-yellow-600 dark:text-yellow-400"
86-
></i>
86+
class="dots-loader"
87+
>
88+
<div></div>
89+
<div></div>
90+
<div></div>
91+
</div>
8792
</div>
8893
</div>
94+
<!-- Progress bar with gradient -->
95+
<div
96+
v-if="file.status === 'pending' || file.status === 'queued'"
97+
class="w-full h-1.5 bg-gray-100 rounded-full mt-2 overflow-hidden"
98+
>
99+
<div
100+
class="h-full rounded-full transition-all duration-300 bg-gradient-to-r from-blue-500 via-blue-400 to-blue-500 background-animate"
101+
:class="{
102+
'animate-progress': file.status === 'pending',
103+
'w-0': file.status === 'queued',
104+
}"
105+
></div>
106+
</div>
89107
</div>
90108
<button
91109
class="pi pi-times-circle"
@@ -94,3 +112,71 @@ watch(
94112
></button>
95113
</div>
96114
</template>
115+
116+
<style scoped>
117+
@keyframes progress {
118+
0% {
119+
width: 0;
120+
}
121+
100% {
122+
width: 100%;
123+
}
124+
}
125+
126+
.animate-progress {
127+
animation: progress 2s ease-in-out infinite;
128+
}
129+
130+
/* Dots loader animation */
131+
.dots-loader {
132+
display: flex;
133+
align-items: center;
134+
gap: 2px;
135+
height: 16px;
136+
}
137+
138+
.dots-loader div {
139+
width: 4px;
140+
height: 4px;
141+
background-color: #4b5563;
142+
border-radius: 50%;
143+
animation: dots 1.4s infinite ease-in-out;
144+
}
145+
146+
.dots-loader div:nth-child(1) {
147+
animation-delay: -0.32s;
148+
}
149+
150+
.dots-loader div:nth-child(2) {
151+
animation-delay: -0.16s;
152+
}
153+
154+
@keyframes dots {
155+
0%,
156+
80%,
157+
100% {
158+
transform: scale(0);
159+
}
160+
40% {
161+
transform: scale(1);
162+
}
163+
}
164+
165+
/* Gradient animation for progress bar */
166+
.background-animate {
167+
background-size: 200%;
168+
animation: gradient 2s linear infinite;
169+
}
170+
171+
@keyframes gradient {
172+
0% {
173+
background-position: 0% 50%;
174+
}
175+
50% {
176+
background-position: 100% 50%;
177+
}
178+
100% {
179+
background-position: 0% 50%;
180+
}
181+
}
182+
</style>

src/components/file_upload/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,11 @@ const handleDragOver = (event: DragEvent) => {
105105
<div>
106106
<p class="font-medium">
107107
{{ props.input.label }}
108-
<span v-if="isRequired" class="text-red-500">*</span>
108+
<span
109+
v-if="isRequired"
110+
class="text-red-600 dark:text-red-400 -ml-0.5"
111+
>*</span
112+
>
109113
</p>
110114

111115
<FileUpload

src/components/long_text/index.vue

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
import { computed, defineModel, defineProps } from 'vue'
3-
import type { InputProperties } from '~/types'
3+
import type { InputProperties, Validation } from '~/types'
44
import TextArea from 'primevue/textarea'
55
66
interface Props {
@@ -13,19 +13,27 @@ const model = defineModel<string>({ default: '' })
1313
const isRequired = computed(() =>
1414
props.input.validations?.map((v) => v.rule).includes('required'),
1515
)
16+
17+
const charCount = computed(() => model.value?.length || 0)
18+
const maxLength = computed(() => {
19+
const v = props.input?.validations?.find(
20+
(v: Validation) => v.rule == 'maxLength',
21+
)
22+
return v?.params ? parseInt(v.params[0]) : 255
23+
})
1624
</script>
1725

1826
<template>
1927
<div>
2028
<label :for="input.key" class="font-semibold">
2129
{{ input.label }}
22-
<span v-if="isRequired" class="text-red-600 dark:text-red-400"
30+
<span
31+
v-if="isRequired"
32+
class="text-red-600 dark:text-red-400 -ml-0.5"
2333
>*</span
2434
>
25-
<!-- Adjusted for dark mode -->
2635
</label>
2736
<p class="text-gray-600 text-sm mb-3">{{ input.description }}</p>
28-
<!-- TextArea section -->
2937
<div class="mt-2">
3038
<TextArea
3139
:id="input.key"
@@ -34,11 +42,20 @@ const isRequired = computed(() =>
3442
v-bind="{ ...$attrs, ...input.props }"
3543
rows="5"
3644
:placeholder="input.placeholder"
45+
:maxlength="maxLength"
3746
fluid
3847
/>
48+
<div class="flex justify-end mt-1">
49+
<span class="text-sm text-gray-500">
50+
{{ charCount }}/{{ maxLength }}
51+
</span>
52+
</div>
3953
</div>
40-
<!-- If error -->
41-
<small v-if="error" :id="`${input.key}-help`" class="text-sm mt-0.5">
54+
<small
55+
v-if="error"
56+
:id="`${input.key}-help`"
57+
class="text-sm mt-0.5 text-red-600"
58+
>
4259
{{ error }}
4360
</small>
4461
</div>

src/components/multiple_choice/index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ const model = defineModel<string>({ default: '' })
1818
<div>
1919
<label :for="input.key" class="font-semibold">
2020
{{ input.label }}
21-
<span v-if="isRequired" class="text-red-600 dark:text-red-400"
21+
<span
22+
v-if="isRequired"
23+
class="text-red-600 dark:text-red-400 -ml-0.5"
2224
>*</span
2325
>
2426
<!-- Adjusted for dark mode -->

0 commit comments

Comments
 (0)