Skip to content

Commit

Permalink
Improve on UX for highlighter (remove/hide/refresh)
Browse files Browse the repository at this point in the history
  • Loading branch information
blackforestboi committed Jul 25, 2024
1 parent 8fcff7d commit 72472f4
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 28 deletions.
2 changes: 1 addition & 1 deletion external/@worldbrain/memex-common
8 changes: 8 additions & 0 deletions src/content-scripts/content_script/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,10 @@ export async function main(
deleteAnnotation: async (annotationId) => {
await annotationsFunctions.deleteAnnotation(annotationId)
},
tooltip: {
getState: tooltipUtils.getTooltipState,
setState: tooltipUtils.setTooltipState,
},
annotationsBG,
annotationsCache,
contentSharingBG,
Expand Down Expand Up @@ -1448,6 +1452,10 @@ export async function main(
}),
askAI: annotationsFunctions.askAI(),
createYoutubeTimestamp: annotationsFunctions.createYoutubeTimestamp,
tooltip: {
getState: tooltipUtils.getTooltipState,
setState: tooltipUtils.setTooltipState,
},
})

// 9. Check for page activity status
Expand Down
4 changes: 1 addition & 3 deletions src/in-page-ui/ribbon/react/containers/ribbon/logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1063,15 +1063,13 @@ export class RibbonContainerLogic extends UILogic<

