Improved tooltip behavior and styling.

This commit is contained in:
DebaucheryLibrarian 2020-12-27 04:21:10 +01:00
parent 229d74d266
commit a7e6f470f7
7 changed files with 181 additions and 19 deletions

View File

@ -38,6 +38,24 @@ async function setConsent(consent) {
}
}
function blur(event) {
this.events.emit('blur', event);
}
function resize(event) {
this.events.emit('resize', event);
}
function mounted() {
document.addEventListener('click', this.blur);
window.addEventListener('resize', this.resize);
}
function beforeUnmount() {
document.removeEventListener('click', this.blur);
window.removeEventListener('resize', this.resize);
}
export default {
components: {
Header,
@ -50,9 +68,13 @@ export default {
showWarning: localStorage.getItem('consent') !== window.env.sessionId,
};
},
mounted,
beforeUnmount,
methods: {
toggleSidebar,
setConsent,
blur,
resize,
},
};
</script>

View File

@ -15,7 +15,7 @@
</div>
<template v-slot:tooltip>
<div>
<div class="filter-options">
<select
v-model="mode"
class="filter-mode"
@ -105,3 +105,9 @@ export default {
},
};
</script>
<style lang="scss" scoped>
.filter-options {
width: 15rem;
}
</style>

View File

@ -95,14 +95,17 @@
<template v-slot:tooltip>
<div class="menu">
<ul class="menu-items noselect">
<li class="menu-item disabled">
<li
class="menu-item disabled"
@click.stop
>
<Icon icon="enter2" />Sign in
</li>
<li
v-show="!sfw"
class="menu-item"
@click="setSfw(true)"
@click.stop="setSfw(true)"
>
<Icon
icon="flower"
@ -113,7 +116,7 @@
<li
v-show="sfw"
class="menu-item"
@click="setSfw(false)"
@click.stop="setSfw(false)"
>
<Icon
icon="fire"
@ -124,7 +127,7 @@
<li
v-show="theme === 'light'"
class="menu-item"
@click="setTheme('dark')"
@click.stop="setTheme('dark')"
>
<Icon
icon="moon"
@ -135,7 +138,7 @@
<li
v-show="theme === 'dark'"
class="menu-item"
@click="setTheme('light')"
@click.stop="setTheme('light')"
>
<Icon
icon="sun"
@ -143,7 +146,10 @@
/>Light theme
</li>
<li class="menu-item">
<li
class="menu-item disabled"
@click.stop
>
<Icon icon="filter" />Filters
</li>
</ul>

View File

@ -1,13 +1,24 @@
<template>
<div class="tooltip-container">
<div class="trigger">
<div
ref="trigger"
class="trigger noselect"
@click.stop="toggle"
>
<slot />
</div>
<teleport to="body">
<div class="tooltip">
<div class="tooltip-wrapper">
<slot name="tooltip" />
<div
v-if="opened"
ref="tooltip"
class="tooltip-wrapper"
:style="{ transform: `translate3d(${tooltipX}px, ${tooltipY}px, 0)` }"
>
<div class="tooltip-inner">
<div class="tooltip">
<slot name="tooltip" />
</div>
</div>
</div>
</teleport>
@ -15,23 +26,126 @@
</template>
<script>
import { nextTick } from 'vue';
function getX(triggerBoundary, tooltipBoundary) {
const idealPosition = triggerBoundary.left + (triggerBoundary.width / 2) - (tooltipBoundary.width / 2);
// don't overflow left edge
if (idealPosition < 0) {
return 0;
}
// don't overflow right edge
if (idealPosition + tooltipBoundary.width > window.innerWidth) {
return window.innerWidth - tooltipBoundary.width;
}
// position at the center of trigger
return idealPosition;
}
async function calculate() {
if (!this.opened) {
return;
}
const triggerBoundary = this.$refs.trigger.getBoundingClientRect();
const tooltipBoundary = this.$refs.tooltip.getBoundingClientRect();
this.tooltipY = triggerBoundary.top + triggerBoundary.height;
this.tooltipX = this.getX(triggerBoundary, tooltipBoundary);
}
async function open() {
this.events.emit('blur');
await nextTick();
this.opened = true;
await nextTick();
this.calculate();
}
function close() {
this.opened = false;
this.tooltipY = 0;
this.tooltipX = 0;
}
function toggle() {
if (this.opened) {
this.close();
return;
}
this.open();
}
function mounted() {
this.events.on('blur', () => {
this.close();
});
this.events.on('resize', () => {
this.calculate();
});
}
export default {
data() {
return {
opened: false,
tooltipX: 0,
tooltipY: 0,
};
},
mounted,
methods: {
calculate,
getX,
open,
close,
toggle,
},
};
</script>
<style lang="scss" scoped>
.tooltip-container {
position: relative;
font-size: 1rem;
.tooltip-wrapper {
display: flex;
top: 0;
left: 0;
flex-direction: column;
justify-content: center;
position: absolute;
z-index: 10;
}
.tooltip-frame {
position: fixed;
.tooltip-inner {
position: relative;
box-shadow: 0 0 3px var(--darken-weak);
&:after {
content: '';
width: 0;
height: 0;
position: absolute;
z-index : 11;
top: -.5rem;
left: calc(50% - .5rem);
border-left: .5rem solid transparent;
border-right: .5rem solid transparent;
border-bottom: .5rem solid var(--background-light);
margin: 0 auto;
filter: drop-shadow(0 0 3px var(--darken-weak));
}
}
.tooltip {
position: absolute;
z-index: 10;
top: 2rem;
position: relative;
background: var(--background-light);
}
</style>

View File

@ -1,5 +1,7 @@
import { createApp, reactive } from 'vue';
import dayjs from 'dayjs';
import mitt from 'mitt';
import router from './router';
import initStore from './store';
@ -17,6 +19,7 @@ import Tooltip from '../components/tooltip/tooltip.vue';
async function init() {
const store = initStore(reactive(router));
const app = createApp(Container);
const events = mitt();
initUiObservers(store, router);
@ -36,6 +39,11 @@ async function init() {
Tooltip,
'v-popover': Tooltip,
},
data() {
return {
events,
};
},
watch: {
pageTitle(title) {
if (title) {

5
package-lock.json generated
View File

@ -7569,6 +7569,11 @@
"minipass": "^2.9.0"
}
},
"mitt": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
"integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",

View File

@ -107,6 +107,7 @@
"knex-migrate": "^1.7.4",
"longjohn": "^0.2.12",
"mime": "^2.4.4",
"mitt": "^2.1.0",
"moment": "^2.24.0",
"nanoid": "^2.1.11",
"opn": "^5.5.0",