mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
fix: go to file, highlighting
This commit is contained in:
parent
bf41fabac6
commit
66312dbc0f
5 changed files with 48 additions and 35 deletions
|
|
@ -49,11 +49,15 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
value: { accessToken, compressSingletonFolder, searchMode },
|
||||
} = useConfigs()
|
||||
|
||||
React.useEffect(() => {
|
||||
if (visibleNodesGenerator) {
|
||||
visibleNodesGenerator.search(searchModes[searchMode].getSearchParams(searchKey))
|
||||
}
|
||||
}, [visibleNodesGenerator, searchKey, searchMode])
|
||||
const onSearch = React.useCallback(
|
||||
(searchKey: string) => {
|
||||
updateSearchKey(searchKey)
|
||||
if (visibleNodesGenerator) {
|
||||
visibleNodesGenerator.search(searchModes[searchMode].getSearchParams(searchKey))
|
||||
}
|
||||
},
|
||||
[updateSearchKey, visibleNodesGenerator, searchMode],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (treeRoot) {
|
||||
|
|
@ -63,7 +67,6 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
config: {
|
||||
compressSingletonFolder,
|
||||
accessToken,
|
||||
searchMode,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -95,7 +98,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
onClick={e => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
updateSearchKey(node.path + '/')
|
||||
onSearch(node.path + '/')
|
||||
}}
|
||||
>
|
||||
<Icon type="search" />
|
||||
|
|
@ -109,7 +112,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
return renders.length
|
||||
? node => renders.map((render, i) => <React.Fragment key={i}>{render(node)}</React.Fragment>)
|
||||
: undefined
|
||||
}, [goTo, updateSearchKey, searched, searchMode])
|
||||
}, [goTo, onSearch, searched, searchMode])
|
||||
|
||||
const renderLabelText = React.useCallback(
|
||||
node => searchModes[searchMode].renderNodeLabelText(node, searchKey),
|
||||
|
|
@ -147,11 +150,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
visibleNodes &&
|
||||
renderNodeContext && (
|
||||
<>
|
||||
<SearchBar
|
||||
value={searchKey}
|
||||
onSearch={value => updateSearchKey(value)}
|
||||
onFocus={onFocusSearchBar}
|
||||
/>
|
||||
<SearchBar value={searchKey} onSearch={onSearch} onFocus={onFocusSearchBar} />
|
||||
{searched && visibleNodes.nodes.length === 0 && (
|
||||
<>
|
||||
<Text marginTop={6} textAlign="center" color="text.gray">
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function SearchBar({ onSearch, onFocus, value }: Props) {
|
|||
configs.onChange({
|
||||
searchMode: searchMode === 'regex' ? 'fuzzy' : 'regex',
|
||||
})
|
||||
onSearch('')
|
||||
onSearch(value)
|
||||
}}
|
||||
aria-label="Toggle search mode"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ export const fuzzyMode: ModeShape = {
|
|||
getSearchParams(searchKey) {
|
||||
if (!searchKey) return null
|
||||
|
||||
const matchNode = (node: TreeNode) => fuzzyMatch(searchKey, node.path)
|
||||
const searchKeyInLowerCase = searchKey.toLowerCase()
|
||||
const matchNode = (node: TreeNode) => fuzzyMatch(searchKeyInLowerCase, node.path.toLowerCase())
|
||||
return {
|
||||
matchNode,
|
||||
}
|
||||
|
|
@ -15,21 +16,25 @@ export const fuzzyMode: ModeShape = {
|
|||
renderNodeLabelText(node, searchKey) {
|
||||
const { name, path } = node
|
||||
|
||||
const result: React.ReactNode[] = []
|
||||
const indexes = fuzzyMatchIndexes(
|
||||
searchKey.toLowerCase(),
|
||||
path.toLowerCase(),
|
||||
path.length - name.length,
|
||||
)
|
||||
const chunks = name.split('/')
|
||||
let renderedPath = path.slice(0, path.length - name.length)
|
||||
chunks.forEach((chunk, index, chunks) => {
|
||||
renderedPath += '/' + chunk
|
||||
const indexes = fuzzyMatchIndexes(searchKey, renderedPath, renderedPath.length - chunk.length)
|
||||
const regexp = new RegExp(indexes.map(i => `(?<=^.{${i}}).`).join('|'))
|
||||
result.push(
|
||||
let progress = 0
|
||||
return chunks.map((chunk, index, chunks) => {
|
||||
const chunkIndexes = indexes.filter(i => i >= progress && i < chunk.length + progress)
|
||||
const regexp = chunkIndexes.length
|
||||
? new RegExp(chunkIndexes.map(i => `(?<=^.{${i - progress}}).`).join('|'), 'i')
|
||||
: undefined
|
||||
progress += chunk.length + 1
|
||||
return (
|
||||
<span key={chunk} className={cx({ prefix: index + 1 !== chunks.length })}>
|
||||
<Highlight match={regexp} text={chunk} />
|
||||
{index + 1 !== chunks.length && '/'}
|
||||
</span>,
|
||||
<Highlight match={regexp} text={index + 1 === chunks.length ? chunk : chunk + '/'} />
|
||||
</span>
|
||||
)
|
||||
})
|
||||
return result
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { searchModes } from 'components/searchModes'
|
||||
import { GetCreatedMethod, MethodCreator } from 'driver/connect'
|
||||
import { platform } from 'platforms'
|
||||
import { Config } from 'utils/configHelper'
|
||||
|
|
@ -47,7 +46,7 @@ type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, Connecto
|
|||
export const setUpTree: BoundMethodCreator<
|
||||
[
|
||||
Required<Pick<Props, 'treeRoot' | 'metaData'>> & {
|
||||
config: Pick<Config, 'compressSingletonFolder' | 'accessToken' | 'searchMode'>
|
||||
config: Pick<Config, 'compressSingletonFolder' | 'accessToken'>
|
||||
},
|
||||
]
|
||||
> = dispatch => async ({ treeRoot, metaData, config }) => {
|
||||
|
|
@ -71,11 +70,9 @@ export const setUpTree: BoundMethodCreator<
|
|||
dispatch.call(toggleNodeExpansion, node, { recursive: true }),
|
||||
)
|
||||
})
|
||||
visibleNodesGenerator.search(searchModes[config.searchMode].getSearchParams(''))
|
||||
} else {
|
||||
const targetPath = platform.getCurrentPath(metaData.branchName)
|
||||
if (targetPath) dispatch.call(goTo, targetPath)
|
||||
else visibleNodesGenerator.search(searchModes[config.searchMode].getSearchParams(''))
|
||||
}
|
||||
|
||||
dispatch.set({ state: 'done' })
|
||||
|
|
@ -192,15 +189,17 @@ export const updateSearchKey: BoundMethodCreator<[string]> = dispatch => searchK
|
|||
dispatch.set({ searchKey, searched: searchKey !== '' })
|
||||
}
|
||||
|
||||
export const goTo: BoundMethodCreator<[string[]]> = dispatch => currentPath => {
|
||||
export const goTo: BoundMethodCreator<[string[]]> = dispatch => path => {
|
||||
const {
|
||||
state: { visibleNodesGenerator },
|
||||
} = dispatch.get()
|
||||
if (!visibleNodesGenerator) return
|
||||
|
||||
dispatch.set({ searchKey: '', searched: false })
|
||||
dispatch.call(updateSearchKey, '')
|
||||
visibleNodesGenerator.search(null)
|
||||
dispatch.call(expandTo, currentPath)
|
||||
visibleNodesGenerator.onNextUpdate(() => {
|
||||
dispatch.call(expandTo, path)
|
||||
})
|
||||
}
|
||||
|
||||
export const setExpand: BoundMethodCreator<[TreeNode, boolean]> = dispatch => async (
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class BaseLayer {
|
|||
}
|
||||
|
||||
class ShakeLayer extends BaseLayer {
|
||||
shackedRoot: TreeNode | null = null
|
||||
shackedRoot: TreeNode | null = this.baseRoot
|
||||
lastSearchParams: SearchParams | null = null
|
||||
shakeHub = new EventHub<{ emit: TreeNode | null }>()
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ class ShakeLayer extends BaseLayer {
|
|||
(searchParams: ShakeLayer['lastSearchParams']) => {
|
||||
this.lastSearchParams = searchParams
|
||||
|
||||
let root: TreeNode | null = this.baseRoot
|
||||
let root: ShakeLayer['shackedRoot'] = this.baseRoot
|
||||
if (searchParams) {
|
||||
const { matchNode, onChildMatch } = searchParams
|
||||
root = search(this.baseRoot, matchNode, onChildMatch)
|
||||
|
|
@ -339,12 +339,22 @@ export class VisibleNodesGenerator extends FlattenLayer {
|
|||
|
||||
this.flattenHub.addEventListener('emit', () => this.update())
|
||||
this.baseHub.addEventListener('loadingChange', () => this.update())
|
||||
|
||||
this.search(null)
|
||||
}
|
||||
|
||||
onUpdate(callback: (visibleNodes: VisibleNodes) => void) {
|
||||
return this.hub.addEventListener('emit', callback)
|
||||
}
|
||||
|
||||
onNextUpdate(callback: (visibleNodes: VisibleNodes) => void) {
|
||||
const oneTimeSubscription = (visibleNodes: VisibleNodes) => {
|
||||
callback(visibleNodes)
|
||||
this.hub.removeEventListener('emit', oneTimeSubscription)
|
||||
}
|
||||
return this.hub.addEventListener('emit', oneTimeSubscription)
|
||||
}
|
||||
|
||||
update() {
|
||||
this.hub.emit('emit', this.visibleNodes)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue