refactor(display): mutualized code display
This commit is contained in:
		
							parent
							
								
									422b6eb05a
								
							
						
					
					
						commit
						0be33fb337
					
				
							
								
								
									
										98
									
								
								src/components/TextareaCopyable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/components/TextareaCopyable.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | <template> | ||||||
|  |   <div style="overflow-x: hidden; width: 100%"> | ||||||
|  |     <n-card class="result-card"> | ||||||
|  |       <n-scrollbar | ||||||
|  |         x-scrollable | ||||||
|  |         trigger="none" | ||||||
|  |         :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" /> | ||||||
|  |         </n-config-provider> | ||||||
|  |       </n-scrollbar> | ||||||
|  |       <n-tooltip v-if="value" trigger="hover"> | ||||||
|  |         <template #trigger> | ||||||
|  |           <div class="copy-button" :class="[copyPlacement]"> | ||||||
|  |             <n-button secondary circle size="large" @click="onCopyClicked"> | ||||||
|  |               <n-icon size="22" :component="Copy" /> | ||||||
|  |             </n-button> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |         <span>{{ tooltipText }}</span> | ||||||
|  |       </n-tooltip> | ||||||
|  |     </n-card> | ||||||
|  |     <n-space v-if="copyPlacement === 'outside'" justify="center" style="margin-top: 15px"> | ||||||
|  |       <n-button secondary @click="onCopyClicked"> {{ tooltipText }} </n-button> | ||||||
|  |     </n-space> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { Copy } from '@vicons/tabler'; | ||||||
|  | import { useClipboard, useElementSize } from '@vueuse/core'; | ||||||
|  | import hljs from 'highlight.js/lib/core'; | ||||||
|  | import jsonHljs from 'highlight.js/lib/languages/json'; | ||||||
|  | import sqlHljs from 'highlight.js/lib/languages/sql'; | ||||||
|  | import { ref, toRefs } from 'vue'; | ||||||
|  | 
 | ||||||
|  | hljs.registerLanguage('sql', sqlHljs); | ||||||
|  | hljs.registerLanguage('json', jsonHljs); | ||||||
|  | 
 | ||||||
