Updated tooltips
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
<ViewerControlsButtonToggle
|
||||
v-for="panel in panels"
|
||||
:key="panel.id"
|
||||
v-tippy="panel.tooltip"
|
||||
v-tippy="getTooltipProps(panel.tooltip)"
|
||||
:active="activePanel === panel.id"
|
||||
:icon="panel.icon"
|
||||
@click="toggleActivePanel(panel.id)"
|
||||
@@ -64,6 +64,7 @@ const { toggleSectionBox } = useSectionBoxUtilities()
|
||||
const { getActiveMeasurement, removeMeasurement, enableMeasurements } =
|
||||
useMeasurementUtilities()
|
||||
const { resetExplode } = useFilterUtilities()
|
||||
const { getTooltipProps } = useSmartTooltipDelay()
|
||||
|
||||
const activePanel = ref<ActivePanel>(ActivePanel.none)
|
||||
const panels = shallowRef({
|
||||
|
||||
@@ -10,37 +10,36 @@
|
||||
]"
|
||||
>
|
||||
<div class="flex flex-col gap-2 py-1" :class="isEmbedEnabled ? '' : 'lg:py-2'">
|
||||
<!-- Models -->
|
||||
<ViewerControlsButtonToggle
|
||||
v-tippy="{
|
||||
content: getShortcutDisplayText(shortcuts.ToggleModels),
|
||||
placement: 'right'
|
||||
}"
|
||||
v-tippy="
|
||||
getTooltipProps(getShortcutDisplayText(shortcuts.ToggleModels), {
|
||||
placement: 'right'
|
||||
})
|
||||
"
|
||||
:active="activePanel === 'models'"
|
||||
:icon="'IconViewerModels'"
|
||||
@click="toggleActivePanel('models')"
|
||||
/>
|
||||
|
||||
<!-- Filters -->
|
||||
<ViewerControlsButtonToggle
|
||||
v-tippy="getShortcutDisplayText(shortcuts.ToggleFilters)"
|
||||
v-tippy="
|
||||
getTooltipProps(getShortcutDisplayText(shortcuts.ToggleFilters), {
|
||||
placement: 'right'
|
||||
})
|
||||
"
|
||||
:active="activePanel === 'filters'"
|
||||
:icon="'IconViewerExplorer'"
|
||||
@click="toggleActivePanel('filters')"
|
||||
/>
|
||||
|
||||
<!-- Comment threads -->
|
||||
<ViewerControlsButtonToggle
|
||||
v-tippy="{
|
||||
content: getShortcutDisplayText(shortcuts.ToggleDiscussions),
|
||||
placement: 'right'
|
||||
}"
|
||||
v-tippy="
|
||||
getTooltipProps(getShortcutDisplayText(shortcuts.ToggleDiscussions), {
|
||||
placement: 'right'
|
||||
})
|
||||
"
|
||||
:active="activePanel === 'discussions'"
|
||||
:icon="'IconViewerDiscussions'"
|
||||
@click="toggleActivePanel('discussions')"
|
||||
/>
|
||||
|
||||
<!-- Automation runs -->
|
||||
<ViewerControlsButtonToggle
|
||||
v-if="allAutomationRuns.length !== 0"
|
||||
v-tippy="
|
||||
@@ -165,6 +164,7 @@ const { isEnabled: isEmbedEnabled } = useEmbed()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const { isSmallerOrEqualSm } = useIsSmallerOrEqualThanBreakpoint()
|
||||
const isMobile = breakpoints.smaller('sm')
|
||||
const { getTooltipProps } = useSmartTooltipDelay()
|
||||
|
||||
const activePanel = ref<ActivePanel>('none')
|
||||
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
<aside class="absolute top-[3.75rem] z-20" :style="dynamicStyles">
|
||||
<ViewerControlsButtonGroup direction="vertical">
|
||||
<ViewerControlsButtonToggle
|
||||
v-tippy="{
|
||||
content: getShortcutDisplayText(shortcuts.ZoomExtentsOrSelection),
|
||||
placement: 'left'
|
||||
}"
|
||||
v-tippy="
|
||||
getTooltipProps(getShortcutDisplayText(shortcuts.ZoomExtentsOrSelection), {
|
||||
placement: 'left'
|
||||
})
|
||||
"
|
||||
icon="IconViewerZoom"
|
||||
@click="trackAndzoomExtentsOrSelection()"
|
||||
/>
|
||||
<ViewerControlsButtonToggle
|
||||
v-tippy="{
|
||||
content: 'Camera controls',
|
||||
placement: 'left'
|
||||
}"
|
||||
v-tippy="getTooltipProps('Camera controls', { placement: 'left' })"
|
||||
icon="IconViewerCameraControls"
|
||||
:active="activePanel === 'cameraControls'"
|
||||
@click="toggleActivePanel('cameraControls')"
|
||||
@@ -47,6 +45,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const { zoomExtentsOrSelection } = useCameraUtilities()
|
||||
const { registerShortcuts, getShortcutDisplayText, shortcuts } = useViewerShortcuts()
|
||||
const mixpanel = useMixpanel()
|
||||
const { getTooltipProps } = useSmartTooltipDelay()
|
||||
|
||||
const activePanel = ref<ActivePanel>('none')
|
||||
const menuContainer = ref<Nullable<HTMLElement>>(null)
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<ViewerButtonGroupButton
|
||||
v-for="option in measurementTypeOptions"
|
||||
:key="option.value"
|
||||
v-tippy="option.title"
|
||||
v-tippy="getTooltipProps(option.title)"
|
||||
class="size-8"
|
||||
:is-active="measurementOptions.type === option.value"
|
||||
@click="updateMeasurementsType(option)"
|
||||
@@ -90,6 +90,8 @@ const { measurementOptions, setMeasurementOptions, clearMeasurements } =
|
||||
|
||||
const showSettings = ref(false)
|
||||
|
||||
const { getTooltipProps } = useSmartTooltipDelay()
|
||||
|
||||
const updateMeasurementsType = (selectedOption: MeasurementTypeOption) => {
|
||||
setMeasurementOptions({
|
||||
...measurementOptions.value,
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<ViewerButtonGroupButton
|
||||
v-for="shortcut in viewModeShortcuts"
|
||||
:key="shortcut.name"
|
||||
v-tippy="shortcut.description"
|
||||
v-tippy="getTooltipProps(getShortcutDisplayText(shortcut))"
|
||||
:is-active="isActiveMode(shortcut.viewMode)"
|
||||
@click="handleViewModeChange(shortcut.viewMode)"
|
||||
>
|
||||
@@ -109,8 +109,9 @@ const {
|
||||
setEdgesColor,
|
||||
edgesColor
|
||||
} = useViewModeUtilities()
|
||||
const { registerShortcuts } = useViewerShortcuts()
|
||||
const { registerShortcuts, getShortcutDisplayText } = useViewerShortcuts()
|
||||
const { isLightTheme } = useTheme()
|
||||
const { getTooltipProps } = useSmartTooltipDelay()
|
||||
|
||||
const showSettings = ref(false)
|
||||
|
||||
@@ -126,10 +127,6 @@ const isActiveMode = (mode: ViewMode) => mode === currentViewMode.value
|
||||
|
||||
const viewModeShortcuts = Object.values(ViewModeShortcuts)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'force-close-others'): void
|
||||
}>()
|
||||
|
||||
const edgesColorOptions = computed(() => [
|
||||
isLightTheme.value || currentViewMode.value !== ViewMode.PEN ? 0x1a1a1a : 0xffffff, // black or white
|
||||
0x3b82f6, // blue-500
|
||||
@@ -143,9 +140,6 @@ const handleViewModeChange = (mode: ViewMode, isShortcut = false) => {
|
||||
setViewMode(mode)
|
||||
|
||||
if (isShortcut) {
|
||||
if (!open.value) {
|
||||
emit('force-close-others')
|
||||
}
|
||||
open.value = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
/**
|
||||
* Smart tooltip delay composable
|
||||
*
|
||||
* Provides sophisticated tooltip behavior where:
|
||||
* - First tooltip shows after a configurable delay (default 1 second)
|
||||
* - Subsequent tooltips show instantly once user has shown intent
|
||||
* - State resets after a period of inactivity (default 3 seconds)
|
||||
*/
|
||||
|
||||
export function useSmartTooltipDelay() {
|
||||
const initialDelay = 1000
|
||||
const resetAfter = 3000
|
||||
|
||||
const hasShownAny = ref(false)
|
||||
const resetTimer = ref<NodeJS.Timeout | null>(null)
|
||||
|
||||
const getTooltipProps = (
|
||||
content?: MaybeNullOrUndefined<string>,
|
||||
additionalProps: Record<string, unknown> = {}
|
||||
) => ({
|
||||
content,
|
||||
delay: hasShownAny.value ? 0 : initialDelay,
|
||||
onShow: () => {
|
||||
hasShownAny.value = true
|
||||
if (resetTimer.value) {
|
||||
clearTimeout(resetTimer.value)
|
||||
}
|
||||
resetTimer.value = setTimeout(() => {
|
||||
hasShownAny.value = false
|
||||
}, resetAfter)
|
||||
},
|
||||
...additionalProps
|
||||
})
|
||||
|
||||
const cleanup = () => {
|
||||
if (resetTimer.value) {
|
||||
clearTimeout(resetTimer.value)
|
||||
resetTimer.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
cleanup()
|
||||
hasShownAny.value = false
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
cleanup()
|
||||
})
|
||||
|
||||
return {
|
||||
getTooltipProps,
|
||||
reset
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user