diff options
-rw-r--r-- | auto-imports.d.ts | 72 | ||||
-rw-r--r-- | src/components/FormatTransformer.vue | 41 | ||||
-rw-r--r-- | src/tools/base64-file-converter/base64-file-converter.vue | 32 | ||||
-rw-r--r-- | src/tools/base64-string-converter/base64-string-converter.vue | 75 | ||||
-rw-r--r-- | src/tools/date-time-converter/date-time-converter.vue | 41 | ||||
-rw-r--r-- | src/tools/ipv4-range-expander/ipv4-range-expander.vue | 25 | ||||
-rw-r--r-- | src/tools/json-diff/json-diff.vue | 67 | ||||
-rw-r--r-- | src/tools/mac-address-lookup/mac-address-lookup.vue | 54 | ||||
-rw-r--r-- | src/ui/c-input-text/c-input-text.vue | 4 | ||||
-rw-r--r-- | src/utils/macAddress.ts | 16 |
10 files changed, 195 insertions, 232 deletions
diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 9dccb44..2850890 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -19,9 +19,7 @@ declare global { const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] - const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate'] const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] - const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise'] const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] const customRef: typeof import('vue')['customRef'] const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] @@ -41,6 +39,9 @@ declare global { const isReactive: typeof import('vue')['isReactive'] const isReadonly: typeof import('vue')['isReadonly'] 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 markRaw: typeof import('vue')['markRaw'] const nextTick: typeof import('vue')['nextTick'] @@ -91,9 +92,8 @@ declare global { const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] const toRaw: typeof import('vue')['toRaw'] const toReactive: typeof import('@vueuse/core')['toReactive'] - const toRef: typeof import('@vueuse/core')['toRef'] + const toRef: typeof import('vue')['toRef'] const toRefs: typeof import('vue')['toRefs'] - const toValue: typeof import('@vueuse/core')['toValue'] const triggerRef: typeof import('vue')['triggerRef'] const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] @@ -104,19 +104,6 @@ declare global { const unrefElement: typeof import('@vueuse/core')['unrefElement'] const until: typeof import('@vueuse/core')['until'] 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 useAsyncState: typeof import('@vueuse/core')['useAsyncState'] const useAttrs: typeof import('vue')['useAttrs'] @@ -127,8 +114,8 @@ declare global { const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] const useCached: typeof import('@vueuse/core')['useCached'] + const useClamp: typeof import('@vueuse/core')['useClamp'] const useClipboard: typeof import('@vueuse/core')['useClipboard'] - const useCloned: typeof import('@vueuse/core')['useCloned'] const useColorMode: typeof import('@vueuse/core')['useColorMode'] const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] const useCounter: typeof import('@vueuse/core')['useCounter'] @@ -202,18 +189,12 @@ declare global { const useOnline: typeof import('@vueuse/core')['useOnline'] const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] 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 usePointer: typeof import('@vueuse/core')['usePointer'] - const usePointerLock: typeof import('@vueuse/core')['usePointerLock'] const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] - const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] 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 useRefHistory: typeof import('@vueuse/core')['useRefHistory'] const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] @@ -227,17 +208,14 @@ declare global { const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] const useShare: typeof import('@vueuse/core')['useShare'] const useSlots: typeof import('vue')['useSlots'] - const useSorted: typeof import('@vueuse/core')['useSorted'] const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] const useStepper: typeof import('@vueuse/core')['useStepper'] const useStorage: typeof import('@vueuse/core')['useStorage'] const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] - const useSupported: typeof import('@vueuse/core')['useSupported'] const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] - const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] const useThrottle: typeof import('@vueuse/core')['useThrottle'] @@ -249,8 +227,6 @@ declare global { const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] 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 useTransition: typeof import('@vueuse/core')['useTransition'] const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] @@ -271,10 +247,8 @@ declare global { const watchArray: typeof import('@vueuse/core')['watchArray'] const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] - const watchDeep: typeof import('@vueuse/core')['watchDeep'] const watchEffect: typeof import('vue')['watchEffect'] const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] - const watchImmediate: typeof import('@vueuse/core')['watchImmediate'] const watchOnce: typeof import('@vueuse/core')['watchOnce'] const watchPausable: typeof import('@vueuse/core')['watchPausable'] const watchPostEffect: typeof import('vue')['watchPostEffect'] @@ -308,9 +282,7 @@ declare module 'vue' { readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> 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 createTemplatePromise: UnwrapRef<typeof import('@vueuse/core')['createTemplatePromise']> readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> readonly customRef: UnwrapRef<typeof import('vue')['customRef']> readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> @@ -330,6 +302,9 @@ declare module 'vue' { readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> 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 markRaw: UnwrapRef<typeof import('vue')['markRaw']> readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> @@ -380,9 +355,8 @@ declare module 'vue' { readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> - readonly toRef: UnwrapRef<typeof import('@vueuse/core')['toRef']> + readonly toRef: UnwrapRef<typeof import('vue')['toRef']> readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> - readonly toValue: UnwrapRef<typeof import('@vueuse/core')['toValue']> readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> @@ -393,19 +367,6 @@ declare module 'vue' { readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> 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 useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> @@ -416,8 +377,8 @@ declare module 'vue' { readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> 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 useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']> readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> @@ -491,18 +452,12 @@ declare module 'vue' { readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> 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 usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> - readonly usePointerLock: UnwrapRef<typeof import('@vueuse/core')['usePointerLock']> readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> 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 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 useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> @@ -516,17 +471,14 @@ declare module 'vue' { readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> - readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']> readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> 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 useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> - readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']> readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> @@ -538,8 +490,6 @@ declare module 'vue' { readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> 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 useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> @@ -560,10 +510,8 @@ declare module 'vue' { readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> - readonly watchDeep: UnwrapRef<typeof import('@vueuse/core')['watchDeep']> readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> 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 watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> diff --git a/src/components/FormatTransformer.vue b/src/components/FormatTransformer.vue index d187632..5b187b2 100644 --- a/src/components/FormatTransformer.vue +++ b/src/components/FormatTransformer.vue @@ -1,26 +1,27 @@ <template> - <n-form-item :label="inputLabel" v-bind="validationAttrs as any"> - <n-input - ref="inputElement" - v-model:value="input" - :placeholder="inputPlaceholder" - type="textarea" - rows="20" - autocomplete="off" - autocorrect="off" - autocapitalize="off" - spellcheck="false" - :input-props="{ 'data-test-id': 'input' } as any" - /> - </n-form-item> - <n-form-item :label="outputLabel"> - <textarea-copyable :value="output" :language="outputLanguage" :follow-height-of="inputElement" /> - </n-form-item> + <c-input-text + ref="inputElement" + v-model:value="input" + :placeholder="inputPlaceholder" + :label="inputLabel" + multiline + autosize + rows="20" + raw-text + test-id="input" + :validation-rules="inputValidationRules" + /> + + <div> + <div mb-5px>{{ outputLabel }}</div> + <textarea-copyable :value="output" :language="outputLanguage" :follow-height-of="inputElement?.inputWrapperRef" /> + </div> </template> <script setup lang="ts"> -import { useValidation, type UseValidationRule } from '@/composable/validation'; +import type { UseValidationRule } from '@/composable/validation'; import _ from 'lodash'; +import CInputText from '@/ui/c-input-text/c-input-text.vue'; const props = withDefaults( defineProps<{ @@ -46,12 +47,10 @@ const props = withDefaults( const { transformer, inputValidationRules, inputLabel, outputLabel, outputLanguage, inputPlaceholder, inputDefault } = toRefs(props); -const inputElement = ref(); +const inputElement = ref<typeof CInputText>(); const input = ref(inputDefault.value); const output = computed(() => transformer.value(input.value)); - -const { attrs: validationAttrs } = useValidation({ source: input, rules: inputValidationRules.value }); </script> <style scoped></style> diff --git a/src/tools/base64-file-converter/base64-file-converter.vue b/src/tools/base64-file-converter/base64-file-converter.vue index 5524109..de18ee3 100644 --- a/src/tools/base64-file-converter/base64-file-converter.vue +++ b/src/tools/base64-file-converter/base64-file-converter.vue @@ -1,17 +1,19 @@ <template> <c-card title="Base64 to file"> - <n-form-item - :feedback="base64InputValidation.message" - :validation-status="base64InputValidation.status" - :show-label="false" - > - <n-input v-model:value="base64Input" type="textarea" placeholder="Put your base64 file string here..." rows="5" /> - </n-form-item> - <n-space justify="center"> + <c-input-text + v-model:value="base64Input" + multiline + placeholder="Put your base64 file string here..." + rows="5" + :validation="base64InputValidation" + mb-2 + /> + + <div flex justify-center> <c-button :disabled="base64Input === '' || !base64InputValidation.isValid" @click="downloadFile()"> Download file </c-button> - </n-space> + </div> </c-card> <c-card title="File to base64"> @@ -24,10 +26,11 @@ </n-upload-dragger> </n-upload> - <n-input :value="fileBase64" type="textarea" readonly placeholder="File in base64 will be here" /> - <n-space justify="center"> + <c-input-text :value="fileBase64" multiline readonly placeholder="File in base64 will be here" rows="5" mb-2 /> + + <div flex justify-center> <c-button @click="copyFileBase64()"> Copy </c-button> - </n-space> + </div> </c-card> </template> @@ -77,11 +80,6 @@ async function onUpload({ file: { file } }: { file: UploadFileInfo }) { </script> <style lang="less" scoped> -.n-input, -.n-upload { - margin-bottom: 15px; -} - ::v-deep(.n-upload-trigger) { width: 100%; } diff --git a/src/tools/base64-string-converter/base64-string-converter.vue b/src/tools/base64-string-converter/base64-string-converter.vue index e97c884..0bcd966 100644 --- a/src/tools/base64-string-converter/base64-string-converter.vue +++ b/src/tools/base64-string-converter/base64-string-converter.vue @@ -1,42 +1,59 @@ <template> <c-card title="String to base64"> - <n-form-item label="String to encode"> - <n-input v-model:value="textInput" type="textarea" placeholder="Put your string here..." rows="5" /> - </n-form-item> - - <n-form-item label="Base64 of string"> - <n-input - :value="base64Output" - type="textarea" - readonly - placeholder="The base64 encoding of your string will be here" - rows="5" - /> - </n-form-item> - - <n-space justify="center"> + <c-input-text + v-model:value="textInput" + multiline + placeholder="Put your string here..." + rows="5" + label="String to encode" + raw-text + mb-5 + /> + + <c-input-text + label="Base64 of string" + :value="base64Output" + multiline + readonly + placeholder="The base64 encoding of your string will be here" + rows="5" + mb-5 + /> + + <div flex justify-center> <c-button @click="copyTextBase64()"> Copy base64 </c-button> - </n-space> + </div> </c-card> <c-card title="Base64 to string"> - <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-form-item> + <c-input-text + v-model:value="base64Input" + multiline + placeholder="Your base64 string..." + rows="5" + :validation-rules="b64ValidationRules" + label="Base64 string to decode" + mb-5 + /> - <n-form-item label="Decoded string"> - <n-input :value="textOutput" type="textarea" readonly placeholder="The decoded string will be here" rows="5" /> - </n-form-item> + <c-input-text + v-model:value="textOutput" + label="Decoded string" + placeholder="The decoded string will be here" + multiline + rows="5" + readonly + mb-5 + /> - <n-space justify="center"> + <div flex justify-center> <c-button @click="copyText()"> Copy decoded string </c-button> - </n-space> + </div> </c-card> </template> <script setup lang="ts"> import { useCopy } from '@/composable/copy'; -import { useValidation } from '@/composable/validation'; import { base64ToText, isValidBase64, textToBase64 } from '@/utils/base64'; import { withDefaultOnError } from '@/utils/defaults'; import { computed, ref } from 'vue'; @@ -48,8 +65,8 @@ const { copy: copyTextBase64 } = useCopy({ source: base64Output, text: 'Base64 s const base64Input = ref(''); const textOutput = computed(() => withDefaultOnError(() => base64ToText(base64Input.value.trim()), '')); const { copy: copyText } = useCopy({ source: textOutput, text: 'String copied to the clipboard' }); -const b64Validation = useValidation({ - source: base64Input, - rules: [{ message: 'Invalid base64 string', validator: (value) => isValidBase64(value.trim()) }], -}); + +const b64ValidationRules = [ + { message: 'Invalid base64 string', validator: (value: string) => isValidBase64(value.trim()) }, +]; </script> diff --git a/src/tools/date-time-converter/date-time-converter.vue b/src/tools/date-time-converter/date-time-converter.vue index 276c829..4207eb9 100644 --- a/src/tools/date-time-converter/date-time-converter.vue +++ b/src/tools/date-time-converter/date-time-converter.vue @@ -1,25 +1,26 @@ <template> <div> - <n-form-item :show-label="false" v-bind="validation.attrs as any"> - <n-input-group> - <n-input - v-model:value="inputDate" - autofocus - :on-input="onDateInputChanged" - placeholder="Put you date string here..." - clearable - :input-props="{ 'data-test-id': 'date-time-converter-input' } as any" - /> - - <n-select - v-model:value="formatIndex" - style="flex: 0 0 170px" - :options="formats.map(({ name }, i) => ({ label: name, value: i }))" - data-test-id="date-time-converter-format-select" - /> - </n-input-group> - </n-form-item> - <n-divider style="margin-top: 0" /> + <n-input-group> + <c-input-text + v-model:value="inputDate" + autofocus + placeholder="Put you date string here..." + clearable + test-id="date-time-converter-input" + :validation="validation" + @update:value="onDateInputChanged" + /> + + <n-select + v-model:value="formatIndex" + style="flex: 0 0 170px" + :options="formats.map(({ name }, i) => ({ label: name, value: i }))" + data-test-id="date-time-converter-format-select" + /> + </n-input-group> + + <n-divider /> + <input-copyable v-for="{ name, fromDate } in formats" :key="name" diff --git a/src/tools/ipv4-range-expander/ipv4-range-expander.vue b/src/tools/ipv4-range-expander/ipv4-range-expander.vue index 0d9f067..7f89a6a 100644 --- a/src/tools/ipv4-range-expander/ipv4-range-expander.vue +++ b/src/tools/ipv4-range-expander/ipv4-range-expander.vue @@ -2,14 +2,23 @@ <div> <n-space item-style="flex:1 1 0"> <div> - <n-space item-style="flex:1 1 0"> - <n-form-item label="Start address" v-bind="startIpValidation.attrs as any"> - <n-input v-model:value="rawStartAddress" placeholder="Start IPv4 address..." /> - </n-form-item> - <n-form-item label="End address" v-bind="endIpValidation.attrs as any"> - <n-input v-model:value="rawEndAddress" placeholder="End IPv4 address..." /> - </n-form-item> - </n-space> + <div mb-4 flex gap-4> + <c-input-text + v-model:value="rawStartAddress" + label="Start address" + placeholder="Start IPv4 address..." + :validation="startIpValidation" + clearable + /> + + <c-input-text + v-model:value="rawEndAddress" + label="End address" + placeholder="End IPv4 address..." + :validation="endIpValidation" + clearable + /> + </div> <n-table v-if="showResult" data-test-id="result"> <thead> diff --git a/src/tools/json-diff/json-diff.vue b/src/tools/json-diff/json-diff.vue index 0db06cc..811f7fa 100644 --- a/src/tools/json-diff/json-diff.vue +++ b/src/tools/json-diff/json-diff.vue @@ -1,30 +1,25 @@ <template> - <n-form-item label="Your first json" v-bind="leftJsonValidation.attrs as any"> - <n-input - v-model:value="rawLeftJson" - placeholder="Paste your first json here..." - type="textarea" - rows="20" - autocomplete="off" - autocorrect="off" - autocapitalize="off" - spellcheck="false" - :input-props="{ 'data-test-id': 'leftJson' } as any" - /> - </n-form-item> - <n-form-item label="Your json to compare" v-bind="rightJsonValidation.attrs as any"> - <n-input - v-model:value="rawRightJson" - placeholder="Paste your json to compare here..." - type="textarea" - rows="20" - autocomplete="off" - autocorrect="off" - autocapitalize="off" - spellcheck="false" - :input-props="{ 'data-test-id': 'rightJson' } as any" - /> - </n-form-item> + <c-input-text + v-model:value="rawLeftJson" + :validation-rules="jsonValidationRules" + label="Your first json" + placeholder="Paste your first json here..." + rows="20" + multiline + test-id="leftJson" + raw-text + /> + + <c-input-text + v-model:value="rawRightJson" + :validation-rules="jsonValidationRules" + label="Your json to compare" + placeholder="Paste your json to compare here..." + rows="20" + multiline + test-id="rightJson" + raw-text + /> <DiffsViewer :left-json="leftJson" :right-json="rightJson" /> </template> @@ -33,7 +28,6 @@ import JSON5 from 'json5'; import { withDefaultOnError } from '@/utils/defaults'; -import { useValidation } from '@/composable/validation'; import { isNotThrowing } from '@/utils/boolean'; import DiffsViewer from './diff-viewer/diff-viewer.vue'; @@ -43,17 +37,10 @@ const rawRightJson = ref(''); const leftJson = computed(() => withDefaultOnError(() => JSON5.parse(rawLeftJson.value), undefined)); const rightJson = computed(() => withDefaultOnError(() => JSON5.parse(rawRightJson.value), undefined)); -const createJsonValidation = (json: Ref) => - useValidation({ - source: json, - rules: [ - { - validator: (value) => value === '' || isNotThrowing(() => JSON5.parse(value)), - message: 'Invalid JSON', - }, - ], - }); - -const leftJsonValidation = createJsonValidation(rawLeftJson); -const rightJsonValidation = createJsonValidation(rawRightJson); +const jsonValidationRules = [ + { + validator: (value: string) => value === '' || isNotThrowing(() => JSON5.parse(value)), + message: 'Invalid JSON format', + }, +]; </script> diff --git a/src/tools/mac-address-lookup/mac-address-lookup.vue b/src/tools/mac-address-lookup/mac-address-lookup.vue index 4ff4c2e..095a0ee 100644 --- a/src/tools/mac-address-lookup/mac-address-lookup.vue +++ b/src/tools/mac-address-lookup/mac-address-lookup.vue @@ -1,37 +1,37 @@ <template> <div> - <n-form-item label="MAC address:" v-bind="validationAttrs as any"> - <n-input - v-model:value="macAddress" - size="large" - placeholder="Type a MAC address" - clearable - autocomplete="off" - autocorrect="off" - autocapitalize="off" - spellcheck="false" - /> - </n-form-item> - - <n-form-item label="Vendor info:"> - <c-card> - <n-text v-if="details"> - <div v-for="(detail, index) of details.split('\n')" :key="index">{{ detail }}</div> - </n-text> - - <n-text v-else depth="3" italic>Unknown vendor for this address</n-text> - </c-card> - </n-form-item> - - <n-space justify="center"> + <c-input-text + v-model:value="macAddress" + label="MAC address:" + size="large" + placeholder="Type a MAC address" + clearable + autocomplete="off" + autocorrect="off" + autocapitalize="off" + spellcheck="false" + :validation-rules="macAddressValidationRules" + mb-5 + /> + + <div mb-5px>Vendor info:</div> + <c-card mb-5> + <div v-if="details"> + <div v-for="(detail, index) of details.split('\n')" :key="index">{{ detail }}</div> + </div> + + <div v-else italic op-60>Unknown vendor for this address</div> + </c-card> + + <div flex justify-center> <c-button :disabled="!details" @click="copy"> Copy vendor info </c-button> - </n-space> + </div> </div> </template> <script setup lang="ts"> import db from 'oui/oui.json'; -import { macAddressValidation } from '@/utils/macAddress'; +import { macAddressValidationRules } from '@/utils/macAddress'; import { useCopy } from '@/composable/copy'; const getVendorValue = (address: string) => address.trim().replace(/[.:-]/g, '').toUpperCase().substring(0, 6); @@ -39,8 +39,6 @@ const getVendorValue = (address: string) => address.trim().replace(/[.:-]/g, '') const macAddress = ref('20:37:06:12:34:56'); const details = computed<string | undefined>(() => db[getVendorValue(macAddress.value)]); -const { attrs: validationAttrs } = macAddressValidation(macAddress); - const { copy } = useCopy({ source: details, text: 'Vendor info copied to the clipboard' }); </script> diff --git a/src/ui/c-input-text/c-input-text.vue b/src/ui/c-input-text/c-input-text.vue index 51c2805..d1dd3c6 100644 --- a/src/ui/c-input-text/c-input-text.vue +++ b/src/ui/c-input-text/c-input-text.vue @@ -133,6 +133,10 @@ const appTheme = useAppTheme(); const textareaRef = ref<HTMLTextAreaElement>(); const inputWrapperRef = ref<HTMLElement>(); +defineExpose({ + inputWrapperRef, +}); + watch( value, () => { diff --git a/src/utils/macAddress.ts b/src/utils/macAddress.ts index ff6000c..89f12d3 100644 --- a/src/utils/macAddress.ts +++ b/src/utils/macAddress.ts @@ -1,16 +1,18 @@ import { useValidation } from '@/composable/validation'; import type { Ref } from 'vue'; +const macAddressValidationRules = [ + { + message: 'Invalid MAC address', + validator: (value: string) => value.trim().match(/^([0-9A-Fa-f]{2}[:-]){2,5}([0-9A-Fa-f]{2})$/), + }, +]; + function macAddressValidation(value: Ref) { return useValidation({ source: value, - rules: [ - { - message: 'Invalid MAC address', - validator: (value) => value.trim().match(/^([0-9A-Fa-f]{2}[:-]){2,5}([0-9A-Fa-f]{2})$/), - }, - ], + rules: macAddressValidationRules, }); } -export { macAddressValidation }; +export { macAddressValidation, macAddressValidationRules }; |