Merge 65e137d276 into 07eea0f484
				
					
				
			This commit is contained in:
		
						commit
						a5691306c5
					
				
							
								
								
									
										9
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -130,19 +130,23 @@ declare module '@vue/runtime-core' { | |||||||
|     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'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|     NCheckbox: typeof import('naive-ui')['NCheckbox'] |  | ||||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] |     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||||
|     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'] | ||||||
|  |     NFormItem: typeof import('naive-ui')['NFormItem'] | ||||||
|     NH1: typeof import('naive-ui')['NH1'] |     NH1: typeof import('naive-ui')['NH1'] | ||||||
|     NH3: typeof import('naive-ui')['NH3'] |     NH3: typeof import('naive-ui')['NH3'] | ||||||
|     NIcon: typeof import('naive-ui')['NIcon'] |     NIcon: typeof import('naive-ui')['NIcon'] | ||||||
|  |     NInput: typeof import('naive-ui')['NInput'] | ||||||
|     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'] | ||||||
|  |     NSelect: typeof import('naive-ui')['NSelect'] | ||||||
|     NSpace: typeof import('naive-ui')['NSpace'] |     NSpace: typeof import('naive-ui')['NSpace'] | ||||||
|     NTable: typeof import('naive-ui')['NTable'] |     NSwitch: typeof import('naive-ui')['NSwitch'] | ||||||
|     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'] | ||||||
| @ -173,6 +177,7 @@ declare module '@vue/runtime-core' { | |||||||
|     TextToBinary: typeof import('./src/tools/text-to-binary/text-to-binary.vue')['default'] |     TextToBinary: typeof import('./src/tools/text-to-binary/text-to-binary.vue')['default'] | ||||||
|     TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default'] |     TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default'] | ||||||
|     TextToUnicode: typeof import('./src/tools/text-to-unicode/text-to-unicode.vue')['default'] |     TextToUnicode: typeof import('./src/tools/text-to-unicode/text-to-unicode.vue')['default'] | ||||||
|  |     TimezoneConverter: typeof import('./src/tools/timezone-converter/timezone-converter.vue')['default'] | ||||||
|     TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default'] |     TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default'] | ||||||
|     'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default'] |     'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default'] | ||||||
|     TomlToJson: typeof import('./src/tools/toml-to-json/toml-to-json.vue')['default'] |     TomlToJson: typeof import('./src/tools/toml-to-json/toml-to-json.vue')['default'] | ||||||
|  | |||||||
| @ -56,6 +56,7 @@ | |||||||
|     "change-case": "^4.1.2", |     "change-case": "^4.1.2", | ||||||
|     "colord": "^2.9.3", |     "colord": "^2.9.3", | ||||||
|     "composerize-ts": "^0.6.2", |     "composerize-ts": "^0.6.2", | ||||||
|  |     "countries-and-timezones": "^3.6.0", | ||||||
|     "country-code-lookup": "^0.1.0", |     "country-code-lookup": "^0.1.0", | ||||||
|     "cron-validator": "^1.3.1", |     "cron-validator": "^1.3.1", | ||||||
|     "cronstrue": "^2.26.0", |     "cronstrue": "^2.26.0", | ||||||
| @ -67,6 +68,7 @@ | |||||||
|     "figlet": "^1.7.0", |     "figlet": "^1.7.0", | ||||||
|     "figue": "^1.2.0", |     "figue": "^1.2.0", | ||||||
|     "fuse.js": "^6.6.2", |     "fuse.js": "^6.6.2", | ||||||
|  |     "get-timezone-offset": "^1.0.5", | ||||||
|     "highlight.js": "^11.7.0", |     "highlight.js": "^11.7.0", | ||||||
|     "iarna-toml-esm": "^3.0.5", |     "iarna-toml-esm": "^3.0.5", | ||||||
|     "ibantools": "^4.3.3", |     "ibantools": "^4.3.3", | ||||||
|  | |||||||
							
								
								
									
										14462
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14462
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -9,6 +9,7 @@ import { tool as textToUnicode } from './text-to-unicode'; | |||||||
| import { tool as safelinkDecoder } from './safelink-decoder'; | import { tool as safelinkDecoder } from './safelink-decoder'; | ||||||
| import { tool as xmlToJson } from './xml-to-json'; | import { tool as xmlToJson } from './xml-to-json'; | ||||||
| import { tool as jsonToXml } from './json-to-xml'; | import { tool as jsonToXml } from './json-to-xml'; | ||||||
|  | import { tool as timezoneConverter } from './timezone-converter'; | ||||||
| import { tool as regexTester } from './regex-tester'; | import { tool as regexTester } from './regex-tester'; | ||||||
| import { tool as regexMemo } from './regex-memo'; | import { tool as regexMemo } from './regex-memo'; | ||||||
| import { tool as markdownToHtml } from './markdown-to-html'; | import { tool as markdownToHtml } from './markdown-to-html'; | ||||||
| @ -97,6 +98,7 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|     name: 'Converter', |     name: 'Converter', | ||||||
|     components: [ |     components: [ | ||||||
|       dateTimeConverter, |       dateTimeConverter, | ||||||
|  |       timezoneConverter, | ||||||
|       baseConverter, |       baseConverter, | ||||||
|       romanNumeralConverter, |       romanNumeralConverter, | ||||||
|       base64StringConverter, |       base64StringConverter, | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								src/tools/timezone-converter/get-timezone-offset.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/tools/timezone-converter/get-timezone-offset.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | declare module "get-timezone-offset" { | ||||||
|  |     export default function(timeZoneName: string, date: Date); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								src/tools/timezone-converter/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/timezone-converter/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | import { CalendarTime } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'Timezone Converter', | ||||||
|  |   path: '/timezone-converter', | ||||||
|  |   description: 'Convert Date-Time from a timezone to others and get timezone vs countries infos', | ||||||
|  |   keywords: ['timezone', 'tz', 'date', 'time', 'country', 'converter'], | ||||||
|  |   component: () => import('./timezone-converter.vue'), | ||||||
|  |   icon: CalendarTime, | ||||||
|  |   createdAt: new Date('2024-08-15'), | ||||||
|  | }); | ||||||
							
								
								
									
										141
									
								
								src/tools/timezone-converter/timezone-converter.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/tools/timezone-converter/timezone-converter.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import ctz from 'countries-and-timezones'; | ||||||
|  | import getTimezoneOffset from 'get-timezone-offset'; | ||||||
|  | 
 | ||||||
|  | const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||||||
|  | const allTimezones = Object.values(ctz.getAllTimezones()).map(tz => ({ | ||||||
|  |   value: tz.name, | ||||||
|  |   label: `${tz.name === browserTimezone ? 'Browser TZ - ' : ''}${tz.name} (${tz.utcOffset === tz.dstOffset ? tz.utcOffsetStr : `${tz.utcOffsetStr}/${tz.dstOffsetStr}`})`, | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | function convertMinsToHrsMins(minutes: number) { | ||||||
|  |   const h = String(Math.floor(minutes / 60)).padStart(2, '0'); | ||||||
|  |   const m = String(minutes % 60).padStart(2, '0'); | ||||||
|  |   return `${h}:${m}`; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const otherTimezones = useStorage<{ name: string }[]>('timezone-conv:zones', [{ name: 'Etc/GMT' }]); | ||||||
|  | const currentTimezone = useStorage<string>('timezone-conv:current', browserTimezone); | ||||||
|  | const use24HourTimeFormat = useStorage<boolean>('timezone-conv:24h', true); | ||||||
|  | const format = computed(() => use24HourTimeFormat.value ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd hh:mm:ss a'); | ||||||
|  | const timePickerProps = computed(() => use24HourTimeFormat.value ? ({ use12Hours: false }) : ({ use12Hours: true })); | ||||||
|  | 
 | ||||||
|  | const now = Date.now(); | ||||||
|  | const currentDatetimeRange = ref<[number, number]>([now, now]); | ||||||
|  | const currentTimezoneOffset = computed(() => { | ||||||
|  |   return convertMinsToHrsMins(-getTimezoneOffset(currentTimezone.value, new Date(currentDatetimeRange.value[0]))); | ||||||
|  | }); | ||||||
|  | function convertToTimezone(tz: string, timestamp: number) { | ||||||
|  |   return new Date( | ||||||
|  |     timestamp | ||||||
|  |     + getTimezoneOffset(currentTimezone.value, new Date()) * 60 * 1000 | ||||||
|  |     - getTimezoneOffset(browserTimezone, new Date()) * 60 * 1000, | ||||||
|  |   ).toLocaleString(undefined, | ||||||
|  |     { timeZone: tz, timeZoneName: undefined, hour12: !use24HourTimeFormat.value }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const tzToCountriesInput = ref(browserTimezone); | ||||||
|  | const tzToCountriesOutput = computed(() => ctz.getCountriesForTimezone(tzToCountriesInput.value)); | ||||||
|  | 
 | ||||||
|  | const allCountries = Object.values(ctz.getAllCountries()).map(c => ({ | ||||||
|  |   value: c.id, | ||||||
|  |   label: `${c.name} (${c.id})`, | ||||||
|  | })); | ||||||
|  | const countryToTimezonesInput = ref('FR'); | ||||||
|  | const countryToTimezonesOutput = computed(() => ctz.getTimezonesForCountry(countryToTimezonesInput.value)); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <c-card title="Timezones Date-Time Converter" mb-2> | ||||||
|  |       <c-select | ||||||
|  |         v-model:value="currentTimezone" | ||||||
|  |         label="Timezone" | ||||||
|  |         label-position="left" | ||||||
|  |         searchable | ||||||
|  |         :options="allTimezones" | ||||||
|  |         mb-2 | ||||||
|  |       /> | ||||||
|  |       <n-form-item label="Date/time interval to convert:" label-placement="top"> | ||||||
|  |         <n-date-picker | ||||||
|  |           :key="format" | ||||||
|  |           v-model:value="currentDatetimeRange" | ||||||
|  |           type="datetimerange" | ||||||
|  |           :format="format" | ||||||
|  |           :time-picker-props="timePickerProps" | ||||||
|  |           mb-2 | ||||||
|  |           w-full | ||||||
|  |         /> | ||||||
|  |       </n-form-item> | ||||||
|  | 
 | ||||||
|  |       <n-space justify="space-evenly"> | ||||||
|  |         <n-form-item label="Current Timezone Offset:" label-placement="left"> | ||||||
|  |           <n-input :value="currentTimezoneOffset" readonly style="width:5em" /> | ||||||
|  |         </n-form-item> | ||||||
|  |         <n-form-item label="Use 24 hour time format" label-placement="left"> | ||||||
|  |           <n-switch v-model:value="use24HourTimeFormat" /> | ||||||
|  |         </n-form-item> | ||||||
|  |       </n-space> | ||||||
|  | 
 | ||||||
|  |       <c-card title="Date-Time in other timezones"> | ||||||
|  |         <n-dynamic-input | ||||||
|  |           v-model:value="otherTimezones" | ||||||
|  |           show-sort-button | ||||||
|  |           :on-create="() => ({ name: browserTimezone })" | ||||||
|  |         > | ||||||
|  |           <template #default="{ value }"> | ||||||
|  |             <div flex flex-wrap items-center gap-1> | ||||||
|  |               <n-select | ||||||
|  |                 v-model:value="value.name" | ||||||
|  |                 filterable | ||||||
|  |                 placeholder="Please select a timezone" | ||||||
|  |                 :options="allTimezones" | ||||||
|  |                 w-full | ||||||
|  |               /> | ||||||
|  |               <div w-full flex items-baseline gap-1> | ||||||
|  |                 <n-input style="min-width: 49%" readonly :value="convertToTimezone(value.name, currentDatetimeRange[0])" /> | ||||||
|  |                 <n-input style="min-width: 49%" readonly :value="convertToTimezone(value.name, currentDatetimeRange[1])" /> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |         </n-dynamic-input> | ||||||
|  |       </c-card> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Country to Timezones" mb-2> | ||||||
|  |       <c-select | ||||||
|  |         v-model:value="countryToTimezonesInput" | ||||||
|  |         label="Country" | ||||||
|  |         label-position="left" | ||||||
|  |         searchable | ||||||
|  |         :options="allCountries" | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <n-divider /> | ||||||
|  | 
 | ||||||
|  |       <ul> | ||||||
|  |         <li v-for="(tz, ix) in countryToTimezonesOutput" :key="ix"> | ||||||
|  |           {{ tz.name }} ({{ tz.countries.join(', ') }}): UTC= {{ tz.utcOffsetStr }}, DST= {{ tz.dstOffsetStr }} | ||||||
|  |         </li> | ||||||
|  |       </ul> | ||||||
|  |     </c-card> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Timezones to Countries" mb-2> | ||||||
|  |       <c-select | ||||||
|  |         v-model:value="tzToCountriesInput" | ||||||
|  |         label="Timezone" | ||||||
|  |         label-position="left" | ||||||
|  |         searchable | ||||||
|  |         :options="allTimezones" | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <n-divider /> | ||||||
|  | 
 | ||||||
|  |       <ul> | ||||||
|  |         <li v-for="(country, ix) in tzToCountriesOutput" :key="ix"> | ||||||
|  |           {{ country.name }} ({{ country.id }}): {{ country.timezones.join(', ') }} | ||||||
|  |         </li> | ||||||
|  |       </ul> | ||||||
|  |     </c-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user