Make tooltips render automatically

This commit is contained in:
Riyyi
2025-04-02 22:52:07 +02:00
parent 8110667234
commit 9878bbdb8c
11 changed files with 107 additions and 32 deletions
+13 -9
View File
@@ -6,7 +6,11 @@
</template>
<script setup lang="ts">
const bootstrap = useNuxtApp().$bootstrap;
import { useRouter } from "vue-router";
import { useStateStore } from "@/stores/stateStore";
const router = useRouter();
const store = useStateStore();
useHead({
titleTemplate: (titleChunk: string | undefined): string | null => {
@@ -14,14 +18,14 @@ useHead({
}
})
// Access bootstrap after the DOM is ready
onMounted(() => {
// Initialize popovers
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]')
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
// Init Bootstrap after navigation
router.afterEach((_to, _from) => {
setTimeout(() => { store.initBootstrap(); }, 500);
});
// Initialize tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
// Init Bootstrap on initial page load, after the DOM is ready
onMounted(() => {
// @ts-ignore
store.initBootstrap();
});
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
<a href="#">Overview</a>
</li>
</ul>
<ArticlesTableOfContentsLink :links="toc.links" :first="true" class="font-smaller mb-0" />
<ArticlesTableOfContentsLink :links="toc.links" :first="true" class="font-smaller" />
</aside>
</template>
@@ -1,5 +1,5 @@
<template>
<ul>
<ul class="mb-0">
<template v-for="link in links" :key="link.id">
<li>
<a :href="'#' + link.id">{{ link.text }}</a>
+44 -9
View File
@@ -1,12 +1,16 @@
<template>
<div class="position-relative">
<div @click="copyCode" class="position-absolute" style="top: 10px; right: 10px;">
<template v-if="copied">
<code>Copied!</code>
</template>
<button class="copy text-secondary" title="Copy code">
<button class="copy text-secondary" :class="copied ? 'd-none' : ''" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-title="Copy to clipboard">
<IFaClone />
</button>
<button class="copy text-secondary" :class="!copied ? 'd-none' : ''" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-title="Copied!" data-bs-trigger="manual" data-bs-show
ref="stickyTooltipElement">
<IFaCheck class="text-success" />
</button>
</div>
<pre :class="$props.class"><code class="language-{{ language }}"><slot /></code></pre>
</div>
@@ -30,7 +34,9 @@ button.copy:hover {
</style>
<script setup lang="ts">
import { ref } from "vue"
import { nextTick, ref, watch } from "vue"
const bootstrap = useNuxtApp().$bootstrap;
defineProps({
code: {
@@ -59,19 +65,48 @@ defineProps({
}
});
const copied = ref(false);
const copied = ref<boolean>(false);
const copyCode = async (e: Event) => {
try {
const target = e.currentTarget as HTMLElement;
const element = target.nextElementSibling as HTMLPreElement | null;
const textToCopy = element ? element.textContent.trim() : "";
const textToCopy = element ? element.textContent!.trim() : "";
await navigator.clipboard.writeText(textToCopy);
copied.value = true;
setTimeout(() => (copied.value = false), 2000);
setTimeout(() => { copied.value = false; }, 2000);
} catch (err) {
console.error('Failed to copy:', err)
console.error('Failed to copy:', err);
}
}
// Clicked tooltip
const stickyTooltip = ref<any>();
const stickyTooltipElement = ref<HTMLInputElement | null>(null);
watch(copied, (newValue, oldValue) => {
if (newValue !== oldValue) {
if (newValue) {
// Ensure the DOM is updated before executing
nextTick(() => {
// @ts-ignore
stickyTooltip.value = new bootstrap.Tooltip(stickyTooltipElement.value, { trigger: "manual" });
stickyTooltip.value.show();
});
}
else {
if (stickyTooltip.value) {
stickyTooltip.value.dispose();
stickyTooltip.value = null;
}
}
}
});
onBeforeUnmount(() => {
if (stickyTooltip.value) {
stickyTooltip.value.dispose();
stickyTooltip.value = null;
}
});
</script>
+2 -1
View File
@@ -1,5 +1,6 @@
// @ts-ignore
import bootstrap from "bootstrap/dist/js/bootstrap.bundle.min";
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.provide("bootstrap", bootstrap);
})
});
+19 -1
View File
@@ -1,6 +1,9 @@
import { defineStore } from "pinia"
import { ref } from "vue";
// @ts-ignore
import bootstrap from "bootstrap/dist/js/bootstrap.bundle.min";
export const useStateStore = defineStore("state", () => {
const colorMode = ref<string>("light");
@@ -10,7 +13,22 @@ export const useStateStore = defineStore("state", () => {
html.setAttribute('data-bs-theme', colorMode.value);
};
return { colorMode, toggleColorMode }
const popoverList = ref<any[]>([]);
const tooltipList = ref<any[]>([]);
const initBootstrap = (): void => {
// Initialize popovers
popoverList.value.forEach(popover => popover.dispose());
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
popoverList.value = [...popoverTriggerList].map(popover => new bootstrap.Popover(popover));
// Initialize tooltips
tooltipList.value.forEach(tooltip => tooltip.dispose());
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]:not([data-bs-show])');
tooltipList.value = [...tooltipTriggerList].map(tooltip => new bootstrap.Tooltip(tooltip));
};
return { colorMode, toggleColorMode, initBootstrap }
}, {
persist: process.env.NODE_ENV === 'development' ? true : false,
})