fix: intercom bubble positioning with bulk action bars (#5952)
* fix: intercom bubble positioning + action bar positioning with app sidebar * fix: docs * del: story
This commit is contained in:
@@ -86,6 +86,7 @@ import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
|||||||
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
||||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||||
import WindowControls from '@/components/ui/WindowControls.vue'
|
import WindowControls from '@/components/ui/WindowControls.vue'
|
||||||
|
import { useIntercomPositioning } from '@/composables/intercom-positioning'
|
||||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||||
import { config } from '@/config'
|
import { config } from '@/config'
|
||||||
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||||
@@ -125,6 +126,17 @@ import { AppNotificationManager } from './providers/app-notifications'
|
|||||||
import { AppPopupNotificationManager } from './providers/app-popup-notifications'
|
import { AppPopupNotificationManager } from './providers/app-popup-notifications'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const intercomBubblePositioning = useIntercomPositioning({ route, themeStore })
|
||||||
|
const {
|
||||||
|
sidebarToggled,
|
||||||
|
forceSidebar,
|
||||||
|
sidebarVisible,
|
||||||
|
intercomBubblePosition,
|
||||||
|
updateIntercomBubbleStyles,
|
||||||
|
clearIntercomBubbleStyles,
|
||||||
|
} = intercomBubblePositioning
|
||||||
|
|
||||||
const notificationManager = new AppNotificationManager()
|
const notificationManager = new AppNotificationManager()
|
||||||
provideNotificationManager(notificationManager)
|
provideNotificationManager(notificationManager)
|
||||||
@@ -158,6 +170,7 @@ provideModrinthClient(tauriApiClient)
|
|||||||
providePageContext({
|
providePageContext({
|
||||||
hierarchicalSidebarAvailable: ref(true),
|
hierarchicalSidebarAvailable: ref(true),
|
||||||
showAds: ref(false),
|
showAds: ref(false),
|
||||||
|
...intercomBubblePositioning.pageContext,
|
||||||
featureFlags: {
|
featureFlags: {
|
||||||
serverRamAsBytesAlwaysOn: computed(() =>
|
serverRamAsBytesAlwaysOn: computed(() =>
|
||||||
themeStore.getFeatureFlag('server_ram_as_bytes_always_on'),
|
themeStore.getFeatureFlag('server_ram_as_bytes_always_on'),
|
||||||
@@ -242,6 +255,7 @@ onUnmounted(async () => {
|
|||||||
document.querySelector('body').removeEventListener('click', handleClick)
|
document.querySelector('body').removeEventListener('click', handleClick)
|
||||||
document.querySelector('body').removeEventListener('auxclick', handleAuxClick)
|
document.querySelector('body').removeEventListener('auxclick', handleAuxClick)
|
||||||
shutdownHostingIntercom()
|
shutdownHostingIntercom()
|
||||||
|
clearIntercomBubbleStyles()
|
||||||
|
|
||||||
await unlistenUpdateDownload?.()
|
await unlistenUpdateDownload?.()
|
||||||
})
|
})
|
||||||
@@ -423,9 +437,6 @@ const handleClose = async () => {
|
|||||||
await getCurrentWindow().close()
|
await getCurrentWindow().close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
const loading = setupLoadingStateProvider()
|
const loading = setupLoadingStateProvider()
|
||||||
loading.setEnabled(false)
|
loading.setEnabled(false)
|
||||||
let initialLoadToken = loading.begin()
|
let initialLoadToken = loading.begin()
|
||||||
@@ -643,22 +654,10 @@ const hasPlus = computed(
|
|||||||
(credentials.value.user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG,
|
(credentials.value.user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG,
|
||||||
)
|
)
|
||||||
|
|
||||||
const sidebarToggled = ref(true)
|
|
||||||
|
|
||||||
themeStore.$subscribe(() => {
|
|
||||||
sidebarToggled.value = !themeStore.toggleSidebar
|
|
||||||
})
|
|
||||||
|
|
||||||
const forceSidebar = computed(
|
|
||||||
() => route.path.startsWith('/browse') || route.path.startsWith('/project'),
|
|
||||||
)
|
|
||||||
const sidebarVisible = computed(() => sidebarToggled.value || forceSidebar.value)
|
|
||||||
const showAd = computed(
|
const showAd = computed(
|
||||||
() => sidebarVisible.value && !hasPlus.value && credentials.value !== undefined,
|
() => sidebarVisible.value && !hasPlus.value && credentials.value !== undefined,
|
||||||
)
|
)
|
||||||
const hostingRouteActive = computed(() => route.path.startsWith('/hosting'))
|
const hostingRouteActive = computed(() => route.path.startsWith('/hosting'))
|
||||||
const INTERCOM_DEFAULT_PADDING = 20
|
|
||||||
const INTERCOM_APP_SIDEBAR_WIDTH = 300
|
|
||||||
|
|
||||||
let intercomBooting = false
|
let intercomBooting = false
|
||||||
let intercomBooted = false
|
let intercomBooted = false
|
||||||
@@ -706,10 +705,8 @@ async function bootIntercom() {
|
|||||||
intercom_user_jwt: token,
|
intercom_user_jwt: token,
|
||||||
session_duration: 1000 * 60 * 60 * 24,
|
session_duration: 1000 * 60 * 60 * 24,
|
||||||
alignment: 'right',
|
alignment: 'right',
|
||||||
horizontal_padding: sidebarVisible.value
|
horizontal_padding: intercomBubblePosition.value.horizontalPadding,
|
||||||
? INTERCOM_APP_SIDEBAR_WIDTH + INTERCOM_DEFAULT_PADDING
|
vertical_padding: intercomBubblePosition.value.verticalPadding,
|
||||||
: INTERCOM_DEFAULT_PADDING,
|
|
||||||
vertical_padding: INTERCOM_DEFAULT_PADDING,
|
|
||||||
})
|
})
|
||||||
intercomBooted = true
|
intercomBooted = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -727,14 +724,13 @@ function shutdownHostingIntercom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
sidebarVisible,
|
intercomBubblePosition,
|
||||||
(visible) => {
|
(position) => {
|
||||||
|
updateIntercomBubbleStyles(position)
|
||||||
if (intercomBooted) {
|
if (intercomBooted) {
|
||||||
window.Intercom?.('update', {
|
window.Intercom?.('update', {
|
||||||
horizontal_padding: visible
|
horizontal_padding: position.horizontalPadding,
|
||||||
? INTERCOM_APP_SIDEBAR_WIDTH + INTERCOM_DEFAULT_PADDING
|
vertical_padding: position.verticalPadding,
|
||||||
: INTERCOM_DEFAULT_PADDING,
|
|
||||||
vertical_padding: INTERCOM_DEFAULT_PADDING,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1772,6 +1768,14 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
--os-handle-bg-active: var(--color-scrollbar) !important;
|
--os-handle-bg-active: var(--color-scrollbar) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.intercom-lightweight-app-launcher,
|
||||||
|
.intercom-launcher-frame,
|
||||||
|
iframe[name='intercom-launcher-frame'] {
|
||||||
|
right: var(--app-support-launcher-right, 20px) !important;
|
||||||
|
bottom: var(--app-support-launcher-bottom, 20px) !important;
|
||||||
|
z-index: 9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.mac {
|
.mac {
|
||||||
.app-grid-statusbar {
|
.app-grid-statusbar {
|
||||||
padding-left: 5rem;
|
padding-left: 5rem;
|
||||||
|
|||||||
100
apps/app-frontend/src/composables/intercom-positioning.ts
Normal file
100
apps/app-frontend/src/composables/intercom-positioning.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { computed, onUnmounted, ref } from 'vue'
|
||||||
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
|
||||||
|
interface ThemeStore {
|
||||||
|
toggleSidebar: boolean
|
||||||
|
$subscribe: (callback: () => void) => () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IntercomBubblePosition {
|
||||||
|
horizontalPadding: number
|
||||||
|
verticalPadding: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const APP_LEFT_NAV_WIDTH = '4rem'
|
||||||
|
const APP_SIDEBAR_WIDTH = 300
|
||||||
|
const INTERCOM_BUBBLE_DEFAULT_PADDING = 20
|
||||||
|
const INTERCOM_BUBBLE_WIDTH = 72
|
||||||
|
const INTERCOM_BUBBLE_RIGHT_VAR = '--app-support-launcher-right'
|
||||||
|
const INTERCOM_BUBBLE_BOTTOM_VAR = '--app-support-launcher-bottom'
|
||||||
|
|
||||||
|
export function useIntercomPositioning({
|
||||||
|
route,
|
||||||
|
themeStore,
|
||||||
|
}: {
|
||||||
|
route: RouteLocationNormalizedLoaded
|
||||||
|
themeStore: ThemeStore
|
||||||
|
}) {
|
||||||
|
const sidebarToggled = ref(true)
|
||||||
|
const unsubscribeSidebarToggle = themeStore.$subscribe(() => {
|
||||||
|
sidebarToggled.value = !themeStore.toggleSidebar
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(unsubscribeSidebarToggle)
|
||||||
|
|
||||||
|
const forceSidebar = computed(
|
||||||
|
() => route.path.startsWith('/browse') || route.path.startsWith('/project'),
|
||||||
|
)
|
||||||
|
const sidebarVisible = computed(() => sidebarToggled.value || forceSidebar.value)
|
||||||
|
const intercomBubbleHorizontalPadding = computed(() =>
|
||||||
|
sidebarVisible.value
|
||||||
|
? APP_SIDEBAR_WIDTH + INTERCOM_BUBBLE_DEFAULT_PADDING
|
||||||
|
: INTERCOM_BUBBLE_DEFAULT_PADDING,
|
||||||
|
)
|
||||||
|
const intercomBubbleVerticalClearance = ref<number | null>(null)
|
||||||
|
const intercomBubblePosition = computed(() => ({
|
||||||
|
horizontalPadding: intercomBubbleHorizontalPadding.value,
|
||||||
|
verticalPadding: intercomBubbleVerticalClearance.value ?? INTERCOM_BUBBLE_DEFAULT_PADDING,
|
||||||
|
}))
|
||||||
|
const intercomBubbleClearanceRequests = new Map<symbol, number>()
|
||||||
|
|
||||||
|
function requestIntercomBubbleVerticalClearance(id: symbol, clearance: number | null) {
|
||||||
|
if (clearance === null) {
|
||||||
|
intercomBubbleClearanceRequests.delete(id)
|
||||||
|
} else {
|
||||||
|
intercomBubbleClearanceRequests.set(id, clearance)
|
||||||
|
}
|
||||||
|
|
||||||
|
intercomBubbleVerticalClearance.value =
|
||||||
|
intercomBubbleClearanceRequests.size > 0
|
||||||
|
? Math.max(...intercomBubbleClearanceRequests.values())
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIntercomBubbleStyles({
|
||||||
|
horizontalPadding,
|
||||||
|
verticalPadding,
|
||||||
|
}: IntercomBubblePosition) {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
|
document.documentElement.style.setProperty(INTERCOM_BUBBLE_RIGHT_VAR, `${horizontalPadding}px`)
|
||||||
|
document.documentElement.style.setProperty(INTERCOM_BUBBLE_BOTTOM_VAR, `${verticalPadding}px`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearIntercomBubbleStyles() {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
|
document.documentElement.style.removeProperty(INTERCOM_BUBBLE_RIGHT_VAR)
|
||||||
|
document.documentElement.style.removeProperty(INTERCOM_BUBBLE_BOTTOM_VAR)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sidebarToggled,
|
||||||
|
forceSidebar,
|
||||||
|
sidebarVisible,
|
||||||
|
intercomBubblePosition,
|
||||||
|
updateIntercomBubbleStyles,
|
||||||
|
clearIntercomBubbleStyles,
|
||||||
|
pageContext: {
|
||||||
|
floatingActionBarOffsets: {
|
||||||
|
left: ref(APP_LEFT_NAV_WIDTH),
|
||||||
|
right: computed(() => (sidebarVisible.value ? `${APP_SIDEBAR_WIDTH}px` : '0px')),
|
||||||
|
},
|
||||||
|
intercomBubble: {
|
||||||
|
width: ref(INTERCOM_BUBBLE_WIDTH),
|
||||||
|
horizontalPadding: intercomBubbleHorizontalPadding,
|
||||||
|
requestVerticalClearance: requestIntercomBubbleVerticalClearance,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onUnmounted, ref, watch } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
|
|
||||||
import { useModalStack } from '../../composables/modal-stack'
|
import { useModalStack } from '../../composables/modal-stack'
|
||||||
|
import { injectPageContext } from '../../providers'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
shown: boolean
|
shown: boolean
|
||||||
@@ -9,11 +10,28 @@ const props = defineProps<{
|
|||||||
belowModal?: boolean
|
belowModal?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const INTERCOM_BUBBLE_GAP = 8
|
||||||
|
|
||||||
|
const barEl = ref<HTMLElement | null>(null)
|
||||||
const toolbarEl = ref<HTMLElement | null>(null)
|
const toolbarEl = ref<HTMLElement | null>(null)
|
||||||
const compact = ref(false)
|
const compact = ref(false)
|
||||||
|
|
||||||
const { stackCount } = useModalStack()
|
const { stackCount } = useModalStack()
|
||||||
|
const pageContext = injectPageContext(null)
|
||||||
|
const shown = computed(() => props.shown)
|
||||||
|
const intercomBubbleClearanceRequestId = Symbol('floating-action-bar')
|
||||||
const zIndex = computed(() => 100 + stackCount.value * 10 + 8 + (!props.belowModal ? 1 : 0))
|
const zIndex = computed(() => 100 + stackCount.value * 10 + 8 + (!props.belowModal ? 1 : 0))
|
||||||
|
const leftOffset = computed(
|
||||||
|
() => pageContext?.floatingActionBarOffsets?.left.value ?? 'var(--left-bar-width, 0px)',
|
||||||
|
)
|
||||||
|
const rightOffset = computed(
|
||||||
|
() => pageContext?.floatingActionBarOffsets?.right.value ?? 'var(--right-bar-width, 0px)',
|
||||||
|
)
|
||||||
|
const barStyle = computed(() => ({
|
||||||
|
zIndex: zIndex.value,
|
||||||
|
'--floating-action-bar-left-offset': leftOffset.value,
|
||||||
|
'--floating-action-bar-right-offset': rightOffset.value,
|
||||||
|
}))
|
||||||
|
|
||||||
function checkCompact() {
|
function checkCompact() {
|
||||||
const el = toolbarEl.value
|
const el = toolbarEl.value
|
||||||
@@ -33,7 +51,60 @@ function checkCompact() {
|
|||||||
compact.value = needsCompact
|
compact.value = needsCompact
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearIntercomBubbleClearance() {
|
||||||
|
pageContext?.intercomBubble?.requestVerticalClearance(intercomBubbleClearanceRequestId, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIntercomBubbleClearance() {
|
||||||
|
const intercomBubble = pageContext?.intercomBubble
|
||||||
|
if (!intercomBubble) return
|
||||||
|
|
||||||
|
if (typeof window === 'undefined' || !shown.value || !barEl.value || !toolbarEl.value) {
|
||||||
|
clearIntercomBubbleClearance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const barRect = barEl.value.getBoundingClientRect()
|
||||||
|
const toolbarRight = barRect.left + toolbarEl.value.offsetLeft + toolbarEl.value.offsetWidth
|
||||||
|
const bubbleLeft =
|
||||||
|
window.innerWidth - intercomBubble.horizontalPadding.value - intercomBubble.width.value
|
||||||
|
|
||||||
|
if (toolbarRight + INTERCOM_BUBBLE_GAP <= bubbleLeft) {
|
||||||
|
clearIntercomBubbleClearance()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const barStyle = window.getComputedStyle(barEl.value)
|
||||||
|
const bottomOffset = Number.parseFloat(barStyle.bottom) || 0
|
||||||
|
intercomBubble.requestVerticalClearance(
|
||||||
|
intercomBubbleClearanceRequestId,
|
||||||
|
Math.ceil(bottomOffset + barEl.value.offsetHeight + INTERCOM_BUBBLE_GAP),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBodyState(shown = props.shown) {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
|
document.body.classList.toggle('floating-action-bar-shown', shown)
|
||||||
|
if (!shown) {
|
||||||
|
clearIntercomBubbleClearance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let observer: ResizeObserver | null = null
|
let observer: ResizeObserver | null = null
|
||||||
|
let updateFrame: number | null = null
|
||||||
|
|
||||||
|
function scheduleIntercomBubbleClearanceUpdate() {
|
||||||
|
if (typeof window === 'undefined') return
|
||||||
|
if (updateFrame !== null) {
|
||||||
|
window.cancelAnimationFrame(updateFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFrame = window.requestAnimationFrame(() => {
|
||||||
|
updateFrame = null
|
||||||
|
updateIntercomBubbleClearance()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
toolbarEl,
|
toolbarEl,
|
||||||
@@ -42,24 +113,51 @@ watch(
|
|||||||
if (!el) return
|
if (!el) return
|
||||||
observer = new ResizeObserver(() => {
|
observer = new ResizeObserver(() => {
|
||||||
checkCompact()
|
checkCompact()
|
||||||
|
scheduleIntercomBubbleClearanceUpdate()
|
||||||
})
|
})
|
||||||
observer.observe(el.parentElement!)
|
observer.observe(el.parentElement!)
|
||||||
checkCompact()
|
checkCompact()
|
||||||
|
scheduleIntercomBubbleClearanceUpdate()
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.shown,
|
() => props.shown,
|
||||||
(shown) => {
|
async (shown) => {
|
||||||
document?.body.classList.toggle('floating-action-bar-shown', shown)
|
await nextTick()
|
||||||
|
updateBodyState(shown)
|
||||||
|
scheduleIntercomBubbleClearanceUpdate()
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[
|
||||||
|
shown,
|
||||||
|
leftOffset,
|
||||||
|
rightOffset,
|
||||||
|
() => pageContext?.intercomBubble?.horizontalPadding.value,
|
||||||
|
() => pageContext?.intercomBubble?.width.value,
|
||||||
|
],
|
||||||
|
() => scheduleIntercomBubbleClearanceUpdate(),
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', scheduleIntercomBubbleClearanceUpdate)
|
||||||
|
scheduleIntercomBubbleClearanceUpdate()
|
||||||
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
observer?.disconnect()
|
observer?.disconnect()
|
||||||
document?.body.classList.remove('floating-action-bar-shown')
|
window.removeEventListener('resize', scheduleIntercomBubbleClearanceUpdate)
|
||||||
|
if (updateFrame !== null) {
|
||||||
|
window.cancelAnimationFrame(updateFrame)
|
||||||
|
}
|
||||||
|
clearIntercomBubbleClearance()
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
document.body.classList.remove('floating-action-bar-shown')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -68,8 +166,9 @@ onUnmounted(() => {
|
|||||||
<Transition name="floating-action-bar" appear>
|
<Transition name="floating-action-bar" appear>
|
||||||
<div
|
<div
|
||||||
v-if="shown"
|
v-if="shown"
|
||||||
|
ref="barEl"
|
||||||
class="floating-action-bar drop-shadow-2xl fixed p-4 bottom-0"
|
class="floating-action-bar drop-shadow-2xl fixed p-4 bottom-0"
|
||||||
:style="{ zIndex }"
|
:style="barStyle"
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -88,8 +187,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.floating-action-bar {
|
.floating-action-bar {
|
||||||
left: var(--left-bar-width, 0px);
|
left: var(--floating-action-bar-left-offset, var(--left-bar-width, 0px));
|
||||||
right: var(--right-bar-width, 0px);
|
right: var(--floating-action-bar-right-offset, var(--right-bar-width, 0px));
|
||||||
transition: bottom 0.25s ease-in-out;
|
transition: bottom 0.25s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,10 +226,6 @@ onUnmounted(() => {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.intercom-lightweight-app-launcher {
|
|
||||||
z-index: 9 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-compact .bar-label {
|
.bar-compact .bar-label {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Ref } from 'vue'
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
|
|
||||||
import { createContext } from '.'
|
import { createContext } from '.'
|
||||||
|
|
||||||
@@ -6,6 +6,15 @@ export interface PageContext {
|
|||||||
// pages may render sidebar content in #sidebar-teleport-target instead of in the main layout when true
|
// pages may render sidebar content in #sidebar-teleport-target instead of in the main layout when true
|
||||||
hierarchicalSidebarAvailable: Ref<boolean>
|
hierarchicalSidebarAvailable: Ref<boolean>
|
||||||
showAds: Ref<boolean>
|
showAds: Ref<boolean>
|
||||||
|
floatingActionBarOffsets?: {
|
||||||
|
left: Ref<string> | ComputedRef<string>
|
||||||
|
right: Ref<string> | ComputedRef<string>
|
||||||
|
}
|
||||||
|
intercomBubble?: {
|
||||||
|
width: Ref<number> | ComputedRef<number>
|
||||||
|
horizontalPadding: Ref<number> | ComputedRef<number>
|
||||||
|
requestVerticalClearance: (id: symbol, clearance: number | null) => void
|
||||||
|
}
|
||||||
featureFlags?: {
|
featureFlags?: {
|
||||||
serverRamAsBytesAlwaysOn?: Ref<boolean>
|
serverRamAsBytesAlwaysOn?: Ref<boolean>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user