feature: add border generator module.
This commit is contained in:
		
							parent
							
								
									87984e2081
								
							
						
					
					
						commit
						52df553294
					
				
							
								
								
									
										15
									
								
								src/tools/border-generator/border-generator.e2e.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/tools/border-generator/border-generator.e2e.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | import { test, expect } from '@playwright/test'; | ||||||
|  | 
 | ||||||
|  | test.describe('Tool - Border generator', () => { | ||||||
|  |   test.beforeEach(async ({ page }) => { | ||||||
|  |     await page.goto('/border-generator'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   test('Has correct title', async ({ page }) => { | ||||||
|  |     await expect(page).toHaveTitle('Border generator - IT Tools'); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   test('', async ({ page }) => { | ||||||
|  | 
 | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | import { expect, describe, it } from 'vitest'; | ||||||
|  | // import { } from './border-generator.service';
 | ||||||
|  | //
 | ||||||
|  | // describe('border-generator', () => {
 | ||||||
|  | //
 | ||||||
|  | // })
 | ||||||
							
								
								
									
										15
									
								
								src/tools/border-generator/border-generator.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/tools/border-generator/border-generator.service.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | export interface Border { | ||||||
|  |   label: string; | ||||||
|  |   value: number; | ||||||
|  |   max: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface Borders { | ||||||
|  |   [key: string]: Border; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Asegúrate de que esta función esté correctamente exportada
 | ||||||
|  | export function generateCSSOutput(borders: Borders, borderWidth: number, borderStyle: string, unit: string): string { | ||||||
|  |   const { topLeft, topRight, bottomRight, bottomLeft } = borders; | ||||||
|  |   return `border: ${borderWidth}px ${borderStyle} #000000; border-radius: ${topLeft.value}${unit} ${topRight.value}${unit} ${bottomRight.value}${unit} ${bottomLeft.value}${unit};`; | ||||||
|  | } | ||||||
							
								
								
									
										214
									
								
								src/tools/border-generator/border-generator.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/tools/border-generator/border-generator.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,214 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="container"> | ||||||
|  |     <div class="square" :style="styleObject"></div> | ||||||
|  | 
 | ||||||
|  |     <n-card title="Border Radius and Style Editor" class="controls"> | ||||||
|  |       <n-form> | ||||||
|  |         <n-form-item label="Units"> | ||||||
|  |           <n-select v-model:value="unit" :options="unitOptions" @update:value="updateCSSOutput" /> | ||||||
|  |         </n-form-item> | ||||||
|  | 
 | ||||||
|  |         <div class="radius-controls"> | ||||||
|  |           <n-form-item label="Top Left" class="half-slider"> | ||||||
|  |             <n-slider | ||||||
|  |               :min="0" | ||||||
|  |               :max="borders.topLeft.max" | ||||||
|  |               v-model:value="borders.topLeft.value" | ||||||
|  |               @update:value="updateCSSOutput" | ||||||
|  |               :step="1" | ||||||
|  |             /> | ||||||
|  |             <span>{{ borders.topLeft.value + unit }}</span> | ||||||
|  |           </n-form-item> | ||||||
|  |           <n-form-item label="Top Right" class="half-slider"> | ||||||
|  |             <n-slider | ||||||
|  |               :min="0" | ||||||
|  |               :max="borders.topRight.max" | ||||||
|  |               v-model:value="borders.topRight.value" | ||||||
|  |               @update:value="updateCSSOutput" | ||||||
|  |               :step="1" | ||||||
|  |             /> | ||||||
|  |             <span>{{ borders.topRight.value + unit }}</span> | ||||||
|  |           </n-form-item> | ||||||
|  |         </div> | ||||||
|  |         <div class="radius-controls"> | ||||||
|  |           <n-form-item label="Bottom Left" class="half-slider"> | ||||||
|  |             <n-slider | ||||||
|  |               :min="0" | ||||||
|  |               :max="borders.bottomLeft.max" | ||||||
|  |               v-model:value="borders.bottomLeft.value" | ||||||
|  |               @update:value="updateCSSOutput" | ||||||
|  |               :step="1" | ||||||
|  |             /> | ||||||
|  |             <span>{{ borders.bottomLeft.value + unit }}</span> | ||||||
|  |           </n-form-item> | ||||||
|  |           <n-form-item label="Bottom Right" class="half-slider"> | ||||||
|  |             <n-slider | ||||||
|  |               :min="0" | ||||||
|  |               :max="borders.bottomRight.max" | ||||||
|  |               v-model:value="borders.bottomRight.value" | ||||||
|  |               @update:value="updateCSSOutput" | ||||||
|  |               :step="1" | ||||||
|  |             /> | ||||||
|  |             <span>{{ borders.bottomRight.value + unit }}</span> | ||||||
|  |           </n-form-item> | ||||||
|  |         </div> | ||||||
|  |         <div class="border-controls"> | ||||||
|  |           <n-form-item label="Border Width" class="border-width-slider"> | ||||||
|  |             <n-slider :min="0" :max="100" v-model:value="borderWidth" @update:value="updateCSSOutput" :step="1" /> | ||||||
|  |             <span>{{ borderWidth + 'px' }}</span> | ||||||
|  |           </n-form-item> | ||||||
|  |           <n-form-item label="Border Style" class="border-style-select"> | ||||||
|  |             <n-select v-model:value="borderStyle" :options="borderStyles" @update:value="updateCSSOutput" /> | ||||||
|  |           </n-form-item> | ||||||
|  |         </div> | ||||||
|  | 
 | ||||||
|  |         <n-form-item label="Border Color"> | ||||||
|  |           <n-color-picker v-model:value="borderColor" @update:value="updateCSSOutput" /> | ||||||
|  |         </n-form-item> | ||||||
|  | 
 | ||||||
|  |         <n-form-item label="CSS Properties"> | ||||||
|  |           <TextareaCopyable :value="cssOutput" language="css" /> | ||||||
|  |         </n-form-item> | ||||||
|  |       </n-form> | ||||||
|  |     </n-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts"> | ||||||
|  | import { defineComponent, ref, computed } from 'vue'; | ||||||
|  | import { NSlider, NForm, NFormItem, NSelect, NCard, NColorPicker } from 'naive-ui'; | ||||||
|  | import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||||
|  | import { Borders } from './border-radius-viewer.service'; | ||||||
|  | 
 | ||||||
|  | export default defineComponent({ | ||||||
|  |   name: 'BorderRadiusViewer', | ||||||
|  |   components: { | ||||||
|  |     NSlider, | ||||||
|  |     NForm, | ||||||
|  |     NFormItem, | ||||||
|  |     NSelect, | ||||||
|  |     NCard, | ||||||
|  |     NColorPicker, | ||||||
|  |     TextareaCopyable, | ||||||
|  |   }, | ||||||
|  |   setup() { | ||||||
|  |     const borders = ref<Borders>({ | ||||||
|  |       topLeft: { label: 'Top Left', value: 0, max: 100 }, | ||||||
|  |       topRight: { label: 'Top Right', value: 0, max: 100 }, | ||||||
|  |       bottomLeft: { label: 'Bottom Left', value: 0, max: 100 }, | ||||||
|  |       bottomRight: { label: 'Bottom Right', value: 0, max: 100 }, | ||||||
|  |     }); | ||||||
|  |     const unit = ref('px'); | ||||||
|  |     const borderWidth = ref<number>(0); | ||||||
|  |     const borderStyle = ref('solid'); | ||||||
|  |     const borderColor = ref('#000000'); | ||||||
|  |     const unitOptions = [ | ||||||
|  |       { label: 'Pixels (px)', value: 'px' }, | ||||||
|  |       { label: 'Percentage (%)', value: '%' }, | ||||||
|  |     ]; | ||||||
|  |     const borderStyles = [ | ||||||
|  |       { label: 'Solid', value: 'solid' }, | ||||||
|  |       { label: 'Dashed', value: 'dashed' }, | ||||||
|  |       { label: 'Dotted', value: 'dotted' }, | ||||||
|  |       { label: 'Double', value: 'double' }, | ||||||
|  |       { label: 'Groove', value: 'groove' }, | ||||||
|  |       { label: 'Ridge', value: 'ridge' }, | ||||||
|  |       { label: 'Inset', value: 'inset' }, | ||||||
|  |       { label: 'Outset', value: 'outset' }, | ||||||
|  |       { label: 'None', value: 'none' }, | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     const styleObject = computed(() => ({ | ||||||
|  |       border: `${borderWidth.value}px ${borderStyle.value} ${borderColor.value}`, | ||||||
|  |       borderRadius: `${borders.value.topLeft.value}${unit.value} ${borders.value.topRight.value}${unit.value} ${borders.value.bottomRight.value}${unit.value} ${borders.value.bottomLeft.value}${unit.value}`, | ||||||
|  |     })); | ||||||
|  | 
 | ||||||
|  |     const cssOutput = computed( | ||||||
|  |       () => | ||||||
|  |         `border: ${borderWidth.value}px ${borderStyle.value} ${borderColor.value};\nborder-radius: ${borders.value.topLeft.value}${unit.value} ${borders.value.topRight.value}${unit.value} ${borders.value.bottomRight.value}${unit.value} ${borders.value.bottomLeft.value}${unit.value};`, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     function updateCSSOutput() { | ||||||
|  |       // Forces update computed properties | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |       borders, | ||||||
|  |       unit, | ||||||
|  |       borderWidth, | ||||||
|  |       borderStyle, | ||||||
|  |       borderColor, | ||||||
|  |       unitOptions, | ||||||
|  |       borderStyles, | ||||||
|  |       cssOutput, | ||||||
|  |       updateCSSOutput, | ||||||
|  |       styleObject, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | <style scoped> | ||||||
|  | .container { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   gap: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .square { | ||||||
|  |   width: 250px; | ||||||
|  |   height: 250px; | ||||||
|  |   background-color: #f3f3f3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .controls { | ||||||
|  |   width: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .radius-controls, | ||||||
|  | .border-controls { | ||||||
|  |   display: flex; | ||||||
|  |   justify-content: space-around; | ||||||
|  |   align-items: center; | ||||||
|  |   gap: 20px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .half-slider, | ||||||
|  | .border-width-slider { | ||||||
|  |   position: relative; | ||||||
|  |   padding: 10px 0; | ||||||
|  |   width: 60%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .half-slider span, | ||||||
|  | .border-width-slider span { | ||||||
|  |   position: absolute; | ||||||
|  |   right: 0; | ||||||
|  |   top: 30px; | ||||||
|  |   background-color: #fff; | ||||||
|  |   padding: 2px 6px; | ||||||
|  |   border-radius: 5px; | ||||||
|  |   font-size: 0.9em; | ||||||
|  |   color: #333; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .border-style-select { | ||||||
|  |   width: 30%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | n-slider { | ||||||
|  |   width: calc(100% - 60px); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .controls .n-form-item__label { | ||||||
|  |   min-width: 70px; | ||||||
|  |   text-align: right; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | n-select, | ||||||
|  | n-color-picker { | ||||||
|  |   width: 100%; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | 
 | ||||||
							
								
								
									
										13
									
								
								src/tools/border-generator/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/tools/border-generator/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | import { Square } from '@vicons/tabler'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'Border Generator', | ||||||
|  |   path: '/border-radius-viewer', | ||||||
|  |   description: 'Generate a complete CSS border properties.', | ||||||
|  |   keywords: ['border', 'radius', 'viewer'], | ||||||
|  |   component: () => import('./border-radius-viewer.vue'), | ||||||
|  |   icon: Square, | ||||||
|  |   createdAt: new Date('2024-09-06'), | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| @ -1,6 +1,7 @@ | |||||||
| import { tool as base64FileConverter } from './base64-file-converter'; | import { tool as base64FileConverter } from './base64-file-converter'; | ||||||
| import { tool as base64StringConverter } from './base64-string-converter'; | import { tool as base64StringConverter } from './base64-string-converter'; | ||||||
| import { tool as basicAuthGenerator } from './basic-auth-generator'; | import { tool as basicAuthGenerator } from './basic-auth-generator'; | ||||||
|  | import { tool as borderGenerator } from './border-generator'; | ||||||
| import { tool as emailNormalizer } from './email-normalizer'; | import { tool as emailNormalizer } from './email-normalizer'; | ||||||
| 
 | 
 | ||||||
| import { tool as asciiTextDrawer } from './ascii-text-drawer'; | import { tool as asciiTextDrawer } from './ascii-text-drawer'; | ||||||
| @ -89,7 +90,19 @@ import { tool as yamlViewer } from './yaml-viewer'; | |||||||
| export const toolsByCategory: ToolCategory[] = [ | export const toolsByCategory: ToolCategory[] = [ | ||||||
|   { |   { | ||||||
|     name: 'Crypto', |     name: 'Crypto', | ||||||
|     components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker], |     components: [ | ||||||
|  |       tokenGenerator, | ||||||
|  |       hashText, | ||||||
|  |       bcrypt, | ||||||
|  |       uuidGenerator, | ||||||
|  |       ulidGenerator, | ||||||
|  |       cypher, | ||||||
|  |       bip39, | ||||||
|  |       hmacGenerator, | ||||||
|  |       rsaKeyPairGenerator, | ||||||
|  |       passwordStrengthAnalyser, | ||||||
|  |       pdfSignatureChecker, | ||||||
|  |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Converter', |     name: 'Converter', | ||||||
| @ -135,6 +148,7 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|       httpStatusCodes, |       httpStatusCodes, | ||||||
|       jsonDiff, |       jsonDiff, | ||||||
|       safelinkDecoder, |       safelinkDecoder, | ||||||
|  |       borderGenerator, | ||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
| @ -160,7 +174,14 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Network', |     name: 'Network', | ||||||
|     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], |     components: [ | ||||||
|  |       ipv4SubnetCalculator, | ||||||
|  |       ipv4AddressConverter, | ||||||
|  |       ipv4RangeExpander, | ||||||
|  |       macAddressLookup, | ||||||
|  |       macAddressGenerator, | ||||||
|  |       ipv6UlaGenerator, | ||||||
|  |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Math', |     name: 'Math', | ||||||
| @ -190,5 +211,5 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
| 
 | 
 | ||||||
| export const tools = toolsByCategory.flatMap(({ components }) => components); | export const tools = toolsByCategory.flatMap(({ components }) => components); | ||||||
| export const toolsWithCategory = toolsByCategory.flatMap(({ components, name }) => | export const toolsWithCategory = toolsByCategory.flatMap(({ components, name }) => | ||||||
|   components.map(tool => ({ category: name, ...tool })), |   components.map((tool) => ({ category: name, ...tool })), | ||||||
| ); | ); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user