mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-04 05:19:12 -04:00
feat: add file upload option and word wrap
This commit is contained in:
parent
78c4436b3f
commit
0c2dcbdf67
2 changed files with 93 additions and 12 deletions
|
@ -7,7 +7,15 @@ import sqlHljs from 'highlight.js/lib/languages/sql';
|
|||
import xmlHljs from 'highlight.js/lib/languages/xml';
|
||||
import yamlHljs from 'highlight.js/lib/languages/yaml';
|
||||
import iniHljs from 'highlight.js/lib/languages/ini';
|
||||
import bashHljs from 'highlight.js/lib/languages/bash';
|
||||
import markdownHljs from 'highlight.js/lib/languages/markdown';
|
||||
import jsHljs from 'highlight.js/lib/languages/javascript';
|
||||
import cssHljs from 'highlight.js/lib/languages/css';
|
||||
import goHljs from 'highlight.js/lib/languages/go';
|
||||
import csharpHljs from 'highlight.js/lib/languages/csharp';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -16,12 +24,17 @@ const props = withDefaults(
|
|||
language?: string
|
||||
copyPlacement?: 'top-right' | 'bottom-right' | 'outside' | 'none'
|
||||
copyMessage?: string
|
||||
wordWrap?: boolean
|
||||
downloadFileName?: string
|
||||
downloadButtonText?: string
|
||||
}>(),
|
||||
{
|
||||
followHeightOf: null,
|
||||
language: 'txt',
|
||||
copyPlacement: 'top-right',
|
||||
copyMessage: 'Copy to clipboard',
|
||||
downloadFileName: '',
|
||||
downloadButtonText: 'Download',
|
||||
},
|
||||
);
|
||||
hljs.registerLanguage('sql', sqlHljs);
|
||||
|
@ -30,12 +43,25 @@ hljs.registerLanguage('html', xmlHljs);
|
|||
hljs.registerLanguage('xml', xmlHljs);
|
||||
hljs.registerLanguage('yaml', yamlHljs);
|
||||
hljs.registerLanguage('toml', iniHljs);
|
||||
hljs.registerLanguage('bash', bashHljs);
|
||||
hljs.registerLanguage('markdown', markdownHljs);
|
||||
hljs.registerLanguage('css', cssHljs);
|
||||
hljs.registerLanguage('javascript', jsHljs);
|
||||
hljs.registerLanguage('go', goHljs);
|
||||
hljs.registerLanguage('csharp', csharpHljs);
|
||||
|
||||
const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props);
|
||||
const { value, language, followHeightOf, copyPlacement, copyMessage, downloadFileName, downloadButtonText } = toRefs(props);
|
||||
const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) };
|
||||
|
||||
const { copy, isJustCopied } = useCopy({ source: value, createToast: false });
|
||||
const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.value);
|
||||
|
||||
const valueBase64 = computed(() => Base64.encode(value.value));
|
||||
const { download } = useDownloadFileFromBase64(
|
||||
{
|
||||
source: valueBase64,
|
||||
filename: downloadFileName,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -47,11 +73,16 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
|
|||
:style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''"
|
||||
>
|
||||
<n-config-provider :hljs="hljs">
|
||||
<n-code :code="value" :language="language" :trim="false" data-test-id="area-content" />
|
||||
<n-code :code="value" :language="language" :word-wrap="wordWrap" :trim="false" data-test-id="area-content" />
|
||||
</n-config-provider>
|
||||
</n-scrollbar>
|
||||
<div absolute right-10px top-10px>
|
||||
<c-tooltip v-if="value" :tooltip="tooltipText" position="left">
|
||||
<div
|
||||
v-if="value && copyPlacement !== 'none'"
|
||||
absolute right-10px
|
||||
:top-10px="copyPlacement === 'top-right' ? '' : 'no'"
|
||||
:bottom-10px="copyPlacement === 'bottom-right' ? '' : 'no'"
|
||||
>
|
||||
<c-tooltip v-if="value && copyPlacement !== 'outside'" :tooltip="tooltipText" position="left">
|
||||
<c-button circle important:h-10 important:w-10 @click="copy()">
|
||||
<n-icon size="22" :component="Copy" />
|
||||
</c-button>
|
||||
|
@ -63,6 +94,11 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
|
|||
{{ tooltipText }}
|
||||
</c-button>
|
||||
</div>
|
||||
<div v-if="downloadFileName !== '' && value !== ''" mt-5 flex justify-center>
|
||||
<c-button secondary @click="download">
|
||||
{{ downloadButtonText }}
|
||||
</c-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
import PostalMime from 'postal-mime';
|
||||
|
||||
const inputType = ref<'file' | 'content'>('file');
|
||||
const emailContent = ref('');
|
||||
const fileInput = ref() as Ref<File | null>;
|
||||
const error = ref('');
|
||||
|
||||
const parsedEmail = computedAsync(async () => {
|
||||
const emailContentValue = emailContent.value;
|
||||
const file = fileInput.value;
|
||||
error.value = '';
|
||||
try {
|
||||
if (inputType.value === 'file' && file) {
|
||||
return await PostalMime.parse(await file.arrayBuffer());
|
||||
} else if (inputType.value === 'content' && emailContentValue) {
|
||||
return await PostalMime.parse(emailContentValue);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (e: any) {
|
||||
return e.toString();
|
||||
error.value = e.toString();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
function downloadFile(data: Uint8Array, fileName: string, fileType: string) {
|
||||
function downloadFile(data: ArrayBuffer, fileName: string, fileType: string) {
|
||||
const blob = new Blob([data], { type: fileType || 'application/octet-stream' });
|
||||
const downloadUrl = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
|
@ -23,12 +35,38 @@ function downloadFile(data: Uint8Array, fileName: string, fileType: string) {
|
|||
a.click();
|
||||
URL.revokeObjectURL(downloadUrl);
|
||||
}
|
||||
|
||||
function onUpload(file: File) {
|
||||
if (file) {
|
||||
fileInput.value = file;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="max-width: 600px;">
|
||||
<c-card title="Input" mb-2>
|
||||
<n-radio-group v-model:value="inputType" name="radiogroup" mb-2 flex justify-center>
|
||||
<n-space>
|
||||
<n-radio
|
||||
value="file"
|
||||
label="File"
|
||||
/>
|
||||
<n-radio
|
||||
value="content"
|
||||
label="Content"
|
||||
/>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
|
||||
<c-file-upload
|
||||
v-if="inputType === 'file'"
|
||||
title="Drag and drop EML file here, or click to select a file"
|
||||
@file-upload="onUpload"
|
||||
/>
|
||||
|
||||
<c-input-text
|
||||
v-if="inputType === 'content'"
|
||||
v-model:value="emailContent"
|
||||
label="Email Content"
|
||||
multiline
|
||||
|
@ -38,32 +76,39 @@ function downloadFile(data: Uint8Array, fileName: string, fileType: string) {
|
|||
/>
|
||||
</c-card>
|
||||
|
||||
<c-card v-if="parsedEmail && emailContent" title="Output">
|
||||
<c-alert v-if="error">
|
||||
{{ error }}
|
||||
</c-alert>
|
||||
|
||||
<c-card v-if="!error && parsedEmail" title="Output">
|
||||
<input-copyable v-if="fileInput?.name" label="File Name" :value="fileInput?.name" />
|
||||
<input-copyable v-if="parsedEmail.date" label="Date" :value="parsedEmail.date" />
|
||||
<input-copyable v-if="parsedEmail.from?.name" label="From (name)" :value="parsedEmail.from?.name" />
|
||||
<input-copyable v-if="parsedEmail.from" label="From (address)" :value="parsedEmail.from?.address || parsedEmail.from" />
|
||||
<input-copyable v-if="parsedEmail.to" label="To" :value="JSON.stringify(parsedEmail.to)" />
|
||||
<input-copyable v-if="parsedEmail.cc" label="Cc" :value="JSON.stringify(parsedEmail.cc)" />
|
||||
<input-copyable v-if="parsedEmail.bcc?.name" label="Bcc" :value="JSON.stringify(parsedEmail.bcc)" />
|
||||
<input-copyable v-if="parsedEmail.bcc" label="Bcc" :value="JSON.stringify(parsedEmail.bcc)" />
|
||||
<input-copyable v-if="parsedEmail.replyTo" label="Reply-To" :value="JSON.stringify(parsedEmail.replyTo)" />
|
||||
<input-copyable v-if="parsedEmail.subject" label="Subject" :value="parsedEmail.subject" />
|
||||
<c-card v-if="parsedEmail.text" title="Plain Content" mb-2>
|
||||
<details>
|
||||
<summary>See content</summary>
|
||||
<textarea-copyable :value="parsedEmail.text" />
|
||||
<textarea-copyable :value="parsedEmail.text" word-wrap />
|
||||
</details>
|
||||
</c-card>
|
||||
<c-card v-if="parsedEmail.html" title="Html Content" mb-2>
|
||||
<details>
|
||||
<summary>See content</summary>
|
||||
<textarea-copyable :value="parsedEmail.html" />
|
||||
<textarea-copyable :value="parsedEmail.html" word-wrap />
|
||||
</details>
|
||||
</c-card>
|
||||
<c-card v-if="parsedEmail?.attachments?.length" title="Attachments" mb-2>
|
||||
<n-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Attachment</th><th scope="col" />
|
||||
<th scope="col">
|
||||
Attachment
|
||||
</th><th scope="col" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue