Skip to content

Commit d095ba0

Browse files
committed
feat: make the floating selectionTools follow the scrolling, while the result window remains fixed (#40)
1 parent 9befe11 commit d095ba0

File tree

5 files changed

+17
-15
lines changed

5 files changed

+17
-15
lines changed

src/components/ConversationCard/index.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ function ConversationCard(props) {
213213
<FloatingToolbar
214214
session={session}
215215
selection=""
216-
position={position}
217216
container={toolbarContainer}
218217
closeable={true}
219218
triggered={true}

src/components/FloatingToolbar/index.jsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ConversationCard from '../ConversationCard'
44
import PropTypes from 'prop-types'
55
import { defaultConfig, getUserConfig } from '../../config/index.mjs'
66
import { config as toolsConfig } from '../../content-script/selection-tools'
7-
import { isMobile, setElementPositionInViewport } from '../../utils'
7+
import { getClientPosition, isMobile, setElementPositionInViewport } from '../../utils'
88
import Draggable from 'react-draggable'
99
import { useClampWindowSize } from '../../hooks/use-clamp-window-size'
1010

@@ -16,15 +16,17 @@ function FloatingToolbar(props) {
1616
const [triggered, setTriggered] = useState(props.triggered)
1717
const [config, setConfig] = useState(defaultConfig)
1818
const [render, setRender] = useState(false)
19-
const [position, setPosition] = useState(props.position)
2019
const [closeable, setCloseable] = useState(props.closeable)
20+
const [position, setPosition] = useState(getClientPosition(props.container))
2121
const [virtualPosition, setVirtualPosition] = useState({ x: 0, y: 0 })
2222
const windowSize = useClampWindowSize([750, 1500], [0, Infinity])
2323

2424
useEffect(() => {
2525
getUserConfig().then((config) => {
2626
setConfig(config)
2727
setRender(true)
28+
29+
if (!triggered) props.container.style.position = 'absolute'
2830
})
2931
}, [])
3032

@@ -127,6 +129,9 @@ function FloatingToolbar(props) {
127129
className: 'chatgptbox-selection-toolbar-button',
128130
title: toolConfig.label,
129131
onClick: async () => {
132+
const p = getClientPosition(props.container)
133+
props.container.style.position = 'fixed'
134+
setPosition(p)
130135
setPrompt(await toolConfig.genPrompt(selection))
131136
setTriggered(true)
132137
},
@@ -149,7 +154,6 @@ function FloatingToolbar(props) {
149154
FloatingToolbar.propTypes = {
150155
session: PropTypes.object.isRequired,
151156
selection: PropTypes.string.isRequired,
152-
position: PropTypes.object.isRequired,
153157
container: PropTypes.object.isRequired,
154158
triggered: PropTypes.bool,
155159
closeable: PropTypes.bool,

src/content-script/index.jsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,12 @@ async function prepareForSelectionTools() {
121121
setTimeout(() => {
122122
const selection = window.getSelection()?.toString()
123123
if (selection) {
124-
const position = { x: e.clientX + 15, y: e.clientY - 15 }
125-
toolbarContainer = createElementAtPosition(position.x, position.y)
124+
toolbarContainer = createElementAtPosition(e.pageX + 15, e.pageY - 15)
126125
toolbarContainer.className = 'chatgptbox-toolbar-container'
127126
render(
128127
<FloatingToolbar
129128
session={initSession()}
130129
selection={selection}
131-
position={position}
132130
container={toolbarContainer}
133131
dockable={true}
134132
/>,
@@ -169,17 +167,15 @@ async function prepareForSelectionToolsTouch() {
169167
setTimeout(() => {
170168
const selection = window.getSelection()?.toString()
171169
if (selection) {
172-
const position = {
173-
x: e.changedTouches[0].clientX + 15,
174-
y: e.changedTouches[0].clientY - 15,
175-
}
176-
toolbarContainer = createElementAtPosition(position.x, position.y)
170+
toolbarContainer = createElementAtPosition(
171+
e.changedTouches[0].pageX + 15,
172+
e.changedTouches[0].pageY - 15,
173+
)
177174
toolbarContainer.className = 'chatgptbox-toolbar-container'
178175
render(
179176
<FloatingToolbar
180177
session={initSession()}
181178
selection={selection}
182-
position={position}
183179
container={toolbarContainer}
184180
dockable={true}
185181
/>,
@@ -214,7 +210,6 @@ async function prepareForRightClickMenu() {
214210
<FloatingToolbar
215211
session={initSession()}
216212
selection=""
217-
position={position}
218213
container={container}
219214
triggered={true}
220215
closeable={true}
@@ -229,7 +224,6 @@ async function prepareForRightClickMenu() {
229224
<FloatingToolbar
230225
session={initSession()}
231226
selection={data.selectionText}
232-
position={position}
233227
container={container}
234228
triggered={true}
235229
closeable={true}

src/utils/get-client-position.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export function getClientPosition(e) {
2+
const rect = e.getBoundingClientRect()
3+
return { x: rect.left, y: rect.top }
4+
}

src/utils/index.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './create-element-at-position'
22
export * from './crop-text'
33
export * from './ends-with-question-mark'
44
export * from './fetch-sse'
5+
export * from './get-client-position'
56
export * from './get-conversation-pairs'
67
export * from './get-possible-element-by-query-selector'
78
export * from './init-session'

0 commit comments

Comments
 (0)