refactor(ui): replaced some n-input with c-input-text
This commit is contained in:
		
							parent
							
								
									aad8d84e13
								
							
						
					
					
						commit
						77f2efc0b9
					
				
							
								
								
									
										72
									
								
								auto-imports.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								auto-imports.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -19,7 +19,9 @@ declare global { | |||||||
|   const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] |   const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] | ||||||
|   const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] |   const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] | ||||||
|   const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] |   const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] | ||||||
|  |   const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate'] | ||||||
|   const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] |   const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] | ||||||
|  |   const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise'] | ||||||
|   const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] |   const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] | ||||||
|   const customRef: typeof import('vue')['customRef'] |   const customRef: typeof import('vue')['customRef'] | ||||||
|   const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] |   const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] | ||||||
| @ -39,9 +41,6 @@ declare global { | |||||||
|   const isReactive: typeof import('vue')['isReactive'] |   const isReactive: typeof import('vue')['isReactive'] | ||||||
|   const isReadonly: typeof import('vue')['isReadonly'] |   const isReadonly: typeof import('vue')['isReadonly'] | ||||||
|   const isRef: typeof import('vue')['isRef'] |   const isRef: typeof import('vue')['isRef'] | ||||||
|   const logicAnd: typeof import('@vueuse/core')['logicAnd'] |  | ||||||
|   const logicNot: typeof import('@vueuse/core')['logicNot'] |  | ||||||
|   const logicOr: typeof import('@vueuse/core')['logicOr'] |  | ||||||
|   const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] |   const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] | ||||||
|   const markRaw: typeof import('vue')['markRaw'] |   const markRaw: typeof import('vue')['markRaw'] | ||||||
|   const nextTick: typeof import('vue')['nextTick'] |   const nextTick: typeof import('vue')['nextTick'] | ||||||
| @ -92,8 +91,9 @@ declare global { | |||||||
|   const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] |   const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] | ||||||
|   const toRaw: typeof import('vue')['toRaw'] |   const toRaw: typeof import('vue')['toRaw'] | ||||||
|   const toReactive: typeof import('@vueuse/core')['toReactive'] |   const toReactive: typeof import('@vueuse/core')['toReactive'] | ||||||
|   const toRef: typeof import('vue')['toRef'] |   const toRef: typeof import('@vueuse/core')['toRef'] | ||||||
|   const toRefs: typeof import('vue')['toRefs'] |   const toRefs: typeof import('vue')['toRefs'] | ||||||
|  |   const toValue: typeof import('@vueuse/core')['toValue'] | ||||||
|   const triggerRef: typeof import('vue')['triggerRef'] |   const triggerRef: typeof import('vue')['triggerRef'] | ||||||
|   const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] |   const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] | ||||||
|   const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] |   const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] | ||||||
| @ -104,6 +104,19 @@ declare global { | |||||||
|   const unrefElement: typeof import('@vueuse/core')['unrefElement'] |   const unrefElement: typeof import('@vueuse/core')['unrefElement'] | ||||||
|   const until: typeof import('@vueuse/core')['until'] |   const until: typeof import('@vueuse/core')['until'] | ||||||
|   const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] |   const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] | ||||||
|  |   const useAnimate: typeof import('@vueuse/core')['useAnimate'] | ||||||
|  |   const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference'] | ||||||
|  |   const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] | ||||||
|  |   const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] | ||||||
|  |   const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] | ||||||
|  |   const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] | ||||||
|  |   const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast'] | ||||||
|  |   const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes'] | ||||||
|  |   const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] | ||||||
|  |   const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] | ||||||
|  |   const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] | ||||||
|  |   const useArraySome: typeof import('@vueuse/core')['useArraySome'] | ||||||
|  |   const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique'] | ||||||
|   const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] |   const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] | ||||||
|   const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] |   const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] | ||||||
|   const useAttrs: typeof import('vue')['useAttrs'] |   const useAttrs: typeof import('vue')['useAttrs'] | ||||||
| @ -114,8 +127,8 @@ declare global { | |||||||
|   const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] |   const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] | ||||||
|   const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] |   const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] | ||||||
|   const useCached: typeof import('@vueuse/core')['useCached'] |   const useCached: typeof import('@vueuse/core')['useCached'] | ||||||
|   const useClamp: typeof import('@vueuse/core')['useClamp'] |  | ||||||
|   const useClipboard: typeof import('@vueuse/core')['useClipboard'] |   const useClipboard: typeof import('@vueuse/core')['useClipboard'] | ||||||
|  |   const useCloned: typeof import('@vueuse/core')['useCloned'] | ||||||
|   const useColorMode: typeof import('@vueuse/core')['useColorMode'] |   const useColorMode: typeof import('@vueuse/core')['useColorMode'] | ||||||
|   const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] |   const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] | ||||||
|   const useCounter: typeof import('@vueuse/core')['useCounter'] |   const useCounter: typeof import('@vueuse/core')['useCounter'] | ||||||
| @ -189,12 +202,18 @@ declare global { | |||||||
|   const useOnline: typeof import('@vueuse/core')['useOnline'] |   const useOnline: typeof import('@vueuse/core')['useOnline'] | ||||||
|   const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] |   const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] | ||||||
|   const useParallax: typeof import('@vueuse/core')['useParallax'] |   const useParallax: typeof import('@vueuse/core')['useParallax'] | ||||||
|  |   const useParentElement: typeof import('@vueuse/core')['useParentElement'] | ||||||
|  |   const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver'] | ||||||
|   const usePermission: typeof import('@vueuse/core')['usePermission'] |   const usePermission: typeof import('@vueuse/core')['usePermission'] | ||||||
|   const usePointer: typeof import('@vueuse/core')['usePointer'] |   const usePointer: typeof import('@vueuse/core')['usePointer'] | ||||||
|  |   const usePointerLock: typeof import('@vueuse/core')['usePointerLock'] | ||||||
|   const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] |   const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] | ||||||
|   const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] |   const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] | ||||||
|  |   const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] | ||||||
|   const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] |   const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] | ||||||
|   const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] |   const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] | ||||||
|  |   const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] | ||||||
|  |   const usePrevious: typeof import('@vueuse/core')['usePrevious'] | ||||||
|   const useRafFn: typeof import('@vueuse/core')['useRafFn'] |   const useRafFn: typeof import('@vueuse/core')['useRafFn'] | ||||||
|   const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] |   const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] | ||||||
|   const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] |   const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] | ||||||
| @ -208,14 +227,17 @@ declare global { | |||||||
|   const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] |   const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] | ||||||
|   const useShare: typeof import('@vueuse/core')['useShare'] |   const useShare: typeof import('@vueuse/core')['useShare'] | ||||||
|   const useSlots: typeof import('vue')['useSlots'] |   const useSlots: typeof import('vue')['useSlots'] | ||||||
|  |   const useSorted: typeof import('@vueuse/core')['useSorted'] | ||||||
|   const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] |   const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] | ||||||
|   const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] |   const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] | ||||||
|   const useStepper: typeof import('@vueuse/core')['useStepper'] |   const useStepper: typeof import('@vueuse/core')['useStepper'] | ||||||
|   const useStorage: typeof import('@vueuse/core')['useStorage'] |   const useStorage: typeof import('@vueuse/core')['useStorage'] | ||||||
|   const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] |   const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] | ||||||
|   const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] |   const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] | ||||||
|  |   const useSupported: typeof import('@vueuse/core')['useSupported'] | ||||||
|   const useSwipe: typeof import('@vueuse/core')['useSwipe'] |   const useSwipe: typeof import('@vueuse/core')['useSwipe'] | ||||||
|   const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] |   const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] | ||||||
|  |   const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] | ||||||
|   const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] |   const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] | ||||||
|   const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] |   const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] | ||||||
|   const useThrottle: typeof import('@vueuse/core')['useThrottle'] |   const useThrottle: typeof import('@vueuse/core')['useThrottle'] | ||||||
| @ -227,6 +249,8 @@ declare global { | |||||||
|   const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] |   const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] | ||||||
|   const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] |   const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] | ||||||
|   const useTitle: typeof import('@vueuse/core')['useTitle'] |   const useTitle: typeof import('@vueuse/core')['useTitle'] | ||||||
|  |   const useToNumber: typeof import('@vueuse/core')['useToNumber'] | ||||||
|  |   const useToString: typeof import('@vueuse/core')['useToString'] | ||||||
|   const useToggle: typeof import('@vueuse/core')['useToggle'] |   const useToggle: typeof import('@vueuse/core')['useToggle'] | ||||||
|   const useTransition: typeof import('@vueuse/core')['useTransition'] |   const useTransition: typeof import('@vueuse/core')['useTransition'] | ||||||
|   const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] |   const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] | ||||||
| @ -247,8 +271,10 @@ declare global { | |||||||
|   const watchArray: typeof import('@vueuse/core')['watchArray'] |   const watchArray: typeof import('@vueuse/core')['watchArray'] | ||||||
|   const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] |   const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] | ||||||
|   const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] |   const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] | ||||||
|  |   const watchDeep: typeof import('@vueuse/core')['watchDeep'] | ||||||
|   const watchEffect: typeof import('vue')['watchEffect'] |   const watchEffect: typeof import('vue')['watchEffect'] | ||||||
|   const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] |   const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] | ||||||
|  |   const watchImmediate: typeof import('@vueuse/core')['watchImmediate'] | ||||||
|   const watchOnce: typeof import('@vueuse/core')['watchOnce'] |   const watchOnce: typeof import('@vueuse/core')['watchOnce'] | ||||||
|   const watchPausable: typeof import('@vueuse/core')['watchPausable'] |   const watchPausable: typeof import('@vueuse/core')['watchPausable'] | ||||||
|   const watchPostEffect: typeof import('vue')['watchPostEffect'] |   const watchPostEffect: typeof import('vue')['watchPostEffect'] | ||||||
| @ -282,7 +308,9 @@ declare module 'vue' { | |||||||
|     readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> |     readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> | ||||||
|     readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> |     readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> | ||||||
|     readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']> |     readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']> | ||||||
|  |     readonly createReusableTemplate: UnwrapRef<typeof import('@vueuse/core')['createReusableTemplate']> | ||||||
|     readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']> |     readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']> | ||||||
|  |     readonly createTemplatePromise: UnwrapRef<typeof import('@vueuse/core')['createTemplatePromise']> | ||||||
|     readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> |     readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> | ||||||
|     readonly customRef: UnwrapRef<typeof import('vue')['customRef']> |     readonly customRef: UnwrapRef<typeof import('vue')['customRef']> | ||||||
|     readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> |     readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> | ||||||
| @ -302,9 +330,6 @@ declare module 'vue' { | |||||||
|     readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> |     readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> | ||||||
|     readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> |     readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> | ||||||
|     readonly isRef: UnwrapRef<typeof import('vue')['isRef']> |     readonly isRef: UnwrapRef<typeof import('vue')['isRef']> | ||||||
|     readonly logicAnd: UnwrapRef<typeof import('@vueuse/core')['logicAnd']> |  | ||||||
|     readonly logicNot: UnwrapRef<typeof import('@vueuse/core')['logicNot']> |  | ||||||
|     readonly logicOr: UnwrapRef<typeof import('@vueuse/core')['logicOr']> |  | ||||||
|     readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']> |     readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']> | ||||||
|     readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> |     readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> | ||||||
|     readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> |     readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> | ||||||
| @ -355,8 +380,9 @@ declare module 'vue' { | |||||||
|     readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> |     readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> | ||||||
|     readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> |     readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> | ||||||
|     readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> |     readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> | ||||||
|     readonly toRef: UnwrapRef<typeof import('vue')['toRef']> |     readonly toRef: UnwrapRef<typeof import('@vueuse/core')['toRef']> | ||||||
|     readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> |     readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> | ||||||
|  |     readonly toValue: UnwrapRef<typeof import('@vueuse/core')['toValue']> | ||||||
|     readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> |     readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> | ||||||
|     readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> |     readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> | ||||||
|     readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> |     readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> | ||||||
| @ -367,6 +393,19 @@ declare module 'vue' { | |||||||
|     readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> |     readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> | ||||||
|     readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> |     readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> | ||||||
|     readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']> |     readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']> | ||||||
|  |     readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']> | ||||||
|  |     readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']> | ||||||
|  |     readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']> | ||||||
|  |     readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']> | ||||||
|  |     readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']> | ||||||
|  |     readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']> | ||||||
|  |     readonly useArrayFindLast: UnwrapRef<typeof import('@vueuse/core')['useArrayFindLast']> | ||||||
|  |     readonly useArrayIncludes: UnwrapRef<typeof import('@vueuse/core')['useArrayIncludes']> | ||||||
|  |     readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']> | ||||||
|  |     readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']> | ||||||
|  |     readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']> | ||||||
|  |     readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']> | ||||||
|  |     readonly useArrayUnique: UnwrapRef<typeof import('@vueuse/core')['useArrayUnique']> | ||||||
|     readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']> |     readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']> | ||||||
|     readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> |     readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> | ||||||
|     readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> |     readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> | ||||||
| @ -377,8 +416,8 @@ declare module 'vue' { | |||||||
|     readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> |     readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> | ||||||
|     readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> |     readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> | ||||||
|     readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']> |     readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']> | ||||||
|     readonly useClamp: UnwrapRef<typeof import('@vueuse/core')['useClamp']> |  | ||||||
|     readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']> |     readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']> | ||||||
|  |     readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']> | ||||||
|     readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> |     readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> | ||||||
|     readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> |     readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> | ||||||
|     readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> |     readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> | ||||||
| @ -452,12 +491,18 @@ declare module 'vue' { | |||||||
|     readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> |     readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> | ||||||
|     readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> |     readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> | ||||||
|     readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']> |     readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']> | ||||||
|  |     readonly useParentElement: UnwrapRef<typeof import('@vueuse/core')['useParentElement']> | ||||||
|  |     readonly usePerformanceObserver: UnwrapRef<typeof import('@vueuse/core')['usePerformanceObserver']> | ||||||
|     readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']> |     readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']> | ||||||
|     readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> |     readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> | ||||||
|  |     readonly usePointerLock: UnwrapRef<typeof import('@vueuse/core')['usePointerLock']> | ||||||
|     readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> |     readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> | ||||||
|     readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']> |     readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']> | ||||||
|  |     readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']> | ||||||
|     readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> |     readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> | ||||||
|     readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> |     readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> | ||||||
|  |     readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']> | ||||||
|  |     readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']> | ||||||
|     readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> |     readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> | ||||||
|     readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> |     readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> | ||||||
|     readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> |     readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> | ||||||
| @ -471,14 +516,17 @@ declare module 'vue' { | |||||||
|     readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> |     readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> | ||||||
|     readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> |     readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> | ||||||
|     readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> |     readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> | ||||||
|  |     readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']> | ||||||
|     readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> |     readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> | ||||||
|     readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> |     readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> | ||||||
|     readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> |     readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> | ||||||
|     readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> |     readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> | ||||||
|     readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> |     readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> | ||||||
|     readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']> |     readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']> | ||||||
|  |     readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']> | ||||||
|     readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']> |     readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']> | ||||||
|     readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> |     readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> | ||||||
|  |     readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']> | ||||||
|     readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> |     readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> | ||||||
|     readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> |     readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> | ||||||
|     readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> |     readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> | ||||||
| @ -490,6 +538,8 @@ declare module 'vue' { | |||||||
|     readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> |     readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> | ||||||
|     readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> |     readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> | ||||||
|     readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']> |     readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']> | ||||||
|  |     readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']> | ||||||
|  |     readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']> | ||||||
|     readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']> |     readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']> | ||||||
|     readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> |     readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> | ||||||
|     readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> |     readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> | ||||||
| @ -510,8 +560,10 @@ declare module 'vue' { | |||||||
|     readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> |     readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> | ||||||
|     readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> |     readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> | ||||||
|     readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> |     readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> | ||||||
|  |     readonly watchDeep: UnwrapRef<typeof import('@vueuse/core')['watchDeep']> | ||||||
|     readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> |     readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> | ||||||
|     readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']> |     readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']> | ||||||
|  |     readonly watchImmediate: UnwrapRef<typeof import('@vueuse/core')['watchImmediate']> | ||||||
|     readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']> |     readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']> | ||||||
|     readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> |     readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> | ||||||
|     readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> |     readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -56,7 +56,12 @@ declare module '@vue/runtime-core' { | |||||||
|     HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'] |     HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default'] | ||||||
|     HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] |     HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default'] | ||||||
|     HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] |     HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] | ||||||
|  |     IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] | ||||||
|     IconMdiClose: typeof import('~icons/mdi/close')['default'] |     IconMdiClose: typeof import('~icons/mdi/close')['default'] | ||||||
|  |     IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] | ||||||
|  |     IconMdiEye: typeof import('~icons/mdi/eye')['default'] | ||||||
|  |     IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] | ||||||
|  |     IconMdiRefresh: typeof import('~icons/mdi/refresh')['default'] | ||||||
|     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] |     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] | ||||||
|     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] |     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] | ||||||
|     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] |     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| <template> | <template> | ||||||
|   <n-form-item :label="inputLabel" v-bind="validationAttrs"> |   <n-form-item :label="inputLabel" v-bind="validationAttrs as any"> | ||||||
|     <n-input |     <n-input | ||||||
|       ref="inputElement" |       ref="inputElement" | ||||||
|       v-model:value="input" |       v-model:value="input" | ||||||
| @ -10,7 +10,7 @@ | |||||||
|       autocorrect="off" |       autocorrect="off" | ||||||
|       autocapitalize="off" |       autocapitalize="off" | ||||||
|       spellcheck="false" |       spellcheck="false" | ||||||
|       :input-props="{ 'data-test-id': 'input' }" |       :input-props="{ 'data-test-id': 'input' } as any" | ||||||
|     /> |     /> | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
|   <n-form-item :label="outputLabel"> |   <n-form-item :label="outputLabel"> | ||||||
|  | |||||||
| @ -1,21 +1,20 @@ | |||||||
| <template> | <template> | ||||||
|   <n-input v-model:value="value"> |   <c-input-text v-model:value="value"> | ||||||
|     <template #suffix> |     <template #suffix> | ||||||
|       <n-tooltip trigger="hover"> |       <n-tooltip trigger="hover"> | ||||||
|         <template #trigger> |         <template #trigger> | ||||||
|           <c-button circle variant="text" @click="onCopyClicked"> |           <c-button circle variant="text" size="small" @click="onCopyClicked"> | ||||||
|             <n-icon :component="ContentCopyFilled" /> |             <icon-mdi-content-copy /> | ||||||
|           </c-button> |           </c-button> | ||||||
|         </template> |         </template> | ||||||
|         {{ tooltipText }} |         {{ tooltipText }} | ||||||
|       </n-tooltip> |       </n-tooltip> | ||||||
|     </template> |     </template> | ||||||
|   </n-input> |   </c-input-text> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useVModel, useClipboard } from '@vueuse/core'; | import { useVModel, useClipboard } from '@vueuse/core'; | ||||||
| import { ContentCopyFilled } from '@vicons/material'; |  | ||||||
| import { ref } from 'vue'; | import { ref } from 'vue'; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ value: string }>(); | const props = defineProps<{ value: string }>(); | ||||||
| @ -35,9 +34,3 @@ function onCopyClicked() { | |||||||
|   }, 2000); |   }, 2000); | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
| ::v-deep(.n-input-wrapper) { |  | ||||||
|   padding-right: 5px; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ | |||||||
|   </c-card> |   </c-card> | ||||||
| 
 | 
 | ||||||
|   <c-card title="Base64 to string"> |   <c-card title="Base64 to string"> | ||||||
|     <n-form-item label="Base64 string to decode" v-bind="b64Validation.attrs"> |     <n-form-item label="Base64 string to decode" v-bind="b64Validation.attrs as any"> | ||||||
|       <n-input v-model:value="base64Input" type="textarea" placeholder="Your base64 string..." rows="5" /> |       <n-input v-model:value="base64Input" type="textarea" placeholder="Your base64 string..." rows="5" /> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,17 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item label="Username"> |     <c-input-text v-model:value="username" label="Username" placeholder="Your username..." clearable raw-text mb-5 /> | ||||||
|       <n-input v-model:value="username" placeholder="Your username..." clearable /> |     <c-input-text | ||||||
|     </n-form-item> |       v-model:value="password" | ||||||
|     <n-form-item label="Password"> |       label="Password" | ||||||
|       <n-input |       placeholder="Your password..." | ||||||
|         v-model:value="password" |       clearable | ||||||
|         placeholder="Your password..." |       raw-text | ||||||
|         type="password" |       mb-2 | ||||||
|         show-password-on="click" |       type="password" | ||||||
|         clearable |     /> | ||||||
|       /> |  | ||||||
|     </n-form-item> |  | ||||||
| 
 | 
 | ||||||
|     <c-card> |     <c-card> | ||||||
|       <n-statistic label="Authorization header:" class="header"> |       <n-statistic label="Authorization header:" class="header"> | ||||||
|  | |||||||
| @ -1,21 +1,20 @@ | |||||||
| <template> | <template> | ||||||
|   <c-card title="Hash"> |   <c-card title="Hash"> | ||||||
|     <n-form label-width="120"> |     <c-input-text | ||||||
|       <n-form-item label="Your string: " label-placement="left"> |       v-model:value="input" | ||||||
|         <n-input |       placeholder="Your string to bcrypt..." | ||||||
|           v-model:value="input" |       raw-text | ||||||
|           placeholder="Your string to bcrypt..." |       label="Your string: " | ||||||
|           autocomplete="off" |       label-position="left" | ||||||
|           autocorrect="off" |       label-width="120px" | ||||||
|           autocapitalize="off" |       mb-2 | ||||||
|           spellcheck="false" |     /> | ||||||
|         /> |     <n-form-item label="Salt count: " label-placement="left" label-width="120"> | ||||||
|       </n-form-item> |       <n-input-number v-model:value="saltCount" placeholder="Salt rounds..." :max="10" :min="0" w-full /> | ||||||
|       <n-form-item label="Salt count: " label-placement="left"> |     </n-form-item> | ||||||
|         <n-input-number v-model:value="saltCount" placeholder="Salt rounds..." :max="10" :min="0" w-full /> | 
 | ||||||
|       </n-form-item> |     <c-input-text :value="hashed" readonly text-center /> | ||||||
|       <n-input :value="hashed" readonly style="text-align: center" /> | 
 | ||||||
|     </n-form> |  | ||||||
|     <n-space justify="center" mt-5> |     <n-space justify="center" mt-5> | ||||||
|       <c-button @click="copy"> Copy hash </c-button> |       <c-button @click="copy"> Copy hash </c-button> | ||||||
|     </n-space> |     </n-space> | ||||||
| @ -24,24 +23,10 @@ | |||||||
|   <c-card title="Compare string with hash"> |   <c-card title="Compare string with hash"> | ||||||
|     <n-form label-width="120"> |     <n-form label-width="120"> | ||||||
|       <n-form-item label="Your string: " label-placement="left"> |       <n-form-item label="Your string: " label-placement="left"> | ||||||
|         <n-input |         <c-input-text v-model:value="compareString" placeholder="Your string to compare..." raw-text /> | ||||||
|           v-model:value="compareString" |  | ||||||
|           placeholder="Your string to compare..." |  | ||||||
|           autocomplete="off" |  | ||||||
|           autocorrect="off" |  | ||||||
|           autocapitalize="off" |  | ||||||
|           spellcheck="false" |  | ||||||
|         /> |  | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="Your hash: " label-placement="left"> |       <n-form-item label="Your hash: " label-placement="left"> | ||||||
|         <n-input |         <c-input-text v-model:value="compareHash" placeholder="Your hahs to compare..." raw-text /> | ||||||
|           v-model:value="compareHash" |  | ||||||
|           placeholder="Your hahs to compare..." |  | ||||||
|           autocomplete="off" |  | ||||||
|           autocorrect="off" |  | ||||||
|           autocapitalize="off" |  | ||||||
|           spellcheck="false" |  | ||||||
|         /> |  | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="Do they match ? " label-placement="left" :show-feedback="false"> |       <n-form-item label="Do they match ? " label-placement="left" :show-feedback="false"> | ||||||
|         <div class="compare-result" :class="{ positive: compareMatch }"> |         <div class="compare-result" :class="{ positive: compareMatch }"> | ||||||
|  | |||||||
| @ -1,11 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <n-scrollbar style="flex: 1" x-scrollable> |   <n-scrollbar style="flex: 1" x-scrollable> | ||||||
|     <n-space :wrap="false" style="flex: 1" justify="center" :size="0" mb-5> |     <n-space :wrap="false" style="flex: 1" justify="center" :size="12" mb-5> | ||||||
|       <div v-for="(suite, index) of suites" :key="index"> |       <div v-for="(suite, index) of suites" :key="index"> | ||||||
|         <c-card style="width: 292px; margin: 0 8px 5px"> |         <c-card style="width: 294px"> | ||||||
|           <n-form-item label="Suite name:" :show-feedback="false" label-placement="left"> |           <c-input-text | ||||||
|             <n-input v-model:value="suite.title" placeholder="Suite name..." /> |             v-model:value="suite.title" | ||||||
|           </n-form-item> |             label-position="left" | ||||||
|  |             label="Suite name" | ||||||
|  |             placeholder="Suite name..." | ||||||
|  |             clearable | ||||||
|  |           /> | ||||||
| 
 | 
 | ||||||
|           <n-divider></n-divider> |           <n-divider></n-divider> | ||||||
|           <n-form-item label="Suite values" :show-feedback="false"> |           <n-form-item label="Suite values" :show-feedback="false"> | ||||||
| @ -33,9 +37,7 @@ | |||||||
|   <div style="flex: 0 0 100%"> |   <div style="flex: 0 0 100%"> | ||||||
|     <div style="max-width: 600px; margin: 0 auto"> |     <div style="max-width: 600px; margin: 0 auto"> | ||||||
|       <n-space justify="center"> |       <n-space justify="center"> | ||||||
|         <n-form-item label="Unit:" label-placement="left"> |         <c-input-text v-model:value="unit" placeholder="Unit (eg: ms)" label="Unit" label-position="left" mb-4 /> | ||||||
|           <n-input v-model:value="unit" placeholder="Unit (eg: ms)" /> |  | ||||||
|         </n-form-item> |  | ||||||
| 
 | 
 | ||||||
|         <c-button |         <c-button | ||||||
|           @click=" |           @click=" | ||||||
|  | |||||||
| @ -16,7 +16,8 @@ | |||||||
|           :validation-status="entropyValidation.status" |           :validation-status="entropyValidation.status" | ||||||
|         > |         > | ||||||
|           <n-input-group> |           <n-input-group> | ||||||
|             <n-input v-model:value="entropy" placeholder="Your string..." /> |             <c-input-text v-model:value="entropy" placeholder="Your string..." /> | ||||||
|  | 
 | ||||||
|             <c-button @click="refreshEntropy"> |             <c-button @click="refreshEntropy"> | ||||||
|               <n-icon size="22"> |               <n-icon size="22"> | ||||||
|                 <Refresh /> |                 <Refresh /> | ||||||
| @ -37,15 +38,7 @@ | |||||||
|       :validation-status="mnemonicValidation.status" |       :validation-status="mnemonicValidation.status" | ||||||
|     > |     > | ||||||
|       <n-input-group> |       <n-input-group> | ||||||
|         <n-input |         <c-input-text v-model:value="passphrase" placeholder="Your mnemonic..." raw-text /> | ||||||
|           v-model:value="passphrase" |  | ||||||
|           style="text-align: center; flex: 1" |  | ||||||
|           placeholder="Your mnemonic..." |  | ||||||
|           autocomplete="off" |  | ||||||
|           autocorrect="off" |  | ||||||
|           autocapitalize="off" |  | ||||||
|           spellcheck="false" |  | ||||||
|         /> |  | ||||||
| 
 | 
 | ||||||
|         <c-button @click="copyPassphrase"> |         <c-button @click="copyPassphrase"> | ||||||
|           <n-icon size="22" :component="Copy" /> |           <n-icon size="22" :component="Copy" /> | ||||||
|  | |||||||
| @ -1,9 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <c-card> |   <c-card> | ||||||
|     <n-form label-width="120" label-placement="left" :show-feedback="false"> |     <n-form label-width="120" label-placement="left" :show-feedback="false"> | ||||||
|       <n-form-item label="Your string:"> |       <c-input-text | ||||||
|         <n-input v-model:value="input" /> |         v-model:value="input" | ||||||
|       </n-form-item> |         label="Your string" | ||||||
|  |         label-position="left" | ||||||
|  |         label-width="120px" | ||||||
|  |         label-align="right" | ||||||
|  |         placeholder="Your string..." | ||||||
|  |         raw-text | ||||||
|  |       /> | ||||||
| 
 | 
 | ||||||
|       <n-divider /> |       <n-divider /> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ | |||||||
|       <div class="duration">{{ formatMs(counter) }}</div> |       <div class="duration">{{ formatMs(counter) }}</div> | ||||||
|     </c-card> |     </c-card> | ||||||
|     <n-space justify="center" mt-5> |     <n-space justify="center" mt-5> | ||||||
|       <c-button v-if="!isRunning" secondary type="primary" @click="resume">Start</c-button> |       <c-button v-if="!isRunning" type="primary" @click="resume">Start</c-button> | ||||||
|       <c-button v-else secondary type="warning" @click="pause">Stop</c-button> |       <c-button v-else type="warning" @click="pause">Stop</c-button> | ||||||
| 
 | 
 | ||||||
|       <c-button @click="counter = 0">Reset</c-button> |       <c-button @click="counter = 0">Reset</c-button> | ||||||
|     </n-space> |     </n-space> | ||||||
|  | |||||||
| @ -9,25 +9,25 @@ | |||||||
|         /> |         /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="color name:"> |       <n-form-item label="color name:"> | ||||||
|         <input-copyable v-model:value="name" :on-input="(v: string) => onInputUpdated(v, 'name')" /> |         <input-copyable v-model:value="name" @update:value="(v: string) => onInputUpdated(v, 'name')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="hex:"> |       <n-form-item label="hex:"> | ||||||
|         <input-copyable v-model:value="hex" :on-input="(v: string) => onInputUpdated(v, 'hex')" /> |         <input-copyable v-model:value="hex" @update:value="(v: string) => onInputUpdated(v, 'hex')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="rgb:"> |       <n-form-item label="rgb:"> | ||||||
|         <input-copyable v-model:value="rgb" :on-input="(v: string) => onInputUpdated(v, 'rgb')" /> |         <input-copyable v-model:value="rgb" @update:value="(v: string) => onInputUpdated(v, 'rgb')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="hsl:"> |       <n-form-item label="hsl:"> | ||||||
|         <input-copyable v-model:value="hsl" :on-input="(v: string) => onInputUpdated(v, 'hsl')" /> |         <input-copyable v-model:value="hsl" @update:value="(v: string) => onInputUpdated(v, 'hsl')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="hwb:"> |       <n-form-item label="hwb:"> | ||||||
|         <input-copyable v-model:value="hwb" :on-input="(v: string) => onInputUpdated(v, 'hwb')" /> |         <input-copyable v-model:value="hwb" @update:value="(v: string) => onInputUpdated(v, 'hwb')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="lch:"> |       <n-form-item label="lch:"> | ||||||
|         <input-copyable v-model:value="lch" :on-input="(v: string) => onInputUpdated(v, 'lch')" /> |         <input-copyable v-model:value="lch" @update:value="(v: string) => onInputUpdated(v, 'lch')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-form-item label="cmyk:"> |       <n-form-item label="cmyk:"> | ||||||
|         <input-copyable v-model:value="cmyk" :on-input="(v: string) => onInputUpdated(v, 'cmyk')" /> |         <input-copyable v-model:value="cmyk" @update:value="(v: string) => onInputUpdated(v, 'cmyk')" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|     </n-form> |     </n-form> | ||||||
|   </c-card> |   </c-card> | ||||||
| @ -54,15 +54,19 @@ const cmyk = ref(''); | |||||||
| const lch = ref(''); | const lch = ref(''); | ||||||
| 
 | 
 | ||||||
| function onInputUpdated(value: string, omit: string) { | function onInputUpdated(value: string, omit: string) { | ||||||
|   const color = colord(value); |   try { | ||||||
|  |     const color = colord(value); | ||||||
| 
 | 
 | ||||||
|   if (omit !== 'name') name.value = color.toName({ closest: true }) ?? ''; |     if (omit !== 'name') name.value = color.toName({ closest: true }) ?? ''; | ||||||
|   if (omit !== 'hex') hex.value = color.toHex(); |     if (omit !== 'hex') hex.value = color.toHex(); | ||||||
|   if (omit !== 'rgb') rgb.value = color.toRgbString(); |     if (omit !== 'rgb') rgb.value = color.toRgbString(); | ||||||
|   if (omit !== 'hsl') hsl.value = color.toHslString(); |     if (omit !== 'hsl') hsl.value = color.toHslString(); | ||||||
|   if (omit !== 'hwb') hwb.value = color.toHwbString(); |     if (omit !== 'hwb') hwb.value = color.toHwbString(); | ||||||
|   if (omit !== 'cmyk') cmyk.value = color.toCmykString(); |     if (omit !== 'cmyk') cmyk.value = color.toCmykString(); | ||||||
|   if (omit !== 'lch') lch.value = color.toLchString(); |     if (omit !== 'lch') lch.value = color.toLchString(); | ||||||
|  |   } catch { | ||||||
|  |     // | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| onInputUpdated(hex.value, 'hex'); | onInputUpdated(hex.value, 'hex'); | ||||||
|  | |||||||
| @ -1,13 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <c-card> |   <c-card> | ||||||
|     <n-form-item |     <div mx-auto max-w-sm> | ||||||
|       class="cron" |       <c-input-text | ||||||
|       :show-label="false" |         v-model:value="cron" | ||||||
|       :feedback="cronValidation.message" |         size="large" | ||||||
|       :validation-status="cronValidation.status" |         placeholder="* * * * *" | ||||||
|     > |         :validation-rules="cronValidationRules" | ||||||
|       <n-input v-model:value="cron" size="large" placeholder="* * * * *" /> |         mb-3 | ||||||
|     </n-form-item> |       /> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|     <div class="cron-string"> |     <div class="cron-string"> | ||||||
|       {{ cronString }} |       {{ cronString }} | ||||||
|     </div> |     </div> | ||||||
| @ -86,7 +88,6 @@ | |||||||
| import cronstrue from 'cronstrue'; | import cronstrue from 'cronstrue'; | ||||||
| import { isValidCron } from 'cron-validator'; | import { isValidCron } from 'cron-validator'; | ||||||
| import { computed, reactive, ref } from 'vue'; | import { computed, reactive, ref } from 'vue'; | ||||||
| import { useValidation } from '@/composable/validation'; |  | ||||||
| import { useStyleStore } from '@/stores/style.store'; | import { useStyleStore } from '@/stores/style.store'; | ||||||
| 
 | 
 | ||||||
| function isCronValid(v: string) { | function isCronValid(v: string) { | ||||||
| @ -185,30 +186,20 @@ const cronString = computed(() => { | |||||||
|   return ' '; |   return ' '; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const cronValidation = useValidation({ | const cronValidationRules = [ | ||||||
|   source: cron, |   { | ||||||
|   rules: [ |     validator: (value: string) => isCronValid(value), | ||||||
|     { |     message: 'This cron is invalid', | ||||||
|       validator: (value) => isCronValid(value), |   }, | ||||||
|       message: 'This cron is invalid', | ]; | ||||||
|     }, |  | ||||||
|   ], |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="less" scoped> | <style lang="less" scoped> | ||||||
| .cron { | ::v-deep(input) { | ||||||
|  |   font-size: 30px; | ||||||
|  |   font-family: monospace; | ||||||
|  |   padding: 5px; | ||||||
|   text-align: center; |   text-align: center; | ||||||
| 
 |  | ||||||
|   margin: auto; |  | ||||||
|   max-width: 400px; |  | ||||||
|   display: block; |  | ||||||
| 
 |  | ||||||
|   .n-input { |  | ||||||
|     font-size: 30px; |  | ||||||
|     font-family: monospace; |  | ||||||
|     padding: 5px; |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .cron-string { | .cron-string { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item :show-label="false" v-bind="validation.attrs"> |     <n-form-item :show-label="false" v-bind="validation.attrs as any"> | ||||||
|       <n-input-group> |       <n-input-group> | ||||||
|         <n-input |         <n-input | ||||||
|           v-model:value="inputDate" |           v-model:value="inputDate" | ||||||
| @ -8,7 +8,7 @@ | |||||||
|           :on-input="onDateInputChanged" |           :on-input="onDateInputChanged" | ||||||
|           placeholder="Put you date string here..." |           placeholder="Put you date string here..." | ||||||
|           clearable |           clearable | ||||||
|           :input-props="{ 'data-test-id': 'date-time-converter-input' }" |           :input-props="{ 'data-test-id': 'date-time-converter-input' } as any" | ||||||
|         /> |         /> | ||||||
| 
 | 
 | ||||||
|         <n-select |         <n-select | ||||||
| @ -20,16 +20,19 @@ | |||||||
|       </n-input-group> |       </n-input-group> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
|     <n-divider style="margin-top: 0" /> |     <n-divider style="margin-top: 0" /> | ||||||
|     <div v-for="{ name, fromDate } in formats" :key="name" mt-1> |     <input-copyable | ||||||
|       <n-input-group> |       v-for="{ name, fromDate } in formats" | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> {{ name }}: </n-input-group-label> |       :key="name" | ||||||
|         <input-copyable |       :label="name" | ||||||
|           :value="formatDateUsingFormatter(fromDate, normalizedDate)" |       label-width="150px" | ||||||
|           placeholder="Invalid date..." |       label-position="left" | ||||||
|           :input-props="{ 'data-test-id': name }" |       label-align="right" | ||||||
|         /> |       :value="formatDateUsingFormatter(fromDate, normalizedDate)" | ||||||
|       </n-input-group> |       placeholder="Invalid date..." | ||||||
|     </div> |       :test-id="name" | ||||||
|  |       readonly | ||||||
|  |       mt-2 | ||||||
|  |     /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,12 +7,15 @@ | |||||||
|           type="textarea" |           type="textarea" | ||||||
|           placeholder="The string to cypher" |           placeholder="The string to cypher" | ||||||
|           :autosize="{ minRows: 4 }" |           :autosize="{ minRows: 4 }" | ||||||
|  |           autocomplete="off" | ||||||
|  |           autocorrect="off" | ||||||
|  |           autocapitalize="off" | ||||||
|  |           spellcheck="false" | ||||||
|         /> |         /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-space vertical> |       <n-space vertical> | ||||||
|         <n-form-item label="Your secret key:" :show-feedback="false"> |         <c-input-text v-model:value="cypherSecret" label="Your secret key:" clearable raw-text /> | ||||||
|           <n-input v-model:value="cypherSecret" /> | 
 | ||||||
|         </n-form-item> |  | ||||||
|         <n-form-item label="Encryption algorithm:" :show-feedback="false"> |         <n-form-item label="Encryption algorithm:" :show-feedback="false"> | ||||||
|           <n-select |           <n-select | ||||||
|             v-model:value="cypherAlgo" |             v-model:value="cypherAlgo" | ||||||
| @ -43,12 +46,15 @@ | |||||||
|           type="textarea" |           type="textarea" | ||||||
|           placeholder="The string to cypher" |           placeholder="The string to cypher" | ||||||
|           :autosize="{ minRows: 4 }" |           :autosize="{ minRows: 4 }" | ||||||
|  |           autocomplete="off" | ||||||
|  |           autocorrect="off" | ||||||
|  |           autocapitalize="off" | ||||||
|  |           spellcheck="false" | ||||||
|         /> |         /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
|       <n-space vertical> |       <n-space vertical> | ||||||
|         <n-form-item label="Your secret key:" :show-feedback="false"> |         <c-input-text v-model:value="decryptSecret" label="Your secret key:" clearable raw-text /> | ||||||
|           <n-input v-model:value="decryptSecret" /> | 
 | ||||||
|         </n-form-item> |  | ||||||
|         <n-form-item label="Encryption algorithm:" :show-feedback="false"> |         <n-form-item label="Encryption algorithm:" :show-feedback="false"> | ||||||
|           <n-select |           <n-select | ||||||
|             v-model:value="decryptAlgo" |             v-model:value="decryptAlgo" | ||||||
|  | |||||||
| @ -22,59 +22,54 @@ | |||||||
|       <n-alert v-if="error" style="margin-top: 25px" type="error">{{ error }}</n-alert> |       <n-alert v-if="error" style="margin-top: 25px" type="error">{{ error }}</n-alert> | ||||||
|       <n-divider /> |       <n-divider /> | ||||||
| 
 | 
 | ||||||
|       <n-input-group> |       <input-copyable | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> Binary (2): </n-input-group-label> |         label="Binary (2)" | ||||||
|         <input-copyable |         v-bind="inputProps" | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 2 })" |         :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 2 })" | ||||||
|           readonly |         placeholder="Binary version will be here..." | ||||||
|           placeholder="Binary version will be here..." |       /> | ||||||
|         /> |  | ||||||
|       </n-input-group> |  | ||||||
| 
 | 
 | ||||||
|       <n-input-group> |       <input-copyable | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> Octal (8): </n-input-group-label> |         label="Octal (8)" | ||||||
|         <input-copyable |         v-bind="inputProps" | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 8 })" |         :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 8 })" | ||||||
|           readonly |         placeholder="Octal version will be here..." | ||||||
|           placeholder="Octal version will be here..." |       /> | ||||||
|         /> |  | ||||||
|       </n-input-group> |  | ||||||
| 
 | 
 | ||||||
|       <n-input-group> |       <input-copyable | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> Decimal (10): </n-input-group-label> |         label="Decimal (10)" | ||||||
|         <input-copyable |         v-bind="inputProps" | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 10 })" |         :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 10 })" | ||||||
|           readonly |         placeholder="Decimal version will be here..." | ||||||
|           placeholder="Decimal version will be here..." |       /> | ||||||
|         /> |  | ||||||
|       </n-input-group> |  | ||||||
| 
 | 
 | ||||||
|       <n-input-group> |       <input-copyable | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> Hexadecimal (16): </n-input-group-label> |         label="Hexadecimal (16)" | ||||||
|         <input-copyable |         v-bind="inputProps" | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 16 })" |         :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 16 })" | ||||||
|           readonly |         placeholder="Hexadecimal version will be here..." | ||||||
|           placeholder="Decimal version will be here..." |       /> | ||||||
|         /> | 
 | ||||||
|       </n-input-group> |       <input-copyable | ||||||
|  |         label="Base64 (64)" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 64 })" | ||||||
|  |         placeholder="Base64 version will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <div flex items-baseline> | ||||||
|  |         <n-input-group style="width: 160px; margin-right: 10px"> | ||||||
|  |           <n-input-group-label> Custom: </n-input-group-label> | ||||||
|  |           <n-input-number v-model:value="outputBase" max="64" min="2" /> | ||||||
|  |         </n-input-group> | ||||||
| 
 | 
 | ||||||
|       <n-input-group> |  | ||||||
|         <n-input-group-label style="flex: 0 0 170px"> Base64 (64): </n-input-group-label> |  | ||||||
|         <input-copyable |  | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 64 })" |  | ||||||
|           readonly |  | ||||||
|           placeholder="Base64 version will be here..." |  | ||||||
|         /> |  | ||||||
|       </n-input-group> |  | ||||||
|       <n-input-group> |  | ||||||
|         <n-input-group-label style="flex: 0 0 85px"> Custom: </n-input-group-label> |  | ||||||
|         <n-input-number v-model:value="outputBase" style="flex: 0 0 86px" max="64" min="2" /> |  | ||||||
|         <input-copyable |         <input-copyable | ||||||
|  |           flex-1 | ||||||
|  |           v-bind="inputProps" | ||||||
|           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: outputBase })" |           :value="errorlessConvert({ value: input, fromBase: inputBase, toBase: outputBase })" | ||||||
|           readonly |  | ||||||
|           :placeholder="`Base ${outputBase} will be here...`" |           :placeholder="`Base ${outputBase} will be here...`" | ||||||
|         /> |         /> | ||||||
|       </n-input-group> |       </div> | ||||||
|     </c-card> |     </c-card> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| @ -88,6 +83,14 @@ import InputCopyable from '../../components/InputCopyable.vue'; | |||||||
| 
 | 
 | ||||||
| const styleStore = useStyleStore(); | const styleStore = useStyleStore(); | ||||||
| 
 | 
 | ||||||
|  | const inputProps = { | ||||||
|  |   labelPosition: 'left', | ||||||
|  |   labelWidth: '170px', | ||||||
|  |   labelAlign: 'right', | ||||||
|  |   readonly: true, | ||||||
|  |   'mb-2': '', | ||||||
|  | } as const; | ||||||
|  | 
 | ||||||
| const input = ref('42'); | const input = ref('42'); | ||||||
| const inputBase = ref(10); | const inputBase = ref(10); | ||||||
| const outputBase = ref(42); | const outputBase = ref(42); | ||||||
|  | |||||||
| @ -1,23 +1,20 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item label="An ipv4 address:" v-bind="validationAttrs"> |     <c-input-text v-model:value="rawIpAddress" label="The ipv4 address:" placeholder="The ipv4 address..." readonly /> | ||||||
|       <n-input v-model:value="rawIpAddress" placeholder="An ipv4 address..." /> |  | ||||||
|     </n-form-item> |  | ||||||
| 
 | 
 | ||||||
|     <n-divider style="margin-top: 0" mt-0 /> |     <n-divider /> | ||||||
| 
 | 
 | ||||||
|     <n-form-item |     <input-copyable | ||||||
|       v-for="{ label, value } of convertedSections" |       v-for="{ label, value } of convertedSections" | ||||||
|       :key="label" |       :key="label" | ||||||
|       :label="label" |       :label="label" | ||||||
|       label-placement="left" |       label-position="left" | ||||||
|       label-width="100" |       label-width="100px" | ||||||
|     > |       label-align="right" | ||||||
|       <input-copyable |       mb-2 | ||||||
|         :value="validationAttrs.validationStatus === 'error' ? '' : value" |       :value="validationAttrs.validationStatus === 'error' ? '' : value" | ||||||
|         placeholder="Set a correct ipv4 address" |       placeholder="Set a correct ipv4 address" | ||||||
|       /> |     /> | ||||||
|     </n-form-item> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| @ -33,7 +30,7 @@ const convertedSections = computed(() => { | |||||||
| 
 | 
 | ||||||
|   return [ |   return [ | ||||||
|     { |     { | ||||||
|       label: 'Decimal : ', |       label: 'Decimal: ', | ||||||
|       value: String(ipInDecimal), |       value: String(ipInDecimal), | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -3,10 +3,10 @@ | |||||||
|     <n-space item-style="flex:1 1 0"> |     <n-space item-style="flex:1 1 0"> | ||||||
|       <div> |       <div> | ||||||
|         <n-space item-style="flex:1 1 0"> |         <n-space item-style="flex:1 1 0"> | ||||||
|           <n-form-item label="Start address" v-bind="startIpValidation.attrs"> |           <n-form-item label="Start address" v-bind="startIpValidation.attrs as any"> | ||||||
|             <n-input v-model:value="rawStartAddress" placeholder="Start IPv4 address..." /> |             <n-input v-model:value="rawStartAddress" placeholder="Start IPv4 address..." /> | ||||||
|           </n-form-item> |           </n-form-item> | ||||||
|           <n-form-item label="End address" v-bind="endIpValidation.attrs"> |           <n-form-item label="End address" v-bind="endIpValidation.attrs as any"> | ||||||
|             <n-input v-model:value="rawEndAddress" placeholder="End IPv4 address..." /> |             <n-input v-model:value="rawEndAddress" placeholder="End IPv4 address..." /> | ||||||
|           </n-form-item> |           </n-form-item> | ||||||
|         </n-space> |         </n-space> | ||||||
|  | |||||||
| @ -1,8 +1,12 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item label="An IPv4 address with or without mask" v-bind="validationAttrs"> |     <c-input-text | ||||||
|       <n-input v-model:value="ip" /> |       v-model:value="ip" | ||||||
|     </n-form-item> |       label="An IPv4 address with or without mask" | ||||||
|  |       placeholder="The ipv4 address..." | ||||||
|  |       :validation-rules="ipValidationRules" | ||||||
|  |       mb-4 | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|     <div v-if="networkInfo"> |     <div v-if="networkInfo"> | ||||||
|       <n-table> |       <n-table> | ||||||
| @ -37,7 +41,6 @@ | |||||||
| import { computed } from 'vue'; | import { computed } from 'vue'; | ||||||
| import { Netmask } from 'netmask'; | import { Netmask } from 'netmask'; | ||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import { useValidation } from '@/composable/validation'; |  | ||||||
| import { isNotThrowing } from '@/utils/boolean'; | import { isNotThrowing } from '@/utils/boolean'; | ||||||
| import { useStorage } from '@vueuse/core'; | import { useStorage } from '@vueuse/core'; | ||||||
| import { ArrowLeft, ArrowRight } from '@vicons/tabler'; | import { ArrowLeft, ArrowRight } from '@vicons/tabler'; | ||||||
| @ -50,15 +53,12 @@ const getNetworkInfo = (address: string) => new Netmask(address.trim()); | |||||||
| 
 | 
 | ||||||
| const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined)); | const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined)); | ||||||
| 
 | 
 | ||||||
| const { attrs: validationAttrs } = useValidation({ | const ipValidationRules = [ | ||||||
|   source: ip, |   { | ||||||
|   rules: [ |     message: 'We cannot parse this address, check the format', | ||||||
|     { |     validator: (value: string) => isNotThrowing(() => getNetworkInfo(value.trim())), | ||||||
|       message: 'We cannot parse this address, check the format', |   }, | ||||||
|       validator: (value) => isNotThrowing(() => getNetworkInfo(value.trim())), | ]; | ||||||
|     }, |  | ||||||
|   ], |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| const sections: { | const sections: { | ||||||
|   label: string; |   label: string; | ||||||
|  | |||||||
| @ -1,30 +1,32 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-space vertical :size="50"> |     <n-alert title="Info" type="info"> | ||||||
|       <n-alert title="Info" type="info"> |       This tool uses the first method suggested by IETF using the current timestamp plus the mac address, sha1 hashed, | ||||||
|         This tool uses the first method suggested by IETF using the current timestamp plus the mac address, sha1 hashed, |       and the lower 40 bits to generate your random ULA. | ||||||
|         and the lower 40 bits to generate your random ULA. |     </n-alert> | ||||||
|       </n-alert> |  | ||||||
| 
 | 
 | ||||||
|       <n-form-item label="MAC address:" v-bind="validationAttrs"> |     <c-input-text | ||||||
|         <n-input |       v-model:value="macAddress" | ||||||
|           v-model:value="macAddress" |       placeholder="Type a MAC address" | ||||||
|           size="large" |       clearable | ||||||
|           placeholder="Type a MAC address" |       label="MAC address:" | ||||||
|           clearable |       raw-text | ||||||
|           autocomplete="off" |       my-8 | ||||||
|           autocorrect="off" |       :validation="addressValidation" | ||||||
|           autocapitalize="off" |     /> | ||||||
|           spellcheck="false" |  | ||||||
|         /> |  | ||||||
|       </n-form-item> |  | ||||||
|     </n-space> |  | ||||||
| 
 | 
 | ||||||
|     <div v-if="validationAttrs.validationStatus !== 'error'"> |     <div v-if="addressValidation.isValid"> | ||||||
|       <n-input-group v-for="{ label, value } in calculatedSections" :key="label" style="margin: 5px 0"> |       <input-copyable | ||||||
|         <n-input-group-label style="flex: 0 0 160px"> {{ label }} </n-input-group-label> |         v-for="{ label, value } in calculatedSections" | ||||||
|         <input-copyable :value="value" readonly /> |         :key="label" | ||||||
|       </n-input-group> |         :value="value" | ||||||
|  |         :label="label" | ||||||
|  |         label-width="160px" | ||||||
|  |         label-align="right" | ||||||
|  |         label-position="left" | ||||||
|  |         readonly | ||||||
|  |         mb-2 | ||||||
|  |       /> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| @ -59,7 +61,7 @@ const calculatedSections = computed(() => { | |||||||
|   ]; |   ]; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const { attrs: validationAttrs } = macAddressValidation(macAddress); | const addressValidation = macAddressValidation(macAddress); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="less" scoped></style> | <style lang="less" scoped></style> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| <template> | <template> | ||||||
|   <n-form-item label="Your first json" v-bind="leftJsonValidation.attrs"> |   <n-form-item label="Your first json" v-bind="leftJsonValidation.attrs as any"> | ||||||
|     <n-input |     <n-input | ||||||
|       v-model:value="rawLeftJson" |       v-model:value="rawLeftJson" | ||||||
|       placeholder="Paste your first json here..." |       placeholder="Paste your first json here..." | ||||||
| @ -9,10 +9,10 @@ | |||||||
|       autocorrect="off" |       autocorrect="off" | ||||||
|       autocapitalize="off" |       autocapitalize="off" | ||||||
|       spellcheck="false" |       spellcheck="false" | ||||||
|       :input-props="{ 'data-test-id': 'leftJson' }" |       :input-props="{ 'data-test-id': 'leftJson' }  as any" | ||||||
|     /> |     /> | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
|   <n-form-item label="Your json to compare" v-bind="rightJsonValidation.attrs"> |   <n-form-item label="Your json to compare" v-bind="rightJsonValidation.attrs as any"> | ||||||
|     <n-input |     <n-input | ||||||
|       v-model:value="rawRightJson" |       v-model:value="rawRightJson" | ||||||
|       placeholder="Paste your json to compare here..." |       placeholder="Paste your json to compare here..." | ||||||
| @ -22,7 +22,7 @@ | |||||||
|       autocorrect="off" |       autocorrect="off" | ||||||
|       autocapitalize="off" |       autocapitalize="off" | ||||||
|       spellcheck="false" |       spellcheck="false" | ||||||
|       :input-props="{ 'data-test-id': 'rightJson' }" |       :input-props="{ 'data-test-id': 'rightJson' }  as any" | ||||||
|     /> |     /> | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,8 +30,8 @@ test.describe('Tool - List converter', () => { | |||||||
|     3 |     3 | ||||||
|     5`);
 |     5`);
 | ||||||
|     await page.getByTestId('removeDuplicates').check(); |     await page.getByTestId('removeDuplicates').check(); | ||||||
|     await page.getByTestId('itemPrefix').locator('input').fill("'"); |     await page.getByTestId('itemPrefix').fill("'"); | ||||||
|     await page.getByTestId('itemSuffix').locator('input').fill("'"); |     await page.getByTestId('itemSuffix').fill("'"); | ||||||
| 
 | 
 | ||||||
|     const result = await page.getByTestId('area-content').innerText(); |     const result = await page.getByTestId('area-content').innerText(); | ||||||
|     expect(result.trim()).toEqual("'1', '2', '4', '3', '5'"); |     expect(result.trim()).toEqual("'1', '2', '4', '3', '5'"); | ||||||
|  | |||||||
| @ -36,37 +36,39 @@ | |||||||
|               /> |               /> | ||||||
|             </n-form-item> |             </n-form-item> | ||||||
| 
 | 
 | ||||||
|             <n-form-item label="Separator" label-placement="left" label-width="120" :show-feedback="false" mb-2> |             <c-input-text | ||||||
|               <n-input v-model:value="conversionConfig.separator" placeholder="," /> |               v-model:value="conversionConfig.separator" | ||||||
|             </n-form-item> |               label="Separator" | ||||||
|  |               label-position="left" | ||||||
|  |               label-width="120px" | ||||||
|  |               label-align="right" | ||||||
|  |               mb-2 | ||||||
|  |               placeholder="," | ||||||
|  |             /> | ||||||
| 
 | 
 | ||||||
|             <n-form-item label="Wrap item" label-placement="left" label-width="120" :show-feedback="false" mb-2> |             <n-form-item label="Wrap item" label-placement="left" label-width="120" :show-feedback="false" mb-2> | ||||||
|               <n-input-group> |               <c-input-text | ||||||
|                 <n-input |                 v-model:value="conversionConfig.itemPrefix" | ||||||
|                   v-model:value="conversionConfig.itemPrefix" |                 placeholder="Item prefix" | ||||||
|                   placeholder="Item prefix" |                 test-id="itemPrefix" | ||||||
|                   data-test-id="itemPrefix" |               /> | ||||||
|                 /> |               <c-input-text | ||||||
|                 <n-input |                 v-model:value="conversionConfig.itemSuffix" | ||||||
|                   v-model:value="conversionConfig.itemSuffix" |                 placeholder="Item suffix" | ||||||
|                   placeholder="Item suffix" |                 test-id="itemSuffix" | ||||||
|                   data-test-id="itemSuffix" |               /> | ||||||
|                 /> |  | ||||||
|               </n-input-group> |  | ||||||
|             </n-form-item> |             </n-form-item> | ||||||
|             <n-form-item label="Wrap list" label-placement="left" label-width="120" :show-feedback="false" mb-2> |             <n-form-item label="Wrap list" label-placement="left" label-width="120" :show-feedback="false" mb-2> | ||||||
|               <n-input-group> |               <c-input-text | ||||||
|                 <n-input |                 v-model:value="conversionConfig.listPrefix" | ||||||
|                   v-model:value="conversionConfig.listPrefix" |                 placeholder="List prefix" | ||||||
|                   placeholder="List prefix" |                 test-id="listPrefix" | ||||||
|                   data-test-id="listPrefix" |               /> | ||||||
|                 /> |               <c-input-text | ||||||
|                 <n-input |                 v-model:value="conversionConfig.listSuffix" | ||||||
|                   v-model:value="conversionConfig.listSuffix" |                 placeholder="List suffix" | ||||||
|                   placeholder="List suffix" |                 test-id="listSuffix" | ||||||
|                   data-test-id="listSuffix" |               /> | ||||||
|                 /> |  | ||||||
|               </n-input-group> |  | ||||||
|             </n-form-item> |             </n-form-item> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item label="MAC address:" v-bind="validationAttrs"> |     <n-form-item label="MAC address:" v-bind="validationAttrs as any"> | ||||||
|       <n-input |       <n-input | ||||||
|         v-model:value="macAddress" |         v-model:value="macAddress" | ||||||
|         size="large" |         size="large" | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
|       <n-input-group v-for="{ key, type, label, placeholder, ...element } of elements" :key="key"> |       <n-input-group v-for="{ key, type, label, placeholder, ...element } of elements" :key="key"> | ||||||
|         <n-input-group-label style="flex: 0 0 110px">{{ label }}</n-input-group-label> |         <n-input-group-label style="flex: 0 0 110px">{{ label }}</n-input-group-label> | ||||||
|         <n-input v-if="type === 'input'" v-model:value="metadata[key]" :placeholder="placeholder" /> |         <c-input-text v-if="type === 'input'" v-model:value="metadata[key]" :placeholder="placeholder" clearable /> | ||||||
|         <n-dynamic-input |         <n-dynamic-input | ||||||
|           v-else-if="type === 'input-multiple'" |           v-else-if="type === 'input-multiple'" | ||||||
|           v-model:value="metadata[key]" |           v-model:value="metadata[key]" | ||||||
|  | |||||||
| @ -1,19 +1,23 @@ | |||||||
| <template> | <template> | ||||||
|   <div style="max-width: 350px"> |   <div style="max-width: 350px"> | ||||||
|     <n-form-item label="Secret" v-bind="secretValidationAttrs"> |     <c-input-text | ||||||
|       <n-input v-model:value="secret" placeholder="Paste your TOTP secret..."> |       v-model:value="secret" | ||||||
|         <template #suffix> |       label="Secret" | ||||||
|           <n-tooltip trigger="hover"> |       placeholder="Paste your TOTP secret..." | ||||||
|             <template #trigger> |       mb-5 | ||||||
|               <c-button circle variant="text" @click="refreshSecret"> |       :validation-rules="secretValidationRules" | ||||||
|                 <n-icon :component="Refresh" /> |     > | ||||||
|               </c-button> |       <template #suffix> | ||||||
|             </template> |         <n-tooltip trigger="hover"> | ||||||
|             Generate secret token |           <template #trigger> | ||||||
|           </n-tooltip> |             <c-button circle variant="text" size="small" @click="refreshSecret"> | ||||||
|         </template> |               <icon-mdi-refresh /> | ||||||
|       </n-input> |             </c-button> | ||||||
|     </n-form-item> |           </template> | ||||||
|  |           Generate secret token | ||||||
|  |         </n-tooltip> | ||||||
|  |       </template> | ||||||
|  |     </c-input-text> | ||||||
| 
 | 
 | ||||||
|     <div> |     <div> | ||||||
|       <token-display :tokens="tokens" style="margin-top: 2px" /> |       <token-display :tokens="tokens" style="margin-top: 2px" /> | ||||||
| @ -27,49 +31,52 @@ | |||||||
|     </n-space> |     </n-space> | ||||||
|   </div> |   </div> | ||||||
|   <div style="max-width: 350px"> |   <div style="max-width: 350px"> | ||||||
|     <n-form-item label="Secret in hexadecimal"> |     <input-copyable | ||||||
|       <input-copyable :value="base32toHex(secret)" readonly placeholder="Secret in hex will be displayed here" /> |       label="Secret in hexadecimal" | ||||||
|     </n-form-item> |       :value="base32toHex(secret)" | ||||||
|  |       readonly | ||||||
|  |       placeholder="Secret in hex will be displayed here" | ||||||
|  |       mb-5 | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|     <n-form-item label="Epoch"> |     <input-copyable | ||||||
|       <input-copyable |       label="Epoch" | ||||||
|         :value="Math.floor(now / 1000).toString()" |       :value="Math.floor(now / 1000).toString()" | ||||||
|         readonly |       readonly | ||||||
|         placeholder="Epoch in sec will be displayed here" |       mb-5 | ||||||
|       /> |       placeholder="Epoch in sec will be displayed here" | ||||||
|     </n-form-item> |     /> | ||||||
|     <n-form-item label="Iteration" :show-feedback="false"> |  | ||||||
|       <n-input-group> |  | ||||||
|         <n-input-group-label style="width: 110px">Count:</n-input-group-label> |  | ||||||
|         <input-copyable |  | ||||||
|           :value="String(getCounterFromTime({ now, timeStep: 30 }))" |  | ||||||
|           readonly |  | ||||||
|           placeholder="Iteration count will be displayed here" |  | ||||||
|         /> |  | ||||||
|       </n-input-group> |  | ||||||
|     </n-form-item> |  | ||||||
| 
 | 
 | ||||||
|     <n-form-item label="Iteration" :show-label="false" style="margin-top: 5px"> |     <p>Iteration</p> | ||||||
|       <n-input-group> | 
 | ||||||
|         <n-input-group-label style="width: 110px">Padded hex:</n-input-group-label> |     <input-copyable | ||||||
|         <input-copyable |       :value="String(getCounterFromTime({ now, timeStep: 30 }))" | ||||||
|           :value="getCounterFromTime({ now, timeStep: 30 }).toString(16).padStart(16, '0')" |       readonly | ||||||
|           readonly |       label="Count:" | ||||||
|           placeholder="Iteration count in hex will be displayed here" |       label-position="left" | ||||||
|         /> |       label-width="90px" | ||||||
|       </n-input-group> |       label-align="right" | ||||||
|     </n-form-item> |       placeholder="Iteration count will be displayed here" | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <input-copyable | ||||||
|  |       :value="getCounterFromTime({ now, timeStep: 30 }).toString(16).padStart(16, '0')" | ||||||
|  |       readonly | ||||||
|  |       placeholder="Iteration count in hex will be displayed here" | ||||||
|  |       label-position="left" | ||||||
|  |       label-width="90px" | ||||||
|  |       label-align="right" | ||||||
|  |       label="Padded hex:" | ||||||
|  |     /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { computed, ref } from 'vue'; | import { computed, ref } from 'vue'; | ||||||
| import { Refresh } from '@vicons/tabler'; |  | ||||||
| import { useTimestamp } from '@vueuse/core'; | import { useTimestamp } from '@vueuse/core'; | ||||||
| import { useThemeVars } from 'naive-ui'; | import { useThemeVars } from 'naive-ui'; | ||||||
| import { useStyleStore } from '@/stores/style.store'; | import { useStyleStore } from '@/stores/style.store'; | ||||||
| import InputCopyable from '@/components/InputCopyable.vue'; | import InputCopyable from '@/components/InputCopyable.vue'; | ||||||
| import { useValidation } from '@/composable/validation'; |  | ||||||
| import { computedRefreshable } from '@/composable/computedRefreshable'; | import { computedRefreshable } from '@/composable/computedRefreshable'; | ||||||
| import { generateTOTP, buildKeyUri, generateSecret, base32toHex, getCounterFromTime } from './otp.service'; | import { generateTOTP, buildKeyUri, generateSecret, base32toHex, getCounterFromTime } from './otp.service'; | ||||||
| import { useQRCode } from '../qr-code-generator/useQRCode'; | import { useQRCode } from '../qr-code-generator/useQRCode'; | ||||||
| @ -106,19 +113,16 @@ const { qrcode } = useQRCode({ | |||||||
|   options: { width: 210 }, |   options: { width: 210 }, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const { attrs: secretValidationAttrs } = useValidation({ | const secretValidationRules = [ | ||||||
|   source: secret, |   { | ||||||
|   rules: [ |     message: 'Secret should be a base32 string', | ||||||
|     { |     validator: (value: string) => value.toUpperCase().match(/^[A-Z234567]+$/), | ||||||
|       message: 'Secret should be a base32 string', |   }, | ||||||
|       validator: (value) => value.toUpperCase().match(/^[A-Z234567]+$/), |   { | ||||||
|     }, |     message: 'Please set a secret', | ||||||
|     { |     validator: (value: string) => value !== '', | ||||||
|       message: 'Please set a secret', |   }, | ||||||
|       validator: (value) => value !== '', | ]; | ||||||
|     }, |  | ||||||
|   ], |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="less" scoped> | <style lang="less" scoped> | ||||||
|  | |||||||
| @ -3,9 +3,14 @@ | |||||||
|     <n-form-item label="Default country code:"> |     <n-form-item label="Default country code:"> | ||||||
|       <n-select v-model:value="defaultCountryCode" :options="countriesOptions" /> |       <n-select v-model:value="defaultCountryCode" :options="countriesOptions" /> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
|     <n-form-item label="Phone number:" v-bind="validation.attrs"> | 
 | ||||||
|       <n-input v-model:value="rawPhone" placeholder="Enter a phone number" /> |     <c-input-text | ||||||
|     </n-form-item> |       v-model:value="rawPhone" | ||||||
|  |       placeholder="Enter a phone number" | ||||||
|  |       label="Phone number:" | ||||||
|  |       :validation="validation" | ||||||
|  |       mb-5 | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|     <n-table v-if="parsedDetails"> |     <n-table v-if="parsedDetails"> | ||||||
|       <tbody> |       <tbody> | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|   <div> |   <div> | ||||||
|     <c-card title="Arabic to roman"> |     <c-card title="Arabic to roman"> | ||||||
|       <n-space align="center" justify="space-between"> |       <n-space align="center" justify="space-between"> | ||||||
|         <n-form-item v-bind="validationNumeral"> |         <n-form-item v-bind="validationNumeral as any"> | ||||||
|           <n-input-number v-model:value="inputNumeral" :min="1" style="width: 200px" :show-button="false" /> |           <n-input-number v-model:value="inputNumeral" :min="1" style="width: 200px" :show-button="false" /> | ||||||
|         </n-form-item> |         </n-form-item> | ||||||
|         <div class="result"> |         <div class="result"> | ||||||
| @ -15,13 +15,12 @@ | |||||||
|     </c-card> |     </c-card> | ||||||
|     <c-card title="Roman to arabic" mt-5> |     <c-card title="Roman to arabic" mt-5> | ||||||
|       <n-space align="center" justify="space-between"> |       <n-space align="center" justify="space-between"> | ||||||
|         <n-form-item v-bind="validationRoman"> |         <c-input-text v-model:value="inputRoman" style="width: 200px" :validation="validationRoman" /> | ||||||
|           <n-input v-model:value="inputRoman" style="width: 200px" /> | 
 | ||||||
|         </n-form-item> |  | ||||||
|         <div class="result"> |         <div class="result"> | ||||||
|           {{ outputNumeral }} |           {{ outputNumeral }} | ||||||
|         </div> |         </div> | ||||||
|         <c-button :disabled="validationRoman.validationStatus === 'error'" @click="copyArabic"> Copy </c-button> |         <c-button :disabled="!validationRoman.isValid" @click="copyArabic"> Copy </c-button> | ||||||
|       </n-space> |       </n-space> | ||||||
|     </c-card> |     </c-card> | ||||||
|   </div> |   </div> | ||||||
| @ -55,7 +54,7 @@ const { attrs: validationNumeral } = useValidation({ | |||||||
| const inputRoman = ref('XLII'); | const inputRoman = ref('XLII'); | ||||||
| const outputNumeral = computed(() => romanToArabic(inputRoman.value)); | const outputNumeral = computed(() => romanToArabic(inputRoman.value)); | ||||||
| 
 | 
 | ||||||
| const { attrs: validationRoman } = useValidation({ | const validationRoman = useValidation({ | ||||||
|   source: inputRoman, |   source: inputRoman, | ||||||
|   rules: [ |   rules: [ | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
|   <div style="flex: 0 0 100%"> |   <div style="flex: 0 0 100%"> | ||||||
|     <n-space item-style="flex: 1 1 0" style="margin: 0 auto; max-width: 600px" justify="center"> |     <n-space item-style="flex: 1 1 0" style="margin: 0 auto; max-width: 600px" justify="center"> | ||||||
|       <n-form-item label="Bits :" v-bind="bitsValidationAttrs" label-placement="left" label-width="100"> |       <n-form-item label="Bits :" v-bind="bitsValidationAttrs as any" label-placement="left" label-width="100"> | ||||||
|         <n-input-number v-model:value="bits" min="256" max="16384" step="8" /> |         <n-input-number v-model:value="bits" min="256" max="16384" step="8" /> | ||||||
|       </n-form-item> |       </n-form-item> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -21,9 +21,15 @@ | |||||||
|         <n-form-item label="Font size"> |         <n-form-item label="Font size"> | ||||||
|           <n-input-number v-model:value="fontSize" placeholder="Font size..." min="1" /> |           <n-input-number v-model:value="fontSize" placeholder="Font size..." min="1" /> | ||||||
|         </n-form-item> |         </n-form-item> | ||||||
|         <n-form-item label="Custom text"> | 
 | ||||||
|           <n-input v-model:value="customText" :placeholder="`Default is ${width}x${height}`" /> |         <c-input-text | ||||||
|         </n-form-item> |           v-model:value="customText" | ||||||
|  |           label="Custom text" | ||||||
|  |           :placeholder="`Default is ${width}x${height}`" | ||||||
|  |           label-position="left" | ||||||
|  |           label-width="100px" | ||||||
|  |           label-align="right" | ||||||
|  |         /> | ||||||
|       </n-space> |       </n-space> | ||||||
|       <n-form-item label="Use exact size" label-placement="left"> |       <n-form-item label="Use exact size" label-placement="left"> | ||||||
|         <n-switch v-model:value="useExactSize" /> |         <n-switch v-model:value="useExactSize" /> | ||||||
|  | |||||||
| @ -1,8 +1,12 @@ | |||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <n-form-item label="Your text to convert to NATO phonetic alphabet"> |     <c-input-text | ||||||
|       <n-input v-model:value="input" placeholder="Put your text here..." clearable /> |       v-model:value="input" | ||||||
|     </n-form-item> |       label="Your text to convert to NATO phonetic alphabet" | ||||||
|  |       placeholder="Put your text here..." | ||||||
|  |       clearable | ||||||
|  |       mb-5 | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|     <n-space v-if="natoText" vertical> |     <n-space v-if="natoText" vertical> | ||||||
|       <n-text>Your text in NATO phonetic alphabet</n-text> |       <n-text>Your text in NATO phonetic alphabet</n-text> | ||||||
|  | |||||||
| @ -1,51 +1,59 @@ | |||||||
| <template> | <template> | ||||||
|   <c-card> |   <c-card> | ||||||
|     <n-form-item label="Your url to parse:" :feedback="validation.message" :validation-status="validation.status"> |     <c-input-text | ||||||
|       <n-input v-model:value="urlToParse" placeholder="Your url to parse..." /> |       v-model:value="urlToParse" | ||||||
|     </n-form-item> |       label="Your url to parse:" | ||||||
|  |       placeholder="Your url to parse..." | ||||||
|  |       raw-text | ||||||
|  |       :validation-rules="urlValidationRules" | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|     <n-divider style="margin-top: 0" /> |     <n-divider /> | ||||||
| 
 | 
 | ||||||
|     <n-form> |     <input-copyable | ||||||
|       <n-input-group v-for="{ title, key } in properties" :key="key"> |       v-for="{ title, key } in properties" | ||||||
|         <n-input-group-label style="flex: 0 0 120px"> {{ title }}: </n-input-group-label> |       :key="key" | ||||||
|         <input-copyable :value="(urlParsed?.[key] as string) ?? ''" readonly placeholder=" " /> |       :label="title" | ||||||
|       </n-input-group> |       :value="(urlParsed?.[key] as string) ?? ''" | ||||||
|  |       readonly | ||||||
|  |       label-position="left" | ||||||
|  |       label-width="110px" | ||||||
|  |       mb-2 | ||||||
|  |       placeholder=" " | ||||||
|  |     /> | ||||||
| 
 | 
 | ||||||
|       <n-input-group |     <div | ||||||
|         v-for="[k, v] in Object.entries(Object.fromEntries(urlParsed?.searchParams.entries() ?? []))" |       v-for="[k, v] in Object.entries(Object.fromEntries(urlParsed?.searchParams.entries() ?? []))" | ||||||
|         :key="k" |       :key="k" | ||||||
|       > |       mb-2 | ||||||
|         <n-input-group-label style="flex: 0 0 120px"> |       w-full | ||||||
|           <n-icon :component="SubdirectoryArrowRightRound" /> |       flex | ||||||
|         </n-input-group-label> |     > | ||||||
|         <input-copyable :value="k" readonly /> |       <div style="flex: 1 0 110px"> | ||||||
|         <input-copyable :value="v" readonly /> |         <icon-mdi-arrow-right-bottom /> | ||||||
|       </n-input-group> |       </div> | ||||||
|     </n-form> | 
 | ||||||
|  |       <input-copyable :value="k" readonly /> | ||||||
|  |       <input-copyable :value="v" readonly /> | ||||||
|  |     </div> | ||||||
|   </c-card> |   </c-card> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useValidation } from '@/composable/validation'; |  | ||||||
| import { isNotThrowing } from '@/utils/boolean'; | import { isNotThrowing } from '@/utils/boolean'; | ||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import { SubdirectoryArrowRightRound } from '@vicons/material'; |  | ||||||
| import { computed, ref } from 'vue'; | import { computed, ref } from 'vue'; | ||||||
| import InputCopyable from '../../components/InputCopyable.vue'; | import InputCopyable from '../../components/InputCopyable.vue'; | ||||||
| 
 | 
 | ||||||
| const urlToParse = ref('https://me:pwd@it-tools.tech:3000/url-parser?key1=value&key2=value2#the-hash'); | const urlToParse = ref('https://me:pwd@it-tools.tech:3000/url-parser?key1=value&key2=value2#the-hash'); | ||||||
| 
 | 
 | ||||||
| const urlParsed = computed(() => withDefaultOnError(() => new URL(urlToParse.value), undefined)); | const urlParsed = computed(() => withDefaultOnError(() => new URL(urlToParse.value), undefined)); | ||||||
| const validation = useValidation({ | const urlValidationRules = [ | ||||||
|   source: urlToParse, |   { | ||||||
|   rules: [ |     validator: (value: string) => isNotThrowing(() => new URL(value)), | ||||||
|     { |     message: 'Invalid url', | ||||||
|       validator: (value) => isNotThrowing(() => new URL(value)), |   }, | ||||||
|       message: 'Invalid url', | ]; | ||||||
|     }, |  | ||||||
|   ], |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| const properties: { title: string; key: keyof URL }[] = [ | const properties: { title: string; key: keyof URL }[] = [ | ||||||
|   { title: 'Protocol', key: 'protocol' }, |   { title: 'Protocol', key: 'protocol' }, | ||||||
|  | |||||||
| @ -25,6 +25,18 @@ | |||||||
|       > |       > | ||||||
|         A |         A | ||||||
|       </c-button> |       </c-button> | ||||||
|  | 
 | ||||||
|  |       <c-button | ||||||
|  |         v-for="buttonType of buttonTypes" | ||||||
|  |         :key="buttonType" | ||||||
|  |         :variant="buttonVariant" | ||||||
|  |         :type="buttonType" | ||||||
|  |         :size="buttonSize" | ||||||
|  |         circle | ||||||
|  |         mx-1 | ||||||
|  |       > | ||||||
|  |         <icon-mdi-content-copy /> | ||||||
|  |       </c-button> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| @ -33,7 +45,7 @@ | |||||||
| import _ from 'lodash'; | import _ from 'lodash'; | ||||||
| 
 | 
 | ||||||
| const buttonVariants = ['basic', 'text'] as const; | const buttonVariants = ['basic', 'text'] as const; | ||||||
| const buttonTypes = ['default', 'primary'] as const; | const buttonTypes = ['default', 'primary', 'warning'] as const; | ||||||
| const buttonSizes = ['small', 'medium', 'large'] as const; | const buttonSizes = ['small', 'medium', 'large'] as const; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -56,10 +56,10 @@ const createTheme = ({ style }: { style: 'light' | 'dark' }) => { | |||||||
|         pressedBackground: darken(theme.primary.colorFaded, 30), |         pressedBackground: darken(theme.primary.colorFaded, 30), | ||||||
|       }), |       }), | ||||||
|       warning: createState({ |       warning: createState({ | ||||||
|         textColor: theme.text.baseColor, |         textColor: theme.warning.color, | ||||||
|         backgroundColor: theme.warning.color, |         backgroundColor: theme.warning.colorFaded, | ||||||
|         hoverBackground: theme.warning.colorHover, |         hoverBackground: lighten(theme.warning.colorFaded, 30), | ||||||
|         pressedBackground: theme.warning.colorPressed, |         pressedBackground: darken(theme.warning.colorFaded, 30), | ||||||
|       }), |       }), | ||||||
|     }, |     }, | ||||||
|     text: { |     text: { | ||||||
| @ -76,10 +76,10 @@ const createTheme = ({ style }: { style: 'light' | 'dark' }) => { | |||||||
|         pressedBackground: darken(theme.primary.colorFaded, 30), |         pressedBackground: darken(theme.primary.colorFaded, 30), | ||||||
|       }), |       }), | ||||||
|       warning: createState({ |       warning: createState({ | ||||||
|         textColor: theme.text.baseColor, |         textColor: darken(theme.warning.color, 20), | ||||||
|         backgroundColor: theme.warning.color, |         backgroundColor: 'transparent', | ||||||
|         hoverBackground: theme.warning.colorHover, |         hoverBackground: theme.warning.colorFaded, | ||||||
|         pressedBackground: theme.warning.colorPressed, |         pressedBackground: darken(theme.warning.colorFaded, 30), | ||||||
|       }), |       }), | ||||||
|     }, |     }, | ||||||
|   }; |   }; | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ import { useAppTheme } from '../theme/themes'; | |||||||
| 
 | 
 | ||||||
| const props = withDefaults( | const props = withDefaults( | ||||||
|   defineProps<{ |   defineProps<{ | ||||||
|     type?: 'default' | 'primary'; |     type?: 'default' | 'primary' | 'warning'; | ||||||
|     variant?: 'basic' | 'text'; |     variant?: 'basic' | 'text'; | ||||||
|     disabled?: boolean; |     disabled?: boolean; | ||||||
|     round?: boolean; |     round?: boolean; | ||||||
|  | |||||||
| @ -2,6 +2,9 @@ | |||||||
|   <h2>Default</h2> |   <h2>Default</h2> | ||||||
| 
 | 
 | ||||||
|   <c-input-text value="qsd" /> |   <c-input-text value="qsd" /> | ||||||
|  |   <c-input-text | ||||||
|  |     value="Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, est modi iusto repellendus fuga accusantium atque at magnam aliquam eum explicabo vero quia, nobis quasi quis! Earum amet quam a?" | ||||||
|  |   /> | ||||||
| 
 | 
 | ||||||
|   <h2>With placeholder</h2> |   <h2>With placeholder</h2> | ||||||
| 
 | 
 | ||||||
| @ -24,16 +27,50 @@ | |||||||
| 
 | 
 | ||||||
|   <h2>Validation</h2> |   <h2>Validation</h2> | ||||||
| 
 | 
 | ||||||
|   <c-input-text |   <c-input-text v-model:value="value" :validation-rules="validationRules" mb-2 /> | ||||||
|     v-model:value="value" |   <c-input-text v-model:value="value" :validation-rules="validationRules" mb-2 label-position="left" label="Yo " /> | ||||||
|     :validation-rules="[{ message: 'Length must be > 10', validator: (value) => value.length > 10 }]" |   <c-input-text v-model:value="value" :validation="validation" /> | ||||||
|   /> |   <c-input-text v-model:value="value" :validation="validation" multiline rows="3" /> | ||||||
| 
 | 
 | ||||||
|   <h2>Clearable</h2> |   <h2>Clearable</h2> | ||||||
| 
 | 
 | ||||||
|   <c-input-text v-model:value="value" clearable /> |   <c-input-text v-model:value="value" clearable /> | ||||||
|  | 
 | ||||||
|  |   <h2>Type password</h2> | ||||||
|  | 
 | ||||||
|  |   <c-input-text value="value" type="password" /> | ||||||
|  | 
 | ||||||
|  |   <h2>Multiline</h2> | ||||||
|  | 
 | ||||||
|  |   <c-input-text value="value" multiline label="Label" mb-2 rows="1" /> | ||||||
|  |   <c-input-text value="value" multiline label="Label" mb-2 /> | ||||||
|  |   <c-input-text | ||||||
|  |     value="Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, est modi iusto repellendus fuga accusantium atque at magnam aliquam eum explicabo vero quia, nobis quasi quis! Earum amet quam a?" | ||||||
|  |     multiline | ||||||
|  |     mb-2 | ||||||
|  |   /> | ||||||
|  | 
 | ||||||
|  |   <c-input-text v-model:value="valueLong" multiline autosize mb-2 rows="5" /> | ||||||
|  | 
 | ||||||
|  |   <c-input-text | ||||||
|  |     value="Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, est modi iusto repellendus fuga accusantium atque at magnam aliquam eum explicabo vero quia, nobis quasi quis! Earum amet quam a?" | ||||||
|  |     multiline | ||||||
|  |     clearable | ||||||
|  |   /> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
|  | import { useValidation } from '@/composable/validation'; | ||||||
|  | 
 | ||||||
| const value = ref('value'); | const value = ref('value'); | ||||||
|  | const valueLong = ref( | ||||||
|  |   'Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, est modi iusto repellendus fuga accusantium atque at magnam aliquam eum explicabo vero quia, nobis quasi quis! Earum amet quam a?', | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | const validationRules = [{ message: 'Length must be > 10', validator: (value: string) => value.length > 10 }]; | ||||||
|  | 
 | ||||||
|  | const validation = useValidation({ | ||||||
|  |   source: value, | ||||||
|  |   rules: validationRules, | ||||||
|  | }); | ||||||
| </script> | </script> | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| import { describe, expect, it, beforeEach } from 'vitest'; | import { describe, expect, it, beforeEach } from 'vitest'; | ||||||
| import { shallowMount } from '@vue/test-utils'; | import { shallowMount, mount } from '@vue/test-utils'; | ||||||
| import { setActivePinia, createPinia } from 'pinia'; | import { setActivePinia, createPinia } from 'pinia'; | ||||||
| import _ from 'lodash'; | import _ from 'lodash'; | ||||||
|  | import { useValidation } from '@/composable/validation'; | ||||||
| import CInputText from './c-input-text.vue'; | import CInputText from './c-input-text.vue'; | ||||||
| 
 | 
 | ||||||
| describe('CInputText', () => { | describe('CInputText', () => { | ||||||
| @ -71,10 +72,28 @@ describe('CInputText', () => { | |||||||
| 
 | 
 | ||||||
|   it('renders a feedback message for invalid rules', async () => { |   it('renders a feedback message for invalid rules', async () => { | ||||||
|     const wrapper = shallowMount(CInputText, { |     const wrapper = shallowMount(CInputText, { | ||||||
|       props: { rules: [{ validator: () => false, message: 'Message' }] }, |       props: { validationRules: [{ validator: () => false, message: 'Message' }] }, | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     expect(wrapper.get('.feedback').text()).to.equal('Message'); |     const feedback = wrapper.find('.feedback'); | ||||||
|  |     expect(feedback.exists()).to.equal(true); | ||||||
|  |     expect(feedback.text()).to.equal('Message'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('if the value become valid according to rules, the feedback disappear', async () => { | ||||||
|  |     const wrapper = shallowMount(CInputText, { | ||||||
|  |       props: { | ||||||
|  |         validationRules: [{ validator: (value: string) => value === 'Hello', message: 'Value should be Hello' }], | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const feedback = wrapper.find('.feedback'); | ||||||
|  |     expect(feedback.exists()).to.equal(true); | ||||||
|  |     expect(feedback.text()).to.equal('Value should be Hello'); | ||||||
|  | 
 | ||||||
|  |     await wrapper.setProps({ value: 'Hello' }); | ||||||
|  | 
 | ||||||
|  |     expect(wrapper.find('.feedback').exists()).to.equal(false); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('feedback does not render for valid rules', async () => { |   it('feedback does not render for valid rules', async () => { | ||||||
| @ -84,4 +103,58 @@ describe('CInputText', () => { | |||||||
| 
 | 
 | ||||||
|     expect(wrapper.find('.feedback').exists()).to.equal(false); |     expect(wrapper.find('.feedback').exists()).to.equal(false); | ||||||
|   }); |   }); | ||||||
|  | 
 | ||||||
|  |   it('renders a feedback message for invalid custom validation wrapper', async () => { | ||||||
|  |     const wrapper = shallowMount(CInputText, { | ||||||
|  |       props: { | ||||||
|  |         validation: useValidation({ source: ref(), rules: [{ validator: () => false, message: 'Message' }] }), | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const feedback = wrapper.find('.feedback'); | ||||||
|  |     expect(feedback.exists()).to.equal(true); | ||||||
|  |     expect(feedback.text()).to.equal('Message'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('feedback does not render for valid custom validation wrapper', async () => { | ||||||
|  |     const wrapper = shallowMount(CInputText, { | ||||||
|  |       props: { | ||||||
|  |         validation: useValidation({ source: ref(), rules: [{ validator: () => true, message: 'Message' }] }), | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  |     expect(wrapper.find('.feedback').exists()).to.equal(false); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('if the value become valid according to the custom validation wrapper, the feedback disappear', async () => { | ||||||
|  |     const source = ref(''); | ||||||
|  | 
 | ||||||
|  |     const wrapper = shallowMount(CInputText, { | ||||||
|  |       props: { | ||||||
|  |         validation: useValidation({ | ||||||
|  |           source, | ||||||
|  |           rules: [{ validator: (value: string) => value === 'Hello', message: 'Value should be Hello' }], | ||||||
|  |         }), | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const feedback = wrapper.find('.feedback'); | ||||||
|  |     expect(feedback.exists()).to.equal(true); | ||||||
|  |     expect(feedback.text()).to.equal('Value should be Hello'); | ||||||
|  | 
 | ||||||
|  |     source.value = 'Hello'; | ||||||
|  | 
 | ||||||
|  |     await wrapper.vm.$nextTick(); | ||||||
|  | 
 | ||||||
|  |     expect(wrapper.find('.feedback').exists()).to.equal(false); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('[prop:testId] renders a test id on the input', async () => { | ||||||
|  |     const wrapper = mount(CInputText, { | ||||||
|  |       props: { | ||||||
|  |         testId: 'TEST', | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     expect(wrapper.get('input').attributes('data-test-id')).to.equal('TEST'); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -1,32 +1,60 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="c-input-text" :class="{ disabled, error: !validation.isValid, 'label-left': labelPosition === 'left' }"> |   <div | ||||||
|  |     class="c-input-text" | ||||||
|  |     :class="{ disabled, error: !validation.isValid, 'label-left': labelPosition === 'left', multiline }" | ||||||
|  |   > | ||||||
|     <label v-if="label" :for="id" class="label"> {{ label }} </label> |     <label v-if="label" :for="id" class="label"> {{ label }} </label> | ||||||
| 
 | 
 | ||||||
|     <div class="input-wrapper"> |     <div class="feedback-wrapper"> | ||||||
|       <slot name="prefix" /> |       <div ref="inputWrapperRef" class="input-wrapper"> | ||||||
|  |         <slot name="prefix" /> | ||||||
| 
 | 
 | ||||||
|       <input |         <textarea | ||||||
|         :id="id" |           v-if="multiline" | ||||||
|         v-model="value" |           :id="id" | ||||||
|         type="text" |           ref="textareaRef" | ||||||
|         class="input" |           v-model="value" | ||||||
|         :placeholder="placeholder" |           class="input" | ||||||
|         :readonly="readonly" |           :placeholder="placeholder" | ||||||
|         :disabled="disabled" |           :readonly="readonly" | ||||||
|         :data-test-id="testId" |           :disabled="disabled" | ||||||
|         :autocapitalize="autocapitalize ?? (rawText ? 'off' : undefined)" |           :data-test-id="testId" | ||||||
|         :autocomplete="autocomplete ?? (rawText ? 'off' : undefined)" |           :autocapitalize="autocapitalize ?? (rawText ? 'off' : undefined)" | ||||||
|         :autocorrect="autocorrect ?? (rawText ? 'off' : undefined)" |           :autocomplete="autocomplete ?? (rawText ? 'off' : undefined)" | ||||||
|         :spellcheck="spellcheck ?? (rawText ? false : undefined)" |           :autocorrect="autocorrect ?? (rawText ? 'off' : undefined)" | ||||||
|       /> |           :spellcheck="spellcheck ?? (rawText ? false : undefined)" | ||||||
|  |           :rows="rows" | ||||||
|  |         /> | ||||||
| 
 | 
 | ||||||
|       <c-button v-if="clearable && value" variant="text" circle size="small" @click="value = ''"> |         <input | ||||||
|         <icon-mdi-close /> |           v-else | ||||||
|       </c-button> |           :id="id" | ||||||
|       <slot name="suffix" /> |           v-model="value" | ||||||
|  |           :type="htmlInputType" | ||||||
|  |           class="input" | ||||||
|  |           size="1" | ||||||
|  |           :placeholder="placeholder" | ||||||
|  |           :readonly="readonly" | ||||||
|  |           :disabled="disabled" | ||||||
|  |           :data-test-id="testId" | ||||||
|  |           :autocapitalize="autocapitalize ?? (rawText ? 'off' : undefined)" | ||||||
|  |           :autocomplete="autocomplete ?? (rawText ? 'off' : undefined)" | ||||||
|  |           :autocorrect="autocorrect ?? (rawText ? 'off' : undefined)" | ||||||
|  |           :spellcheck="spellcheck ?? (rawText ? false : undefined)" | ||||||
|  |         /> | ||||||
|  | 
 | ||||||
|  |         <c-button v-if="clearable && value" variant="text" circle size="small" @click="value = ''"> | ||||||
|  |           <icon-mdi-close /> | ||||||
|  |         </c-button> | ||||||
|  | 
 | ||||||
|  |         <c-button v-if="type === 'password'" variant="text" circle size="small" @click="showPassword = !showPassword"> | ||||||
|  |           <icon-mdi-eye v-if="!showPassword" /> | ||||||
|  |           <icon-mdi-eye-off v-if="showPassword" /> | ||||||
|  |         </c-button> | ||||||
|  |         <slot name="suffix" /> | ||||||
|  |       </div> | ||||||
|  |       <span v-if="!validation.isValid" class="feedback"> {{ validation.message }} </span> | ||||||
|     </div> |     </div> | ||||||
| 
 |  | ||||||
|     <span v-if="!validation.isValid" class="feedback"> {{ validation.message }} </span> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| @ -45,6 +73,7 @@ const props = withDefaults( | |||||||
|     readonly?: boolean; |     readonly?: boolean; | ||||||
|     disabled?: boolean; |     disabled?: boolean; | ||||||
|     validationRules?: UseValidationRule<string>[]; |     validationRules?: UseValidationRule<string>[]; | ||||||
|  |     validation?: ReturnType<typeof useValidation>; | ||||||
|     labelPosition?: 'top' | 'left'; |     labelPosition?: 'top' | 'left'; | ||||||
|     labelWidth?: string; |     labelWidth?: string; | ||||||
|     labelAlign?: 'left' | 'right'; |     labelAlign?: 'left' | 'right'; | ||||||
| @ -55,6 +84,10 @@ const props = withDefaults( | |||||||
|     autocorrect?: 'on' | 'off' | string; |     autocorrect?: 'on' | 'off' | string; | ||||||
|     spellcheck?: 'true' | 'false' | boolean; |     spellcheck?: 'true' | 'false' | boolean; | ||||||
|     rawText?: boolean; |     rawText?: boolean; | ||||||
|  |     type?: 'text' | 'password'; | ||||||
|  |     multiline?: boolean; | ||||||
|  |     rows?: number | string; | ||||||
|  |     autosize?: boolean; | ||||||
|   }>(), |   }>(), | ||||||
|   { |   { | ||||||
|     value: '', |     value: '', | ||||||
| @ -64,6 +97,7 @@ const props = withDefaults( | |||||||
|     readonly: false, |     readonly: false, | ||||||
|     disabled: false, |     disabled: false, | ||||||
|     validationRules: () => [], |     validationRules: () => [], | ||||||
|  |     validation: undefined, | ||||||
|     labelPosition: 'top', |     labelPosition: 'top', | ||||||
|     labelWidth: 'auto', |     labelWidth: 'auto', | ||||||
|     labelAlign: 'left', |     labelAlign: 'left', | ||||||
| @ -74,20 +108,58 @@ const props = withDefaults( | |||||||
|     autocorrect: undefined, |     autocorrect: undefined, | ||||||
|     spellcheck: undefined, |     spellcheck: undefined, | ||||||
|     rawText: false, |     rawText: false, | ||||||
|  |     type: 'text', | ||||||
|  |     multiline: false, | ||||||
|  |     rows: 3, | ||||||
|  |     autosize: false, | ||||||
|   }, |   }, | ||||||
| ); | ); | ||||||
| const emit = defineEmits(['update:value']); | const emit = defineEmits(['update:value']); | ||||||
| const value = useVModel(props, 'value', emit); | const value = useVModel(props, 'value', emit); | ||||||
|  | const showPassword = ref(false); | ||||||
| 
 | 
 | ||||||
| const { id, placeholder, label, validationRules, labelPosition, labelWidth, labelAlign } = toRefs(props); | const { id, placeholder, label, validationRules, labelPosition, labelWidth, labelAlign, autosize } = toRefs(props); | ||||||
| 
 | 
 | ||||||
| const validation = useValidation({ | const validation = | ||||||
|   rules: validationRules, |   props.validation ?? | ||||||
|   source: value, |   useValidation({ | ||||||
| }); |     rules: validationRules, | ||||||
|  |     source: value, | ||||||
|  |   }); | ||||||
| 
 | 
 | ||||||
| const theme = useTheme(); | const theme = useTheme(); | ||||||
| const appTheme = useAppTheme(); | const appTheme = useAppTheme(); | ||||||
|  | 
 | ||||||
|  | const textareaRef = ref<HTMLTextAreaElement>(); | ||||||
|  | const inputWrapperRef = ref<HTMLElement>(); | ||||||
|  | 
 | ||||||
|  | watch( | ||||||
|  |   value, | ||||||
|  |   () => { | ||||||
|  |     if (props.multiline && autosize.value) { | ||||||
|  |       resizeTextarea(); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { immediate: true }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | function resizeTextarea() { | ||||||
|  |   if (!textareaRef.value || !inputWrapperRef.value) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const { scrollHeight } = textareaRef.value; | ||||||
|  | 
 | ||||||
|  |   inputWrapperRef.value.style.height = `${scrollHeight + 2}px`; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const htmlInputType = computed(() => { | ||||||
|  |   if (props.type === 'password' && !showPassword.value) { | ||||||
|  |     return 'password'; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return 'text'; | ||||||
|  | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="less" scoped> | <style lang="less" scoped> | ||||||
| @ -114,29 +186,55 @@ const appTheme = useAppTheme(); | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     & > .feedback { |     & .feedback { | ||||||
|       color: v-bind('appTheme.error.color'); |       color: v-bind('appTheme.error.color'); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   & > .label { |   & > .label { | ||||||
|  |     flex-shrink: 0; | ||||||
|     margin-bottom: 5px; |     margin-bottom: 5px; | ||||||
|     flex: 0 0 v-bind('labelWidth'); |     flex: 0 0 v-bind('labelWidth'); | ||||||
|     text-align: v-bind('labelAlign'); |     text-align: v-bind('labelAlign'); | ||||||
|     padding-right: 10px; |     padding-right: 12px; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .input-wrapper { |   .feedback-wrapper { | ||||||
|     flex: 1 1 0; |     flex: 1 1 0; | ||||||
|     min-width: 0; |     min-width: 0; | ||||||
| 
 |   } | ||||||
|  |   .input-wrapper { | ||||||
|     display: flex; |     display: flex; | ||||||
|     flex-direction: row; |     flex-direction: row; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|     background-color: v-bind('theme.backgroundColor'); |     background-color: v-bind('theme.backgroundColor'); | ||||||
|  |     color: transparent; | ||||||
|     border: 1px solid v-bind('theme.borderColor'); |     border: 1px solid v-bind('theme.borderColor'); | ||||||
|     border-radius: 4px; |     border-radius: 4px; | ||||||
|     padding: 0 4px 0 12px; |     padding: 0 4px 0 12px; | ||||||
|  |     transition: border-color 0.2s ease-in-out; | ||||||
|  | 
 | ||||||
|  |     .multiline& { | ||||||
|  |       resize: vertical; | ||||||
|  |       overflow: hidden; | ||||||
|  | 
 | ||||||
|  |       & > textarea { | ||||||
|  |         height: 100%; | ||||||
|  |         resize: none; | ||||||
|  |         word-break: break-word; | ||||||
|  |         white-space: pre-wrap; | ||||||
|  |         overflow-wrap: break-word; | ||||||
|  |         border: none; | ||||||
|  |         outline: none; | ||||||
|  |         font-family: inherit; | ||||||
|  |         font-size: inherit; | ||||||
|  |         color: v-bind('appTheme.text.baseColor'); | ||||||
|  | 
 | ||||||
|  |         &::placeholder { | ||||||
|  |           color: v-bind('appTheme.text.mutedColor'); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     & > .input { |     & > .input { | ||||||
|       flex: 1 1 0; |       flex: 1 1 0; | ||||||
| @ -144,7 +242,6 @@ const appTheme = useAppTheme(); | |||||||
| 
 | 
 | ||||||
|       padding: 8px 0; |       padding: 8px 0; | ||||||
|       outline: none; |       outline: none; | ||||||
|       transition: border-color 0.2s ease-in-out; |  | ||||||
|       background-color: transparent; |       background-color: transparent; | ||||||
|       background-image: none; |       background-image: none; | ||||||
|       -webkit-box-shadow: none; |       -webkit-box-shadow: none; | ||||||
| @ -159,12 +256,13 @@ const appTheme = useAppTheme(); | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &:hover, |     &:hover { | ||||||
|     &:focus { |  | ||||||
|       border-color: v-bind('appTheme.primary.color'); |       border-color: v-bind('appTheme.primary.color'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &:focus { |     &:focus-within { | ||||||
|  |       border-color: v-bind('appTheme.primary.color'); | ||||||
|  | 
 | ||||||
|       background-color: v-bind('theme.focus.backgroundColor'); |       background-color: v-bind('theme.focus.backgroundColor'); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -173,11 +271,11 @@ const appTheme = useAppTheme(); | |||||||
|     border-color: v-bind('appTheme.error.color'); |     border-color: v-bind('appTheme.error.color'); | ||||||
| 
 | 
 | ||||||
|     &:hover, |     &:hover, | ||||||
|     &:focus { |     &:focus-within { | ||||||
|       border-color: v-bind('appTheme.error.color'); |       border-color: v-bind('appTheme.error.color'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &:focus { |     &:focus-within { | ||||||
|       background-color: v-bind('appTheme.error.color + 22'); |       background-color: v-bind('appTheme.error.color + 22'); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -186,7 +284,7 @@ const appTheme = useAppTheme(); | |||||||
|     opacity: 0.5; |     opacity: 0.5; | ||||||
| 
 | 
 | ||||||
|     &:hover, |     &:hover, | ||||||
|     &:focus { |     &:focus-within { | ||||||
|       border-color: v-bind('theme.borderColor'); |       border-color: v-bind('theme.borderColor'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({ | |||||||
|       color: '#f59e0b', |       color: '#f59e0b', | ||||||
|       colorHover: '#f59e0b', |       colorHover: '#f59e0b', | ||||||
|       colorPressed: '#f59e0b', |       colorPressed: '#f59e0b', | ||||||
|  |       colorFaded: '#f59e0b2f', | ||||||
|     }, |     }, | ||||||
|     success: { |     success: { | ||||||
|       color: '#18a058', |       color: '#18a058', | ||||||
| @ -55,6 +56,7 @@ export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({ | |||||||
|       color: '#f59e0b', |       color: '#f59e0b', | ||||||
|       colorHover: '#f59e0b', |       colorHover: '#f59e0b', | ||||||
|       colorPressed: '#f59e0b', |       colorPressed: '#f59e0b', | ||||||
|  |       colorFaded: '#f59e0b2f', | ||||||
|     }, |     }, | ||||||
|     success: { |     success: { | ||||||
|       color: '#18a058', |       color: '#18a058', | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user