mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-21 17:26:45 +02:00
fix: Move Tooltip as vue component
This commit is contained in:
88
packages/mermaid/src/docs/.vitepress/theme/Tooltip.vue
Normal file
88
packages/mermaid/src/docs/.vitepress/theme/Tooltip.vue
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="isVisible"
|
||||||
|
class="mermaid-chart-tooltip"
|
||||||
|
:class="{ visible: isVisible }"
|
||||||
|
:style="tooltipStyle"
|
||||||
|
>
|
||||||
|
<span class="mdi mdi-open-in-new"></span>
|
||||||
|
Opens in MermaidChart.com
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
|
|
||||||
|
const isVisible = ref(false);
|
||||||
|
const currentTarget = ref<HTMLElement | null>(null);
|
||||||
|
const tooltipStyle = ref({});
|
||||||
|
|
||||||
|
const showTooltip = (target: HTMLElement) => {
|
||||||
|
currentTarget.value = target;
|
||||||
|
const rect = target.getBoundingClientRect();
|
||||||
|
tooltipStyle.value = {
|
||||||
|
left: `${rect.left + rect.width / 2}px`,
|
||||||
|
top: `${rect.top}px`,
|
||||||
|
};
|
||||||
|
isVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideTooltip = () => {
|
||||||
|
currentTarget.value = null;
|
||||||
|
isVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseOver = (e: MouseEvent) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (
|
||||||
|
target.matches('a[href*="mermaidchart.com"]') ||
|
||||||
|
target.matches('button[onclick*="mermaidchart.com"]')
|
||||||
|
) {
|
||||||
|
showTooltip(target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseOut = (e: MouseEvent) => {
|
||||||
|
if (!currentTarget.value?.contains(e.relatedTarget as HTMLElement)) {
|
||||||
|
hideTooltip();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('mouseover', handleMouseOver);
|
||||||
|
document.addEventListener('mouseout', handleMouseOut);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('mouseover', handleMouseOver);
|
||||||
|
document.removeEventListener('mouseout', handleMouseOut);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.mermaid-chart-tooltip {
|
||||||
|
position: fixed;
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
padding: 0.3rem 0.6rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1000;
|
||||||
|
text-align: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition:
|
||||||
|
opacity 0.3s ease,
|
||||||
|
transform 0.3s ease;
|
||||||
|
transform: translate(-50%, -90%);
|
||||||
|
margin-top: -0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mermaid-chart-tooltip.visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -100%);
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,13 +1,10 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import DefaultTheme from 'vitepress/theme';
|
import DefaultTheme from 'vitepress/theme';
|
||||||
import './custom.css';
|
import './custom.css';
|
||||||
// @ts-ignore Type not available
|
|
||||||
import Mermaid from './Mermaid.vue';
|
import Mermaid from './Mermaid.vue';
|
||||||
// @ts-ignore Type not available
|
import Tooltip from './Tooltip.vue';
|
||||||
import Contributors from '../components/Contributors.vue';
|
import Contributors from '../components/Contributors.vue';
|
||||||
// @ts-ignore Type not available
|
|
||||||
import HomePage from '../components/HomePage.vue';
|
import HomePage from '../components/HomePage.vue';
|
||||||
// @ts-ignore Type not available
|
|
||||||
import TopBar from '../components/TopBar.vue';
|
import TopBar from '../components/TopBar.vue';
|
||||||
import { getRedirect } from './redirect.js';
|
import { getRedirect } from './redirect.js';
|
||||||
// @ts-ignore Type not available
|
// @ts-ignore Type not available
|
||||||
@@ -17,89 +14,14 @@ import Theme from 'vitepress/theme';
|
|||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import '../style/main.css';
|
import '../style/main.css';
|
||||||
|
|
||||||
// Add tooltips to Mermaid Chart buttons
|
|
||||||
const addMermaidChartTooltips = () => {
|
|
||||||
const tooltipStyle = document.createElement('style');
|
|
||||||
tooltipStyle.textContent = `
|
|
||||||
.mermaid-chart-tooltip {
|
|
||||||
position: absolute;
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
padding: 0.3rem 0.6rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 1000;
|
|
||||||
max-width: 20rem;
|
|
||||||
text-align: center;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
||||||
transform: translateY(-90%);
|
|
||||||
margin-top: -0.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.375rem;
|
|
||||||
}
|
|
||||||
.mermaid-chart-tooltip.visible {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(-100%);
|
|
||||||
}
|
|
||||||
.mermaid-chart-tooltip svg {
|
|
||||||
width: 1.25rem;
|
|
||||||
height: 1.25rem;
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(tooltipStyle);
|
|
||||||
|
|
||||||
const tooltip = document.createElement('div');
|
|
||||||
tooltip.className = 'mermaid-chart-tooltip';
|
|
||||||
document.body.appendChild(tooltip);
|
|
||||||
|
|
||||||
let currentTarget: HTMLElement | null = null;
|
|
||||||
|
|
||||||
const showTooltip = (target: HTMLElement) => {
|
|
||||||
currentTarget = target;
|
|
||||||
const rect = target.getBoundingClientRect();
|
|
||||||
tooltip.innerHTML = `
|
|
||||||
<span class="mdi mdi-open-in-new"></span>
|
|
||||||
Opens in MermaidChart.com
|
|
||||||
`;
|
|
||||||
tooltip.style.left = rect.left + rect.width / 2 - tooltip.offsetWidth / 2 + 'px';
|
|
||||||
tooltip.style.top = rect.top + 'px';
|
|
||||||
tooltip.classList.add('visible');
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideTooltip = () => {
|
|
||||||
currentTarget = null;
|
|
||||||
tooltip.classList.remove('visible');
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('mouseover', (e) => {
|
|
||||||
const target = e.target as HTMLElement;
|
|
||||||
if (
|
|
||||||
target.matches('a[href*="mermaidchart.com"]') ||
|
|
||||||
target.matches('button[onclick*="mermaidchart.com"]')
|
|
||||||
) {
|
|
||||||
showTooltip(target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('mouseout', (e) => {
|
|
||||||
if (!currentTarget?.contains(e.relatedTarget as HTMLElement)) {
|
|
||||||
hideTooltip();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...DefaultTheme,
|
...DefaultTheme,
|
||||||
Layout() {
|
Layout() {
|
||||||
return h(Theme.Layout, null, {
|
return h(Theme.Layout, null, {
|
||||||
// Keeping this as comment as it took a lot of time to figure out how to add a component to the top bar.
|
|
||||||
'home-hero-before': () => h(TopBar),
|
|
||||||
'home-features-after': () => h(HomePage),
|
'home-features-after': () => h(HomePage),
|
||||||
|
'home-hero-before': () => h(TopBar),
|
||||||
'doc-before': () => h(TopBar),
|
'doc-before': () => h(TopBar),
|
||||||
|
'layout-bottom': () => h(Tooltip),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
enhanceApp({ app, router }: EnhanceAppContext) {
|
enhanceApp({ app, router }: EnhanceAppContext) {
|
||||||
@@ -107,13 +29,6 @@ export default {
|
|||||||
app.component('Mermaid', Mermaid);
|
app.component('Mermaid', Mermaid);
|
||||||
app.component('Contributors', Contributors);
|
app.component('Contributors', Contributors);
|
||||||
|
|
||||||
// Add tooltips after app is mounted
|
|
||||||
app.mixin({
|
|
||||||
mounted() {
|
|
||||||
addMermaidChartTooltips();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
router.onBeforeRouteChange = (to) => {
|
router.onBeforeRouteChange = (to) => {
|
||||||
try {
|
try {
|
||||||
const url = new URL(window.location.origin + to);
|
const url = new URL(window.location.origin + to);
|
||||||
|
Reference in New Issue
Block a user