aboutsummaryrefslogtreecommitdiff
path: root/src/components/TextareaCopyable.vue
diff options
context:
space:
mode:
authorGravatar Corentin Thomasset <corentin.thomasset74@gmail.com> 2022-08-03 12:47:00 +0200
committerGravatar Corentin THOMASSET <corentin.thomasset74@gmail.com> 2022-08-03 17:18:18 +0200
commit0be33fb337e8d82474922c0fdf9555aa328cd729 (patch)
tree070038038f942cf313e090a53687806c7e4a307d /src/components/TextareaCopyable.vue
parent422b6eb05a2fb5e7eec816a6bd2d37b53e4a6bdc (diff)
downloadit-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.vue98
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>