@a-vision-software/vue-input-components 1.2.4 → 1.2.6
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/package.json +2 -1
- package/src/App.vue +7 -0
- package/src/assets/colors.css +67 -0
- package/src/assets/logo.svg +1 -0
- package/src/assets/main.css +160 -0
- package/src/components/Action.vue +208 -0
- package/src/components/FileUpload.vue +310 -0
- package/src/components/Navigation.vue +634 -0
- package/src/components/TextInput.vue +503 -0
- package/src/env.d.ts +9 -0
- package/src/index.ts +8 -0
- package/src/main.ts +21 -0
- package/src/router/index.ts +44 -0
- package/src/types/index.ts +3 -0
- package/src/types/navigation.ts +32 -0
- package/src/types.d.ts +23 -0
- package/src/types.ts +108 -0
- package/src/views/ActionTestView.vue +307 -0
- package/src/views/DashboardView.vue +98 -0
- package/src/views/FileUploadTestView.vue +177 -0
- package/src/views/NavigationTestView.vue +319 -0
- package/src/views/TextInputTestView.vue +372 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="navigation-test">
|
|
3
|
+
<div class="navigation-test__back">
|
|
4
|
+
<router-link to="/" class="back-link"> ← Back to Dashboard </router-link>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="navigation-test__section">
|
|
8
|
+
<h2>Tiles Navigation (Default)</h2>
|
|
9
|
+
<Navigation
|
|
10
|
+
:items="defaultItems"
|
|
11
|
+
type="tiles"
|
|
12
|
+
orientation="horizontal"
|
|
13
|
+
v-model:activeItem="activeDefaultItem"
|
|
14
|
+
@item-click="handleDefaultClick"
|
|
15
|
+
iconSize="large"
|
|
16
|
+
height="90px"
|
|
17
|
+
backgroundColor="#fff"
|
|
18
|
+
activeBackgroundColor="var(--background-color)"
|
|
19
|
+
/>
|
|
20
|
+
<div v-if="lastClicked.default" class="click-info">
|
|
21
|
+
Last clicked: {{ lastClicked.default.url || `id:${lastClicked.default.id}` }}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="navigation-test__section">
|
|
26
|
+
<h2>Tabs Navigation (Mixed Alignment)</h2>
|
|
27
|
+
<Navigation
|
|
28
|
+
:items="mixedAlignmentItems"
|
|
29
|
+
type="tiles"
|
|
30
|
+
orientation="horizontal"
|
|
31
|
+
v-model:activeItem="activeTabsItem"
|
|
32
|
+
@item-click="handleTabsClick"
|
|
33
|
+
height="2em"
|
|
34
|
+
showBottomBorder
|
|
35
|
+
/>
|
|
36
|
+
<div v-if="lastClicked.tabs" class="click-info">
|
|
37
|
+
Last clicked: {{ lastClicked.tabs.label }}
|
|
38
|
+
<span v-if="lastClicked.tabs.alignment">({{ lastClicked.tabs.alignment }} aligned)</span>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="navigation-test__section">
|
|
43
|
+
<h2>Dropdown Navigation (Vertical)</h2>
|
|
44
|
+
<Navigation
|
|
45
|
+
:items="dropdownItems"
|
|
46
|
+
type="dropdowns"
|
|
47
|
+
orientation="vertical"
|
|
48
|
+
v-model:activeItem="activeDropdownItem"
|
|
49
|
+
@item-click="handleDropdownClick"
|
|
50
|
+
:showIcons="false"
|
|
51
|
+
color="#805ad5"
|
|
52
|
+
hoverColor="#6b46c1"
|
|
53
|
+
activeColor="#553c9a"
|
|
54
|
+
disabledColor="#b794f4"
|
|
55
|
+
gap="0.5rem"
|
|
56
|
+
padding="0.75rem 1rem"
|
|
57
|
+
borderRadius="6px"
|
|
58
|
+
/>
|
|
59
|
+
<div v-if="lastClicked.dropdown" class="click-info">
|
|
60
|
+
Last clicked: {{ lastClicked.dropdown.label }}
|
|
61
|
+
<span v-if="lastClicked.dropdown.children"
|
|
62
|
+
>(has {{ lastClicked.dropdown.children.length }} children)</span
|
|
63
|
+
>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="navigation-test__section">
|
|
68
|
+
<h2>Custom Styled Navigation</h2>
|
|
69
|
+
<Navigation
|
|
70
|
+
:items="customItems"
|
|
71
|
+
type="tiles"
|
|
72
|
+
orientation="horizontal"
|
|
73
|
+
v-model:activeItem="activeCustomItem"
|
|
74
|
+
@item-click="handleCustomClick"
|
|
75
|
+
:showIcons="false"
|
|
76
|
+
color="#4a90e2"
|
|
77
|
+
hoverColor="#357abd"
|
|
78
|
+
activeColor="#2c5a8c"
|
|
79
|
+
disabledColor="#a0c4e8"
|
|
80
|
+
gap="1.5rem"
|
|
81
|
+
padding="1rem 2rem"
|
|
82
|
+
borderRadius="8px"
|
|
83
|
+
/>
|
|
84
|
+
<div v-if="lastClicked.custom" class="click-info">
|
|
85
|
+
Last clicked: {{ lastClicked.custom.label }}
|
|
86
|
+
<span v-if="lastClicked.custom.disabled">(disabled)</span>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
92
|
+
<script setup lang="ts">
|
|
93
|
+
import { ref } from 'vue'
|
|
94
|
+
import type { NavigationItem } from '../types/navigation'
|
|
95
|
+
import Navigation from '@/components/Navigation.vue'
|
|
96
|
+
|
|
97
|
+
const activeDefaultItem = ref('')
|
|
98
|
+
const activeTabsItem = ref('')
|
|
99
|
+
const activeDropdownItem = ref('')
|
|
100
|
+
const activeCustomItem = ref('')
|
|
101
|
+
|
|
102
|
+
const lastClicked = ref<Record<string, NavigationItem>>({
|
|
103
|
+
default: {} as NavigationItem,
|
|
104
|
+
tabs: {} as NavigationItem,
|
|
105
|
+
dropdown: {} as NavigationItem,
|
|
106
|
+
custom: {} as NavigationItem,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const defaultItems: NavigationItem[] = [
|
|
110
|
+
{
|
|
111
|
+
id: 'home',
|
|
112
|
+
label: 'Home',
|
|
113
|
+
icon: 'house',
|
|
114
|
+
width: '150px',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'dashboard',
|
|
118
|
+
label: 'Dashboard',
|
|
119
|
+
icon: 'gauge-high',
|
|
120
|
+
width: '200px',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'spacer',
|
|
124
|
+
label: '',
|
|
125
|
+
width: '1fr',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 'about',
|
|
129
|
+
label: 'About',
|
|
130
|
+
url: 'https://example.com',
|
|
131
|
+
icon: 'info',
|
|
132
|
+
alignment: 'right',
|
|
133
|
+
width: '150px',
|
|
134
|
+
children: [
|
|
135
|
+
{
|
|
136
|
+
id: 'about-1',
|
|
137
|
+
label: 'About 1',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'about-2',
|
|
141
|
+
label: 'About 2',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: 'contact',
|
|
147
|
+
label: 'Contact',
|
|
148
|
+
icon: 'envelope',
|
|
149
|
+
width: '150px',
|
|
150
|
+
alignment: 'right',
|
|
151
|
+
},
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
const mixedAlignmentItems: NavigationItem[] = [
|
|
155
|
+
{
|
|
156
|
+
id: 'home',
|
|
157
|
+
label: 'Home',
|
|
158
|
+
url: 'https://example.com',
|
|
159
|
+
icon: 'house',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'about',
|
|
163
|
+
label: 'About',
|
|
164
|
+
width: '200px',
|
|
165
|
+
children: [
|
|
166
|
+
{
|
|
167
|
+
id: 'about-1',
|
|
168
|
+
label: 'About 1',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'about-2',
|
|
172
|
+
label: 'About 2',
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'spacer',
|
|
178
|
+
label: '',
|
|
179
|
+
width: '1fr',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: 'contact',
|
|
183
|
+
label: 'Contact',
|
|
184
|
+
icon: 'envelope',
|
|
185
|
+
alignment: 'right',
|
|
186
|
+
},
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
const dropdownItems: NavigationItem[] = [
|
|
190
|
+
{
|
|
191
|
+
id: 'home',
|
|
192
|
+
label: 'Home',
|
|
193
|
+
url: 'https://example.com',
|
|
194
|
+
alignment: 'start',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: 'about',
|
|
198
|
+
label: 'About',
|
|
199
|
+
alignment: 'start',
|
|
200
|
+
children: [
|
|
201
|
+
{
|
|
202
|
+
id: 'about-1',
|
|
203
|
+
label: 'About 1',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'about-2',
|
|
207
|
+
label: 'About 2',
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
const customItems: NavigationItem[] = [
|
|
214
|
+
{
|
|
215
|
+
id: 'home',
|
|
216
|
+
label: 'Home',
|
|
217
|
+
url: 'https://example.com',
|
|
218
|
+
alignment: 'start',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 'about',
|
|
222
|
+
label: 'About',
|
|
223
|
+
alignment: 'start',
|
|
224
|
+
children: [
|
|
225
|
+
{
|
|
226
|
+
id: 'about-1',
|
|
227
|
+
label: 'About 1',
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: 'about-2',
|
|
231
|
+
label: 'About 2',
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: 'contact',
|
|
237
|
+
label: 'Contact',
|
|
238
|
+
icon: 'envelope',
|
|
239
|
+
alignment: 'end',
|
|
240
|
+
disabled: true,
|
|
241
|
+
},
|
|
242
|
+
]
|
|
243
|
+
|
|
244
|
+
const handleDefaultClick = (item: NavigationItem) => {
|
|
245
|
+
console.log('Default navigation clicked:', item)
|
|
246
|
+
lastClicked.value.default = item
|
|
247
|
+
if (item.url) {
|
|
248
|
+
console.log('Navigating to:', item.url)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const handleTabsClick = (item: NavigationItem) => {
|
|
253
|
+
console.log('Tabs navigation clicked:', item)
|
|
254
|
+
lastClicked.value.tabs = item
|
|
255
|
+
if (item.url) {
|
|
256
|
+
console.log('Navigating to:', item.url)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const handleDropdownClick = (item: NavigationItem) => {
|
|
261
|
+
console.log('Dropdown navigation clicked:', item)
|
|
262
|
+
lastClicked.value.dropdown = item
|
|
263
|
+
if (item.url) {
|
|
264
|
+
console.log('Navigating to:', item.url)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const handleCustomClick = (item: NavigationItem) => {
|
|
269
|
+
console.log('Custom navigation clicked:', item)
|
|
270
|
+
lastClicked.value.custom = item
|
|
271
|
+
if (item.url) {
|
|
272
|
+
console.log('Navigating to:', item.url)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
</script>
|
|
276
|
+
|
|
277
|
+
<style scoped>
|
|
278
|
+
.navigation-test {
|
|
279
|
+
padding: 2rem;
|
|
280
|
+
max-width: 1200px;
|
|
281
|
+
margin: 0 auto;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.navigation-test__back {
|
|
285
|
+
margin-bottom: 2rem;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.back-link {
|
|
289
|
+
display: inline-flex;
|
|
290
|
+
align-items: center;
|
|
291
|
+
gap: 0.5rem;
|
|
292
|
+
color: #4a90e2;
|
|
293
|
+
text-decoration: none;
|
|
294
|
+
font-weight: 500;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.back-link:hover {
|
|
298
|
+
color: #357abd;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.navigation-test__section {
|
|
302
|
+
margin-bottom: 3rem;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.navigation-test__section h2 {
|
|
306
|
+
margin-bottom: 1rem;
|
|
307
|
+
color: #333;
|
|
308
|
+
font-size: 1.5rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.click-info {
|
|
312
|
+
margin-top: 1rem;
|
|
313
|
+
padding: 0.5rem;
|
|
314
|
+
background-color: #f7fafc;
|
|
315
|
+
border-radius: 4px;
|
|
316
|
+
font-size: 0.9rem;
|
|
317
|
+
color: #4a5568;
|
|
318
|
+
}
|
|
319
|
+
</style>
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="text-input-test">
|
|
3
|
+
<div class="header">
|
|
4
|
+
<router-link to="/" class="back-link">
|
|
5
|
+
<font-awesome-icon icon="home" />
|
|
6
|
+
<span>Back to Dashboard</span>
|
|
7
|
+
</router-link>
|
|
8
|
+
<h1>Text Input Testing</h1>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="test-container">
|
|
11
|
+
<div class="column">
|
|
12
|
+
<div class="input-group">
|
|
13
|
+
<h2>Account Information</h2>
|
|
14
|
+
<TextInput
|
|
15
|
+
v-model="username"
|
|
16
|
+
type="text"
|
|
17
|
+
icon="user"
|
|
18
|
+
placeholder="Enter your username"
|
|
19
|
+
:required="true"
|
|
20
|
+
:error="usernameError"
|
|
21
|
+
label="Username"
|
|
22
|
+
label-position="left"
|
|
23
|
+
label-align="right"
|
|
24
|
+
label-width="20%"
|
|
25
|
+
total-width="100%"
|
|
26
|
+
/>
|
|
27
|
+
<TextInput
|
|
28
|
+
v-model="password"
|
|
29
|
+
type="password"
|
|
30
|
+
icon="lock"
|
|
31
|
+
placeholder="Enter your password"
|
|
32
|
+
:required="true"
|
|
33
|
+
:error="passwordError"
|
|
34
|
+
label="Password"
|
|
35
|
+
label-position="left"
|
|
36
|
+
label-align="right"
|
|
37
|
+
label-width="20%"
|
|
38
|
+
total-width="100%"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="input-group">
|
|
42
|
+
<h2>Additional Information</h2>
|
|
43
|
+
<TextInput
|
|
44
|
+
v-model="bio"
|
|
45
|
+
isTextarea
|
|
46
|
+
label="Bio"
|
|
47
|
+
icon="user-circle"
|
|
48
|
+
placeholder="Tell us about yourself..."
|
|
49
|
+
:rows="4"
|
|
50
|
+
:maxLength="500"
|
|
51
|
+
:error="bioError"
|
|
52
|
+
:autosave="handleBioAutosave"
|
|
53
|
+
label-position="top"
|
|
54
|
+
label-align="left"
|
|
55
|
+
total-width="100%"
|
|
56
|
+
height="10rem"
|
|
57
|
+
max-height="20rem"
|
|
58
|
+
/>
|
|
59
|
+
<TextInput
|
|
60
|
+
v-model="feedback"
|
|
61
|
+
isTextarea
|
|
62
|
+
label="Feedback"
|
|
63
|
+
icon="comment"
|
|
64
|
+
placeholder="Share your thoughts..."
|
|
65
|
+
:rows="3"
|
|
66
|
+
:maxLength="1000"
|
|
67
|
+
:error="feedbackError"
|
|
68
|
+
:autosave="handleFeedbackAutosave"
|
|
69
|
+
label-position="left"
|
|
70
|
+
label-align="left"
|
|
71
|
+
label-width="auto"
|
|
72
|
+
total-width="100%"
|
|
73
|
+
max-height="8rem"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="column">
|
|
78
|
+
<div class="input-group">
|
|
79
|
+
<h2>Address Information</h2>
|
|
80
|
+
<TextInput
|
|
81
|
+
v-model="street"
|
|
82
|
+
label="Street Address"
|
|
83
|
+
type="text"
|
|
84
|
+
icon="road"
|
|
85
|
+
placeholder="Enter your street address"
|
|
86
|
+
:error="streetError"
|
|
87
|
+
:autosave="handleStreetAutosave"
|
|
88
|
+
label-position="top"
|
|
89
|
+
label-align="left"
|
|
90
|
+
total-width="100%"
|
|
91
|
+
/>
|
|
92
|
+
<div class="address-row">
|
|
93
|
+
<TextInput
|
|
94
|
+
v-model="city"
|
|
95
|
+
label="City"
|
|
96
|
+
type="text"
|
|
97
|
+
icon="building"
|
|
98
|
+
placeholder="Enter your city"
|
|
99
|
+
:error="cityError"
|
|
100
|
+
:autosave="handleCityAutosave"
|
|
101
|
+
label-position="top"
|
|
102
|
+
label-align="left"
|
|
103
|
+
total-width="calc(100% - 11rem)"
|
|
104
|
+
/>
|
|
105
|
+
<TextInput
|
|
106
|
+
v-model="postalCode"
|
|
107
|
+
label="Postal Code"
|
|
108
|
+
type="text"
|
|
109
|
+
icon="fas fa-hashtag"
|
|
110
|
+
placeholder="1234AB"
|
|
111
|
+
:error="postalCodeError"
|
|
112
|
+
@update:modelValue="handlePostalCodeInput"
|
|
113
|
+
:autosave="handlePostalCodeAutosave"
|
|
114
|
+
label-position="top"
|
|
115
|
+
label-align="left"
|
|
116
|
+
total-width="10rem"
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
<TextInput
|
|
120
|
+
v-model="country"
|
|
121
|
+
label="Country"
|
|
122
|
+
type="text"
|
|
123
|
+
icon="flag"
|
|
124
|
+
placeholder="Enter your country"
|
|
125
|
+
:error="countryError"
|
|
126
|
+
:autosave="handleCountryAutosave"
|
|
127
|
+
label-position="top"
|
|
128
|
+
label-align="left"
|
|
129
|
+
total-width="100%"
|
|
130
|
+
/>
|
|
131
|
+
<TextInput
|
|
132
|
+
v-model="birthDate"
|
|
133
|
+
type="date"
|
|
134
|
+
label="Date of Birth"
|
|
135
|
+
icon="calendar"
|
|
136
|
+
placeholder="DD/MM/YYYY"
|
|
137
|
+
:min="minDate"
|
|
138
|
+
:max="maxDate"
|
|
139
|
+
:error="birthDateError"
|
|
140
|
+
:autosave="handleBirthDateAutosave"
|
|
141
|
+
label-position="top"
|
|
142
|
+
label-align="left"
|
|
143
|
+
/>
|
|
144
|
+
<TextInput
|
|
145
|
+
v-model="comment"
|
|
146
|
+
label="Comment"
|
|
147
|
+
type="text"
|
|
148
|
+
placeholder="Your comment"
|
|
149
|
+
label-position="top"
|
|
150
|
+
label-align="left"
|
|
151
|
+
total-width="100%"
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script setup lang="ts">
|
|
160
|
+
import { ref } from 'vue'
|
|
161
|
+
import TextInput from '@/components/TextInput.vue'
|
|
162
|
+
|
|
163
|
+
const username = ref('')
|
|
164
|
+
const password = ref('')
|
|
165
|
+
const street = ref('')
|
|
166
|
+
const city = ref('')
|
|
167
|
+
const postalCode = ref('')
|
|
168
|
+
const country = ref('')
|
|
169
|
+
const birthDate = ref('')
|
|
170
|
+
const comment = ref('')
|
|
171
|
+
const bio = ref('')
|
|
172
|
+
const feedback = ref('')
|
|
173
|
+
|
|
174
|
+
const usernameError = ref('')
|
|
175
|
+
const passwordError = ref('')
|
|
176
|
+
const streetError = ref('')
|
|
177
|
+
const cityError = ref('')
|
|
178
|
+
const postalCodeError = ref('')
|
|
179
|
+
const countryError = ref('')
|
|
180
|
+
const birthDateError = ref('')
|
|
181
|
+
const bioError = ref('')
|
|
182
|
+
const feedbackError = ref('')
|
|
183
|
+
|
|
184
|
+
const minDate = '01/01/1900'
|
|
185
|
+
const maxDate = '31/12/2024'
|
|
186
|
+
|
|
187
|
+
const formatPostalCode = (value: string) => {
|
|
188
|
+
// Remove all non-alphanumeric characters except spaces
|
|
189
|
+
let formatted = value.replace(/[^a-zA-Z0-9\s]/g, '')
|
|
190
|
+
|
|
191
|
+
// Convert to uppercase
|
|
192
|
+
formatted = formatted.toUpperCase()
|
|
193
|
+
|
|
194
|
+
// Format as NNNN AA
|
|
195
|
+
if (formatted.length > 4) {
|
|
196
|
+
formatted = formatted.slice(0, 4) + ' ' + formatted.slice(4, 6)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return formatted
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const handlePostalCodeInput = (_value: string) => {
|
|
203
|
+
postalCodeError.value = ''
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const handlePostalCodeAutosave = async (value: string) => {
|
|
207
|
+
// First validate the format
|
|
208
|
+
if (value.length > 0) {
|
|
209
|
+
const postalCodeRegex = /^[0-9]{4}\s?[A-Za-z]{2}$/
|
|
210
|
+
if (!postalCodeRegex.test(value)) {
|
|
211
|
+
postalCodeError.value = 'Postal code must be in format NNNN AA (e.g., 1234 AB)'
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Format the value after successful validation
|
|
217
|
+
const formattedValue = formatPostalCode(value)
|
|
218
|
+
postalCode.value = formattedValue
|
|
219
|
+
|
|
220
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
221
|
+
postalCodeError.value = ''
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const handleStreetAutosave = async (value: string) => {
|
|
225
|
+
console.log('Autosaving street:', value)
|
|
226
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
227
|
+
streetError.value = ''
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const handleCityAutosave = async (value: string) => {
|
|
231
|
+
console.log('Autosaving city:', value)
|
|
232
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
233
|
+
cityError.value = ''
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const handleCountryAutosave = async (value: string) => {
|
|
237
|
+
console.log('Autosaving country:', value)
|
|
238
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
239
|
+
countryError.value = ''
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const handleBirthDateAutosave = async (value: string) => {
|
|
243
|
+
console.log('Autosaving birth date:', value)
|
|
244
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
245
|
+
birthDateError.value = ''
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const handleBioAutosave = async (value: string) => {
|
|
249
|
+
console.log('Autosaving bio:', value)
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
251
|
+
bioError.value = ''
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const handleFeedbackAutosave = async (value: string) => {
|
|
255
|
+
console.log('Autosaving feedback:', value)
|
|
256
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
257
|
+
feedbackError.value = ''
|
|
258
|
+
}
|
|
259
|
+
</script>
|
|
260
|
+
|
|
261
|
+
<style scoped>
|
|
262
|
+
.text-input-test {
|
|
263
|
+
padding: 2rem;
|
|
264
|
+
min-height: 100vh;
|
|
265
|
+
background-image: url('https://images.unsplash.com/photo-1519681393784-d120267933ba?auto=format&fit=crop&q=80&w=2070');
|
|
266
|
+
background-size: cover;
|
|
267
|
+
background-position: center;
|
|
268
|
+
background-attachment: fixed;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.text-input-grid {
|
|
272
|
+
display: grid;
|
|
273
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
274
|
+
gap: 2rem;
|
|
275
|
+
margin-top: 2rem;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.input-section {
|
|
279
|
+
background: rgba(255, 255, 255, 0.9);
|
|
280
|
+
padding: 2rem;
|
|
281
|
+
border-radius: 0.75rem;
|
|
282
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
283
|
+
backdrop-filter: blur(10px);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.input-section h2 {
|
|
287
|
+
margin-bottom: 1rem;
|
|
288
|
+
color: var(--text-color);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.group {
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
gap: 1rem;
|
|
295
|
+
padding: 2rem;
|
|
296
|
+
border-radius: 1rem;
|
|
297
|
+
background-color: rgba(255, 255, 255, 1);
|
|
298
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
299
|
+
backdrop-filter: blur(5px);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.header {
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
gap: 0.5rem;
|
|
306
|
+
margin-bottom: 1rem;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.back-link {
|
|
310
|
+
display: flex;
|
|
311
|
+
align-items: center;
|
|
312
|
+
gap: 0.25rem;
|
|
313
|
+
color: var(--text-color);
|
|
314
|
+
text-decoration: none;
|
|
315
|
+
font-size: 1rem;
|
|
316
|
+
transition: color 0.2s;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.back-link:hover {
|
|
320
|
+
color: var(--primary-color);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
h1 {
|
|
324
|
+
margin: 0;
|
|
325
|
+
color: #212529;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
h2 {
|
|
329
|
+
color: #495057;
|
|
330
|
+
font-size: 1.1rem;
|
|
331
|
+
margin-bottom: 0.5rem;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.test-container {
|
|
335
|
+
display: grid;
|
|
336
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 600px), 1fr));
|
|
337
|
+
gap: 1rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.column {
|
|
341
|
+
display: flex;
|
|
342
|
+
flex-direction: column;
|
|
343
|
+
gap: 1rem;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.input-group {
|
|
347
|
+
background: rgba(255, 255, 255, 0.8);
|
|
348
|
+
border-radius: 8px;
|
|
349
|
+
padding: 1rem;
|
|
350
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
351
|
+
height: fit-content;
|
|
352
|
+
backdrop-filter: blur(5px);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.input-group h2 {
|
|
356
|
+
margin: 0 0 0.5rem 0;
|
|
357
|
+
color: var(--text-color);
|
|
358
|
+
font-size: 1.1rem;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.address-row {
|
|
362
|
+
display: flex;
|
|
363
|
+
justify-content: space-between;
|
|
364
|
+
gap: 0.5rem;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
@media (max-width: 1200px) {
|
|
368
|
+
.test-container {
|
|
369
|
+
grid-template-columns: 1fr;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
</style>
|