add new funtion

This commit is contained in:
lidong-sal 2026-06-04 16:14:36 +08:00
parent 9ddb92ccc0
commit be9d705c96
22 changed files with 1260 additions and 191 deletions

295
auto-imports.d.ts vendored
View file

@ -1,7 +1,6 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
@ -296,8 +295,7 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue'
}
// for vue template auto import
import { UnwrapRef } from 'vue'
@ -335,7 +333,6 @@ declare module 'vue' {
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
@ -363,10 +360,8 @@ declare module 'vue' {
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
@ -430,7 +425,6 @@ declare module 'vue' {
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
@ -474,7 +468,6 @@ declare module 'vue' {
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']>
readonly useId: UnwrapRef<typeof import('vue')['useId']>
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
@ -493,7 +486,6 @@ declare module 'vue' {
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
readonly useMessage: UnwrapRef<typeof import('naive-ui')['useMessage']>
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
@ -542,7 +534,290 @@ declare module 'vue' {
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 useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
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']>
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']>
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']>
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
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']>
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']>
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']>
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']>
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']>
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']>
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']>
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']>
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']>
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']>
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']>
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']>
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']>
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
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']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']>
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']>
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']>
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']>
}
}
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']>
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']>
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
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']>
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']>
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']>
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']>
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']>
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']>
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']>
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']>
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']>
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']>
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('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']>
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']>
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
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']>
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
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 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']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']>
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']>
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']>
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']>
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']>
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']>
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']>
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']>
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']>
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']>
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']>
readonly useDialog: UnwrapRef<typeof import('naive-ui')['useDialog']>
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']>
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']>
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']>
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']>
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']>
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']>
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']>
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']>
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']>
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']>
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']>
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']>
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']>
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']>
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']>
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']>
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']>
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']>
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']>
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']>
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']>
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']>
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
readonly useMessage: UnwrapRef<typeof import('naive-ui')['useMessage']>
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']>
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']>
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']>
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']>
readonly useNotification: UnwrapRef<typeof import('naive-ui')['useNotification']>
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']>
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']>
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']>
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']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']>
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']>
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']>

9
components.d.ts vendored
View file

@ -3,9 +3,11 @@
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module 'vue' {
declare module '@vue/runtime-core' {
export interface GlobalComponents {
'404.page': typeof import('./src/pages/404.page.vue')['default']
About: typeof import('./src/pages/About.vue')['default']
@ -18,6 +20,7 @@ declare module 'vue' {
Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']
BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']
Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']
ByteUnitConverter: typeof import('./src/tools/byte-unit-converter/byte-unit-converter.vue')['default']
CAlert: typeof import('./src/ui/c-alert/c-alert.vue')['default']
'CAlert.demo': typeof import('./src/ui/c-alert/c-alert.demo.vue')['default']
CameraRecorder: typeof import('./src/tools/camera-recorder/camera-recorder.vue')['default']
@ -56,12 +59,14 @@ declare module 'vue' {
CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']
CSelect: typeof import('./src/ui/c-select/c-select.vue')['default']
'CSelect.demo': typeof import('./src/ui/c-select/c-select.demo.vue')['default']
CssJsPrettifyMinify: typeof import('./src/tools/css-js-prettify-minify/css-js-prettify-minify.vue')['default']
CTable: typeof import('./src/ui/c-table/c-table.vue')['default']
'CTable.demo': typeof import('./src/ui/c-table/c-table.demo.vue')['default']
CTextCopyable: typeof import('./src/ui/c-text-copyable/c-text-copyable.vue')['default']
'CTextCopyable.demo': typeof import('./src/ui/c-text-copyable/c-text-copyable.demo.vue')['default']
CTooltip: typeof import('./src/ui/c-tooltip/c-tooltip.vue')['default']
'CTooltip.demo': typeof import('./src/ui/c-tooltip/c-tooltip.demo.vue')['default']
CurlToCode: typeof import('./src/tools/curl-to-code/curl-to-code.vue')['default']
DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']
'DemoHome.page': typeof import('./src/ui/demo/demo-home.page.vue')['default']
DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default']
@ -84,6 +89,7 @@ declare module 'vue' {
HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']
'Home.page': typeof import('./src/pages/Home.page.vue')['default']
HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']
HtmlToMarkdown: typeof import('./src/tools/html-to-markdown/html-to-markdown.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']
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
@ -120,6 +126,7 @@ declare module 'vue' {
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']
JsonToToml: typeof import('./src/tools/json-to-toml/json-to-toml.vue')['default']
JsonToTypes: typeof import('./src/tools/json-to-types/json-to-types.vue')['default']
JsonToXml: typeof import('./src/tools/json-to-xml/json-to-xml.vue')['default']
JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']
JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']

View file

@ -392,3 +392,23 @@ tools:
text-to-binary:
title: Text to ASCII binary
description: Convert text to its ASCII binary representation and vice-versa.
html-to-markdown:
title: HTML to Markdown
description: Convert HTML to Markdown with this online converter.
byte-unit-converter:
title: Byte unit converter
description: Convert between data size units (bytes, KB, MB, GB, TB) in both decimal (SI) and binary (IEC) systems.
json-to-types:
title: JSON to TypeScript/Go
description: Generate TypeScript interfaces or Go structs from a JSON sample.
css-js-prettify-minify:
title: CSS/JS Prettify & Minify
description: Prettify or minify your CSS and JavaScript code online.
curl-to-code:
title: cURL to Code
description: Convert cURL commands to code in various programming languages.

View file

@ -388,3 +388,23 @@ tools:
text-to-binary:
title: 文本到 ASCII 二进制
description: 将文本转换为其 ASCII 二进制表示形式,反之亦然。
html-to-markdown:
title: HTML 转 Markdown
description: 使用此在线转换器将 HTML 转换为 Markdown。
byte-unit-converter:
title: 字节单位转换器
description: 在十进制SI和二进制IEC系统中转换数据大小单位字节、KB、MB、GB、TB
json-to-types:
title: JSON 转 TypeScript/Go
description: 从 JSON 样本生成 TypeScript 接口或 Go 结构体。
css-js-prettify-minify:
title: CSS/JS 格式化与压缩
description: 在线格式化或压缩您的 CSS 和 JavaScript 代码。
curl-to-code:
title: cURL 转代码
description: 将 cURL 命令转换为多种编程语言的代码。

View file

@ -60,6 +60,7 @@
"cron-validator": "^1.3.1",
"cronstrue": "^2.26.0",
"crypto-js": "^4.1.1",
"curlconverter": "^4.12.0",
"date-fns": "^2.29.3",
"date-fns-tz": "^2.0.1",
"dompurify": "^3.0.6",
@ -72,6 +73,7 @@
"iarna-toml-esm": "^3.0.5",
"ibantools": "^4.3.3",
"js-base64": "^3.7.6",
"js-beautify": "^1.15.4",
"json5": "^2.2.3",
"jwt-decode": "^3.1.2",
"libphonenumber-js": "^1.10.28",
@ -91,6 +93,7 @@
"qrcode": "^1.5.1",
"randexp": "^0.5.3",
"sql-formatter": "^13.0.0",
"turndown": "^7.2.4",
"ua-parser-js": "^1.0.35",
"ulid": "^2.3.0",
"unicode-emoji-json": "^0.4.0",
@ -116,6 +119,7 @@
"@types/bcryptjs": "^2.4.2",
"@types/crypto-js": "^4.1.1",
"@types/dompurify": "^3.0.5",
"@types/js-beautify": "^1.14.3",
"@types/jsdom": "^21.0.0",
"@types/lodash": "^4.14.192",
"@types/mime-types": "^2.1.1",
@ -123,6 +127,7 @@
"@types/node": "^18.15.11",
"@types/node-forge": "^1.3.2",
"@types/qrcode": "^1.5.0",
"@types/turndown": "^5.0.6",
"@types/ua-parser-js": "^0.7.36",
"@types/uuid": "^9.0.0",
"@unocss/eslint-config": "^0.57.0",

547
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

BIN
public/tree-sitter-bash.wasm Executable file

Binary file not shown.

BIN
public/tree-sitter.wasm Executable file

Binary file not shown.

View file

@ -8,6 +8,11 @@ import xmlHljs from 'highlight.js/lib/languages/xml';
import yamlHljs from 'highlight.js/lib/languages/yaml';
import iniHljs from 'highlight.js/lib/languages/ini';
import markdownHljs from 'highlight.js/lib/languages/markdown';
import typescriptHljs from 'highlight.js/lib/languages/typescript';
import javascriptHljs from 'highlight.js/lib/languages/javascript';
import pythonHljs from 'highlight.js/lib/languages/python';
import goHljs from 'highlight.js/lib/languages/go';
import cssHljs from 'highlight.js/lib/languages/css';
import { useCopy } from '@/composable/copy';
const props = withDefaults(
@ -32,6 +37,11 @@ hljs.registerLanguage('xml', xmlHljs);
hljs.registerLanguage('yaml', yamlHljs);
hljs.registerLanguage('toml', iniHljs);
hljs.registerLanguage('markdown', markdownHljs);
hljs.registerLanguage('typescript', typescriptHljs);
hljs.registerLanguage('javascript', javascriptHljs);
hljs.registerLanguage('python', pythonHljs);
hljs.registerLanguage('go', goHljs);
hljs.registerLanguage('css', cssHljs);
const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props);
const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) };

View file

@ -0,0 +1,82 @@
<script setup lang="ts">
import _ from 'lodash';
interface UnitDef {
title: string
unit: string
ref: number
factor: number
}
const decimalUnits = reactive<Record<string, UnitDef>>({
b: { title: 'Bytes', unit: 'B', ref: 0, factor: 1 },
kb: { title: 'Kilobytes', unit: 'KB', ref: 0, factor: 1e3 },
mb: { title: 'Megabytes', unit: 'MB', ref: 0, factor: 1e6 },
gb: { title: 'Gigabytes', unit: 'GB', ref: 0, factor: 1e9 },
tb: { title: 'Terabytes', unit: 'TB', ref: 0, factor: 1e12 },
pb: { title: 'Petabytes', unit: 'PB', ref: 0, factor: 1e15 },
});
const binaryUnits = reactive<Record<string, UnitDef>>({
b: { title: 'Bytes', unit: 'B', ref: 0, factor: 1 },
kib: { title: 'Kibibytes', unit: 'KiB', ref: 0, factor: 1024 },
mib: { title: 'Mebibytes', unit: 'MiB', ref: 0, factor: 1024 ** 2 },
gib: { title: 'Gibibytes', unit: 'GiB', ref: 0, factor: 1024 ** 3 },
tib: { title: 'Tebibytes', unit: 'TiB', ref: 0, factor: 1024 ** 4 },
pib: { title: 'Pebibytes', unit: 'PiB', ref: 0, factor: 1024 ** 5 },
});
function update(key: string, source: Record<string, UnitDef>) {
const bytes = (source[key].ref ?? 0) * source[key].factor;
_.forEach(decimalUnits, (unit, k) => {
if (source === decimalUnits && k === key) {
return;
}
unit.ref = bytes / unit.factor;
});
_.forEach(binaryUnits, (unit, k) => {
if (source === binaryUnits && k === key) {
return;
}
unit.ref = bytes / unit.factor;
});
}
</script>
<template>
<div style="flex: 0 0 100%; display: flex; gap: 16px; align-items: flex-start; justify-content: center">
<c-card title="Decimal (SI) — Base 1000" style="width: 500px; flex: 0 0 500px">
<n-input-group v-for="[key, { title, unit }] in Object.entries(decimalUnits)" :key="key" mb-3>
<n-input-group-label style="flex: 0 0 100px">
{{ title }}
</n-input-group-label>
<n-input-number
v-model:value="decimalUnits[key].ref"
style="flex: 1 1 0"
@update:value="() => update(key, decimalUnits)"
/>
<n-input-group-label style="flex: 0 0 45px">
{{ unit }}
</n-input-group-label>
</n-input-group>
</c-card>
<c-card title="Binary (IEC) — Base 1024" style="width: 500px; flex: 0 0 500px">
<n-input-group v-for="[key, { title, unit }] in Object.entries(binaryUnits)" :key="key" mb-3>
<n-input-group-label style="flex: 0 0 100px">
{{ title }}
</n-input-group-label>
<n-input-number
v-model:value="binaryUnits[key].ref"
style="flex: 1 1 0"
@update:value="() => update(key, binaryUnits)"
/>
<n-input-group-label style="flex: 0 0 45px">
{{ unit }}
</n-input-group-label>
</n-input-group>
</c-card>
</div>
</template>

View file

@ -0,0 +1,13 @@
import { Binary } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.byte-unit-converter.title'),
path: '/byte-unit-converter',
description: translate('tools.byte-unit-converter.description'),
keywords: ['byte', 'data', 'unit', 'converter', 'KB', 'MB', 'GB', 'TB', 'PB', 'kibibyte', 'mebibyte', 'gibibyte', 'size'],
component: () => import('./byte-unit-converter.vue'),
icon: Binary,
createdAt: new Date('2026-06-04'),
});

View file

@ -0,0 +1,111 @@
<script setup lang="ts">
import { css as cssBeautify, js as jsBeautify } from 'js-beautify';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
import { useStyleStore } from '@/stores/style.store';
import { withDefaultOnError } from '@/utils/defaults';
const styleStore = useStyleStore();
const languages = [
{ label: 'JavaScript', value: 'javascript' },
{ label: 'CSS', value: 'css' },
] as { label: string; value: string }[];
const selectedLanguage = ref('javascript');
const indentSize = ref('2');
const prettifyInput = ref('');
const minifyInput = ref('');
const prettifyOutput = computed(() =>
withDefaultOnError(() => {
if (!prettifyInput.value) {
return '';
}
const opts = { indent_size: Number.parseInt(indentSize.value, 10) || 2 };
return selectedLanguage.value === 'css'
? cssBeautify(prettifyInput.value, opts)
: jsBeautify(prettifyInput.value, opts);
}, ''),
);
function minifyCss(input: string): string {
return input
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\s+/g, ' ')
.replace(/\s*([{}:;,>~+])\s*/g, '$1')
.replace(/;}/g, '}')
.trim();
}
function minifyJs(input: string): string {
return input
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\/\/.*$/gm, '')
.replace(/\s+/g, ' ')
.replace(/\s*([{}();,=:+\-*/<>!&|?])\s*/g, '$1')
.trim();
}
const minifyOutput = computed(() =>
withDefaultOnError(() => {
if (!minifyInput.value) {
return '';
}
return selectedLanguage.value === 'css'
? minifyCss(minifyInput.value)
: minifyJs(minifyInput.value);
}, ''),
);
</script>
<template>
<div style="flex: 0 0 100%">
<div style="max-width: 600px" :class="{ 'flex-col': styleStore.isSmallScreen }" mx-auto mb-5 flex gap-2>
<c-select
v-model:value="selectedLanguage"
label="Language"
style="flex: 1"
:options="languages"
/>
<c-input-text
v-model:value="indentSize"
label="Indent size"
placeholder="2"
style="flex: 1"
/>
</div>
</div>
<c-card title="Prettify">
<n-form-item label="Your code">
<c-input-text
v-model:value="prettifyInput"
placeholder="Paste your code to prettify..."
rows="10"
multiline
monospace
raw-text
/>
</n-form-item>
<n-form-item label="Prettified code">
<TextareaCopyable :value="prettifyOutput" :language="selectedLanguage" />
</n-form-item>
</c-card>
<c-card title="Minify" mt-5>
<n-form-item label="Your code">
<c-input-text
v-model:value="minifyInput"
placeholder="Paste your code to minify..."
rows="10"
multiline
monospace
raw-text
/>
</n-form-item>
<n-form-item label="Minified code">
<TextareaCopyable :value="minifyOutput" :language="selectedLanguage" />
</n-form-item>
</c-card>
</template>

View file

@ -0,0 +1,13 @@
import { Code } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.css-js-prettify-minify.title'),
path: '/css-js-prettify-minify',
description: translate('tools.css-js-prettify-minify.description'),
keywords: ['css', 'javascript', 'js', 'prettify', 'minify', 'beautify', 'format', 'uglify', 'compress', 'formatter'],
component: () => import('./css-js-prettify-minify.vue'),
icon: Code,
createdAt: new Date('2026-06-04'),
});