|  | const props = withDefaults( | ||||||
|  |   defineProps<{ | ||||||
|  |     value: string; | ||||||
|  |     followHeightOf?: HTMLElement | null; | ||||||
|  |     language?: string; | ||||||
|  |     copyPlacement?: 'top-right' | 'bottom-right' | 'outside' | 'none'; | ||||||
|  |     copyMessage?: string; | ||||||
|  |   }>(), | ||||||
|  |   { | ||||||
|  |     followHeightOf: null, | ||||||
|  |     language: 'txt', | ||||||
|  |     copyPlacement: 'top-right', | ||||||
|  |     copyMessage: 'Copy to clipboard', | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props); | ||||||
|  | const { height } = followHeightOf ? useElementSize(followHeightOf) : { height: ref(null) }; | ||||||
|  | 
 | ||||||
|  | const { copy } = useClipboard({ source: value }); | ||||||
|  | const tooltipText = ref(copyMessage.value); | ||||||
|  | 
 | ||||||
|  | function onCopyClicked() { | ||||||
|  |   copy(); | ||||||
|  |   tooltipText.value = 'Copied !'; | ||||||
|  | 
 | ||||||
|  |   setTimeout(() => { | ||||||
|  |     tooltipText.value = copyMessage.value; | ||||||
|  |   }, 2000); | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="less" scoped> | ||||||
|  | ::v-deep(.n-scrollbar) { | ||||||
|  |   padding-bottom: 10px; | ||||||
|  |   margin-bottom: -10px; | ||||||
|  | } | ||||||
|  | .result-card { | ||||||
|  |   position: relative; | ||||||
|  |   .copy-button { | ||||||
|  |     position: absolute; | ||||||
|  |     opacity: 1; | ||||||
|  | 
 | ||||||
|  |     &.top-right { | ||||||
|  |       top: 10px; | ||||||
|  |       right: 10px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.bottom-right { | ||||||
|  |       bottom: 10px; | ||||||
|  |       right: 10px; | ||||||
|  |     } | ||||||
|  |     &.outside, | ||||||
|  |     &.none { | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @ -17,26 +17,16 @@ | |||||||
|     /> |     /> | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
|   <n-form-item label="Prettify version of your json"> |   <n-form-item label="Prettify version of your json"> | ||||||
|     <n-card class="result-card" :style="`min-height: ${inputElementHeight ?? 400}px`"> |     <textarea-copyable :value="cleanJson" language="json" :follow-height-of="inputElement" /> | ||||||
|       <n-config-provider :hljs="hljs"> |  | ||||||
|         <n-code :code="cleanJson" language="json" :trim="false" /> |  | ||||||
|       </n-config-provider> |  | ||||||
|       <n-button v-if="cleanJson" class="copy-button" secondary @click="copy">Copy</n-button> |  | ||||||
|     </n-card> |  | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useCopy } from '@/composable/copy'; | import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||||
| import { useValidation } from '@/composable/validation'; | import { useValidation } from '@/composable/validation'; | ||||||
| import { useElementSize } from '@vueuse/core'; |  | ||||||
| import hljs from 'highlight.js/lib/core'; |  | ||||||
| import json from 'highlight.js/lib/languages/json'; |  | ||||||
| import { computed, ref } from 'vue'; | import { computed, ref } from 'vue'; | ||||||
| 
 | 
 | ||||||
| hljs.registerLanguage('json', json); |  | ||||||
| const inputElement = ref<HTMLElement>(); | const inputElement = ref<HTMLElement>(); | ||||||
| const { height: inputElementHeight } = useElementSize(inputElement); |  | ||||||
| 
 | 
 | ||||||
| const rawJson = ref('{"hello": "world"}'); | const rawJson = ref('{"hello": "world"}'); | ||||||
| const cleanJson = computed(() => { | const cleanJson = computed(() => { | ||||||
| @ -47,8 +37,6 @@ const cleanJson = computed(() => { | |||||||
|   } |   } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const { copy } = useCopy({ source: cleanJson }); |  | ||||||
| 
 |  | ||||||
| const rawJsonValidation = useValidation({ | const rawJsonValidation = useValidation({ | ||||||
|   source: rawJson, |   source: rawJson, | ||||||
|   rules: [ |   rules: [ | ||||||
|  | |||||||
| @ -58,27 +58,17 @@ | |||||||
|     /> |     /> | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
|   <n-form-item label="Prettify version of your query"> |   <n-form-item label="Prettify version of your query"> | ||||||
|     <n-card class="result-card" :style="`min-height: ${inputElementHeight ?? 400}px`"> |     <textarea-copyable :value="prettySQL" language="sql" :follow-height-of="inputElement" /> | ||||||
|       <n-config-provider :hljs="hljs"> |  | ||||||
|         <n-code :code="prettySQL" language="sql" :trim="false" /> |  | ||||||
|       </n-config-provider> |  | ||||||
|       <n-button v-if="prettySQL" class="copy-button" secondary @click="copy">Copy</n-button> |  | ||||||
|     </n-card> |  | ||||||
|   </n-form-item> |   </n-form-item> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useCopy } from '@/composable/copy'; | import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||||
| import { useStyleStore } from '@/stores/style.store'; | import { useStyleStore } from '@/stores/style.store'; | ||||||
| import { useElementSize } from '@vueuse/core'; |  | ||||||
| import hljs from 'highlight.js/lib/core'; |  | ||||||
| import sqlHljs from 'highlight.js/lib/languages/sql'; |  | ||||||
| import { format as formatSQL, type FormatFnOptions } from 'sql-formatter'; | import { format as formatSQL, type FormatFnOptions } from 'sql-formatter'; | ||||||
| import { computed, reactive, ref } from 'vue'; | import { computed, reactive, ref } from 'vue'; | ||||||
| hljs.registerLanguage('sql', sqlHljs); |  | ||||||
| 
 | 
 | ||||||
| const inputElement = ref<HTMLElement>(); | const inputElement = ref<HTMLElement>(); | ||||||
| const { height: inputElementHeight } = useElementSize(inputElement); |  | ||||||
| const styleStore = useStyleStore(); | const styleStore = useStyleStore(); | ||||||
| const config = reactive<Partial<FormatFnOptions>>({ | const config = reactive<Partial<FormatFnOptions>>({ | ||||||
|   keywordCase: 'upper', |   keywordCase: 'upper', | ||||||
| @ -90,7 +80,6 @@ const config = reactive<Partial<FormatFnOptions>>({ | |||||||
| 
 | 
 | ||||||
| const rawSQL = ref('select field1,field2,field3 from my_table where my_condition;'); | const rawSQL = ref('select field1,field2,field3 from my_table where my_condition;'); | ||||||
| const prettySQL = computed(() => formatSQL(rawSQL.value, config)); | const prettySQL = computed(() => formatSQL(rawSQL.value, config)); | ||||||
| const { copy } = useCopy({ source: prettySQL }); |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="less" scoped> | <style lang="less" scoped> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user