Using teleport for tooltips. Moved theme class to body tag with UI observer.
This commit is contained in:
		
							parent
							
								
									12f247a927
								
							
						
					
					
						commit
						229d74d266
					
				|  | @ -1,8 +1,5 @@ | |||
| <template> | ||||
| 	<div | ||||
| 		class="container" | ||||
| 		:class="theme" | ||||
| 	> | ||||
| 	<div class="container"> | ||||
| 		<Warning | ||||
| 			v-if="showWarning" | ||||
| 			class="warning-container" | ||||
|  | @ -26,16 +23,10 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { mapState } from 'vuex'; | ||||
| 
 | ||||
| import Warning from './warning.vue'; | ||||
| import Header from '../header/header.vue'; | ||||
| import Sidebar from '../sidebar/sidebar.vue'; | ||||
| 
 | ||||
| function theme(state) { | ||||
| 	return state.ui.theme; | ||||
| } | ||||
| 
 | ||||
| function toggleSidebar(state) { | ||||
| 	this.showSidebar = typeof state === 'boolean' ? state : !this.showSidebar; | ||||
| } | ||||
|  | @ -59,11 +50,6 @@ export default { | |||
| 			showWarning: localStorage.getItem('consent') !== window.env.sessionId, | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		...mapState({ | ||||
| 			theme, | ||||
| 		}), | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		toggleSidebar, | ||||
| 		setConsent, | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
| 	<v-popover class="filter-container"> | ||||
| 	<Tooltip class="filter-container"> | ||||
| 		<div class="filter"> | ||||
| 			<Icon icon="users" /> | ||||
| 
 | ||||
|  | @ -14,46 +14,48 @@ | |||
| 			>Actors</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div slot="popover"> | ||||
| 			<router-link | ||||
| 				class="filter-clear" | ||||
| 				:to="{ query: { ...$route.query, actors: undefined } }" | ||||
| 				:class="{ active: selectedActors.length > 0 }" | ||||
| 			>clear all<Icon icon="cross2" /></router-link> | ||||
| 		<template v-slot:tooltip> | ||||
| 			<div> | ||||
| 				<router-link | ||||
| 					class="filter-clear" | ||||
| 					:to="{ query: { ...$route.query, actors: undefined } }" | ||||
| 					:class="{ active: selectedActors.length > 0 }" | ||||
| 				>clear all<Icon icon="cross2" /></router-link> | ||||
| 
 | ||||
| 			<ul class="filter-items nolist"> | ||||
| 				<li | ||||
| 					v-for="actor in availableActors" | ||||
| 					:key="actor.id" | ||||
| 					class="filter-item" | ||||
| 					:class="{ selected: selectedActors.includes(actor.slug) }" | ||||
| 				> | ||||
| 					<router-link | ||||
| 						:to="{ query: { | ||||
| 							...$route.query, | ||||
| 							actors: actor.slug, | ||||
| 						}, params: { pageNumber: 1 } }" | ||||
| 						class="filter-name" | ||||
| 					>{{ actor.name }}</router-link> | ||||
| 
 | ||||
| 					<router-link | ||||
| 						:to="{ query: { ...$route.query, ...getNewRange(actor) }, params: { pageNumber: 1 } }" | ||||
| 						class="filter-include" | ||||
| 				<ul class="filter-items nolist"> | ||||
| 					<li | ||||
| 						v-for="actor in availableActors" | ||||
| 						:key="actor.id" | ||||
| 						class="filter-item" | ||||
| 						:class="{ selected: selectedActors.includes(actor.slug) }" | ||||
| 					> | ||||
| 						<Icon | ||||
| 							icon="checkmark" | ||||
| 							class="filter-add" | ||||
| 						/> | ||||
| 						<router-link | ||||
| 							:to="{ query: { | ||||
| 								...$route.query, | ||||
| 								actors: actor.slug, | ||||
| 							}, params: { pageNumber: 1 } }" | ||||
| 							class="filter-name" | ||||
| 						>{{ actor.name }}</router-link> | ||||
| 
 | ||||
