feat: added file-to-base64
This commit is contained in:
		
							parent
							
								
									5fa81533d9
								
							
						
					
					
						commit
						1034296359
					
				
							
								
								
									
										148
									
								
								components/FileUploader.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								components/FileUploader.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| <template> | ||||
|   <div | ||||
|     class="drop-area pa-4 text-center" | ||||
|     :class="{'drag-over':dragging, 'pb-0':!loading}" | ||||
|     @dragover.prevent | ||||
|     @drop.prevent="imageDropped" | ||||
|     @dragenter="dragEnter()" | ||||
|     @dragend="dragEnd()" | ||||
|     @dragleave="dragLeave()" | ||||
|     @dragexit="dragExit()" | ||||
|   > | ||||
|     <div v-if="loading"> | ||||
|       <v-progress-circular | ||||
|         indeterminate | ||||
|         color="primary" | ||||
|       /> | ||||
|     </div> | ||||
|     <div v-else> | ||||
|       <p>Drag & drop a file here</p> | ||||
|       <p class="or"> | ||||
|         or | ||||
|       </p> | ||||
|       <v-btn depressed @click="manualUploadClicked"> | ||||
|         select a file | ||||
|       </v-btn> | ||||
|       <input ref="uploadInput" type="file" hidden @change="(e) => handleFiles(e.target.files[0])"> | ||||
| 
 | ||||
|       <div v-if="allowUrl"> | ||||
|         <p class="or"> | ||||
|           or | ||||
|         </p> | ||||
|         <v-text-field | ||||
|           ref="urlInput" | ||||
|           v-model="url" | ||||
|           append-icon="fa-arrow-right" | ||||
|           dense | ||||
|           label="Paste the file url" | ||||
|           outlined | ||||
|           :error-messages="urlErrors" | ||||
|           @click:append="urlFilled(url)" | ||||
|           @keypress.enter="urlFilled(url)" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import {Component, Prop, Vue} from 'nuxt-property-decorator' | ||||
| 
 | ||||
