@illuminateeducation/dna-atd-frontend 1.0.1-DNAATD-2189.0 → 1.0.5
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/README.md +3 -4
- package/dist/AdminLayout-BQWZADPC.js +74 -0
- package/dist/AdminLayout-BQWZADPC.js.map +1 -0
- package/dist/AdminLayout-BaO704Tp.cjs +2 -0
- package/dist/AdminLayout-BaO704Tp.cjs.map +1 -0
- package/dist/CustomizationView-BJlqBq4I.js +15 -0
- package/dist/CustomizationView-BJlqBq4I.js.map +1 -0
- package/dist/CustomizationView-BRNwaKvj.cjs +2 -0
- package/dist/CustomizationView-BRNwaKvj.cjs.map +1 -0
- package/dist/HomeView-7jy27idX.js +10 -0
- package/dist/HomeView-7jy27idX.js.map +1 -0
- package/dist/HomeView-D6NWAtxc.cjs +2 -0
- package/dist/HomeView-D6NWAtxc.cjs.map +1 -0
- package/dist/NotFoundView-BCWgZLYs.js +28 -0
- package/dist/NotFoundView-BCWgZLYs.js.map +1 -0
- package/dist/NotFoundView-CNvAC47u.cjs +2 -0
- package/dist/NotFoundView-CNvAC47u.cjs.map +1 -0
- package/dist/ValidationView-DY83tE4M.js +15 -0
- package/dist/ValidationView-DY83tE4M.js.map +1 -0
- package/dist/ValidationView-ltSgO4AC.cjs +2 -0
- package/dist/ValidationView-ltSgO4AC.cjs.map +1 -0
- package/dist/assets/dna-atd-frontend.css +1 -0
- package/dist/index-1yktdPHs.cjs +2 -0
- package/dist/index-1yktdPHs.cjs.map +1 -0
- package/dist/index-CiZS9VrS.js +461 -0
- package/dist/index-CiZS9VrS.js.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.es.js +30 -0
- package/dist/index.es.js.map +1 -0
- package/package.json +11 -21
- package/dist/.vite/manifest.json +0 -87
- package/dist/assets/AdminLayout.css +0 -1
- package/dist/assets/AdminLayout.js +0 -1
- package/dist/assets/CustomizationView.css +0 -1
- package/dist/assets/CustomizationView.js +0 -1
- package/dist/assets/HomeView.css +0 -1
- package/dist/assets/HomeView.js +0 -1
- package/dist/assets/NotFoundView.css +0 -1
- package/dist/assets/NotFoundView.js +0 -1
- package/dist/assets/ValidationView.css +0 -1
- package/dist/assets/ValidationView.js +0 -1
- package/dist/assets/_plugin-vue_export-helper.js +0 -1
- package/dist/assets/index.css +0 -1
- package/dist/assets/index.js +0 -2
- package/dist/index.html +0 -14
- package/index.js +0 -1
- package/src/App.vue +0 -68
- package/src/__tests__/App.spec.js +0 -26
- package/src/components/common/BaseButton.vue +0 -20
- package/src/components/common/BaseInput.vue +0 -27
- package/src/components/common/BaseModal.vue +0 -37
- package/src/composables/useAsync.js +0 -34
- package/src/composables/useClickOutside.js +0 -29
- package/src/composables/useForm.js +0 -89
- package/src/composables/useLocalStorage.js +0 -51
- package/src/composables/useWindowSize.js +0 -30
- package/src/config/app.config.js +0 -79
- package/src/features/admin/customization/composables/useCustomization.js +0 -19
- package/src/features/admin/customization/store/customizationStore.js +0 -30
- package/src/features/admin/customization/views/CustomizationView.vue +0 -17
- package/src/features/admin/validation/composables/useValidation.js +0 -18
- package/src/features/admin/validation/store/validationStore.js +0 -25
- package/src/features/admin/validation/views/ValidationView.vue +0 -17
- package/src/index.js +0 -53
- package/src/layouts/AdminLayout.vue +0 -146
- package/src/main.js +0 -41
- package/src/router/index.js +0 -57
- package/src/services/apiService.js +0 -72
- package/src/services/integration.js +0 -59
- package/src/services/phpIntegration.js +0 -1
- package/src/stores/counter.js +0 -12
- package/src/utils/helpers.js +0 -119
- package/src/utils/validators.js +0 -131
- package/src/views/HomeView.vue +0 -121
- package/src/views/NotFoundView.vue +0 -56
package/src/router/index.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
-
|
|
3
|
-
const router = createRouter({
|
|
4
|
-
history: createWebHistory(import.meta.env.BASE_URL),
|
|
5
|
-
routes: [
|
|
6
|
-
{
|
|
7
|
-
path: '/',
|
|
8
|
-
name: 'home',
|
|
9
|
-
component: () => import('../views/HomeView.vue')
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
path: '/admin',
|
|
13
|
-
name: 'admin',
|
|
14
|
-
component: () => import('../layouts/AdminLayout.vue'),
|
|
15
|
-
redirect: '/admin/validation',
|
|
16
|
-
children: [
|
|
17
|
-
{
|
|
18
|
-
path: 'validation',
|
|
19
|
-
name: 'admin-validation',
|
|
20
|
-
component: () => import('../features/admin/validation/views/ValidationView.vue'),
|
|
21
|
-
meta: {
|
|
22
|
-
title: 'Validation Management'
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
path: 'customization',
|
|
27
|
-
name: 'admin-customization',
|
|
28
|
-
component: () => import('../features/admin/customization/views/CustomizationView.vue'),
|
|
29
|
-
meta: {
|
|
30
|
-
title: 'UI Customization'
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
meta: {
|
|
35
|
-
requiresAuth: true
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
path: '/:pathMatch(.*)*',
|
|
40
|
-
name: 'not-found',
|
|
41
|
-
component: () => import('../views/NotFoundView.vue')
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
// Navigation guard for authentication
|
|
47
|
-
router.beforeEach((to, from, next) => {
|
|
48
|
-
if (to.meta.requiresAuth) {
|
|
49
|
-
// Add your authentication logic here
|
|
50
|
-
// For now, we'll just allow access
|
|
51
|
-
next()
|
|
52
|
-
} else {
|
|
53
|
-
next()
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
export default router
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Service
|
|
3
|
-
* Centralized API calls using fetch
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api'
|
|
7
|
-
|
|
8
|
-
class ApiService {
|
|
9
|
-
constructor(baseURL = API_BASE_URL) {
|
|
10
|
-
this.baseURL = baseURL
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async request(endpoint, options = {}) {
|
|
14
|
-
const url = `${this.baseURL}${endpoint}`
|
|
15
|
-
const config = {
|
|
16
|
-
headers: {
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
...options.headers
|
|
19
|
-
},
|
|
20
|
-
...options
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
const response = await fetch(url, config)
|
|
25
|
-
|
|
26
|
-
if (!response.ok) {
|
|
27
|
-
throw new Error(`HTTP error! status: ${response.status}`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return await response.json()
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error('API request failed:', error)
|
|
33
|
-
throw error
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get(endpoint, options = {}) {
|
|
38
|
-
return this.request(endpoint, { method: 'GET', ...options })
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
post(endpoint, data, options = {}) {
|
|
42
|
-
return this.request(endpoint, {
|
|
43
|
-
method: 'POST',
|
|
44
|
-
body: JSON.stringify(data),
|
|
45
|
-
...options
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
put(endpoint, data, options = {}) {
|
|
50
|
-
return this.request(endpoint, {
|
|
51
|
-
method: 'PUT',
|
|
52
|
-
body: JSON.stringify(data),
|
|
53
|
-
...options
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
patch(endpoint, data, options = {}) {
|
|
58
|
-
return this.request(endpoint, {
|
|
59
|
-
method: 'PATCH',
|
|
60
|
-
body: JSON.stringify(data),
|
|
61
|
-
...options
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
delete(endpoint, options = {}) {
|
|
66
|
-
return this.request(endpoint, { method: 'DELETE', ...options })
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const apiService = new ApiService()
|
|
71
|
-
export default apiService
|
|
72
|
-
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration Service
|
|
3
|
-
* Handles communication between Vue app and backend
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export class Integration {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.config = this.getConfig()
|
|
9
|
-
this.user = this.getUser()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Get configuration from backend
|
|
14
|
-
*/
|
|
15
|
-
getConfig() {
|
|
16
|
-
const appElement = document.getElementById('app')
|
|
17
|
-
const configData = appElement?.getAttribute('data-config')
|
|
18
|
-
return configData ? JSON.parse(configData) : {}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get user data from backend
|
|
23
|
-
*/
|
|
24
|
-
getUser() {
|
|
25
|
-
const appElement = document.getElementById('app')
|
|
26
|
-
const userData = appElement?.getAttribute('data-user')
|
|
27
|
-
return userData ? JSON.parse(userData) : {}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Get any custom data attribute
|
|
32
|
-
*/
|
|
33
|
-
getData(attribute) {
|
|
34
|
-
const appElement = document.getElementById('app')
|
|
35
|
-
const data = appElement?.getAttribute(`data-${attribute}`)
|
|
36
|
-
return data ? JSON.parse(data) : null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Emit event to backend (via window for backend to listen)
|
|
41
|
-
*/
|
|
42
|
-
emitToBackend(eventName, data) {
|
|
43
|
-
window.dispatchEvent(new CustomEvent(`vue:${eventName}`, { detail: data }))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Listen for backend events
|
|
48
|
-
*/
|
|
49
|
-
listenFromBackend(eventName, callback) {
|
|
50
|
-
window.addEventListener(`backend:${eventName}`, (event) => {
|
|
51
|
-
callback(event.detail)
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Singleton instance
|
|
57
|
-
export const integration = new Integration()
|
|
58
|
-
export default integration
|
|
59
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
package/src/stores/counter.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ref, computed } from 'vue'
|
|
2
|
-
import { defineStore } from 'pinia'
|
|
3
|
-
|
|
4
|
-
export const useCounterStore = defineStore('counter', () => {
|
|
5
|
-
const count = ref(0)
|
|
6
|
-
const doubleCount = computed(() => count.value * 2)
|
|
7
|
-
function increment() {
|
|
8
|
-
count.value++
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return { count, doubleCount, increment }
|
|
12
|
-
})
|
package/src/utils/helpers.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for common operations
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Debounce function to limit rate of function execution
|
|
7
|
-
* @param {Function} func - Function to debounce
|
|
8
|
-
* @param {number} wait - Delay in milliseconds
|
|
9
|
-
* @returns {Function}
|
|
10
|
-
*/
|
|
11
|
-
export function debounce(func, wait = 300) {
|
|
12
|
-
let timeout
|
|
13
|
-
return function executedFunction(...args) {
|
|
14
|
-
const later = () => {
|
|
15
|
-
clearTimeout(timeout)
|
|
16
|
-
func(...args)
|
|
17
|
-
}
|
|
18
|
-
clearTimeout(timeout)
|
|
19
|
-
timeout = setTimeout(later, wait)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Throttle function to limit function execution frequency
|
|
25
|
-
* @param {Function} func - Function to throttle
|
|
26
|
-
* @param {number} limit - Time limit in milliseconds
|
|
27
|
-
* @returns {Function}
|
|
28
|
-
*/
|
|
29
|
-
export function throttle(func, limit = 300) {
|
|
30
|
-
let inThrottle
|
|
31
|
-
return function executedFunction(...args) {
|
|
32
|
-
if (!inThrottle) {
|
|
33
|
-
func.apply(this, args)
|
|
34
|
-
inThrottle = true
|
|
35
|
-
setTimeout(() => (inThrottle = false), limit)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Deep clone an object
|
|
42
|
-
* @param {*} obj - Object to clone
|
|
43
|
-
* @returns {*}
|
|
44
|
-
*/
|
|
45
|
-
export function deepClone(obj) {
|
|
46
|
-
if (obj === null || typeof obj !== 'object') return obj
|
|
47
|
-
if (obj instanceof Date) return new Date(obj.getTime())
|
|
48
|
-
if (obj instanceof Array) return obj.map(item => deepClone(item))
|
|
49
|
-
|
|
50
|
-
const clonedObj = {}
|
|
51
|
-
for (const key in obj) {
|
|
52
|
-
if (obj.hasOwnProperty(key)) {
|
|
53
|
-
clonedObj[key] = deepClone(obj[key])
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return clonedObj
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Format date to readable string
|
|
61
|
-
* @param {Date|string} date - Date to format
|
|
62
|
-
* @param {string} format - Format type ('short', 'long', 'time')
|
|
63
|
-
* @returns {string}
|
|
64
|
-
*/
|
|
65
|
-
export function formatDate(date, format = 'short') {
|
|
66
|
-
const d = new Date(date)
|
|
67
|
-
|
|
68
|
-
const options = {
|
|
69
|
-
short: { year: 'numeric', month: 'short', day: 'numeric' },
|
|
70
|
-
long: { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' },
|
|
71
|
-
time: { hour: '2-digit', minute: '2-digit', second: '2-digit' }
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return d.toLocaleDateString('en-US', options[format] || options.short)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Generate unique ID
|
|
79
|
-
* @returns {string}
|
|
80
|
-
*/
|
|
81
|
-
export function generateId() {
|
|
82
|
-
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Capitalize first letter of string
|
|
87
|
-
* @param {string} str - String to capitalize
|
|
88
|
-
* @returns {string}
|
|
89
|
-
*/
|
|
90
|
-
export function capitalize(str) {
|
|
91
|
-
if (!str) return ''
|
|
92
|
-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Truncate string to specified length
|
|
97
|
-
* @param {string} str - String to truncate
|
|
98
|
-
* @param {number} length - Max length
|
|
99
|
-
* @param {string} suffix - Suffix to add
|
|
100
|
-
* @returns {string}
|
|
101
|
-
*/
|
|
102
|
-
export function truncate(str, length = 50, suffix = '...') {
|
|
103
|
-
if (!str || str.length <= length) return str
|
|
104
|
-
return str.substring(0, length).trim() + suffix
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Check if value is empty (null, undefined, empty string, empty array, empty object)
|
|
109
|
-
* @param {*} value - Value to check
|
|
110
|
-
* @returns {boolean}
|
|
111
|
-
*/
|
|
112
|
-
export function isEmpty(value) {
|
|
113
|
-
if (value === null || value === undefined) return true
|
|
114
|
-
if (typeof value === 'string' && value.trim() === '') return true
|
|
115
|
-
if (Array.isArray(value) && value.length === 0) return true
|
|
116
|
-
if (typeof value === 'object' && Object.keys(value).length === 0) return true
|
|
117
|
-
return false
|
|
118
|
-
}
|
|
119
|
-
|
package/src/utils/validators.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation utility functions
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Validate email format
|
|
7
|
-
* @param {string} email - Email to validate
|
|
8
|
-
* @returns {boolean}
|
|
9
|
-
*/
|
|
10
|
-
export function isValidEmail(email) {
|
|
11
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
12
|
-
return emailRegex.test(email)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Validate phone number
|
|
17
|
-
* @param {string} phone - Phone number to validate
|
|
18
|
-
* @returns {boolean}
|
|
19
|
-
*/
|
|
20
|
-
export function isValidPhone(phone) {
|
|
21
|
-
const phoneRegex = /^\d{10}$/
|
|
22
|
-
return phoneRegex.test(phone.replace(/[\s-()]/g, ''))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Validate URL format
|
|
27
|
-
* @param {string} url - URL to validate
|
|
28
|
-
* @returns {boolean}
|
|
29
|
-
*/
|
|
30
|
-
export function isValidUrl(url) {
|
|
31
|
-
try {
|
|
32
|
-
new URL(url)
|
|
33
|
-
return true
|
|
34
|
-
} catch {
|
|
35
|
-
return false
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Validate password strength
|
|
41
|
-
* @param {string} password - Password to validate
|
|
42
|
-
* @returns {Object} - { isValid: boolean, strength: string, message: string }
|
|
43
|
-
*/
|
|
44
|
-
export function validatePassword(password) {
|
|
45
|
-
const minLength = 8
|
|
46
|
-
const hasUpperCase = /[A-Z]/.test(password)
|
|
47
|
-
const hasLowerCase = /[a-z]/.test(password)
|
|
48
|
-
const hasNumbers = /\d/.test(password)
|
|
49
|
-
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password)
|
|
50
|
-
|
|
51
|
-
if (password.length < minLength) {
|
|
52
|
-
return { isValid: false, strength: 'weak', message: `Password must be at least ${minLength} characters` }
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let strength = 'weak'
|
|
56
|
-
let strengthScore = 0
|
|
57
|
-
|
|
58
|
-
if (hasUpperCase) strengthScore++
|
|
59
|
-
if (hasLowerCase) strengthScore++
|
|
60
|
-
if (hasNumbers) strengthScore++
|
|
61
|
-
if (hasSpecialChar) strengthScore++
|
|
62
|
-
|
|
63
|
-
if (strengthScore === 4) {
|
|
64
|
-
strength = 'strong'
|
|
65
|
-
} else if (strengthScore >= 2) {
|
|
66
|
-
strength = 'medium'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
isValid: true,
|
|
71
|
-
strength,
|
|
72
|
-
message: `Password strength: ${strength}`,
|
|
73
|
-
hasUpperCase,
|
|
74
|
-
hasLowerCase,
|
|
75
|
-
hasNumbers,
|
|
76
|
-
hasSpecialChar
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Validate required field
|
|
82
|
-
* @param {*} value - Value to validate
|
|
83
|
-
* @returns {boolean}
|
|
84
|
-
*/
|
|
85
|
-
export function isRequired(value) {
|
|
86
|
-
if (value === null || value === undefined) return false
|
|
87
|
-
if (typeof value === 'string' && value.trim() === '') return false
|
|
88
|
-
if (Array.isArray(value) && value.length === 0) return false
|
|
89
|
-
return true
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Validate min length
|
|
94
|
-
* @param {string} value - Value to validate
|
|
95
|
-
* @param {number} min - Minimum length
|
|
96
|
-
* @returns {boolean}
|
|
97
|
-
*/
|
|
98
|
-
export function minLength(value, min) {
|
|
99
|
-
return value && value.length >= min
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Validate max length
|
|
104
|
-
* @param {string} value - Value to validate
|
|
105
|
-
* @param {number} max - Maximum length
|
|
106
|
-
* @returns {boolean}
|
|
107
|
-
*/
|
|
108
|
-
export function maxLength(value, max) {
|
|
109
|
-
return value && value.length <= max
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Validate numeric value
|
|
114
|
-
* @param {*} value - Value to validate
|
|
115
|
-
* @returns {boolean}
|
|
116
|
-
*/
|
|
117
|
-
export function isNumeric(value) {
|
|
118
|
-
return !isNaN(parseFloat(value)) && isFinite(value)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Validate value is within range
|
|
123
|
-
* @param {number} value - Value to validate
|
|
124
|
-
* @param {number} min - Minimum value
|
|
125
|
-
* @param {number} max - Maximum value
|
|
126
|
-
* @returns {boolean}
|
|
127
|
-
*/
|
|
128
|
-
export function inRange(value, min, max) {
|
|
129
|
-
return value >= min && value <= max
|
|
130
|
-
}
|
|
131
|
-
|
package/src/views/HomeView.vue
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="home-view">
|
|
3
|
-
<div class="hero">
|
|
4
|
-
<h1>Welcome to DNA ATD Frontend</h1>
|
|
5
|
-
<p>A modern Vue 3 application with feature-based architecture</p>
|
|
6
|
-
<div class="cta-buttons">
|
|
7
|
-
<router-link to="/admin" class="btn btn-primary">
|
|
8
|
-
Go to Admin Panel
|
|
9
|
-
</router-link>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<div class="features">
|
|
14
|
-
<div class="feature-card">
|
|
15
|
-
<div class="feature-icon">✓</div>
|
|
16
|
-
<h3>Validation Management</h3>
|
|
17
|
-
<p>Manage and configure validation rules for your application</p>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="feature-card">
|
|
20
|
-
<div class="feature-icon">🎨</div>
|
|
21
|
-
<h3>UI Customization</h3>
|
|
22
|
-
<p>Customize themes, colors, and layout settings</p>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script setup>
|
|
29
|
-
// Home view component
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<style scoped>
|
|
33
|
-
.home-view {
|
|
34
|
-
min-height: 100vh;
|
|
35
|
-
display: flex;
|
|
36
|
-
flex-direction: column;
|
|
37
|
-
align-items: center;
|
|
38
|
-
justify-content: center;
|
|
39
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
40
|
-
color: white;
|
|
41
|
-
padding: 2rem;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.hero {
|
|
45
|
-
text-align: center;
|
|
46
|
-
margin-bottom: 4rem;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.hero h1 {
|
|
50
|
-
font-size: 3rem;
|
|
51
|
-
margin-bottom: 1rem;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.hero p {
|
|
55
|
-
font-size: 1.5rem;
|
|
56
|
-
margin-bottom: 2rem;
|
|
57
|
-
opacity: 0.9;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.cta-buttons {
|
|
61
|
-
display: flex;
|
|
62
|
-
gap: 1rem;
|
|
63
|
-
justify-content: center;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.btn {
|
|
67
|
-
padding: 1rem 2rem;
|
|
68
|
-
border-radius: 8px;
|
|
69
|
-
text-decoration: none;
|
|
70
|
-
font-weight: 600;
|
|
71
|
-
transition: all 0.3s;
|
|
72
|
-
display: inline-block;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.btn-primary {
|
|
76
|
-
background-color: white;
|
|
77
|
-
color: #667eea;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.btn-primary:hover {
|
|
81
|
-
transform: translateY(-2px);
|
|
82
|
-
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.features {
|
|
86
|
-
display: grid;
|
|
87
|
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
88
|
-
gap: 2rem;
|
|
89
|
-
max-width: 1200px;
|
|
90
|
-
width: 100%;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.feature-card {
|
|
94
|
-
background: rgba(255,255,255,0.1);
|
|
95
|
-
backdrop-filter: blur(10px);
|
|
96
|
-
padding: 2rem;
|
|
97
|
-
border-radius: 12px;
|
|
98
|
-
text-align: center;
|
|
99
|
-
transition: all 0.3s;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.feature-card:hover {
|
|
103
|
-
transform: translateY(-5px);
|
|
104
|
-
background: rgba(255,255,255,0.15);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.feature-icon {
|
|
108
|
-
font-size: 3rem;
|
|
109
|
-
margin-bottom: 1rem;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.feature-card h3 {
|
|
113
|
-
font-size: 1.5rem;
|
|
114
|
-
margin-bottom: 1rem;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.feature-card p {
|
|
118
|
-
opacity: 0.9;
|
|
119
|
-
}
|
|
120
|
-
</style>
|
|
121
|
-
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="not-found">
|
|
3
|
-
<h1>404</h1>
|
|
4
|
-
<h2>Page Not Found</h2>
|
|
5
|
-
<p>The page you're looking for doesn't exist.</p>
|
|
6
|
-
<router-link to="/" class="btn">Go Home</router-link>
|
|
7
|
-
</div>
|
|
8
|
-
</template>
|
|
9
|
-
|
|
10
|
-
<script setup>
|
|
11
|
-
// 404 Not Found view
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<style scoped>
|
|
15
|
-
.not-found {
|
|
16
|
-
min-height: 100vh;
|
|
17
|
-
display: flex;
|
|
18
|
-
flex-direction: column;
|
|
19
|
-
align-items: center;
|
|
20
|
-
justify-content: center;
|
|
21
|
-
text-align: center;
|
|
22
|
-
padding: 2rem;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.not-found h1 {
|
|
26
|
-
font-size: 6rem;
|
|
27
|
-
margin: 0;
|
|
28
|
-
color: #3498db;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.not-found h2 {
|
|
32
|
-
font-size: 2rem;
|
|
33
|
-
margin: 1rem 0;
|
|
34
|
-
color: #2c3e50;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.not-found p {
|
|
38
|
-
font-size: 1.2rem;
|
|
39
|
-
color: #7f8c8d;
|
|
40
|
-
margin-bottom: 2rem;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.btn {
|
|
44
|
-
background-color: #3498db;
|
|
45
|
-
color: white;
|
|
46
|
-
padding: 1rem 2rem;
|
|
47
|
-
border-radius: 4px;
|
|
48
|
-
text-decoration: none;
|
|
49
|
-
transition: all 0.3s;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.btn:hover {
|
|
53
|
-
background-color: #2980b9;
|
|
54
|
-
}
|
|
55
|
-
</style>
|
|
56
|
-
|