View file

@ -0,0 +1,68 @@
<script setup lang="ts">
import { toCSharp, toGo, toJava, toJavaScript, toNode, toPhp, toPython, toRust } from 'curlconverter';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
import { withDefaultOnError } from '@/utils/defaults';
const converters: Record<string, { fn: (cmd: string) => string; hlLang: string }> = {
python: { fn: toPython, hlLang: 'python' },
javascript: { fn: toJavaScript, hlLang: 'javascript' },
node: { fn: toNode, hlLang: 'javascript' },
go: { fn: toGo, hlLang: 'go' },
php: { fn: toPhp, hlLang: 'php' },
java: { fn: toJava, hlLang: 'java' },
csharp: { fn: toCSharp, hlLang: 'csharp' },
rust: { fn: toRust, hlLang: 'rust' },
};
const languages = [
{ label: 'Python (requests)', value: 'python' },
{ label: 'JavaScript (fetch)', value: 'javascript' },
{ label: 'Node.js (http)', value: 'node' },
{ label: 'Go (net/http)', value: 'go' },
{ label: 'PHP (cURL)', value: 'php' },
{ label: 'Java (OkHttp)', value: 'java' },
{ label: 'C# (HttpClient)', value: 'csharp' },
{ label: 'Rust (reqwest)', value: 'rust' },
];
const selectedLanguage = ref('python');
const curlInput = ref('curl https://example.com');
const output = computed(() =>
withDefaultOnError(() => {
if (!curlInput.value.trim()) {
return '';
}
return converters[selectedLanguage.value].fn(curlInput.value);
}, ''),
);
const outputLanguage = computed(() => converters[selectedLanguage.value]?.hlLang ?? 'txt');
</script>
<template>
<div style="flex: 0 0 100%">
<div style="max-width: 600px" mx-auto mb-5>
<c-select
v-model:value="selectedLanguage"
label="Target language"
:options="languages"
/>
</div>
</div>
<n-form-item label="Your cURL command">
<c-input-text
v-model:value="curlInput"
placeholder="Paste your cURL command here..."
rows="5"
multiline
monospace
raw-text
/>
</n-form-item>
<n-form-item label="Generated code">
<TextareaCopyable :value="output" :language="outputLanguage" />
</n-form-item>
</template>

