mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
refactor: abandon default export
This commit is contained in:
parent
d9aaf72b03
commit
8ed78e2a98
28 changed files with 142 additions and 214 deletions
|
|
@ -1,17 +1,17 @@
|
|||
import LoadingIndicator from 'components/LoadingIndicator'
|
||||
import Node from 'components/Node'
|
||||
import SearchBar from 'components/SearchBar'
|
||||
import connect from 'driver/connect'
|
||||
import { FileExplorer as FileExplorerCore } from 'driver/core'
|
||||
import { LoadingIndicator } from 'components/LoadingIndicator'
|
||||
import { Node } from 'components/Node'
|
||||
import { SearchBar } from 'components/SearchBar'
|
||||
import { connect } from 'driver/connect'
|
||||
import { FileExplorerCore } from 'driver/core'
|
||||
import { ConnectorState } from 'driver/core/FileExplorer'
|
||||
import * as React from 'react'
|
||||
import { FixedSizeList as List, ListChildComponentProps } from 'react-window'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
import { MetaData, TreeData } from 'utils/GitHubHelper'
|
||||
import { usePrevious } from 'utils/hooks'
|
||||
import { TreeNode, VisibleNodes } from 'utils/VisibleNodesGenerator'
|
||||
import Icon from './Icon'
|
||||
import SizeObserver from './SizeObserver'
|
||||
import { Icon } from './Icon'
|
||||
import { SizeObserver } from './SizeObserver'
|
||||
|
||||
export type Props = {
|
||||
treeData?: TreeData
|
||||
|
|
@ -22,7 +22,7 @@ export type Props = {
|
|||
toggleShowSettings: React.MouseEventHandler
|
||||
}
|
||||
|
||||
class FileExplorer extends React.Component<Props & ConnectorState> {
|
||||
class RawFileExplorer extends React.Component<Props & ConnectorState> {
|
||||
static defaultProps: Partial<Props & ConnectorState> = {
|
||||
freeze: false,
|
||||
searchKey: '',
|
||||
|
|
@ -183,4 +183,4 @@ class FileExplorer extends React.Component<Props & ConnectorState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect<Props, ConnectorState>(FileExplorerCore)(FileExplorer)
|
||||
export const FileExplorer = connect<Props, ConnectorState>(FileExplorerCore)(RawFileExplorer)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import SideBar from 'components/SideBar'
|
||||
import { SideBar } from 'components/SideBar'
|
||||
import * as React from 'react'
|
||||
|
||||
export default class Gitako extends React.PureComponent {
|
||||
export class Gitako extends React.PureComponent {
|
||||
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
||||
raiseError(error, errorInfo)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import Octicon, {
|
|||
X,
|
||||
} from '@primer/octicons-react'
|
||||
import * as React from 'react'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
|
||||
function getSVGIconComponent(
|
||||
type: string,
|
||||
|
|
@ -123,7 +123,7 @@ type Props = {
|
|||
onClick?: (event: React.MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
|
||||
const Icon: React.SFC<Props> = function Icon({ type, className = undefined, ...otherProps }) {
|
||||
export function Icon({ type, className = undefined, ...otherProps }: Props) {
|
||||
const { name, IconComponent } = getSVGIconComponent(type)
|
||||
const mergedClassName = cx('octicon', name)
|
||||
return (
|
||||
|
|
@ -135,5 +135,3 @@ const Icon: React.SFC<Props> = function Icon({ type, className = undefined, ...o
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Icon
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Icon from 'components/Icon'
|
||||
import { Icon } from 'components/Icon'
|
||||
import * as React from 'react'
|
||||
|
||||
type Props = {
|
||||
text: React.ReactNode
|
||||
}
|
||||
export default function LoadingIndicator({ text }: Props) {
|
||||
export function LoadingIndicator({ text }: Props) {
|
||||
return (
|
||||
<div className={'loading-indicator-container'}>
|
||||
<div className={'loading-indicator'}>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import * as React from 'react'
|
||||
import { MetaData } from 'utils/GitHubHelper'
|
||||
import { safeTouch } from 'safe-touch'
|
||||
import { MetaData } from 'utils/GitHubHelper'
|
||||
|
||||
type Props = {
|
||||
metaData: MetaData
|
||||
}
|
||||
|
||||
export default function MetaBar({ metaData }: Props) {
|
||||
export function MetaBar({ metaData }: Props) {
|
||||
const userUrl = safeTouch(metaData).api.owner.html_url()
|
||||
const repoUrl = safeTouch(metaData).api.html_url()
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Icon from 'components/Icon'
|
||||
import { Icon } from 'components/Icon'
|
||||
import * as React from 'react'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
import { OperatingSystems, os } from 'utils/general'
|
||||
import { TreeNode } from 'utils/VisibleNodesGenerator'
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ type Props = {
|
|||
renderActions?(node: TreeNode): React.ReactNode
|
||||
style?: React.CSSProperties
|
||||
}
|
||||
export default class Node extends React.PureComponent<Props> {
|
||||
export class Node extends React.PureComponent<Props> {
|
||||
onClick: React.MouseEventHandler = event => {
|
||||
if (
|
||||
(os === OperatingSystems.macOS && event.metaKey) ||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ type Props<P> = {
|
|||
children: React.ReactElement<P>
|
||||
}
|
||||
|
||||
export default function PJAXLink<P>({ to, children }: Props<P>) {
|
||||
export function PJAXLink<P>({ to, children }: Props<P>) {
|
||||
return React.cloneElement(children, {
|
||||
...children.props,
|
||||
onClick: () => DOMHelper.loadWithPJAX(to),
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ type Props = {
|
|||
into: Element | null
|
||||
}
|
||||
|
||||
class Portal extends React.PureComponent<Props> {
|
||||
export class Portal extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { into, children } = this.props
|
||||
if (!(into instanceof Element)) return null
|
||||
return ReactDOM.createPortal(children, into)
|
||||
}
|
||||
}
|
||||
|
||||
export default Portal
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { HorizontalResizeHandler } from 'components/ResizeHandler'
|
||||
import * as React from 'react'
|
||||
import HorizontalResizeHandler from 'components/ResizeHandler'
|
||||
import cx from 'utils/cx'
|
||||
import { useWindowSize, useMediaStyleSheet } from 'utils/hooks'
|
||||
import { configKeys, setOne } from 'utils/configHelper'
|
||||
import { cx } from 'utils/cx'
|
||||
import { bodySpacingClassName } from 'utils/DOMHelper'
|
||||
import configHelper, { configKeys } from 'utils/configHelper'
|
||||
import * as features from 'utils/features'
|
||||
import { useMediaStyleSheet, useWindowSize } from 'utils/hooks'
|
||||
|
||||
export type Size = number
|
||||
type Props = {
|
||||
|
|
@ -15,11 +15,7 @@ type Props = {
|
|||
const MINIMAL_CONTENT_VIEWPORT_WIDTH = 100
|
||||
const GITHUB_WIDTH = 1020
|
||||
|
||||
export default function Resizable({
|
||||
baseSize,
|
||||
className,
|
||||
children,
|
||||
}: React.PropsWithChildren<Props>) {
|
||||
export function Resizable({ baseSize, className, children }: React.PropsWithChildren<Props>) {
|
||||
const [size, setSize] = React.useState(baseSize)
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
@ -36,7 +32,7 @@ export default function Resizable({
|
|||
|
||||
React.useEffect(() => {
|
||||
document.documentElement.style.setProperty('--gitako-width', size + 'px')
|
||||
configHelper.setOne(configKeys.sideBarWidth, size)
|
||||
setOne(configKeys.sideBarWidth, size)
|
||||
}, [size])
|
||||
|
||||
useMediaStyleSheet(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Icon from 'components/Icon'
|
||||
import { Icon } from 'components/Icon'
|
||||
import * as React from 'react'
|
||||
import { Size } from './Resizable'
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ type Props = {
|
|||
style?: React.CSSProperties
|
||||
}
|
||||
|
||||
export default class HorizontalResizeHandler extends React.PureComponent<Props> {
|
||||
export class HorizontalResizeHandler extends React.PureComponent<Props> {
|
||||
pointerDown = false
|
||||
startX = 0
|
||||
baseSize = this.props.size
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
|
||||
type Props = {
|
||||
onSearch: (searchKey: string) => void
|
||||
|
|
@ -7,7 +7,7 @@ type Props = {
|
|||
searchKey: string
|
||||
}
|
||||
|
||||
export default function SearchBar({ onSearch, onFocus, searchKey }: Props) {
|
||||
export function SearchBar({ onSearch, onFocus, searchKey }: Props) {
|
||||
return (
|
||||
<div className={'search-input-wrapper'}>
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import Icon from 'components/Icon'
|
||||
import { Icon } from 'components/Icon'
|
||||
import { oauth } from 'env'
|
||||
import * as React from 'react'
|
||||
import configHelper, { Config, configKeys } from 'utils/configHelper'
|
||||
import { Config, configKeys, setOne } from 'utils/configHelper'
|
||||
import { friendlyFormatShortcut, JSONRequest, parseURLSearch } from 'utils/general'
|
||||
import keyHelper from 'utils/keyHelper'
|
||||
import * as keyHelper from 'utils/keyHelper'
|
||||
import { version } from '../../package.json'
|
||||
|
||||
const WIKI_HOME_LINK = 'https://github.com/EnixCoda/Gitako/wiki'
|
||||
|
|
@ -50,7 +50,7 @@ type State = {
|
|||
}[]
|
||||
}
|
||||
|
||||
export default class SettingsBar extends React.PureComponent<Props, State> {
|
||||
export class SettingsBar extends React.PureComponent<Props, State> {
|
||||
state = {
|
||||
accessToken: '',
|
||||
accessTokenHint: '',
|
||||
|
|
@ -91,7 +91,7 @@ export default class SettingsBar extends React.PureComponent<Props, State> {
|
|||
onChange: async (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { checked } = e.currentTarget
|
||||
const intelligentToggle = checked ? null : true
|
||||
await configHelper.setOne(configKeys.intelligentToggle, intelligentToggle)
|
||||
await setOne(configKeys.intelligentToggle, intelligentToggle)
|
||||
this.props.setIntelligentToggle(intelligentToggle)
|
||||
},
|
||||
getValue: () => this.props.intelligentToggle === null,
|
||||
|
|
@ -159,7 +159,7 @@ export default class SettingsBar extends React.PureComponent<Props, State> {
|
|||
const { onAccessTokenChange } = this.props
|
||||
const { accessToken } = this.state
|
||||
if (accessToken) {
|
||||
await configHelper.setOne(configKeys.accessToken, accessToken)
|
||||
await setOne(configKeys.accessToken, accessToken)
|
||||
onAccessTokenChange(accessToken)
|
||||
this.setState({
|
||||
accessToken: '',
|
||||
|
|
@ -170,7 +170,7 @@ export default class SettingsBar extends React.PureComponent<Props, State> {
|
|||
|
||||
clearToken = async () => {
|
||||
const { onAccessTokenChange } = this.props
|
||||
await configHelper.setOne(configKeys.accessToken, '')
|
||||
await setOne(configKeys.accessToken, '')
|
||||
onAccessTokenChange('')
|
||||
this.setState({ accessToken: '' })
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ export default class SettingsBar extends React.PureComponent<Props, State> {
|
|||
saveShortcut = async () => {
|
||||
const { onShortcutChange } = this.props
|
||||
const { toggleShowSideBarShortcut } = this.state
|
||||
await configHelper.setOne(configKeys.shortcut, toggleShowSideBarShortcut)
|
||||
await setOne(configKeys.shortcut, toggleShowSideBarShortcut)
|
||||
if (typeof toggleShowSideBarShortcut === 'string') {
|
||||
onShortcutChange(toggleShowSideBarShortcut)
|
||||
this.setState({
|
||||
|
|
@ -214,7 +214,7 @@ export default class SettingsBar extends React.PureComponent<Props, State> {
|
|||
): (e: React.FormEvent<HTMLInputElement>) => Promise<void> {
|
||||
return async e => {
|
||||
const enabled = e.currentTarget.checked
|
||||
await configHelper.setOne(configKey, enabled)
|
||||
await setOne(configKey, enabled)
|
||||
set(enabled)
|
||||
this.showReloadHint()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import FileExplorer from 'components/FileExplorer'
|
||||
import MetaBar from 'components/MetaBar'
|
||||
import Portal from 'components/Portal'
|
||||
import Resizable from 'components/Resizable'
|
||||
import SettingsBar from 'components/SettingsBar'
|
||||
import ToggleShowButton from 'components/ToggleShowButton'
|
||||
import connect from 'driver/connect'
|
||||
import { SideBar as SideBarCore } from 'driver/core'
|
||||
import { FileExplorer } from 'components/FileExplorer'
|
||||
import { MetaBar } from 'components/MetaBar'
|
||||
import { Portal } from 'components/Portal'
|
||||
import { Resizable } from 'components/Resizable'
|
||||
import { SettingsBar } from 'components/SettingsBar'
|
||||
import { ToggleShowButton } from 'components/ToggleShowButton'
|
||||
import { connect } from 'driver/connect'
|
||||
import { SideBarCore } from 'driver/core'
|
||||
import { ConnectorState } from 'driver/core/SideBar'
|
||||
import * as React from 'react'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
|
||||
export type Props = {}
|
||||
|
||||
class Gitako extends React.PureComponent<Props & ConnectorState> {
|
||||
class RawGitako extends React.PureComponent<Props & ConnectorState> {
|
||||
static defaultProps: Partial<Props & ConnectorState> = {
|
||||
baseSize: 260,
|
||||
shouldShow: false,
|
||||
|
|
@ -147,4 +147,4 @@ class Gitako extends React.PureComponent<Props & ConnectorState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect<Props, ConnectorState>(SideBarCore)(Gitako)
|
||||
export const SideBar = connect<Props, ConnectorState>(SideBarCore)(RawGitako)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type Props = {
|
|||
children(size: Partial<Size>): React.ReactNode
|
||||
} & React.HTMLAttributes<HTMLElement>
|
||||
|
||||
export default function SizeObserver({ type = 'div', children, ...rest }: Props) {
|
||||
export function SizeObserver({ type = 'div', children, ...rest }: Props) {
|
||||
const ref = React.useRef<any>()
|
||||
|
||||
const [size, setSize] = React.useState<Partial<Size>>({
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Icon } from 'components/Icon'
|
||||
import * as React from 'react'
|
||||
import Icon from 'components/Icon'
|
||||
import cx from 'utils/cx'
|
||||
import { cx } from 'utils/cx'
|
||||
|
||||
type Props = {
|
||||
error?: string
|
||||
shouldShow: boolean
|
||||
toggleShowSideBar: React.MouseEventHandler
|
||||
}
|
||||
export default function Logo({ error, shouldShow, toggleShowSideBar }: Props) {
|
||||
|
||||
export function ToggleShowButton({ error, shouldShow, toggleShowSideBar }: Props) {
|
||||
return (
|
||||
<div
|
||||
className={cx('gitako-toggle-show-button-wrapper', {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { withErrorLog } from 'analytics'
|
||||
import Gitako from 'components/Gitako'
|
||||
import { Gitako } from 'components/Gitako'
|
||||
import { addMiddleware } from 'driver/connect'
|
||||
import * as React from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ function link<P, S>(instance: React.Component<P, S>, sources: Sources<P, S>): Wr
|
|||
return wrappedMethods
|
||||
}
|
||||
|
||||
export default function connect<BaseP, ExtraP>(mapping: Sources<BaseP, ExtraP>) {
|
||||
export function connect<BaseP, ExtraP>(mapping: Sources<BaseP, ExtraP>) {
|
||||
return function linkComponent<S>(
|
||||
ComponentClass: React.ComponentClass<BaseP & ExtraP, S>,
|
||||
): React.ComponentClass<BaseP, ExtraP> {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import * as ini from 'ini'
|
|||
import { Base64 } from 'js-base64'
|
||||
import * as DOMHelper from 'utils/DOMHelper'
|
||||
import { findNode, searchKeyToRegexps } from 'utils/general'
|
||||
import GitHubHelper, { BlobData } from 'utils/GitHubHelper'
|
||||
import treeParser from 'utils/treeParser'
|
||||
import URLHelper from 'utils/URLHelper'
|
||||
import VisibleNodesGenerator, { TreeNode, VisibleNodes } from 'utils/VisibleNodesGenerator'
|
||||
import * as GitHubHelper from 'utils/GitHubHelper'
|
||||
import { BlobData } from 'utils/GitHubHelper'
|
||||
import * as treeParser from 'utils/treeParser'
|
||||
import * as URLHelper from 'utils/URLHelper'
|
||||
import { TreeNode, VisibleNodes, VisibleNodesGenerator } from 'utils/VisibleNodesGenerator'
|
||||
|
||||
export type ConnectorState = {
|
||||
stateText: string
|
||||
|
|
@ -49,7 +50,7 @@ let visibleNodesGenerator: VisibleNodesGenerator
|
|||
|
||||
type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, ConnectorState, Args>
|
||||
|
||||
const init: BoundMethodCreator = dispatch => () =>
|
||||
export const init: BoundMethodCreator = dispatch => () =>
|
||||
dispatch.call(setStateText, 'Fetching File List...')
|
||||
|
||||
const githubSubModuleURLRegex = {
|
||||
|
|
@ -127,7 +128,7 @@ function handleParsed(root: TreeNode, parsed: Parsed) {
|
|||
})
|
||||
}
|
||||
|
||||
const setUpTree: BoundMethodCreator<
|
||||
export const setUpTree: BoundMethodCreator<
|
||||
[Pick<Props, 'treeData' | 'metaData' | 'compressSingletonFolder' | 'accessToken'>]
|
||||
> = dispatch => async ({ treeData, metaData, compressSingletonFolder, accessToken }) => {
|
||||
if (!treeData) return
|
||||
|
|
@ -158,21 +159,21 @@ const setUpTree: BoundMethodCreator<
|
|||
dispatch.call(goTo, URLHelper.getCurrentPath(metaData.branchName))
|
||||
}
|
||||
|
||||
const execAfterRender: BoundMethodCreator = dispatch => () => {
|
||||
export const execAfterRender: BoundMethodCreator = dispatch => () => {
|
||||
for (const task of tasksAfterRender) {
|
||||
task()
|
||||
}
|
||||
tasksAfterRender.length = 0
|
||||
}
|
||||
|
||||
const setStateText: BoundMethodCreator<[ConnectorState['stateText']]> = dispatch => (
|
||||
export const setStateText: BoundMethodCreator<[ConnectorState['stateText']]> = dispatch => (
|
||||
text: string,
|
||||
) =>
|
||||
dispatch.set({
|
||||
stateText: text,
|
||||
})
|
||||
|
||||
const handleKeyDown: BoundMethodCreator<[React.KeyboardEvent]> = dispatch => event => {
|
||||
export const handleKeyDown: BoundMethodCreator<[React.KeyboardEvent]> = dispatch => event => {
|
||||
const { searched, visibleNodes } = dispatch.get()
|
||||
if (!visibleNodes) return
|
||||
const { nodes, focusedNode, expandedNodes, depths } = visibleNodes
|
||||
|
|
@ -277,16 +278,17 @@ const handleKeyDown: BoundMethodCreator<[React.KeyboardEvent]> = dispatch => eve
|
|||
}
|
||||
}
|
||||
|
||||
const onFocusSearchBar: BoundMethodCreator = dispatch => () => dispatch.call(focusNode, null, false)
|
||||
export const onFocusSearchBar: BoundMethodCreator = dispatch => () =>
|
||||
dispatch.call(focusNode, null, false)
|
||||
|
||||
const search: BoundMethodCreator<[string]> = dispatch => searchKey => {
|
||||
export const search: BoundMethodCreator<[string]> = dispatch => searchKey => {
|
||||
dispatch.set({ searchKey, searched: searchKey !== '' })
|
||||
const regexps = searchKeyToRegexps(searchKey)
|
||||
visibleNodesGenerator.search(regexps)
|
||||
dispatch.call(updateVisibleNodes)
|
||||
}
|
||||
|
||||
const goTo: BoundMethodCreator<[string[]]> = dispatch => async currentPath => {
|
||||
export const goTo: BoundMethodCreator<[string[]]> = dispatch => async currentPath => {
|
||||
visibleNodesGenerator.search([])
|
||||
tasksAfterRender.push(() => {
|
||||
const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/'))
|
||||
|
|
@ -298,12 +300,15 @@ const goTo: BoundMethodCreator<[string[]]> = dispatch => async currentPath => {
|
|||
dispatch.set({ searchKey: '', searched: false })
|
||||
}
|
||||
|
||||
const setExpand: BoundMethodCreator<[TreeNode, boolean]> = dispatch => (node, expand = false) => {
|
||||
export const setExpand: BoundMethodCreator<[TreeNode, boolean]> = dispatch => (
|
||||
node,
|
||||
expand = false,
|
||||
) => {
|
||||
visibleNodesGenerator.setExpand(node, expand)
|
||||
dispatch.call(focusNode, node, false)
|
||||
}
|
||||
|
||||
const toggleNodeExpansion: BoundMethodCreator<[TreeNode, boolean]> = dispatch => (
|
||||
export const toggleNodeExpansion: BoundMethodCreator<[TreeNode, boolean]> = dispatch => (
|
||||
node,
|
||||
skipScrollToNode,
|
||||
) => {
|
||||
|
|
@ -312,7 +317,7 @@ const toggleNodeExpansion: BoundMethodCreator<[TreeNode, boolean]> = dispatch =>
|
|||
tasksAfterRender.push(DOMHelper.focusFileExplorer)
|
||||
}
|
||||
|
||||
const focusNode: BoundMethodCreator<[TreeNode | null, boolean]> = dispatch => (
|
||||
export const focusNode: BoundMethodCreator<[TreeNode | null, boolean]> = dispatch => (
|
||||
node: TreeNode | null,
|
||||
skipScroll = false,
|
||||
) => {
|
||||
|
|
@ -322,7 +327,7 @@ const focusNode: BoundMethodCreator<[TreeNode | null, boolean]> = dispatch => (
|
|||
dispatch.call(updateVisibleNodes)
|
||||
}
|
||||
|
||||
const onNodeClick: BoundMethodCreator<[TreeNode]> = dispatch => node => {
|
||||
export const onNodeClick: BoundMethodCreator<[TreeNode]> = dispatch => node => {
|
||||
if (node.type === 'tree') {
|
||||
dispatch.call(toggleNodeExpansion, node, true)
|
||||
} else if (node.type === 'blob') {
|
||||
|
|
@ -335,23 +340,7 @@ const onNodeClick: BoundMethodCreator<[TreeNode]> = dispatch => node => {
|
|||
}
|
||||
}
|
||||
|
||||
const updateVisibleNodes: BoundMethodCreator = dispatch => () => {
|
||||
export const updateVisibleNodes: BoundMethodCreator = dispatch => () => {
|
||||
const { visibleNodes } = visibleNodesGenerator
|
||||
dispatch.set({ visibleNodes })
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
setUpTree,
|
||||
execAfterRender,
|
||||
setStateText,
|
||||
handleKeyDown,
|
||||
onFocusSearchBar,
|
||||
search,
|
||||
setExpand,
|
||||
goTo,
|
||||
toggleNodeExpansion,
|
||||
focusNode,
|
||||
onNodeClick,
|
||||
updateVisibleNodes,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,12 @@
|
|||
import { Props } from 'components/SideBar'
|
||||
import { GetCreatedMethod, MethodCreator } from 'driver/connect'
|
||||
import configHelper, { Config, configKeys } from 'utils/configHelper'
|
||||
import * as configHelper from 'utils/configHelper'
|
||||
import { Config } from 'utils/configHelper'
|
||||
import * as DOMHelper from 'utils/DOMHelper'
|
||||
import GitHubHelper, {
|
||||
API_RATE_LIMIT,
|
||||
BAD_CREDENTIALS,
|
||||
BLOCKED_PROJECT,
|
||||
EMPTY_PROJECT,
|
||||
MetaData,
|
||||
NOT_FOUND,
|
||||
TreeData,
|
||||
} from 'utils/GitHubHelper'
|
||||
import keyHelper from 'utils/keyHelper'
|
||||
import URLHelper from 'utils/URLHelper'
|
||||
import * as GitHubHelper from 'utils/GitHubHelper'
|
||||
import { MetaData, TreeData } from 'utils/GitHubHelper'
|
||||
import * as keyHelper from 'utils/keyHelper'
|
||||
import * as URLHelper from 'utils/URLHelper'
|
||||
|
||||
export type ConnectorState = {
|
||||
// error message
|
||||
|
|
@ -54,7 +48,7 @@ export type ConnectorState = {
|
|||
|
||||
type BoundMethodCreator<Args extends any[] = []> = MethodCreator<Props, ConnectorState, Args>
|
||||
|
||||
const init: BoundMethodCreator = dispatch => async () => {
|
||||
export const init: BoundMethodCreator = dispatch => async () => {
|
||||
const { initializingPromise } = dispatch.get()
|
||||
if (initializingPromise) await initializingPromise
|
||||
|
||||
|
|
@ -159,15 +153,15 @@ const init: BoundMethodCreator = dispatch => async () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
||||
if (err.message === EMPTY_PROJECT) {
|
||||
export const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
||||
if (err.message === GitHubHelper.EMPTY_PROJECT) {
|
||||
dispatch.call(setError, 'This project seems to be empty.')
|
||||
} else if (err.message === BLOCKED_PROJECT) {
|
||||
} else if (err.message === GitHubHelper.BLOCKED_PROJECT) {
|
||||
dispatch.call(setError, 'This project is blocked.')
|
||||
} else if (
|
||||
err.message === NOT_FOUND ||
|
||||
err.message === BAD_CREDENTIALS ||
|
||||
err.message === API_RATE_LIMIT
|
||||
err.message === GitHubHelper.NOT_FOUND ||
|
||||
err.message === GitHubHelper.BAD_CREDENTIALS ||
|
||||
err.message === GitHubHelper.API_RATE_LIMIT
|
||||
) {
|
||||
dispatch.set({ errorDueToAuth: true })
|
||||
dispatch.call(setShowSettings, true)
|
||||
|
|
@ -179,7 +173,7 @@ const handleError: BoundMethodCreator<[Error]> = dispatch => async err => {
|
|||
}
|
||||
}
|
||||
|
||||
const onPJAXEnd: BoundMethodCreator = dispatch => () => {
|
||||
export const onPJAXEnd: BoundMethodCreator = dispatch => () => {
|
||||
const { metaData, copyFileButton, copySnippetButton, intelligentToggle } = dispatch.get()
|
||||
DOMHelper.unmountTopProgressBar()
|
||||
DOMHelper.decorateGitHubPageContent({ copyFileButton, copySnippetButton })
|
||||
|
|
@ -191,7 +185,7 @@ const onPJAXEnd: BoundMethodCreator = dispatch => () => {
|
|||
}
|
||||
}
|
||||
|
||||
const onKeyDown: BoundMethodCreator<[KeyboardEvent]> = dispatch => e => {
|
||||
export const onKeyDown: BoundMethodCreator<[KeyboardEvent]> = dispatch => e => {
|
||||
const { toggleShowSideBarShortcut } = dispatch.get()
|
||||
if (toggleShowSideBarShortcut) {
|
||||
const keys = keyHelper.parseEvent(e)
|
||||
|
|
@ -201,7 +195,7 @@ const onKeyDown: BoundMethodCreator<[KeyboardEvent]> = dispatch => e => {
|
|||
}
|
||||
}
|
||||
|
||||
const toggleShowSideBar: BoundMethodCreator = dispatch => () => {
|
||||
export const toggleShowSideBar: BoundMethodCreator = dispatch => () => {
|
||||
const { intelligentToggle } = dispatch.get()
|
||||
const shouldShow = !dispatch.get().shouldShow
|
||||
dispatch.call(setShouldShow, shouldShow)
|
||||
|
|
@ -211,28 +205,28 @@ const toggleShowSideBar: BoundMethodCreator = dispatch => () => {
|
|||
}
|
||||
}
|
||||
|
||||
const setShouldShow: BoundMethodCreator<
|
||||
export const setShouldShow: BoundMethodCreator<
|
||||
[ConnectorState['shouldShow']]
|
||||
> = dispatch => shouldShow => {
|
||||
dispatch.set({ shouldShow }, shouldShow ? DOMHelper.focusFileExplorer : undefined)
|
||||
DOMHelper.setBodyIndent(shouldShow)
|
||||
}
|
||||
|
||||
const setError: BoundMethodCreator<[ConnectorState['error']]> = dispatch => error => {
|
||||
export const setError: BoundMethodCreator<[ConnectorState['error']]> = dispatch => error => {
|
||||
dispatch.set({ error })
|
||||
dispatch.call(setShouldShow, false)
|
||||
}
|
||||
|
||||
const toggleShowSettings: BoundMethodCreator = dispatch => () =>
|
||||
export const toggleShowSettings: BoundMethodCreator = dispatch => () =>
|
||||
dispatch.set(({ showSettings }) => ({
|
||||
showSettings: !showSettings,
|
||||
}))
|
||||
|
||||
const setShowSettings: BoundMethodCreator<
|
||||
export const setShowSettings: BoundMethodCreator<
|
||||
[ConnectorState['showSettings']]
|
||||
> = dispatch => showSettings => dispatch.set({ showSettings })
|
||||
|
||||
const onAccessTokenChange: BoundMethodCreator<
|
||||
export const onAccessTokenChange: BoundMethodCreator<
|
||||
[ConnectorState['accessToken']]
|
||||
> = dispatch => accessToken => {
|
||||
dispatch.set({ accessToken })
|
||||
|
|
@ -242,33 +236,33 @@ const onAccessTokenChange: BoundMethodCreator<
|
|||
}
|
||||
}
|
||||
|
||||
const onShortcutChange: BoundMethodCreator<
|
||||
export const onShortcutChange: BoundMethodCreator<
|
||||
[ConnectorState['toggleShowSideBarShortcut']]
|
||||
> = dispatch => shortcut => dispatch.set({ toggleShowSideBarShortcut: shortcut })
|
||||
|
||||
const setMetaData: BoundMethodCreator<[ConnectorState['metaData']]> = dispatch => metaData =>
|
||||
export const setMetaData: BoundMethodCreator<[ConnectorState['metaData']]> = dispatch => metaData =>
|
||||
dispatch.set({ metaData })
|
||||
|
||||
const setCompressSingleton: BoundMethodCreator<
|
||||
export const setCompressSingleton: BoundMethodCreator<
|
||||
[ConnectorState['compressSingletonFolder']]
|
||||
> = dispatch => compressSingletonFolder => dispatch.set({ compressSingletonFolder })
|
||||
|
||||
const setCopyFile: BoundMethodCreator<
|
||||
export const setCopyFile: BoundMethodCreator<
|
||||
[ConnectorState['copyFileButton']]
|
||||
> = dispatch => copyFileButton => dispatch.set({ copyFileButton })
|
||||
|
||||
const setCopySnippet: BoundMethodCreator<
|
||||
export const setCopySnippet: BoundMethodCreator<
|
||||
[ConnectorState['copySnippetButton']]
|
||||
> = dispatch => copySnippetButton => dispatch.set({ copySnippetButton })
|
||||
|
||||
const setIntelligentToggle: BoundMethodCreator<
|
||||
export const setIntelligentToggle: BoundMethodCreator<
|
||||
[ConnectorState['intelligentToggle']]
|
||||
> = dispatch => intelligentToggle => {
|
||||
configHelper.setOne(configKeys.intelligentToggle, intelligentToggle)
|
||||
configHelper.setOne(configHelper.configKeys.intelligentToggle, intelligentToggle)
|
||||
dispatch.set({ intelligentToggle })
|
||||
}
|
||||
|
||||
const useListeners: BoundMethodCreator<[boolean]> = dispatch => {
|
||||
export const useListeners: BoundMethodCreator<[boolean]> = dispatch => {
|
||||
const $onPJAXEnd = () => dispatch.call(onPJAXEnd)
|
||||
const $onKeyDown = (e: KeyboardEvent) => dispatch.call(onKeyDown, e)
|
||||
return on => {
|
||||
|
|
@ -282,23 +276,3 @@ const useListeners: BoundMethodCreator<[boolean]> = dispatch => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
onPJAXEnd,
|
||||
onKeyDown,
|
||||
setShouldShow,
|
||||
setShowSettings,
|
||||
toggleShowSideBar,
|
||||
toggleShowSettings,
|
||||
onAccessTokenChange,
|
||||
onShortcutChange,
|
||||
setMetaData,
|
||||
setCompressSingleton,
|
||||
setCopyFile,
|
||||
setCopySnippet,
|
||||
setIntelligentToggle,
|
||||
setError,
|
||||
handleError,
|
||||
useListeners,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
export { default as SideBar } from './SideBar'
|
||||
export { default as FileExplorer } from './FileExplorer'
|
||||
import * as FileExplorer from './FileExplorer'
|
||||
import * as SideBar from './SideBar'
|
||||
|
||||
export const SideBarCore = SideBar
|
||||
export const FileExplorerCore = FileExplorer
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ type RepoMetaData = {
|
|||
}
|
||||
}
|
||||
|
||||
async function getRepoMeta({ userName, repoName, accessToken }: MetaData): Promise<RepoMetaData> {
|
||||
export async function getRepoMeta({
|
||||
userName,
|
||||
repoName,
|
||||
accessToken,
|
||||
}: MetaData): Promise<RepoMetaData> {
|
||||
const url = `https://api.github.com/repos/${userName}/${repoName}`
|
||||
return await request(url, { accessToken })
|
||||
}
|
||||
|
|
@ -91,7 +95,7 @@ export type TreeData = {
|
|||
url: string
|
||||
}
|
||||
|
||||
async function getTreeData({
|
||||
export async function getTreeData({
|
||||
userName,
|
||||
repoName,
|
||||
branchName,
|
||||
|
|
@ -109,7 +113,7 @@ export type BlobData = {
|
|||
url: string
|
||||
}
|
||||
|
||||
async function getBlobData({
|
||||
export async function getBlobData({
|
||||
userName,
|
||||
repoName,
|
||||
accessToken,
|
||||
|
|
@ -121,17 +125,10 @@ async function getBlobData({
|
|||
return await request(url, { accessToken })
|
||||
}
|
||||
|
||||
function getUrlForRedirect(
|
||||
export function getUrlForRedirect(
|
||||
{ userName, repoName, branchName }: MetaData,
|
||||
type = 'blob',
|
||||
path?: string,
|
||||
) {
|
||||
return `https://github.com/${userName}/${repoName}/${type}/${branchName}/${path}`
|
||||
}
|
||||
|
||||
export default {
|
||||
getRepoMeta,
|
||||
getTreeData,
|
||||
getBlobData,
|
||||
getUrlForRedirect,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { raiseError } from 'analytics'
|
||||
import { MetaData } from './GitHubHelper'
|
||||
|
||||
function parse(): MetaData & { path: string[] } {
|
||||
export function parse(): MetaData & { path: string[] } {
|
||||
const { pathname } = window.location
|
||||
let [
|
||||
,
|
||||
|
|
@ -19,12 +19,12 @@ function parse(): MetaData & { path: string[] } {
|
|||
}
|
||||
}
|
||||
|
||||
function parseSHA() {
|
||||
export function parseSHA() {
|
||||
const { type, path } = parse()
|
||||
return type === 'blob' || type === 'tree' ? path[0] : undefined
|
||||
}
|
||||
|
||||
function isInRepoPage() {
|
||||
export function isInRepoPage() {
|
||||
const repoHeaderSelector = '.repohead'
|
||||
return Boolean(document.querySelector(repoHeaderSelector))
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ const TYPES = {
|
|||
// TODO: record more types
|
||||
}
|
||||
|
||||
function isInCodePage(metaData: MetaData = {}) {
|
||||
export function isInCodePage(metaData: MetaData = {}) {
|
||||
const mergedRepo = { ...parse(), ...metaData }
|
||||
const { type, branchName } = mergedRepo
|
||||
return Boolean(
|
||||
|
|
@ -57,7 +57,7 @@ function isCompleteCommitSHA(sha?: string) {
|
|||
return typeof sha === 'string' && /^[abcdef0-9]{40}$/i.test(sha)
|
||||
}
|
||||
|
||||
function getCurrentPath(branchName = '') {
|
||||
export function getCurrentPath(branchName = '') {
|
||||
const { path, type } = parse()
|
||||
if (type === 'blob' || type === 'tree') {
|
||||
if (isCommitPath(path)) {
|
||||
|
|
@ -90,11 +90,3 @@ function getCurrentPath(branchName = '') {
|
|||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export default {
|
||||
getCurrentPath,
|
||||
isInRepoPage,
|
||||
isInCodePage,
|
||||
parse,
|
||||
parseSHA,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import storageHelper from 'utils/storageHelper'
|
||||
import * as storageHelper from 'utils/storageHelper'
|
||||
|
||||
export type Config = {
|
||||
sideBarWidth: number
|
||||
|
|
@ -43,27 +43,20 @@ function applyDefaultConfigs(configs: Config) {
|
|||
)
|
||||
}
|
||||
|
||||
async function getAll(): Promise<Config> {
|
||||
export async function getAll(): Promise<Config> {
|
||||
return applyDefaultConfigs(await storageHelper.get(configKeyArray))
|
||||
}
|
||||
|
||||
async function getOne(key: configKeys) {
|
||||
export async function getOne(key: configKeys) {
|
||||
return (await getAll())[key]
|
||||
}
|
||||
|
||||
async function setAll(partialConfig: Partial<Config>) {
|
||||
export async function setAll(partialConfig: Partial<Config>) {
|
||||
return await storageHelper.set(partialConfig)
|
||||
}
|
||||
|
||||
async function setOne(key: configKeys, value: any) {
|
||||
export async function setOne(key: configKeys, value: any) {
|
||||
return await setAll({
|
||||
[key]: value,
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
getAll,
|
||||
getOne,
|
||||
setAll,
|
||||
setOne,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* cx('class1', { class2: true, class3: false }) --> 'class1 class2'
|
||||
*/
|
||||
export default function cx(...classNames: any[]): string {
|
||||
export function cx(...classNames: any[]): string {
|
||||
return classNames
|
||||
.filter(Boolean)
|
||||
.map(className => {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ function parseKeyCode(code: string) {
|
|||
return code.toLowerCase().replace(/^control$/, 'ctrl')
|
||||
}
|
||||
|
||||
function parseEvent(e: KeyboardEvent | React.KeyboardEvent) {
|
||||
export function parseEvent(e: KeyboardEvent | React.KeyboardEvent) {
|
||||
const { altKey: alt, shiftKey: shift, metaKey: meta, ctrlKey: ctrl } = e
|
||||
try {
|
||||
const code = parseKeyCode(e.key)
|
||||
|
|
@ -57,7 +57,3 @@ function parseEvent(e: KeyboardEvent | React.KeyboardEvent) {
|
|||
throw new Error(`Error parse keyboard event: ${serializedKeyData}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
parseEvent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
const localStorage = browser.storage.local
|
||||
|
||||
function get(mapping: string[] | null): Promise<any> {
|
||||
export function get(mapping: string[] | null): Promise<any> {
|
||||
return localStorage.get(mapping || undefined)
|
||||
}
|
||||
|
||||
function set(value: any): Promise<void> {
|
||||
export function set(value: any): Promise<void> {
|
||||
return localStorage.set(value)
|
||||
}
|
||||
|
||||
export default {
|
||||
get,
|
||||
set,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import GitHubHelper, { MetaData, TreeData } from 'utils/GitHubHelper'
|
||||
import { getUrlForRedirect, MetaData, TreeData } from 'utils/GitHubHelper'
|
||||
import { TreeNode } from './VisibleNodesGenerator'
|
||||
|
||||
interface RawItem {
|
||||
|
|
@ -36,7 +36,7 @@ function findGitModules(root: TreeNode) {
|
|||
return null
|
||||
}
|
||||
|
||||
function parse(treeData: TreeData, metaData: MetaData) {
|
||||
export function parse(treeData: TreeData, metaData: MetaData) {
|
||||
const { tree } = treeData
|
||||
|
||||
// nodes are created from items and put onto tree
|
||||
|
|
@ -70,7 +70,7 @@ function parse(treeData: TreeData, metaData: MetaData) {
|
|||
name: item.path && item.path.replace(/^.*\//, ''),
|
||||
url:
|
||||
item.url && item.type && item.path
|
||||
? GitHubHelper.getUrlForRedirect(metaData, item.type, item.path)
|
||||
? getUrlForRedirect(metaData, item.type, item.path)
|
||||
: null,
|
||||
contents: item.type === 'tree' ? [] : null,
|
||||
} as TreeNode
|
||||
|
|
@ -88,7 +88,3 @@ function parse(treeData: TreeData, metaData: MetaData) {
|
|||
root: sortFoldersToFront(root),
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
parse,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ type Options = {
|
|||
compress?: boolean
|
||||
}
|
||||
|
||||
export default class VisibleNodesGenerator {
|
||||
export class VisibleNodesGenerator {
|
||||
l1: L1
|
||||
l2: L2
|
||||
l3: L3
|
||||
|
|
|
|||
Loading…
Reference in a new issue