| 						<Icon | ||||
| 							icon="cross2" | ||||
| 							class="filter-remove" | ||||
| 						/> | ||||
| 					</router-link> | ||||
| 				</li> | ||||
| 			</ul> | ||||
| 		</div> | ||||
| 	</v-popover> | ||||
| 						<router-link | ||||
| 							:to="{ query: { ...$route.query, ...getNewRange(actor) }, params: { pageNumber: 1 } }" | ||||
| 							class="filter-include" | ||||
| 						> | ||||
| 							<Icon | ||||
| 								icon="checkmark" | ||||
| 								class="filter-add" | ||||
| 							/> | ||||
| 
 | ||||
| 							<Icon | ||||
| 								icon="cross2" | ||||
| 								class="filter-remove" | ||||
| 							/> | ||||
| 						</router-link> | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</div> | ||||
| 		</template> | ||||
| 	</Tooltip> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
| 	<v-popover class="filter-container"> | ||||
| 	<Tooltip class="filter-container"> | ||||
| 		<div class="filter"> | ||||
| 			<Icon icon="antenna" /> | ||||
| 
 | ||||
|  | @ -14,60 +14,62 @@ | |||
| 			>Channels</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div slot="popover"> | ||||
| 			<router-link | ||||
| 				class="filter-clear" | ||||
| 				:to="{ query: { ...$route.query, channels: undefined, networks: undefined } }" | ||||
| 				:class="{ active: selectedLength > 0 }" | ||||
| 			>clear all<Icon icon="cross2" /></router-link> | ||||
| 		<template v-slot:popover> | ||||
| 			<div slot="popover"> | ||||
| 				<router-link | ||||
| 					class="filter-clear" | ||||
| 					:to="{ query: { ...$route.query, channels: undefined, networks: undefined } }" | ||||
| 					:class="{ active: selectedLength > 0 }" | ||||
| 				>clear all<Icon icon="cross2" /></router-link> | ||||
| 
 | ||||
| 			<ul class="filter-items nolist"> | ||||
| 				<li | ||||
| 					v-for="channel in channelsPerNetwork" | ||||
| 					:key="`channel-${channel.id}`" | ||||
| 					class="filter-item" | ||||
| 					:class="{ | ||||
| 						[channel.type]: true, | ||||
| 						independent: channel.independent, | ||||
| 						selected: channel.type === 'network' ? selectedNetworks.includes(channel.slug) : selectedChannels.includes(channel.slug), | ||||
| 						disabled: channel.parent && selectedNetworks.includes(channel.parent.slug), | ||||
| 					}" | ||||
| 				> | ||||
| 					<router-link | ||||
| 						:to="{ query: { | ||||
| 							...$route.query, | ||||
| 							[channel.type === 'network' ? 'networks' : 'channels']: channel.slug, | ||||
| 							[channel.type === 'network' ? 'channels' : 'networks']: undefined, | ||||
| 						}, params: { pageNumber: 1 } }" | ||||
| 						class="filter-name" | ||||
| 				<ul class="filter-items nolist"> | ||||
| 					<li | ||||
| 						v-for="channel in channelsPerNetwork" | ||||
| 						:key="`channel-${channel.id}`" | ||||
| 						class="filter-item" | ||||
| 						:class="{ | ||||
| 							[channel.type]: true, | ||||
| 							independent: channel.independent, | ||||
| 							selected: channel.type === 'network' ? selectedNetworks.includes(channel.slug) : selectedChannels.includes(channel.slug), | ||||
| 							disabled: channel.parent && selectedNetworks.includes(channel.parent.slug), | ||||
| 						}" | ||||
| 					> | ||||
| 						<img | ||||
| 							v-if="channel.type === 'network' || channel.independent || !channel.parent " | ||||
| 							:src="`/img/logos/${channel.slug}/favicon.png`" | ||||
| 							class="favicon" | ||||
| 						<router-link | ||||
| 							:to="{ query: { | ||||
| 								...$route.query, | ||||
| 								[channel.type === 'network' ? 'networks' : 'channels']: channel.slug, | ||||
| 								[channel.type === 'network' ? 'channels' : 'networks']: undefined, | ||||
| 							}, params: { pageNumber: 1 } }" | ||||
| 							class="filter-name" | ||||
| 						> | ||||
| 							<img | ||||
| 								v-if="channel.type === 'network' || channel.independent || !channel.parent " | ||||
| 								:src="`/img/logos/${channel.slug}/favicon.png`" | ||||
| 								class="favicon" | ||||
| 							> | ||||
| 
 | ||||
