Skip to content

Commit

Permalink
WIP: add arrow-key nav to gallery
Browse files Browse the repository at this point in the history
TODO:
- [ ] Address the TODOs in the code
  • Loading branch information
WofWca committed Nov 30, 2024
1 parent 80d2b27 commit 58c89f9
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 72 deletions.
5 changes: 4 additions & 1 deletion packages/frontend/src/components/AudioPlayer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import styles from './styles.module.scss'

type Props = {
src: string
tabIndex?: 0 | -1
}

export default function AudioPlayer(props: Props) {
return (
<audio controls className={styles.audioPlayer}>
// Despite the element having multiple interactive (pseudo?) elements
// inside of it, tabindex works for all of them.
<audio controls className={styles.audioPlayer} tabIndex={props.tabIndex}>
<source src={props.src} />
</audio>
)
Expand Down
126 changes: 72 additions & 54 deletions packages/frontend/src/components/Gallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import FullscreenMedia, {
NeighboringMediaMode,
} from './dialogs/FullscreenMedia'
import { DialogContext } from '../contexts/DialogContext'
import { RovingTabindexProvider } from '../contexts/RovingTabindex'

const log = getLogger('renderer/Gallery')

Expand Down Expand Up @@ -74,6 +75,7 @@ export default class Gallery extends Component<
}
> {
dateHeader = createRef<HTMLDivElement>()
galleryItemsRef = createRef<HTMLDivElement>()
constructor(props: Props) {
super(props)

Expand Down Expand Up @@ -281,6 +283,7 @@ export default class Gallery extends Component<
style={{ flexGrow: 1 }}
>
<div
ref={this.galleryItemsRef}
className={`gallery gallery-image-object-fit_${
galleryImageKeepAspectRatio ? 'contain' : 'cover'
}`}
Expand All @@ -296,13 +299,18 @@ export default class Gallery extends Component<
<>
<AutoSizer>
{({ width, height }) => (
<FileTable
width={width}
height={height}
mediaLoadResult={mediaLoadResult}
mediaMessageIds={filteredMediaMessageIds}
queryText={queryText}
></FileTable>
<RovingTabindexProvider
wrapperElementRef={this.galleryItemsRef}
direction='vertical'
>
<FileTable
width={width}
height={height}
mediaLoadResult={mediaLoadResult}
mediaMessageIds={filteredMediaMessageIds}
queryText={queryText}
></FileTable>
</RovingTabindexProvider>
)}
</AutoSizer>
{filteredMediaMessageIds.length === 0 && (
Expand Down Expand Up @@ -348,54 +356,64 @@ export default class Gallery extends Component<
}

return (
<FixedSizeGrid
width={width}
height={height}
columnWidth={itemWidth}
rowHeight={itemHeight}
columnCount={itemsPerRow}
rowCount={rowCount}
overscanRowCount={10}
onItemsRendered={({
visibleColumnStartIndex,
visibleRowStartIndex,
}) => {
const msgId =
mediaMessageIds[
visibleRowStartIndex * itemsPerRow +
visibleColumnStartIndex
]
const message = mediaLoadResult[msgId]
if (!message) {
return
}
this.updateFirstVisibleMessage(message)
}}
<RovingTabindexProvider
wrapperElementRef={this.galleryItemsRef}
// TODO improvement: perhaps we can easily write
// proper grid navigation,
// since grid dimensions are known.
direction='both'
>
{({ columnIndex, rowIndex, style }) => {
const msgId =
mediaMessageIds[rowIndex * itemsPerRow + columnIndex]
const message = mediaLoadResult[msgId]
if (!message) {
return null
}
return (
<div
style={{ ...style }}
className='item'
key={msgId}
>
<this.state.element
messageId={msgId}
loadResult={message}
openFullscreenMedia={this.openFullscreenMedia.bind(
this
)}
/>
</div>
)
}}
</FixedSizeGrid>
<FixedSizeGrid
width={width}
height={height}
columnWidth={itemWidth}
rowHeight={itemHeight}
columnCount={itemsPerRow}
rowCount={rowCount}
overscanRowCount={10}
onItemsRendered={({
visibleColumnStartIndex,
visibleRowStartIndex,
}) => {
const msgId =
mediaMessageIds[
visibleRowStartIndex * itemsPerRow +
visibleColumnStartIndex
]
const message = mediaLoadResult[msgId]
if (!message) {
return
}
this.updateFirstVisibleMessage(message)
}}
>
{({ columnIndex, rowIndex, style }) => {
const msgId =
mediaMessageIds[
rowIndex * itemsPerRow + columnIndex
]
const message = mediaLoadResult[msgId]
if (!message) {
return null
}
return (
<div
style={{ ...style }}
className='item'
key={msgId}
>
<this.state.element
messageId={msgId}
loadResult={message}
openFullscreenMedia={this.openFullscreenMedia.bind(
this
)}
/>
</div>
)
}}
</FixedSizeGrid>
</RovingTabindexProvider>
)
}}
</AutoSizer>
Expand Down
Loading

0 comments on commit 58c89f9

Please sign in to comment.