| @Component | ||||
| export default class FileUploader extends Vue { | ||||
|   @Prop({default: true}) readonly allowUrl!: boolean | ||||
|   dragging = false | ||||
|   urlErrors = null | ||||
|   dragEnterCounter = 0 | ||||
|   url = '' | ||||
|   loading = false | ||||
| 
 | ||||
|   imageDropped(e) { | ||||
|     this.dragging = false | ||||
|     if (e.dataTransfer.items.length > 0) { | ||||
|       const item = e.dataTransfer.items[0] | ||||
|       switch (item.kind) { | ||||
|         case 'string': | ||||
|           item.getAsString(url => this.urlFilled(url)) | ||||
|           break | ||||
|         case 'file': | ||||
|           this.handleFiles(item.getAsFile()) | ||||
|           break | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   dragEnter() { | ||||
|     this.dragEnterCounter++ | ||||
|     this.dragging = true | ||||
|   } | ||||
| 
 | ||||
|   dragLeave() { | ||||
|     if (--this.dragEnterCounter <= 0) { | ||||
|       this.dragging = false | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async urlFilled(url) { | ||||
|     if (url && url.length > 0) { | ||||
|       this.loading = true | ||||
|       try { | ||||
|         const {data, headers} = await axios.get(url) | ||||
|         const name = url.split('/').pop() | ||||
|         const file = new File([data], name, {type: headers['content-type']}) | ||||
|         this.handleFiles(file) | ||||
|       } catch (ignored) { | ||||
|         this.urlErrors = 'Incorrect url' | ||||
|       } | ||||
|       this.loading = false | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   dragEnd() { | ||||
|     this.dragging = false | ||||
|   } | ||||
| 
 | ||||
|   dragExit() { | ||||
|     this.dragging = false | ||||
|   } | ||||
| 
 | ||||
|   handleFiles(file) { | ||||
|     if (!file) { | ||||
|       return | ||||
|     } | ||||
|     this.$emit('input', file) | ||||
|   } | ||||
| 
 | ||||
|   manualUploadClicked() { | ||||
|     this.$refs.uploadInput.click() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less"> | ||||
| .drop-area { | ||||
|   border: 2px dashed rgba(255,255,255,0.3); | ||||
|   border-radius: 10px; | ||||
|   background-color: rgba(255, 255, 255, 0.03); | ||||
| 
 | ||||
|   & > *, .v-btn { | ||||
|     margin: 0 !important; | ||||
|   } | ||||
| 
 | ||||
|   .or { | ||||
|     opacity: 0.7; | ||||
|     margin: 5px 0 !important; | ||||
|   } | ||||
| 
 | ||||
|   &.drag-over { | ||||
|     border-color: var(--v-primary-base); | ||||
|   } | ||||
| 
 | ||||
|   .v-input__icon { | ||||
|     button { | ||||
|       margin-top: 0 !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -4,16 +4,22 @@ | ||||
|       <v-col cols="12" xl="6" lg="8" md="10"> | ||||
|         <div class="tool-wrapper-info"> | ||||
|           <h1>{{ config.title }}</h1> | ||||
|           <div class="spacer" /> | ||||
|           <div class="spacer"/> | ||||
|           <div class="description"> | ||||
|             {{ config.description }} | ||||
|           </div> | ||||
|         </div> | ||||
|         <v-card flat> | ||||
|           <v-card-text class="pa-10"> | ||||
|             <slot /> | ||||
|           </v-card-text> | ||||
|         </v-card> | ||||
|         <template v-if="!noCard"> | ||||
|           <v-card flat> | ||||
|             <v-card-text class="pa-10"> | ||||
|               <slot/> | ||||
|             </v-card-text> | ||||
|           </v-card> | ||||
|         </template> | ||||
|         <template v-else> | ||||
|           <slot/> | ||||
|         </template> | ||||
| 
 | ||||
|       </v-col> | ||||
|     </v-row> | ||||
|   </div> | ||||
| @ -25,7 +31,8 @@ import {ToolConfig} from '~/types/ToolConfig' | ||||
| 
 | ||||
| @Component | ||||
| export default class ToolWrapper extends Vue { | ||||
|   @Prop() config!: ToolConfig; | ||||
|   @Prop() readonly config!: ToolConfig; | ||||
|   @Prop({default: () => false}) readonly noCard!: boolean; | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
| @ -34,7 +41,7 @@ export default class ToolWrapper extends Vue { | ||||
| .tool-wrapper { | ||||
|   height: 100%; | ||||
| 
 | ||||
|   .tool-wrapper-info{ | ||||
|   .tool-wrapper-info { | ||||
|     padding: 50px 0 30px; | ||||
|   } | ||||
| 
 | ||||
| @ -49,7 +56,7 @@ export default class ToolWrapper extends Vue { | ||||
|     padding: 0; | ||||
|   } | ||||
| 
 | ||||
|   .spacer{ | ||||
|   .spacer { | ||||
|     width: 200px; | ||||
|     height: 2px; | ||||
|     background: var(--v-primary-base); | ||||
|  | ||||
| @ -1,29 +1,38 @@ | ||||
| <template> | ||||
|   <v-row justify="center" align="center"> | ||||
|     <v-col cols="12" sm="12" md="8"> | ||||
|     <v-col cols="12" sm="12" md="12"> | ||||
|       <h1>Yolo</h1> | ||||
| 
 | ||||
|       <v-card v-for="(items, section) in toolRoutesSections" :key="section"> | ||||
|         <v-card-title>{{ section }}</v-card-title> | ||||
|         <v-card-text> | ||||
|           <v-list> | ||||
|             <v-list-item | ||||
|               v-for="(item, i) in items" | ||||
|               :key="i" | ||||
|               :to="item.path" | ||||
|               router | ||||
|               exact | ||||
|             > | ||||
|               <v-list-item-action> | ||||
|                 <v-icon>{{ item.config.icon }}</v-icon> | ||||
|               </v-list-item-action> | ||||
|               <v-list-item-content> | ||||
|                 <v-list-item-title v-text="item.config.title" /> | ||||
|               </v-list-item-content> | ||||
|             </v-list-item> | ||||
|           </v-list> | ||||
|         </v-card-text> | ||||
|       </v-card> | ||||
|       <v-row justify="center" > | ||||
|         <v-col | ||||
|           cols="12" | ||||
|           sm="12" | ||||
|           md="6" | ||||
|           v-for="(items, section) in toolRoutesSections" :key="section" | ||||
|         > | ||||
|           <v-card> | ||||
|             <v-card-title>{{ section }}</v-card-title> | ||||
|             <v-card-text> | ||||
|               <v-list> | ||||
|                 <v-list-item | ||||
|                   v-for="(item, i) in items" | ||||
|                   :key="i" | ||||
|                   :to="item.path" | ||||
|                   router | ||||
|                   exact | ||||
|                 > | ||||
|                   <v-list-item-action> | ||||
|                     <v-icon>{{ item.config.icon }}</v-icon> | ||||
|                   </v-list-item-action> | ||||
|                   <v-list-item-content> | ||||
|                     <v-list-item-title v-text="item.config.title"/> | ||||
|                   </v-list-item-content> | ||||
|                 </v-list-item> | ||||
|               </v-list> | ||||
|             </v-card-text> | ||||
|           </v-card> | ||||
|         </v-col> | ||||
|       </v-row> | ||||
|     </v-col> | ||||
|   </v-row> | ||||
| </template> | ||||
| @ -37,22 +46,22 @@ export default class Index extends mixins(ToolRoutesMixin) { | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scopedlang="less"> | ||||
|   .v-list{ | ||||
|     background: transparent !important; | ||||
|   } | ||||
| <style scoped lang="less"> | ||||
| .v-list { | ||||
|   background: transparent !important; | ||||
| } | ||||
| 
 | ||||
|   .v-card__title{ | ||||
|     background: var(--v-primary-base) !important; | ||||
|     background: linear-gradient(90deg, rgba(37,99,108,1) 0%, rgba(59,149,111,1) 60%, rgba(71,177,113,1) 100%) !important; | ||||
|     padding-left: 33px; | ||||
|   } | ||||
| .v-card__title { | ||||
|   background: var(--v-primary-base) !important; | ||||
|   background: linear-gradient(90deg, rgba(37, 99, 108, 1) 0%, rgba(59, 149, 111, 1) 60%, rgba(71, 177, 113, 1) 100%) !important; | ||||
|   padding-left: 33px; | ||||
| } | ||||
| 
 | ||||
|   .v-list-item{ | ||||
|     padding-left: 31px; | ||||
|   } | ||||
| .v-list-item { | ||||
|   padding-left: 31px; | ||||
| } | ||||
| 
 | ||||
|   .v-card__text{ | ||||
|     padding: 0; | ||||
|   } | ||||
| .v-card__text { | ||||
|   padding: 0; | ||||
| } | ||||
| </style> | ||||
|  | ||||
							
								
								
									
										105
									
								
								pages/tools/Web/file-to-base64.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								pages/tools/Web/file-to-base64.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| <template> | ||||
|   <ToolWrapper :config="config()" noCard="true"> | ||||
| 
 | ||||
|     <FileUploader v-model="file"/> | ||||
| 
 | ||||
|     <div v-if="base64 || loading" class="mt-10"> | ||||
|       <v-card> | ||||
|         <v-card-title>Result</v-card-title> | ||||
|         <v-card-text> | ||||
|           <v-textarea | ||||
|             v-model="base64" | ||||
|             label="File in base 64" | ||||
|             outlined | ||||
|             readonly | ||||
|             hide-details | ||||
|             :loading="loading" | ||||
|           /> | ||||
|           <div class="text-center mt-4"> | ||||
|             <v-btn depressed @click="copy(base64)"> | ||||
|               Copy base64 | ||||
|             </v-btn> | ||||
|           </div> | ||||
|         </v-card-text> | ||||
|       </v-card> | ||||
|     </div> | ||||
| 
 | ||||
|   </ToolWrapper> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import {Component, Watch} from 'nuxt-property-decorator' | ||||
| import {CopyableMixin} from '@/mixins/copyable.mixin' | ||||
| import Tool from '@/components/Tool' | ||||
| import {ToolConfig} from '@/types/ToolConfig' | ||||
| import FileUploader from '~/components/FileUploader' | ||||
| 
 | ||||
| @Component({ | ||||
|   mixins: [CopyableMixin], | ||||
|   components: {FileUploader} | ||||
| }) | ||||
| export default class FileToBase64 extends Tool { | ||||
|   config(): ToolConfig { | ||||
|     return { | ||||
|       title: 'File to base64', | ||||
|       description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.', | ||||
|       icon: 'mdi-key-chain-variant', | ||||
|       keywords: ['file', 'base64'] | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   file = null | ||||
|   loading = false | ||||
|   base64= '' | ||||
| 
 | ||||
|   handleBase64(base64) { | ||||
|     this.base64 = base64 | ||||
|     this.loading = false | ||||
|   } | ||||
| 
 | ||||
|   @Watch('file') | ||||
|   onFile() { | ||||
|     this.loading = true | ||||
|     this.base64 = '' | ||||
|     const reader = new FileReader() | ||||
|     reader.onload = () => this.handleBase64(reader.result) | ||||
|     reader.onerror = () => this.handleBase64('[An error as occurred]') | ||||
|     reader.readAsDataURL(this.file) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // export default { | ||||
| //   name: 'FileToBase64', | ||||
| //   components: {FileUploader}, | ||||
| //   data() { | ||||
| //     return { | ||||
| //       file: undefined, | ||||
| //       loading: false, | ||||
| //       base64: '', | ||||
| //       copyBase64() { | ||||
| //         copyToClipboard(this.base64) | ||||
| //         this.$toast.success('Copied to clipboard.') | ||||
| //       } | ||||
| //     } | ||||
| //   }, | ||||
| //   watch: { | ||||
| //     file() { | ||||
| //       this.loading = true | ||||
| //       this.base64 = '' | ||||
| //       const reader = new FileReader() | ||||
| //       reader.onload = () => this.handleBase64(reader.result) | ||||
| //       reader.onerror = () => this.handleBase64('[An error as occurred]') | ||||
| //       reader.readAsDataURL(this.file) | ||||
| //     } | ||||
| //   }, | ||||
| //   methods: { | ||||
| //     handleBase64(base64) { | ||||
| //       this.base64 = base64 | ||||
| //       this.loading = false | ||||
| //     } | ||||
| //   } | ||||
| // } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| </style> | ||||
| @ -45,7 +45,7 @@ | ||||
| <script lang="ts"> | ||||
| import {Component} from 'nuxt-property-decorator' | ||||
| import {CopyableMixin} from '@/mixins/copyable.mixin' | ||||
| import Tool from '@/components/Tool' | ||||
| import Tool from '@/components/Tool.vue' | ||||
| import {ToolConfig} from '@/types/ToolConfig' | ||||
| import CryptoJS from 'crypto-js' | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user