diff options
author | 2022-08-03 12:47:00 +0200 | |
---|---|---|
committer | 2022-08-03 17:18:18 +0200 | |
commit | 0be33fb337e8d82474922c0fdf9555aa328cd729 (patch) | |
tree | 070038038f942cf313e090a53687806c7e4a307d /src/components/TextareaCopyable.vue | |
parent | 422b6eb05a2fb5e7eec816a6bd2d37b53e4a6bdc (diff) | |
download | it-tools-0be33fb337e8d82474922c0fdf9555aa328cd729.tar.gz it-tools-0be33fb337e8d82474922c0fdf9555aa328cd729.tar.zst it-tools-0be33fb337e8d82474922c0fdf9555aa328cd729.zip |
refactor(display): mutualized code display
Diffstat (limited to 'src/components/TextareaCopyable.vue')
-rw-r--r-- | src/components/TextareaCopyable.vue | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/components/TextareaCopyable.vue b/src/components/TextareaCopyable.vue new file mode 100644 index 0000000..49fb96d --- /dev/null +++ b/src/components/TextareaCopyable.vue @@ -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> |