setState(!currentSetting)
try {
await this.dependencies.tooltip.setState(!currentSetting)
if (currentSetting === true) {
await this.dependencies.inPageUI.removeTooltip()
} else {
await this.dependencies.tooltip.setState(!currentSetting)
await this.dependencies.inPageUI.toggleTooltip()

await this.dependencies.inPageUI.showTooltip()
}
await this.dependencies.tooltip.setState(!currentSetting)
} catch (err) {
setState(!currentSetting)
throw err
Expand Down
15 changes: 8 additions & 7 deletions src/in-page-ui/shared-state/shared-in-page-ui-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ export class SharedInPageUIState implements SharedInPageUIInterface {
}

async showTooltip(options?: ToolTipActionOptions) {
if (this.componentsSetUp.tooltip) {
await this.options.loadComponent('tooltip')
}

const maybeEmitAction = () => {
if (options) {
this._emitAction({
Expand All @@ -275,12 +279,6 @@ export class SharedInPageUIState implements SharedInPageUIInterface {
})
}
}

if (this.componentsShown.tooltip) {
maybeEmitAction()
return
}

await this._setState('tooltip', true)
maybeEmitAction()
return
Expand Down Expand Up @@ -320,7 +318,10 @@ export class SharedInPageUIState implements SharedInPageUIInterface {
}

private async _setState(component: InPageUIComponent, visible: boolean) {
if (this.componentsShown[component] === visible) {
if (
this.componentsShown[component] === visible &&
component !== 'tooltip'
) {
return
}

Expand Down
11 changes: 10 additions & 1 deletion src/in-page-ui/tooltip/content_script/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { cloneSelectionAsPseudoObject } from '@worldbrain/memex-common/lib/annot

interface TooltipRootProps {
mount: InPageUIRootMount
params: Omit<Props, 'onTooltipInit'>
params: Props
onTooltipInit: (showTooltip: () => void) => void
toggleTooltipState: (state: boolean) => Promise<void>
analyticsBG: AnalyticsCoreInterface
Expand All @@ -72,6 +72,11 @@ interface TooltipRootProps {
preventHideTooltip?: boolean,
): Promise<any | null>
getWindow: () => Window
tooltip: {
getState: () => void
setState: (tooltipValue: boolean) => void
}
shouldInitTooltip: boolean
}

interface TooltipRootState {
Expand Down Expand Up @@ -533,6 +538,8 @@ class TooltipRoot extends React.Component<TooltipRootProps, TooltipRootState> {
}
showColorPicker={this.state.showColorPicker}
toggleTooltipState={props.toggleTooltipState}
tooltip={props.params.tooltip}
shouldInitTooltip={props.shouldInitTooltip}
/>
</ThemeProvider>
</StyleSheetManager>
Expand Down Expand Up @@ -566,6 +573,8 @@ export function setupUIContainer(
createHighlight={params.createHighlight}
getWindow={params.getWindow}
toggleTooltipState={props.toggleTooltipState}
tooltip={params.tooltip}
shouldInitTooltip={params.shouldInitTooltip}
/>,
mount.rootElement,
)
Expand Down
78 changes: 62 additions & 16 deletions src/in-page-ui/tooltip/content_script/interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ let manualOverride = false

let removeTooltipStateChangeListener: () => void

let shouldInitTooltip = true // You can set this based on your conditions

export const setShouldInitTooltip = (value: boolean) => {
shouldInitTooltip = value
}

interface TooltipInsertDependencies extends TooltipDependencies {
mount: InPageUIRootMount
}
Expand Down Expand Up @@ -103,6 +109,7 @@ export const insertTooltip = async (params: TooltipInsertDependencies) => {
askAI: shortcutToKeyStrs(state.askAI),
}
},

onTooltipHide: () => params.inPageUI.hideTooltip(),
onTooltipClose: () => params.inPageUI.removeTooltip(),
toggleTooltipState: async (state: boolean) => {
Expand Down Expand Up @@ -154,7 +161,13 @@ export const insertTooltip = async (params: TooltipInsertDependencies) => {
params.inPageUI.events.on(
'tooltipAction',
(event, callback) => {
handleExternalAction(event, callback)
if (event.annotationCacheId || event.openForSpaces) {
handleExternalAction(event, callback)
callback(true)
} else {
setShouldInitTooltip(true)
}

callback(true)
},
)
Expand Down Expand Up @@ -186,6 +199,11 @@ export const insertTooltip = async (params: TooltipInsertDependencies) => {
// Placeholder function, replace with actual implementation
},
openImageInPreview: async (src: string) => null,
tooltip: {
getState: params.tooltip.getState,
setState: params.tooltip.setState,
},
shouldInitTooltip: shouldInitTooltip,
},
{
annotationsBG: params.annotationsBG,
Expand All @@ -203,9 +221,13 @@ export const insertTooltip = async (params: TooltipInsertDependencies) => {
createHighlight: params.createHighlight,
getWindow: () => window,
toggleTooltipState: params.toggleTooltipState,
tooltip: {
getState: params.tooltip.getState,
setState: params.tooltip.setState,
},
shouldInitTooltip: shouldInitTooltip,
},
)

setupTooltipTrigger(() => {
params.inPageUI.showTooltip()
}, null)
Expand Down Expand Up @@ -279,16 +301,35 @@ export const removeTooltip = (options?: { override?: boolean }) => {
// }

export const showContentTooltip = async (params: TooltipInsertDependencies) => {
if (!showTooltip) {
if (showTooltip == null) {
await insertTooltip(params)
}

if (userSelectedText()) {
const position = calculateTooltipPostion()
showTooltip(position)
// There seems to be a race condition with the tooltip setup function to get the "showtooltip" function
// This is a temporary fix to keep trying to get the showtooltip function until it is available

let attempts = 0
const maxAttempts = 20 // 5 seconds total
const baseDelay = 50

while (showTooltip == null && attempts < maxAttempts) {
await new Promise((resolve) =>
setTimeout(resolve, baseDelay * Math.pow(1.5, attempts)),
)

attempts++
}

if (showTooltip == null) {
console.error(
'Failed to initialize showTooltip after multiple attempts',
)
return
}
}

const position = calculateTooltipPosition()
showTooltip(position)
}
/**
* Checks for certain conditions before triggering the tooltip.
* i) Whether the selection made by the user is just text.
Expand Down Expand Up @@ -325,7 +366,7 @@ export const conditionallyTriggerTooltip = delayed(
// } else if (positioning === 'mouse' && event) {
// position = calculateTooltipPostion()
// }
position = calculateTooltipPostion()
position = calculateTooltipPosition()
analytics.trackEvent({
category: 'InPageTooltip',
action: 'showTooltip',
Expand All @@ -340,17 +381,22 @@ export const conditionallyTriggerTooltip = delayed(
10,
)

export function calculateTooltipPostion(): TooltipPosition {
const range = document.getSelection().getRangeAt(0)
export function calculateTooltipPosition(): TooltipPosition {
const selection = document.getSelection()
if (!selection || selection.rangeCount === 0) {
// Return a default position if there's no selection
return { x: window.innerWidth / 2, y: window.innerHeight / 2 }
}

const range = selection.getRangeAt(0)
const boundingRect = range.getBoundingClientRect()
// x = position of element from the left + half of it's width

// x = position of element from the left + half of its width
const x = boundingRect.left + boundingRect.width / 2
// y = scroll height from top + pixels from top + height of element - offset
// y = scroll height from top + pixels from top + height of element
const y = window.pageYOffset + boundingRect.top + boundingRect.height
return {
x,
y,
}

return { x, y }
}

function isAnchorOrContentEditable(selected) {
Expand Down

0 comments on commit 72472f4

Please sign in to comment.