View file

@ -0,0 +1,13 @@
import { Terminal } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.curl-to-code.title'),
path: '/curl-to-code',
description: translate('tools.curl-to-code.description'),
keywords: ['curl', 'code', 'converter', 'python', 'javascript', 'go', 'fetch', 'requests', 'http', 'api'],
component: () => import('./curl-to-code.vue'),
icon: Terminal,
createdAt: new Date('2026-06-04'),
});

View file

@ -0,0 +1,28 @@
<script setup lang="ts">
import TurndownService from 'turndown';
import type { UseValidationRule } from '@/composable/validation';
import { isNotThrowing } from '@/utils/boolean';
import { withDefaultOnError } from '@/utils/defaults';
const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });
const transformer = (value: string) => withDefaultOnError(() => turndown.turndown(value), '');
const rules: UseValidationRule<string>[] = [
{
validator: (v: string) => v === '' || isNotThrowing(() => turndown.turndown(v)),
message: 'Provided HTML is not valid.',
},
];
</script>
<template>
<format-transformer
input-label="Your HTML"
input-placeholder="Paste your HTML here..."
output-label="Markdown from your HTML"
output-language="markdown"
:input-validation-rules="rules"
:transformer="transformer"
/>
</template>

View file

@ -0,0 +1,13 @@
import { Markdown } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.html-to-markdown.title'),
path: '/html-to-markdown',
description: translate('tools.html-to-markdown.description'),
keywords: ['html', 'markdown', 'converter', 'turndown', 'markup'],
component: () => import('./html-to-markdown.vue'),
icon: Markdown,
createdAt: new Date('2026-06-04'),
});

View file

@ -1,7 +1,12 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as byteUnitConverter } from './byte-unit-converter';
import { tool as cssJsPrettifyMinify } from './css-js-prettify-minify';
import { tool as curlToCode } from './curl-to-code';
import { tool as emailNormalizer } from './email-normalizer';
import { tool as htmlToMarkdown } from './html-to-markdown';
import { tool as jsonToTypes } from './json-to-types';
import { tool as asciiTextDrawer } from './ascii-text-drawer';
@ -116,6 +121,7 @@ export const toolsByCategory: ToolCategory[] = [
xmlToJson,
jsonToXml,
markdownToHtml,
htmlToMarkdown,
],
},
{
@ -160,6 +166,9 @@ export const toolsByCategory: ToolCategory[] = [
emailNormalizer,
regexTester,
regexMemo,
curlToCode,
jsonToTypes,
cssJsPrettifyMinify,
],
},
{
@ -172,7 +181,7 @@ export const toolsByCategory: ToolCategory[] = [
},
{
name: 'Measurement',
components: [chronometer, temperatureConverter, benchmarkBuilder],
components: [chronometer, temperatureConverter, benchmarkBuilder, byteUnitConverter],
},
{
name: 'Text',

View file

@ -0,0 +1,13 @@
import { Braces } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: translate('tools.json-to-types.title'),
path: '/json-to-types',
description: translate('tools.json-to-types.description'),
keywords: ['json', 'typescript', 'go', 'struct', 'interface', 'type', 'convert', 'generate', 'definition'],
component: () => import('./json-to-types.vue'),
icon: Braces,
createdAt: new Date('2026-06-04'),
});

