feat: Implement data storage unit conversion functionality (#848)
This commit is contained in:
		
							parent
							
								
									d3b32cc14e
								
							
						
					
					
						commit
						2b6b523be6
					
				
							
								
								
									
										31
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -64,6 +64,7 @@ declare module '@vue/runtime-core' { | |||||||
|     'CTextCopyable.demo': typeof import('./src/ui/c-text-copyable/c-text-copyable.demo.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: typeof import('./src/ui/c-tooltip/c-tooltip.vue')['default'] | ||||||
|     'CTooltip.demo': typeof import('./src/ui/c-tooltip/c-tooltip.demo.vue')['default'] |     'CTooltip.demo': typeof import('./src/ui/c-tooltip/c-tooltip.demo.vue')['default'] | ||||||
|  |     DataStorageUnitConverter: typeof import('./src/tools/data-storage-unit-converter/data-storage-unit-converter.vue')['default'] | ||||||
|     DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.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'] |     'DemoHome.page': typeof import('./src/ui/demo/demo-home.page.vue')['default'] | ||||||
|     DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'] |     DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default'] | ||||||
| @ -89,17 +90,28 @@ declare module '@vue/runtime-core' { | |||||||
|     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'] | ||||||
|     IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] |     IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] | ||||||
|     'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] |     'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] | ||||||
|  |     'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default'] | ||||||
|     'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] |     'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] | ||||||
|  |     IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default'] | ||||||
|  |     IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] | ||||||
|  |     IconMdiCamera: typeof import('~icons/mdi/camera')['default'] | ||||||
|     IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] |     IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] | ||||||
|     IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] |     IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] | ||||||
|     IconMdiClose: typeof import('~icons/mdi/close')['default'] |     IconMdiClose: typeof import('~icons/mdi/close')['default'] | ||||||
|     IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] |     IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] | ||||||
|  |     IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default'] | ||||||
|  |     IconMdiDownload: typeof import('~icons/mdi/download')['default'] | ||||||
|     IconMdiEye: typeof import('~icons/mdi/eye')['default'] |     IconMdiEye: typeof import('~icons/mdi/eye')['default'] | ||||||
|     IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] |     IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] | ||||||
|     IconMdiHeart: typeof import('~icons/mdi/heart')['default'] |     IconMdiHeart: typeof import('~icons/mdi/heart')['default'] | ||||||
|  |     IconMdiPause: typeof import('~icons/mdi/pause')['default'] | ||||||
|  |     IconMdiPlay: typeof import('~icons/mdi/play')['default'] | ||||||
|  |     IconMdiRecord: typeof import('~icons/mdi/record')['default'] | ||||||
|  |     IconMdiRefresh: typeof import('~icons/mdi/refresh')['default'] | ||||||
|     IconMdiSearch: typeof import('~icons/mdi/search')['default'] |     IconMdiSearch: typeof import('~icons/mdi/search')['default'] | ||||||
|     IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] |     IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] | ||||||
|     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] |     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] | ||||||
|  |     IconMdiVideo: typeof import('~icons/mdi/video')['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'] | ||||||
| @ -126,25 +138,41 @@ declare module '@vue/runtime-core' { | |||||||
|     MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] |     MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] | ||||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] |     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] | ||||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] |     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||||
|  |     NAlert: typeof import('naive-ui')['NAlert'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|  |     NCheckbox: typeof import('naive-ui')['NCheckbox'] | ||||||
|     NCode: typeof import('naive-ui')['NCode'] |     NCode: typeof import('naive-ui')['NCode'] | ||||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] |     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||||
|  |     NColorPicker: typeof import('naive-ui')['NColorPicker'] | ||||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] |     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||||
|  |     NDatePicker: typeof import('naive-ui')['NDatePicker'] | ||||||
|     NDivider: typeof import('naive-ui')['NDivider'] |     NDivider: typeof import('naive-ui')['NDivider'] | ||||||
|  |     NDynamicInput: typeof import('naive-ui')['NDynamicInput'] | ||||||
|     NEllipsis: typeof import('naive-ui')['NEllipsis'] |     NEllipsis: typeof import('naive-ui')['NEllipsis'] | ||||||
|  |     NForm: typeof import('naive-ui')['NForm'] | ||||||
|     NFormItem: typeof import('naive-ui')['NFormItem'] |     NFormItem: typeof import('naive-ui')['NFormItem'] | ||||||
|     NGi: typeof import('naive-ui')['NGi'] |     NGi: typeof import('naive-ui')['NGi'] | ||||||
|     NGrid: typeof import('naive-ui')['NGrid'] |     NGrid: typeof import('naive-ui')['NGrid'] | ||||||
|     NH1: typeof import('naive-ui')['NH1'] |     NH1: typeof import('naive-ui')['NH1'] | ||||||
|  |     NH2: typeof import('naive-ui')['NH2'] | ||||||
|     NH3: typeof import('naive-ui')['NH3'] |     NH3: typeof import('naive-ui')['NH3'] | ||||||
|     NIcon: typeof import('naive-ui')['NIcon'] |     NIcon: typeof import('naive-ui')['NIcon'] | ||||||
|  |     NImage: typeof import('naive-ui')['NImage'] | ||||||
|  |     NInputGroup: typeof import('naive-ui')['NInputGroup'] | ||||||
|  |     NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] | ||||||
|     NInputNumber: typeof import('naive-ui')['NInputNumber'] |     NInputNumber: typeof import('naive-ui')['NInputNumber'] | ||||||
|     NLabel: typeof import('naive-ui')['NLabel'] |  | ||||||
|     NLayout: typeof import('naive-ui')['NLayout'] |     NLayout: typeof import('naive-ui')['NLayout'] | ||||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] |     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||||
|     NMenu: typeof import('naive-ui')['NMenu'] |     NMenu: typeof import('naive-ui')['NMenu'] | ||||||
|  |     NProgress: typeof import('naive-ui')['NProgress'] | ||||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] |     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||||
|  |     NSelect: typeof import('naive-ui')['NSelect'] | ||||||
|  |     NSlider: typeof import('naive-ui')['NSlider'] | ||||||
|     NSpin: typeof import('naive-ui')['NSpin'] |     NSpin: typeof import('naive-ui')['NSpin'] | ||||||
|  |     NStatistic: typeof import('naive-ui')['NStatistic'] | ||||||
|  |     NSwitch: typeof import('naive-ui')['NSwitch'] | ||||||
|  |     NTable: typeof import('naive-ui')['NTable'] | ||||||
|  |     NTag: typeof import('naive-ui')['NTag'] | ||||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] |     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] | ||||||
|     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] |     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] | ||||||
|     PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] |     PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] | ||||||
| @ -159,6 +187,7 @@ declare module '@vue/runtime-core' { | |||||||
|     RouterLink: typeof import('vue-router')['RouterLink'] |     RouterLink: typeof import('vue-router')['RouterLink'] | ||||||
|     RouterView: typeof import('vue-router')['RouterView'] |     RouterView: typeof import('vue-router')['RouterView'] | ||||||
|     RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] |     RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] | ||||||
|  |     SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] | ||||||
|     SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] |     SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] | ||||||
|     SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] |     SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] | ||||||
|     SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] |     SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] | ||||||
|  | |||||||
| @ -340,6 +340,10 @@ tools: | |||||||
|     title: String obfuscator |     title: String obfuscator | ||||||
|     description: Obfuscate a string (like a secret, an IBAN, or a token) to make it shareable and identifiable without revealing its content. |     description: Obfuscate a string (like a secret, an IBAN, or a token) to make it shareable and identifiable without revealing its content. | ||||||
| 
 | 
 | ||||||
