Browse Source

fix mobile highlights

imwald
Silberengel 2 weeks ago
parent
commit
9af5efdbce
  1. 4
      package-lock.json
  2. 2
      package.json
  3. 70
      src/components/Note/SelectionHighlightTrigger.tsx

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "imwald", "name": "imwald",
"version": "23.18.1", "version": "23.18.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "imwald", "name": "imwald",
"version": "23.18.1", "version": "23.18.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@asciidoctor/core": "^3.0.4", "@asciidoctor/core": "^3.0.4",

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "imwald", "name": "imwald",
"version": "23.18.1", "version": "23.18.2",
"description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery", "description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery",
"private": true, "private": true,
"type": "module", "type": "module",

70
src/components/Note/SelectionHighlightTrigger.tsx

@ -1,6 +1,5 @@
import { buildHighlightDataFromEvent } from '@/lib/build-highlight-data' import { buildHighlightDataFromEvent } from '@/lib/build-highlight-data'
import { useCreateHighlight } from './CreateHighlightContext' import { useCreateHighlight } from './CreateHighlightContext'
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from '@/components/ui/drawer'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { Highlighter } from 'lucide-react' import { Highlighter } from 'lucide-react'
@ -80,7 +79,6 @@ export default function SelectionHighlightTrigger({
const [selectedText, setSelectedText] = useState('') const [selectedText, setSelectedText] = useState('')
const [paragraphContext, setParagraphContext] = useState('') const [paragraphContext, setParagraphContext] = useState('')
const [toolbarPos, setToolbarPos] = useState<{ top: number; left: number } | null>(null) const [toolbarPos, setToolbarPos] = useState<{ top: number; left: number } | null>(null)
const [showMobileDrawer, setShowMobileDrawer] = useState(false)
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null) const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const touchEndTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null) const touchEndTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
@ -92,7 +90,6 @@ export default function SelectionHighlightTrigger({
setSelectedText('') setSelectedText('')
setParagraphContext('') setParagraphContext('')
setToolbarPos(null) setToolbarPos(null)
setShowMobileDrawer(false)
}, []) }, [])
const applySelection = useCallback( const applySelection = useCallback(
@ -104,25 +101,19 @@ export default function SelectionHighlightTrigger({
return return
} }
if (isSmallScreen && isSelectingRef.current && !forceShow) return
setSelectedText(hit.selectedText) setSelectedText(hit.selectedText)
setParagraphContext(hit.paragraphContext) setParagraphContext(hit.paragraphContext)
if (isSmallScreen) { const toolbarHeight = isSmallScreen ? 48 : 44
if (forceShow || !isSelectingRef.current) { const toolbarWidth = isSmallScreen ? 200 : 176
setShowMobileDrawer(true)
setToolbarPos(null)
}
return
}
const toolbarHeight = 44
const margin = 8 const margin = 8
const top = const top =
hit.rect.top - toolbarHeight < margin ? hit.rect.bottom + margin : hit.rect.top - toolbarHeight hit.rect.top - toolbarHeight < margin ? hit.rect.bottom + margin : hit.rect.top - toolbarHeight
const rawLeft = hit.rect.left + hit.rect.width / 2 - 80 const rawLeft = hit.rect.left + hit.rect.width / 2 - toolbarWidth / 2
const left = Math.max(margin, Math.min(rawLeft, window.innerWidth - 176 - margin)) const left = Math.max(margin, Math.min(rawLeft, window.innerWidth - toolbarWidth - margin))
setToolbarPos({ top, left }) setToolbarPos({ top, left })
setShowMobileDrawer(false)
}, },
[clearUi, isSmallScreen, openHighlight] [clearUi, isSmallScreen, openHighlight]
) )
@ -158,14 +149,14 @@ export default function SelectionHighlightTrigger({
if (!isSmallScreen) return if (!isSmallScreen) return
isSelectingRef.current = true isSelectingRef.current = true
if (selectionStableTimeoutRef.current) clearTimeout(selectionStableTimeoutRef.current) if (selectionStableTimeoutRef.current) clearTimeout(selectionStableTimeoutRef.current)
setShowMobileDrawer(false) setToolbarPos(null)
} }
const onTouchMove = () => { const onTouchMove = () => {
if (!isSmallScreen) return if (!isSmallScreen) return
isSelectingRef.current = true isSelectingRef.current = true
if (selectionStableTimeoutRef.current) clearTimeout(selectionStableTimeoutRef.current) if (selectionStableTimeoutRef.current) clearTimeout(selectionStableTimeoutRef.current)
setShowMobileDrawer(false) setToolbarPos(null)
} }
const onTouchEnd = () => { const onTouchEnd = () => {
@ -195,6 +186,7 @@ export default function SelectionHighlightTrigger({
return return
} }
setToolbarPos(null)
scheduleMobileStableSelection() scheduleMobileStableSelection()
return return
} }
@ -251,12 +243,12 @@ export default function SelectionHighlightTrigger({
if (!openHighlight) return <>{children}</> if (!openHighlight) return <>{children}</>
const showDesktopToolbar = !isSmallScreen && selectedText && toolbarPos const showToolbar = selectedText && toolbarPos
return ( return (
<div ref={containerRef} className="relative select-text"> <div ref={containerRef} className="relative select-text">
{children} {children}
{showDesktopToolbar ? ( {showToolbar ? (
<> <>
<div <div
className="highlight-button-container fixed z-[150] flex items-center gap-1 rounded-md border bg-background px-2 py-1.5 shadow-lg" className="highlight-button-container fixed z-[150] flex items-center gap-1 rounded-md border bg-background px-2 py-1.5 shadow-lg"
@ -266,8 +258,8 @@ export default function SelectionHighlightTrigger({
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
size="sm" size={isSmallScreen ? 'default' : 'sm'}
className="h-8 gap-1.5" className={isSmallScreen ? 'h-10 gap-1.5' : 'h-8 gap-1.5'}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleCreateHighlight() handleCreateHighlight()
@ -279,8 +271,8 @@ export default function SelectionHighlightTrigger({
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
size="sm" size={isSmallScreen ? 'default' : 'sm'}
className="h-8 px-2" className={isSmallScreen ? 'h-10 px-3' : 'h-8 px-2'}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleDismiss() handleDismiss()
@ -289,43 +281,15 @@ export default function SelectionHighlightTrigger({
{t('Cancel')} {t('Cancel')}
</Button> </Button>
</div> </div>
{!isSmallScreen ? (
<div <div
className="fixed inset-0 z-[149]" className="fixed inset-0 z-[149]"
aria-hidden aria-hidden
data-selection-highlight-ui data-selection-highlight-ui
onClick={handleDismiss} onClick={handleDismiss}
/> />
</>
) : null} ) : null}
</>
{isSmallScreen ? (
<Drawer
open={showMobileDrawer && selectedText.length > 0}
onOpenChange={(open) => {
setShowMobileDrawer(open)
if (!open) handleDismiss()
}}
>
<DrawerContent data-selection-highlight-ui>
<DrawerHeader>
<DrawerTitle>{t('Create Highlight')}</DrawerTitle>
</DrawerHeader>
<div className="space-y-4 p-4 pb-8">
<div className="text-sm text-muted-foreground">{t('Selected text')}:</div>
<div className="break-words rounded-lg bg-muted p-3 text-sm">&ldquo;{selectedText}&rdquo;</div>
<Button
className="w-full"
onClick={(e) => {
e.stopPropagation()
handleCreateHighlight()
}}
>
<Highlighter className="mr-2 h-4 w-4" />
{t('Create Highlight')}
</Button>
</div>
</DrawerContent>
</Drawer>
) : null} ) : null}
</div> </div>
) )

Loading…
Cancel
Save