| 						{{ channel.name }} | ||||
| 					</router-link> | ||||
| 							{{ channel.name }} | ||||
| 						</router-link> | ||||
| 
 | ||||
| 					<router-link | ||||
| 						:to="{ query: { ...$route.query, ...getNewRange(channel) }, params: { pageNumber: 1 } }" | ||||
| 						class="filter-include" | ||||
| 					> | ||||
| 						<Icon | ||||
| 							icon="checkmark" | ||||
| 							class="filter-add" | ||||
| 						/> | ||||
| 						<router-link | ||||
| 							:to="{ query: { ...$route.query, ...getNewRange(channel) }, params: { pageNumber: 1 } }" | ||||
| 							class="filter-include" | ||||
| 						> | ||||
| 							<Icon | ||||
| 								icon="checkmark" | ||||
| 								class="filter-add" | ||||
| 							/> | ||||
| 
 | ||||
| 						<Icon | ||||
| 							icon="cross2" | ||||
| 							class="filter-remove" | ||||
| 						/> | ||||
| 					</router-link> | ||||
| 				</li> | ||||
| 			</ul> | ||||
| 		</div> | ||||
| 	</v-popover> | ||||
| 							<Icon | ||||
| 								icon="cross2" | ||||
| 								class="filter-remove" | ||||
| 							/> | ||||
| 						</router-link> | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</div> | ||||
| 		</template> | ||||
| 	</Tooltip> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ | |||
| 			>New</router-link> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<!-- | ||||
| 		<div class="filters"> | ||||
| 			<ActorFilter | ||||
| 				class="filters-filter" | ||||
|  | @ -40,7 +39,6 @@ | |||
| 				:available-tags="availableTags" | ||||
| 			/> | ||||
| 		</div> | ||||
| 		--> | ||||
| 	</div> | ||||
| </template> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
| 	<v-popover class="filter-container"> | ||||
| 	<Tooltip class="filter-container"> | ||||
| 		<div class="filter"> | ||||
| 			<Icon icon="price-tag4" /> | ||||
| 
 | ||||
|  | @ -14,52 +14,54 @@ | |||
| 			>Tags</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div slot="popover"> | ||||
| 			<select | ||||
| 				v-model="mode" | ||||
| 				class="filter-mode" | ||||
| 				@change="$router.push({ query: { ...$route.query, mode }, params: { pageNumber: 1 } })" | ||||
| 			> | ||||
| 				<option value="all">match all selected</option> | ||||
| 				<option value="any">match any selected</option> | ||||
| 			</select> | ||||
| 
 | ||||
| 			<router-link | ||||
| 				class="filter-clear" | ||||
| 				:to="{ query: { ...$route.query, tags: undefined, mode: undefined } }" | ||||
| 				:class="{ active: selectedTags.length > 0 }" | ||||
| 			>clear all<Icon icon="cross2" /></router-link> | ||||
| 
 | ||||