|  |   data-storage-unit-converter: | ||||||
|  |     title: Data storage unit converter | ||||||
|  |     description: Convert data storage units (bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes) | ||||||
|  | 
 | ||||||
|   base-converter: |   base-converter: | ||||||
|     title: Integer base converter |     title: Integer base converter | ||||||
|     description: Convert number between different bases (decimal, hexadecimal, binary, octal, base64, ...) |     description: Convert number between different bases (decimal, hexadecimal, binary, octal, base64, ...) | ||||||
|  | |||||||
| @ -336,6 +336,10 @@ tools: | |||||||
|     title: 字符串混淆器 |     title: 字符串混淆器 | ||||||
|     description: 混淆字符串(如秘密、IBAN 或令牌),使其可共享和可识别,而不泄露其内容。 |     description: 混淆字符串(如秘密、IBAN 或令牌),使其可共享和可识别,而不泄露其内容。 | ||||||
| 
 | 
 | ||||||
|  |   data-storage-unit-converter: | ||||||
|  |     title: 数据存储单位转换器 | ||||||
|  |     description: 在不同数据存储单位(字节、千字节、兆字节、千兆字节、太字节、拍字节)之间转换数字 | ||||||
|  | 
 | ||||||
|   base-converter: |   base-converter: | ||||||
|     title: 整数基转换器 |     title: 整数基转换器 | ||||||
|     description: 在不同的基数(十进制、十六进制、二进制、八进制、base64…)之间转换数字 |     description: 在不同的基数(十进制、十六进制、二进制、八进制、base64…)之间转换数字 | ||||||
|  | |||||||
| @ -0,0 +1,10 @@ | |||||||
|  | export function convertStorage({ value, fromUnit, toUnit }: { value: number; fromUnit: string; toUnit: string }): string { | ||||||
|  |   const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; | ||||||
|  |   const factor = 1024; | ||||||
|  |   const fromIndex = units.indexOf(fromUnit); | ||||||
|  |   const toIndex = units.indexOf(toUnit); | ||||||
|  |   const exponent = fromIndex - toIndex; | ||||||
|  | 
 | ||||||
|  |   const result = value * factor ** exponent; | ||||||
|  |   return result.toString(); | ||||||
|  | } | ||||||
| @ -0,0 +1,98 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import InputCopyable from '../../components/InputCopyable.vue'; | ||||||
|  | import { convertStorage } from './data-storage-unit-converter.model'; | ||||||
|  | 
 | ||||||
