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"> |       <v-col cols="12" xl="6" lg="8" md="10"> | ||||||
|         <div class="tool-wrapper-info"> |         <div class="tool-wrapper-info"> | ||||||
|           <h1>{{ config.title }}</h1> |           <h1>{{ config.title }}</h1> | ||||||
|           <div class="spacer" /> |           <div class="spacer"/> | ||||||
|           <div class="description"> |           <div class="description"> | ||||||
|             {{ config.description }} |             {{ config.description }} | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|  |         <template v-if="!noCard"> | ||||||
|           <v-card flat> |           <v-card flat> | ||||||
|             <v-card-text class="pa-10"> |             <v-card-text class="pa-10"> | ||||||
|             <slot /> |               <slot/> | ||||||
|             </v-card-text> |             </v-card-text> | ||||||
|           </v-card> |           </v-card> | ||||||
|  |         </template> | ||||||
|  |         <template v-else> | ||||||
|  |           <slot/> | ||||||
|  |         </template> | ||||||
|  | 
 | ||||||
|       </v-col> |       </v-col> | ||||||
|     </v-row> |     </v-row> | ||||||
|   </div> |   </div> | ||||||
| @ -25,7 +31,8 @@ import {ToolConfig} from '~/types/ToolConfig' | |||||||
| 
 | 
 | ||||||
| @Component | @Component | ||||||
| export default class ToolWrapper extends Vue { | export default class ToolWrapper extends Vue { | ||||||
|   @Prop() config!: ToolConfig; |   @Prop() readonly config!: ToolConfig; | ||||||
|  |   @Prop({default: () => false}) readonly noCard!: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| </script> | </script> | ||||||
| @ -34,7 +41,7 @@ export default class ToolWrapper extends Vue { | |||||||
| .tool-wrapper { | .tool-wrapper { | ||||||
|   height: 100%; |   height: 100%; | ||||||
| 
 | 
 | ||||||
|   .tool-wrapper-info{ |   .tool-wrapper-info { | ||||||
|     padding: 50px 0 30px; |     padding: 50px 0 30px; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -49,7 +56,7 @@ export default class ToolWrapper extends Vue { | |||||||
|     padding: 0; |     padding: 0; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .spacer{ |   .spacer { | ||||||
|     width: 200px; |     width: 200px; | ||||||
|     height: 2px; |     height: 2px; | ||||||
|     background: var(--v-primary-base); |     background: var(--v-primary-base); | ||||||
|  | |||||||
| @ -1,9 +1,16 @@ | |||||||
| <template> | <template> | ||||||
|   <v-row justify="center" align="center"> |   <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> |       <h1>Yolo</h1> | ||||||
| 
 | 
 | ||||||
|       <v-card v-for="(items, section) in toolRoutesSections" :key="section"> |       <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-title>{{ section }}</v-card-title> | ||||||
|             <v-card-text> |             <v-card-text> | ||||||
|               <v-list> |               <v-list> | ||||||
| @ -18,7 +25,7 @@ | |||||||
|                     <v-icon>{{ item.config.icon }}</v-icon> |                     <v-icon>{{ item.config.icon }}</v-icon> | ||||||
|                   </v-list-item-action> |                   </v-list-item-action> | ||||||
|                   <v-list-item-content> |                   <v-list-item-content> | ||||||
|                 <v-list-item-title v-text="item.config.title" /> |                     <v-list-item-title v-text="item.config.title"/> | ||||||
|                   </v-list-item-content> |                   </v-list-item-content> | ||||||
|                 </v-list-item> |                 </v-list-item> | ||||||
|               </v-list> |               </v-list> | ||||||
| @ -26,6 +33,8 @@ | |||||||
|           </v-card> |           </v-card> | ||||||
|         </v-col> |         </v-col> | ||||||
|       </v-row> |       </v-row> | ||||||
|  |     </v-col> | ||||||
|  |   </v-row> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
| @ -37,22 +46,22 @@ export default class Index extends mixins(ToolRoutesMixin) { | |||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style scopedlang="less"> | <style scoped lang="less"> | ||||||
|   .v-list{ | .v-list { | ||||||
|   background: transparent !important; |   background: transparent !important; | ||||||
|   } | } | ||||||
| 
 | 
 | ||||||
|   .v-card__title{ | .v-card__title { | ||||||
|   background: var(--v-primary-base) !important; |   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; |   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; |   padding-left: 33px; | ||||||
|   } | } | ||||||
| 
 | 
 | ||||||
|   .v-list-item{ | .v-list-item { | ||||||
|   padding-left: 31px; |   padding-left: 31px; | ||||||
|   } | } | ||||||
| 
 | 
 | ||||||
|   .v-card__text{ | .v-card__text { | ||||||
|   padding: 0; |   padding: 0; | ||||||
|   } | } | ||||||
| </style> | </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"> | <script lang="ts"> | ||||||
| import {Component} from 'nuxt-property-decorator' | import {Component} from 'nuxt-property-decorator' | ||||||
| import {CopyableMixin} from '@/mixins/copyable.mixin' | import {CopyableMixin} from '@/mixins/copyable.mixin' | ||||||
| import Tool from '@/components/Tool' | import Tool from '@/components/Tool.vue' | ||||||
| import {ToolConfig} from '@/types/ToolConfig' | import {ToolConfig} from '@/types/ToolConfig' | ||||||
| import CryptoJS from 'crypto-js' | import CryptoJS from 'crypto-js' | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user