Skip to content

Commit

Permalink
Work in Progress - Prototype of navigating left and right between sid…
Browse files Browse the repository at this point in the history
…e panel articles
  • Loading branch information
tntmarket committed Jun 28, 2020
1 parent f8e7c11 commit 2f85f93
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/ts/core/features/vim-mode/commands/panel-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {RoamPanel} from 'src/core/features/vim-mode/roam/roam-panel'
import {RoamBlock} from 'src/core/features/vim-mode/roam/roam-block'

export const panelCommands = [
nmap('h', 'Select Panel Left', () => RoamPanel.select('MAIN')),
nmap('h', 'Select Panel Left', () => RoamPanel.selectPreviousPanel()),
nmap('l', 'Select Panel Right', () => {
if (document.querySelector(Selectors.sidebarContent)) {
RoamPanel.select('SIDE')
RoamPanel.selectNextPanel()
}
}),
map('Control+w', 'Close Page in Side Bar', () => {
Expand Down
70 changes: 49 additions & 21 deletions src/ts/core/features/vim-mode/roam/roam-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@ import {assumeExists} from 'src/core/common/assert'
import {RoamBlock, BlockElement, BlockId} from 'src/core/features/vim-mode/roam/roam-block'
import {relativeItem} from 'src/core/common/array'


type BlockNavigationState = {
panels: Map<PanelId, BlockId | null>
focusedPanel: PanelId
panels: Array<PanelId>
panelToBlock: Map<PanelId, BlockId | null>
focusedPanel: PanelIndex
}

const state: BlockNavigationState = {
panels: new Map([
['MAIN', null],
['SIDE', null],
panels: ['__MAIN_PANEL__'],
panelToBlock: new Map([
['__MAIN_PANEL__', null],
]),
focusedPanel: 'MAIN',
focusedPanel: 0,
}

export type PanelId = 'MAIN' | 'SIDE'
type PanelId = '__MAIN_PANEL__' | PageName
type PageName = string
type PanelIndex = number

type PanelElement = HTMLElement

Expand All @@ -32,10 +36,10 @@ type PanelElement = HTMLElement
* The generically reusable parts of this should probably move to core/roam
*/
export class RoamPanel {
private readonly panelId: PanelId
private readonly panelIndex: number

constructor(panelId: PanelId) {
this.panelId = panelId
constructor(panelIndex: number) {
this.panelIndex = panelIndex
}

private blocks = (): BlockElement[] => Array.from(this.element().querySelectorAll(Selectors.block))
Expand All @@ -47,7 +51,7 @@ export class RoamPanel {
}

selectedBlockId(): BlockId {
const blockId = state.panels.get(this.panelId)
const blockId = state.panelToBlock.get(this.panelId())

if (!blockId || !document.getElementById(blockId)) {
// Fallback to selecting the first block,
Expand All @@ -65,42 +69,66 @@ export class RoamPanel {
}

selectBlock(blockId: string) {
state.panels.set(this.panelId, blockId)
state.panelToBlock.set(this.panelId(), blockId)
}

selectRelativeBlock(blocksToJump: number) {
const block = this.selectedBlock().element()
this.selectBlock(this.relativeBlockId(block.id, blocksToJump))
this.scrollUntilBlockIsVisible(block)
this.scrollUntilBlockIsVisible(this.selectedBlock().element())
}

scrollUntilBlockIsVisible(block: BlockElement) {
this.scroll(blockScrollOverflow(block))
}

element(): PanelElement {
if (this.panelId === 'SIDE') {
return assumeExists(document.querySelector(Selectors.sidebarContent) as HTMLElement)
} else {
// 0 means the main panel
if (this.panelIndex === 0) {
const articleElement = assumeExists(document.querySelector(Selectors.mainContent))
return assumeExists(articleElement.parentElement)
}

const sidePanel = assumeExists(document.querySelector(Selectors.sidebarContent) as HTMLElement)
return assumeExists(sidePanel.children[this.panelIndex - 1] as HTMLElement)
}

firstBlockId(): BlockId {
return assumeExists(this.element().querySelector(Selectors.block)).id
}

static get(panelId: PanelId): RoamPanel {
return new RoamPanel(panelId)
private panelId(): PanelId {
return state.panels[this.panelIndex]
}

static selected(): RoamPanel {
return this.get(state.focusedPanel)
// Select the next closest panel when closing the last panel
state.focusedPanel = Math.min(state.focusedPanel, state.panels.length - 1)
return new RoamPanel(state.focusedPanel)
}

static select(panelId: PanelId) {
state.focusedPanel = panelId
static selectPanel(panelIndex: PanelIndex) {
state.focusedPanel = panelIndex
this.selected().element().scrollIntoView({ behavior: 'smooth' })
}

static selectPreviousPanel() {
this.selectPanel(Math.max(state.focusedPanel - 1, 0))
}

static selectNextPanel() {
this.selectPanel(Math.min(state.focusedPanel + 1, state.panels.length - 1))
}

static updateSidePanels() {
const sidePanel = document.querySelector(Selectors.sidebarContent)
if (sidePanel) {
const sidePanelPages = Array.from(assumeExists(sidePanel.children))
const sidePanelPageNames = sidePanelPages.map(page => assumeExists(page.querySelector('h1')).innerText)
state.panels = ['__MAIN_PANEL__'].concat(sidePanelPageNames)
} else {
state.panels = ['__MAIN_PANEL__']
}
}

scrollAndReselectBlockToStayVisible(scrollPx: number) {
Expand Down
14 changes: 11 additions & 3 deletions src/ts/core/features/vim-mode/vim-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export const initializeBlockNavigationMode = async () => {

// Select block when clicked
RoamEvent.onFocusBlock(blockElement => {
RoamPanel.select(blockElement.closest(Selectors.mainContent) ? 'MAIN' : 'SIDE')
if (blockElement.closest(Selectors.mainContent)) {
RoamPanel.selectPreviousPanel()
} else {
RoamPanel.selectNextPanel()
}
RoamPanel.selected().selectBlock(blockElement.id)
updateBlockNavigationView()
})
Expand All @@ -30,12 +34,16 @@ export const initializeBlockNavigationMode = async () => {
// Re-select main panel block after the closing right panel
RoamEvent.onRightPanelToggle(isRightPanelOn => {
if (!isRightPanelOn) {
RoamPanel.select('MAIN')
RoamPanel.selectPreviousPanel()
}
RoamPanel.updateSidePanels()
updateBlockNavigationView()
})
// Select first block in right panel when closing pages in right panel
RoamEvent.onRightPanelChange(updateBlockNavigationView)
RoamEvent.onRightPanelChange(() => {
RoamPanel.updateSidePanels()
updateBlockNavigationView()
})

// Select first block when switching pages
RoamEvent.onChangePage(updateBlockNavigationView)
Expand Down

0 comments on commit 2f85f93

Please sign in to comment.