| 			<ul class="filter-items nolist"> | ||||
| 				<li | ||||
| 					v-for="tag in availableTags" | ||||
| 					:key="`tag-${tag.id}`" | ||||
| 					class="filter-item" | ||||
| 					:class="{ selected: selectedTags.includes(tag.slug) }" | ||||
| 		<template v-slot:tooltip> | ||||
| 			<div> | ||||
| 				<select | ||||
| 					v-model="mode" | ||||
| 					class="filter-mode" | ||||
| 					@change="$router.push({ query: { ...$route.query, mode }, params: { pageNumber: 1 } })" | ||||
| 				> | ||||
| 					<router-link | ||||
| 						:to="{ query: { ...$route.query, tags: tag.slug, mode }, params: { pageNumber: 1 } }" | ||||
| 						class="filter-name" | ||||
| 					>{{ tag.name }}</router-link> | ||||
| 					<option value="all">match all selected</option> | ||||
| 					<option value="any">match any selected</option> | ||||
| 				</select> | ||||
| 
 | ||||
| 					<router-link | ||||
| 						:to="{ query: { ...$route.query, ...getNewRange(tag.slug), mode }, params: { pageNumber: 1 } }" | ||||
| 						class="filter-include" | ||||
| 				<router-link | ||||
| 					class="filter-clear" | ||||
| 					:to="{ query: { ...$route.query, tags: undefined, mode: undefined } }" | ||||
| 					:class="{ active: selectedTags.length > 0 }" | ||||
| 				>clear all<Icon icon="cross2" /></router-link> | ||||
| 
 | ||||
| 				<ul class="filter-items nolist"> | ||||
| 					<li | ||||
| 						v-for="tag in availableTags" | ||||
| 						:key="`tag-${tag.id}`" | ||||
| 						class="filter-item" | ||||
| 						:class="{ selected: selectedTags.includes(tag.slug) }" | ||||
| 					> | ||||
| 						<Icon | ||||
| 							icon="checkmark" | ||||
| 							class="filter-add" | ||||
| 						/> | ||||
| 						<router-link | ||||
| 							:to="{ query: { ...$route.query, tags: tag.slug, mode }, params: { pageNumber: 1 } }" | ||||
| 							class="filter-name" | ||||
| 						>{{ tag.name }}</router-link> | ||||
| 
 | ||||
| 						<Icon | ||||
| 							icon="cross2" | ||||
| 							class="filter-remove" | ||||
| 						/> | ||||
| 					</router-link> | ||||
| 				</li> | ||||
| 			</ul> | ||||
| 		</div> | ||||
| 	</v-popover> | ||||
| 						<router-link | ||||
| 							:to="{ query: { ...$route.query, ...getNewRange(tag.slug), mode }, params: { pageNumber: 1 } }" | ||||
| 							class="filter-include" | ||||
| 						> | ||||
| 							<Icon | ||||
| 								icon="checkmark" | ||||
| 								class="filter-add" | ||||
| 							/> | ||||
| 
 | ||||
| 							<Icon | ||||
| 								icon="cross2" | ||||
| 								class="filter-remove" | ||||
| 							/> | ||||
| 						</router-link> | ||||
| 					</li> | ||||
| 				</ul> | ||||
| 			</div> | ||||
| 		</template> | ||||
| 	</Tooltip> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|  |  | |||
|  | @ -82,7 +82,7 @@ | |||
| 				@click.stop="toggleSidebar" | ||||
| 			><Icon icon="menu" /></div> | ||||
| 
 | ||||
| 			<v-popover> | ||||
| 			<Tooltip> | ||||
| 				<div class="header-account"> | ||||
| 					<div class="account"> | ||||
| 						<Icon | ||||
|  | @ -92,7 +92,7 @@ | |||
| 					</div> | ||||
| 				</div> | ||||
| 
 | ||||
