Make tooltips render automatically
This commit is contained in:
@@ -40,7 +40,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version: "22"
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
# run: bun install
|
||||
|
||||
@@ -16,6 +16,7 @@ export default defineNuxtConfig({
|
||||
]
|
||||
},
|
||||
toc: {
|
||||
// @ts-ignore
|
||||
title: "Table of Contents",
|
||||
depth: 4, // include h4 headings
|
||||
searchDepth: 2
|
||||
@@ -51,6 +52,9 @@ export default defineNuxtConfig({
|
||||
},
|
||||
srcDir: "src/",
|
||||
ssr: false,
|
||||
typescript: {
|
||||
typeCheck: true
|
||||
},
|
||||
vite: {
|
||||
plugins: [
|
||||
ViteComponents({
|
||||
|
||||
Generated
+19
-1
@@ -30,7 +30,8 @@
|
||||
"nuxt": "^3.14.1592",
|
||||
"typescript": "^5.7.2",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"unplugin-vue-components": "^28.4.1"
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -12502,6 +12503,23 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.8.tgz",
|
||||
"integrity": "sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@volar/typescript": "~2.4.11",
|
||||
"@vue/language-core": "2.2.8"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"dev": true,
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@
|
||||
"nuxt": "^3.14.1592",
|
||||
"typescript": "^5.7.2",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"unplugin-vue-components": "^28.4.1"
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vue-tsc": "^2.2.8"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"@parcel/watcher"
|
||||
|
||||
+13
-9
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" data-bs-hover="hover">
|
||||
<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>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @ts-ignore
|
||||
import bootstrap from "bootstrap/dist/js/bootstrap.bundle.min";
|
||||
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
nuxtApp.provide("bootstrap", bootstrap);
|
||||
})
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
+1
-7
@@ -1,10 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"bootstrap",
|
||||
"unplugin-icons/types/vue"
|
||||
]
|
||||
}
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user