forked from DebaucheryLibrarian/traxxx
				
			Improved tooltip behavior and styling.
This commit is contained in:
		
							parent
							
								
									229d74d266
								
							
						
					
					
						commit
						a7e6f470f7
					
				|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue