125 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script setup lang="ts">
 | |
| import { Netmask } from 'netmask';
 | |
| import { useStorage } from '@vueuse/core';
 | |
| import { IconArrowLeft, IconArrowRight } from '@tabler/icons-vue';
 | |
| import { getIPClass } from './ipv4-subnet-calculator.models';
 | |
| import { withDefaultOnError } from '@/utils/defaults';
 | |
| import { isNotThrowing } from '@/utils/boolean';
 | |
| import SpanCopyable from '@/components/SpanCopyable.vue';
 | |
| 
 | |
| const ip = useStorage('ipv4-subnet-calculator:ip', '192.168.0.1/24');
 | |
| 
 | |
| const getNetworkInfo = (address: string) => new Netmask(address.trim());
 | |
| 
 | |
| const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined));
 | |
| 
 | |
| const ipValidationRules = [
 | |
|   {
 | |
|     message: 'We cannot parse this address, check the format',
 | |
|     validator: (value: string) => isNotThrowing(() => getNetworkInfo(value.trim())),
 | |
|   },
 | |
| ];
 | |
| 
 | |
| const sections: {
 | |
|   label: string
 | |
|   getValue: (blocks: Netmask) => string | undefined
 | |
|   undefinedFallback?: string
 | |
| }[] = [
 | |
|   {
 | |
|     label: 'Netmask',
 | |
|     getValue: block => block.toString(),
 | |
|   },
 | |
|   {
 | |
|     label: 'Network address',
 | |
|     getValue: ({ base }) => base,
 | |
|   },
 | |
|   {
 | |
|     label: 'Network mask',
 | |
|     getValue: ({ mask }) => mask,
 | |
|   },
 | |
|   {
 | |
|     label: 'Network mask in binary',
 | |
|     getValue: ({ bitmask }) => ('1'.repeat(bitmask) + '0'.repeat(32 - bitmask)).match(/.{8}/g)?.join('.') ?? '',
 | |
|   },
 | |
|   {
 | |
|     label: 'CIDR notation',
 | |
|     getValue: ({ bitmask }) => `/${bitmask}`,
 | |
|   },
 | |
|   {
 | |
|     label: 'Wildcard mask',
 | |
|     getValue: ({ hostmask }) => hostmask,
 | |
|   },
 | |
|   {
 | |
|     label: 'Network size',
 | |
|     getValue: ({ size }) => String(size),
 | |
|   },
 | |
|   {
 | |
|     label: 'First address',
 | |
|     getValue: ({ first }) => first,
 | |
|   },
 | |
|   {
 | |
|     label: 'Last address',
 | |
|     getValue: ({ last }) => last,
 | |
|   },
 | |
|   {
 | |
|     label: 'Broadcast address',
 | |
|     getValue: ({ broadcast }) => broadcast,
 | |
|     undefinedFallback: 'No broadcast address with this mask',
 | |
|   },
 | |
|   {
 | |
|     label: 'IP class',
 | |
|     getValue: ({ base: ip }) => getIPClass({ ip }),
 | |
|     undefinedFallback: 'Unknown class type',
 | |
|   },
 | |
| ];
 | |
| 
 | |
| function switchToBlock({ count = 1 }: { count?: number }) {
 | |
|   const next = networkInfo.value?.next(count);
 | |
| 
 | |
|   if (next) {
 | |
|     ip.value = next.toString();
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <div>
 | |
|     <c-input-text
 | |
|       v-model:value="ip"
 | |
|       label="An IPv4 address with or without mask"
 | |
|       placeholder="The ipv4 address..."
 | |
|       :validation-rules="ipValidationRules"
 | |
|       mb-4
 | |
|     />
 | |
| 
 | |
|     <div v-if="networkInfo">
 | |
|       <n-table>
 | |
|         <tbody>
 | |
|           <tr v-for="{ getValue, label, undefinedFallback } in sections" :key="label">
 | |
|             <td font-bold>
 | |
|               {{ label }}
 | |
|             </td>
 | |
|             <td>
 | |
|               <SpanCopyable v-if="getValue(networkInfo)" :value="getValue(networkInfo)" />
 | |
|               <span v-else op-70>
 | |
|                 {{ undefinedFallback }}
 | |
|               </span>
 | |
|             </td>
 | |
|           </tr>
 | |
|         </tbody>
 | |
|       </n-table>
 | |
| 
 | |
|       <div mt-3 flex items-center justify-between>
 | |
|         <c-button @click="switchToBlock({ count: -1 })">
 | |
|           <IconArrowLeft size="15" />
 | |
|           Previous block
 | |
|         </c-button>
 | |
|         <c-button @click="switchToBlock({ count: 1 })">
 | |
|           Next block
 | |
|           <IconArrowRight size="15" />
 | |
|         </c-button>
 | |
|       </div>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 |