diff options
-rw-r--r-- | src/tools/index.ts | 8 | ||||
-rw-r--r-- | src/tools/svg-placeholder-generator/index.ts | 11 | ||||
-rw-r--r-- | src/tools/svg-placeholder-generator/svg-placeholder-generator.vue | 89 |
3 files changed, 107 insertions, 1 deletions
diff --git a/src/tools/index.ts b/src/tools/index.ts index 5a218f3..6f30200 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -25,6 +25,7 @@ import { tool as qrCodeGenerator } from './qr-code-generator'; import { tool as randomPortGenerator } from './random-port-generator'; import { tool as romanNumeralConverter } from './roman-numeral-converter'; import { tool as sqlPrettify } from './sql-prettify'; +import { tool as svgPlaceholderGenerator } from './svg-placeholder-generator'; import { tool as textStatistics } from './text-statistics'; import { tool as tokenGenerator } from './token-generator'; import { tool as urlEncoder } from './url-encoder'; @@ -53,7 +54,12 @@ export const toolsByCategory: ToolCategory[] = [ { name: 'Web', icon: LockOpen, - components: [urlEncoder, htmlEntities, qrCodeGenerator, urlParser, deviceInformation, basicAuthGenerator], + components: [urlEncoder, htmlEntities, urlParser, deviceInformation, basicAuthGenerator], + }, + { + name: 'Images', + icon: LockOpen, + components: [qrCodeGenerator, svgPlaceholderGenerator], }, { name: 'Development', diff --git a/src/tools/svg-placeholder-generator/index.ts b/src/tools/svg-placeholder-generator/index.ts new file mode 100644 index 0000000..d676294 --- /dev/null +++ b/src/tools/svg-placeholder-generator/index.ts @@ -0,0 +1,11 @@ +import { ImageOutlined } from '@vicons/material'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'SVG placeholder generator', + path: '/svg-placeholder-generator', + description: 'Generate svg images to use as placeholder in your applications.', + keywords: ['svg', 'placeholder', 'generator', 'image', 'size', 'mockup'], + component: () => import('./svg-placeholder-generator.vue'), + icon: ImageOutlined, +}); diff --git a/src/tools/svg-placeholder-generator/svg-placeholder-generator.vue b/src/tools/svg-placeholder-generator/svg-placeholder-generator.vue new file mode 100644 index 0000000..33c0f69 --- /dev/null +++ b/src/tools/svg-placeholder-generator/svg-placeholder-generator.vue @@ -0,0 +1,89 @@ +<template> + <div> + <n-form label-placement="left" label-width="100"> + <n-space item-style="flex:1 1 0"> + <n-form-item label="Width (in px)"> + <n-input-number v-model:value="width" placeholder="SVG width..." min="1" /> + </n-form-item> + <n-form-item label="Background"> + <n-color-picker v-model:value="bgColor" :modes="['hex']" /> + </n-form-item> + </n-space> + <n-space item-style="flex:1 1 0"> + <n-form-item label="Height (in px)"> + <n-input-number v-model:value="height" placeholder="SVG height..." min="1" /> + </n-form-item> + <n-form-item label="Text color"> + <n-color-picker v-model:value="fgColor" :modes="['hex']" /> + </n-form-item> + </n-space> + <n-space item-style="flex:1 1 0"> + <n-form-item label="Font size"> + <n-input-number v-model:value="fontSize" placeholder="Font size..." min="1" /> + </n-form-item> + <n-form-item label="Custom text"> + <n-input v-model:value="customText" :placeholder="`Default is ${width}x${height}`" /> + </n-form-item> + </n-space> + <n-form-item label="Use exact size" label-placement="left"> + <n-switch v-model:value="useExactSize" /> + </n-form-item> + </n-form> + + <n-form-item label="SVG HTML element"> + <textarea-copyable :value="svgString" copy-placement="none" /> + </n-form-item> + <n-form-item label="SVG in Base64"> + <textarea-copyable :value="base64" copy-placement="none" /> + </n-form-item> + + <n-space justify="center"> + <n-button secondary @click="copySVG()">Copy svg</n-button> + <n-button secondary @click="copyBase64()">Copy base64</n-button> + <n-button secondary @click="download()">Download svg</n-button> + </n-space> + </div> + + <n-space vertical justify="start"> + <img :src="base64" alt="Image" /> + </n-space> +</template> + +<script setup lang="ts"> +import TextareaCopyable from '@/components/TextareaCopyable.vue'; +import { useCopy } from '@/composable/copy'; +import { useDownloadFileFromBase64 } from '@/composable/downloadBase64.js'; +import { computed, ref } from 'vue'; + +const width = ref(600); +const height = ref(350); +const fontSize = ref(26); +const bgColor = ref('#cccccc'); +const fgColor = ref('#333333'); +const useExactSize = ref(true); +const customText = ref(''); +const svgString = computed(() => { + const w = width.value; + const h = height.value; + const text = customText.value.length > 0 ? customText.value : `${w}x${h}`; + const size = useExactSize.value ? ` width="${w}" height="${h}"` : ''; + + return ` +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}"${size}> + <rect width="${w}" height="${h}" fill="${bgColor.value}"></rect> + <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="monospace" font-size="${fontSize.value}px" fill="${fgColor.value}">${text}</text> +</svg> + `.trim(); +}); +const base64 = computed(() => 'data:image/svg+xml;base64,' + window.btoa(svgString.value)); + +const { copy: copySVG } = useCopy({ source: svgString }); +const { copy: copyBase64 } = useCopy({ source: base64 }); +const { download } = useDownloadFileFromBase64({ source: base64 }); +</script> + +<style lang="less" scoped> +.n-input-number { + width: 100%; +} +</style> |