View file

@ -0,0 +1,115 @@
function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function toPascalCase(str: string): string {
return str
.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
.replace(/^./, s => s.toUpperCase());
}
function inferTsType(value: unknown, name: string, interfaces: Map<string, string>): string {
if (value === null) {
return 'null';
}
switch (typeof value) {
case 'string':
return 'string';
case 'number':
return 'number';
case 'boolean':
return 'boolean';
default:
break;
}
if (Array.isArray(value)) {
if (value.length === 0) {
return 'unknown[]';
}
const elementTypes = new Set(value.map(item => inferTsType(item, `${name}Item`, interfaces)));
const uniqueTypes = [...elementTypes];
if (uniqueTypes.length === 1) {
return `${uniqueTypes[0]}[]`;
}
return `(${uniqueTypes.join(' | ')})[]`;
}
if (typeof value === 'object') {
const interfaceName = capitalize(toPascalCase(name));
const entries = Object.entries(value as Record<string, unknown>);
const fields = entries.map(([key, val]) => {
const type = inferTsType(val, key, interfaces);
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `'${key}'`;
return ` ${safeKey}: ${type};`;
});
interfaces.set(interfaceName, `interface ${interfaceName} {\n${fields.join('\n')}\n}`);
return interfaceName;
}
return 'unknown';
}
export function jsonToTypeScript(json: unknown, rootName: string = 'RootType'): string {
const interfaces = new Map<string, string>();
inferTsType(json, rootName, interfaces);
if (interfaces.size === 0) {
const simpleType = inferTsType(json, rootName, interfaces);
return `type ${toPascalCase(rootName)} = ${simpleType};`;
}
return [...interfaces.values()].reverse().join('\n\n');
}
function inferGoType(value: unknown, name: string, structs: Map<string, string>): string {
if (value === null) {
return 'interface{}';
}
switch (typeof value) {
case 'string':
return 'string';
case 'number':
return Number.isInteger(value) ? 'int64' : 'float64';
case 'boolean':
return 'bool';
default:
break;
}
if (Array.isArray(value)) {
if (value.length === 0) {
return '[]interface{}';
}
const elementType = inferGoType(value[0], `${name}Item`, structs);
return `[]${elementType}`;
}
if (typeof value === 'object') {
const structName = toPascalCase(name);
const entries = Object.entries(value as Record<string, unknown>);
const fields = entries.map(([key, val]) => {
const goType = inferGoType(val, key, structs);
const fieldName = toPascalCase(key);
return `\t${fieldName} ${goType} \`json:"${key}"\``;
});
structs.set(structName, `type ${structName} struct {\n${fields.join('\n')}\n}`);
return structName;
}
return 'interface{}';
}
export function jsonToGoStruct(json: unknown, rootName: string = 'RootType'): string {
const structs = new Map<string, string>();
inferGoType(json, rootName, structs);
if (structs.size === 0) {
const simpleType = inferGoType(json, rootName, structs);
return `type ${toPascalCase(rootName)} ${simpleType}`;
}
return [...structs.values()].reverse().join('\n\n');
}

View file

@ -0,0 +1,64 @@
<script setup lang="ts">
import JSON5 from 'json5';
import { jsonToGoStruct, jsonToTypeScript } from './json-to-types.service';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
import { useStyleStore } from '@/stores/style.store';
import { withDefaultOnError } from '@/utils/defaults';
const styleStore = useStyleStore();
const languages = [
{ label: 'TypeScript', value: 'typescript' },
{ label: 'Go', value: 'go' },
] as { label: string; value: string }[];
const selectedLanguage = ref('typescript');
const rootName = ref('RootType');
const inputJson = ref('{\n "name": "John",\n "age": 30,\n "active": true,\n "tags": ["admin", "user"],\n "address": {\n "street": "123 Main St",\n "city": "Springfield"\n }\n}');
const output = computed(() =>
withDefaultOnError(() => {
const parsed = JSON5.parse(inputJson.value);
if (selectedLanguage.value === 'go') {
return jsonToGoStruct(parsed, rootName.value || 'RootType');
}
return jsonToTypeScript(parsed, rootName.value || 'RootType');
}, ''),
);
const outputLanguage = computed(() => selectedLanguage.value === 'go' ? 'go' : 'typescript');
</script>
<template>
<div style="flex: 0 0 100%">
<div style="max-width: 600px" :class="{ 'flex-col': styleStore.isSmallScreen }" mx-auto mb-5 flex gap-2>
<c-select
v-model:value="selectedLanguage"
label="Target language"
style="flex: 1"
:options="languages"
/>
<c-input-text
v-model:value="rootName"
label="Root type name"
placeholder="RootType"
style="flex: 1"
/>
</div>
</div>
<n-form-item label="Your JSON">
<c-input-text
v-model:value="inputJson"
placeholder="Paste your JSON here..."
rows="15"
multiline
monospace
raw-text
/>
</n-form-item>
<n-form-item label="Generated types">
<TextareaCopyable :value="output" :language="outputLanguage" />
</n-form-item>
</template>

View file

@ -102,6 +102,7 @@ export default defineConfig({
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@vueuse/shared': fileURLToPath(new URL('./node_modules/@vueuse/shared/index.mjs', import.meta.url)),
},
},
define: {