|  | const inputProps = { | ||||||
|  |   'labelPosition': 'left', | ||||||
|  |   'labelWidth': '170px', | ||||||
|  |   'labelAlign': 'right', | ||||||
|  |   'readonly': true, | ||||||
|  |   'mb-2': '', | ||||||
|  | } as const; | ||||||
|  | 
 | ||||||
|  | const input = ref('1024'); | ||||||
|  | const inputUnit = ref('KB'); | ||||||
|  | 
 | ||||||
|  | function errorlessConvert(...args: Parameters<typeof convertStorage>) { | ||||||
|  |   try { | ||||||
|  |     return convertStorage(...args); | ||||||
|  |   } | ||||||
|  |   catch (err) { | ||||||
|  |     return ''; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <c-card> | ||||||
|  |       <c-input-text v-model:value="input" :min="0" label="Input number" placeholder="Put your number here (ex: 1024)" label-position="left" label-width="110px" mb-2 label-align="right" /> | ||||||
|  | 
 | ||||||
|  |       <n-form-item label="Input unit" label-placement="left" label-width="110" :show-feedback="false"> | ||||||
|  |         <n-select | ||||||
|  |           v-model:value="inputUnit" | ||||||
|  |           :options="[ | ||||||
|  |             { label: 'Bytes', value: 'B' }, | ||||||
|  |             { label: 'Kilobytes', value: 'KB' }, | ||||||
|  |             { label: 'Megabytes', value: 'MB' }, | ||||||
|  |             { label: 'Gigabytes', value: 'GB' }, | ||||||
|  |             { label: 'Terabytes', value: 'TB' }, | ||||||
|  |             { label: 'Petabytes', value: 'PB' }, | ||||||
|  |           ]" | ||||||
|  |           placeholder="Select unit" | ||||||
|  |           w-full | ||||||
|  |         /> | ||||||
|  |       </n-form-item> | ||||||
|  | 
 | ||||||
|  |       <n-divider /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="Bytes" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'B' })" | ||||||
|  |         placeholder="Bytes will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="KB" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'KB' })" | ||||||
|  |         placeholder="Kilobytes will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="MB" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'MB' })" | ||||||
|  |         placeholder="Megabytes will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="GB" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'GB' })" | ||||||
|  |         placeholder="Gigabytes will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="TB" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'TB' })" | ||||||
|  |         placeholder="Terabytes will be here..." | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <InputCopyable | ||||||
|  |         label="PB" | ||||||
|  |         v-bind="inputProps" | ||||||
|  |         :value="errorlessConvert({ value: Number(input), fromUnit: inputUnit, toUnit: 'PB' })" | ||||||
|  |         placeholder="Petabytes will be here..." | ||||||
|  |       /> | ||||||
|  |     </c-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style lang="less" scoped> | ||||||
|  | .n-input-group:not(:first-child) { | ||||||
|  |   margin-top: 5px; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										12
									
								
								src/tools/data-storage-unit-converter/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/data-storage-unit-converter/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { ArrowsLeftRight } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: translate('tools.data-storage-unit-converter.title'), | ||||||
|  |   path: '/data-storage-unit-converter', | ||||||
|  |   description: translate('tools.data-storage-unit-converter.description'), | ||||||
|  |   keywords: ['data', 'storage', 'unit', 'conversion', 'bytes', 'KB', 'MB', 'GB', 'TB', 'PB'], | ||||||
|  |   component: () => import('./data-storage-unit-converter.vue'), | ||||||
|  |   icon: ArrowsLeftRight, | ||||||
|  | }); | ||||||
| @ -57,6 +57,7 @@ import { tool as gitMemo } from './git-memo'; | |||||||
| import { tool as hashText } from './hash-text'; | import { tool as hashText } from './hash-text'; | ||||||
| import { tool as hmacGenerator } from './hmac-generator'; | import { tool as hmacGenerator } from './hmac-generator'; | ||||||
| import { tool as htmlEntities } from './html-entities'; | import { tool as htmlEntities } from './html-entities'; | ||||||
|  | import { tool as storageUnitConverter } from './data-storage-unit-converter'; | ||||||
| import { tool as baseConverter } from './integer-base-converter'; | import { tool as baseConverter } from './integer-base-converter'; | ||||||
| import { tool as jsonViewer } from './json-viewer'; | import { tool as jsonViewer } from './json-viewer'; | ||||||
| import { tool as jwtParser } from './jwt-parser'; | import { tool as jwtParser } from './jwt-parser'; | ||||||
| @ -92,6 +93,7 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|     components: [ |     components: [ | ||||||
|       dateTimeConverter, |       dateTimeConverter, | ||||||
|       baseConverter, |       baseConverter, | ||||||
|  |       storageUnitConverter, | ||||||
|       romanNumeralConverter, |       romanNumeralConverter, | ||||||
|       base64StringConverter, |       base64StringConverter, | ||||||
|       base64FileConverter, |       base64FileConverter, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user