| 				<template v-slot:popover> | ||||
| 				<template v-slot:tooltip> | ||||
| 					<div class="menu"> | ||||
| 						<ul class="menu-items noselect"> | ||||
| 							<li class="menu-item disabled"> | ||||
|  | @ -149,11 +149,11 @@ | |||
| 						</ul> | ||||
| 					</div> | ||||
| 				</template> | ||||
| 			</v-popover> | ||||
| 			</Tooltip> | ||||
| 
 | ||||
| 			<Search class="search-full" /> | ||||
| 
 | ||||
| 			<v-popover | ||||
| 			<Tooltip | ||||
| 				class="search-compact" | ||||
| 				:open="searching" | ||||
| 				@show="searching = true" | ||||
|  | @ -167,12 +167,12 @@ | |||
| 				/></button> | ||||
| 
 | ||||
| 				<Search | ||||
| 					slot="popover" | ||||
| 					slot="tooltip" | ||||
| 					:searching="searching" | ||||
| 					class="compact" | ||||
| 					@search="searching = false" | ||||
| 				/> | ||||
| 			</v-popover> | ||||
| 			</Tooltip> | ||||
| 		</div> | ||||
| 	</header> | ||||
| </template> | ||||
|  |  | |||
|  | @ -4,24 +4,34 @@ | |||
| 			<slot /> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div class="tooltip"> | ||||
| 			<div class="tooltip-wrapper"> | ||||
| 				<slot name="popover" /> | ||||
| 		<teleport to="body"> | ||||
| 			<div class="tooltip"> | ||||
| 				<div class="tooltip-wrapper"> | ||||
| 					<slot name="tooltip" /> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		</teleport> | ||||
| 	</div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .tooltip-container { | ||||
| 	position: relative; | ||||
| 	font-size: 1rem; | ||||
| } | ||||
| 
 | ||||
| .tooltip-frame { | ||||
| 	position: fixed; | ||||
| } | ||||
| 
 | ||||
| .tooltip { | ||||
| 	position: absolute; | ||||
| 	z-index: 10; | ||||
| 	top: 2rem; | ||||
| 	background: var(--background); | ||||
| 	background: var(--background-light); | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -12,6 +12,9 @@ $breakpoint4: 1500px; | |||
|     --text-dark: #222; | ||||
|     --text-light: #fff; | ||||
| 
 | ||||
|     --background-light: #fff; | ||||
|     --background-dark: #222; | ||||
| 
 | ||||
|     --darken: rgba(0, 0, 0, .5); | ||||
|     --darken-strong: rgba(0, 0, 0, .7); | ||||
|     --darken-extreme: rgba(0, 0, 0, .9); | ||||
|  | @ -40,7 +43,7 @@ $breakpoint4: 1500px; | |||
|     --text: #222; | ||||
|     --text-contrast: #fff; | ||||
| 
 | ||||
|     --background: #fff; | ||||
|     --background: var(--background-light); | ||||
|     --background-dim: #fafafa; | ||||
|     --background-soft: #fdfdfd; | ||||
| 
 | ||||
|  | @ -71,7 +74,7 @@ $breakpoint4: 1500px; | |||
|     --text: #fff; | ||||
|     --text-contrast: #222; | ||||
| 
 | ||||
|     --background: #222; | ||||
|     --background: var(--background-dark); | ||||
|     --background-dim: #181818; | ||||
|     --background-soft: #111; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,13 @@ | |||
| function initUiObservers(store, _router) { | ||||
| 	const body = document.querySelector('body'); | ||||
| 
 | ||||
| 	body.classList.add(store.state.ui.theme); | ||||
| 
 | ||||
| 	store.watch(state => state.ui.theme, (newTheme, oldTheme) => { | ||||
| 		body.classList.add(newTheme); | ||||
| 		body.classList.remove(oldTheme); | ||||
| 	}); | ||||
| 
 | ||||
| 	document.addEventListener('keypress', (event) => { | ||||
| 		if (event.target.tagName === 'INPUT') { | ||||
| 			return; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue