From d02c32bb4b54eb8d37b7068e876c1d359c51c165 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sat, 25 Jun 2022 12:41:04 +0800 Subject: [PATCH] feat: add pjax mode setting --- src/components/SideBar.tsx | 3 +- src/components/SideBarBodyWrapper.tsx | 9 ++-- src/components/settings/SettingsBar.tsx | 21 +++++++- src/platforms/GitHub/index.ts | 17 +++++-- src/platforms/platform.d.ts | 2 +- src/styles/index.scss | 67 +++++++++++++------------ src/utils/config/helper.ts | 23 +++++++-- src/utils/hooks/usePJAX.ts | 22 ++++---- 8 files changed, 105 insertions(+), 59 deletions(-) diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index f2b82d5..8d23b6a 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -108,12 +108,11 @@ export function SideBar() { } }, [intelligentToggle, sidebarToggleMode]) + usePJAX() useOnPJAXDone(updateSideBarVisibility) platform.usePlatformHooks?.() - usePJAX() - // Hide sidebar when error due to auth but token is set #128 const hideSidebarOnInvalidToken: boolean = intelligentToggle === null && Boolean(state === 'error-due-to-auth' && accessToken) diff --git a/src/components/SideBarBodyWrapper.tsx b/src/components/SideBarBodyWrapper.tsx index e9a6a98..4698895 100644 --- a/src/components/SideBarBodyWrapper.tsx +++ b/src/components/SideBarBodyWrapper.tsx @@ -2,7 +2,7 @@ import { ResizeHandler } from 'components/ResizeHandler' import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' import { useDebounce, useWindowSize } from 'react-use' -import { defaultConfigs } from 'utils/config/helper' +import { getDefaultConfigs } from 'utils/config/helper' import { cx } from 'utils/cx' import { setCSSVariable } from 'utils/DOMHelper' import * as features from 'utils/features' @@ -103,6 +103,9 @@ export function SideBarBodyWrapper({ ) const dummySize: [number, number] = React.useMemo(() => [size, size], [size]) + + const defaultSideBarWidth = React.useMemo(() => getDefaultConfigs().sideBarWidth, []); + return (
{ - setSize(defaultConfigs.sideBarWidth) - apply(sizeVariableMountPoint, defaultConfigs.sideBarWidth) + setSize(defaultSideBarWidth) + apply(sizeVariableMountPoint, defaultSideBarWidth) }} onResizeStateChange={state => { blockLeaveRef.current = state === 'resizing' diff --git a/src/components/settings/SettingsBar.tsx b/src/components/settings/SettingsBar.tsx index 4e60491..ded58b3 100644 --- a/src/components/settings/SettingsBar.tsx +++ b/src/components/settings/SettingsBar.tsx @@ -1,9 +1,11 @@ import { Link } from '@primer/components' import { Icon } from 'components/Icon' +import { useConfigs } from 'containers/ConfigsContext' import { VERSION } from 'env' import { platform } from 'platforms' import { GitHub } from 'platforms/GitHub' import * as React from 'react' +import { useUpdateEffect } from 'react-use' import { useStateIO } from 'utils/hooks/useStateIO' import { SimpleField, SimpleToggleField } from '../SimpleToggleField' import { AccessTokenSettings } from './AccessTokenSettings' @@ -19,6 +21,7 @@ export const wikiLinks = { copyFileButton: `${WIKI_HOME_LINK}/Copy-file-and-snippet`, copySnippet: `${WIKI_HOME_LINK}/Copy-file-and-snippet`, createAccessToken: `${WIKI_HOME_LINK}/Access-token-for-Gitako`, + pjaxMode: `${WIKI_HOME_LINK}/Pjax-Mode`, } type Props = { @@ -30,7 +33,9 @@ function SettingsBarContent() { const useReloadHint = useStateIO('') const { value: reloadHint } = useReloadHint - const moreFields: SimpleField<'copyFileButton' | 'copySnippetButton'|'codeFolding'>[] = + const moreFields: SimpleField< + 'copyFileButton' | 'copySnippetButton' | 'codeFolding' | 'pjaxMode' + >[] = platform === GitHub ? [ { @@ -39,6 +44,16 @@ function SettingsBarContent() { wikiLink: wikiLinks.codeFolding, tooltip: `Read more in Gitako's Wiki`, }, + { + key: 'pjaxMode', + label: 'Native PJAX mode', + wikiLink: wikiLinks.pjaxMode, + tooltip: 'Please keep it enabled unless Gitako crashes after redirecting', + overwrite: { + value: pjaxMode => pjaxMode === 'native', + onChange: checked => (checked ? 'native' : 'pjax-api'), + }, + }, { key: 'copyFileButton', label: 'Copy file button', @@ -54,6 +69,10 @@ function SettingsBarContent() { ] : [] + useUpdateEffect(() => { + window.location.reload() + }, [useConfigs().value.pjaxMode]) + return ( <>

Settings

diff --git a/src/platforms/GitHub/index.ts b/src/platforms/GitHub/index.ts index e21855c..c9a8d15 100644 --- a/src/platforms/GitHub/index.ts +++ b/src/platforms/GitHub/index.ts @@ -1,6 +1,7 @@ import { useConfigs } from 'containers/ConfigsContext' import { GITHUB_OAUTH } from 'env' import { Base64 } from 'js-base64' +import { configRef } from 'utils/config/helper' import { run } from 'utils/general' import { resolveGitModules } from 'utils/gitSubmodule' import { sortFoldersToFront } from 'utils/treeParser' @@ -169,7 +170,10 @@ export const GitHub: Platform = { return await getRepositoryTreeData(metaData, path, recursive, accessToken) }, shouldShow() { - return Boolean(DOMHelper.isInCodePage() || (URLHelper.isInPullPage() && !DOMHelper.isNativePRFileTreeShown())) + return Boolean( + DOMHelper.isInCodePage() || + (URLHelper.isInPullPage() && !DOMHelper.isNativePRFileTreeShown()), + ) }, shouldExpandAll() { return Boolean(URLHelper.isInPullPage()) @@ -205,8 +209,8 @@ export const GitHub: Platform = { useGitHubCodeFold(codeFolding) useEnterpriseStatBarStyleFix() }, - delegatePJAXProps(options) { - if (!options?.node || options.node.type === 'blob') + delegatePJAXProps: options => { + if (configRef.pjaxMode === 'native' && (!options?.node || options.node.type === 'blob')) return { 'data-pjax': pjaxContainerSelector, onClick() { @@ -214,8 +218,11 @@ export const GitHub: Platform = { }, } }, - loadWithPJAX(url, element) { - element.click() + loadWithPJAX: (url, element) => { + if (configRef.pjaxMode === 'native') { + element.click() + return true + } }, } diff --git a/src/platforms/platform.d.ts b/src/platforms/platform.d.ts index e555d7a..8431249 100644 --- a/src/platforms/platform.d.ts +++ b/src/platforms/platform.d.ts @@ -26,6 +26,6 @@ type Platform = { delegatePJAXProps?(options?: { node?: TreeNode }): void | (React.DOMAttributes & Record) // support data-* attributes - loadWithPJAX?(url: string, element: HTMLElement): void + loadWithPJAX?(url: string, element: HTMLElement): boolean | void usePlatformHooks?(): void } diff --git a/src/styles/index.scss b/src/styles/index.scss index 60570e5..ddf9ad4 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -883,6 +883,40 @@ $minimal-z-index: max( overflow: auto; position: relative; + .select-wrapper { + position: relative; + + select { + width: 100%; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + // make it look like text inputs + height: 36px; + padding: 0 6px; + border-radius: 6px; + border: 1px solid var(--gitako-border-default); + background: var(--gitako-canvas-default); + color: var(--gitako-fg-default); + box-shadow: var(--gitako-primer-shadow-inset); + } + + .chevron { + position: absolute; + right: 6px; + top: 8px; + width: 10px; + height: 20px; + + &::before { + width: 10px; + height: 20px; + background-color: var(--gitako-fg-subtle); + @include pseudo-primer-icon('chevron-down'); + } + } + } + .shadow-shelter { position: absolute; width: 100%; @@ -914,39 +948,6 @@ $minimal-z-index: max( cursor: not-allowed; } } - .select-wrapper { - position: relative; - - select { - width: 100%; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - // make it look like text inputs - height: 36px; - padding: 0 6px; - border-radius: 6px; - border: 1px solid var(--gitako-border-default); - background: var(--gitako-canvas-default); - color: var(--gitako-fg-default); - box-shadow: var(--gitako-primer-shadow-inset); - } - - .chevron { - position: absolute; - right: 6px; - top: 8px; - width: 10px; - height: 20px; - - &::before { - width: 10px; - height: 20px; - background-color: var(--gitako-fg-subtle); - @include pseudo-primer-icon('chevron-down'); - } - } - } &.field-checkbox { padding-left: 20px; vertical-align: middle; diff --git a/src/utils/config/helper.ts b/src/utils/config/helper.ts index ea3c369..e541087 100644 --- a/src/utils/config/helper.ts +++ b/src/utils/config/helper.ts @@ -1,4 +1,5 @@ import { SearchMode } from 'components/searchModes' +import { platformName } from 'platforms' import { storageHelper } from 'utils/storageHelper' import { migrateConfig } from './migrations' @@ -21,6 +22,7 @@ export type Config = { compactFileTree: boolean restoreExpandedFolders: boolean showDiffInText: boolean + pjaxMode: 'native' | 'pjax-api' } enum configKeys { @@ -42,18 +44,20 @@ enum configKeys { compactFileTree = 'compactFileTree', restoreExpandedFolders = 'restoreExpandedFolders', showDiffInText = 'showDiffInText', + pjaxMode = 'pjaxMode', } -// do NOT use platform name +// NOT use platform name to distinguish GHE from github.com const platformStorageKey = `platform_` + window.location.host.toLowerCase() +const isInGitHub = platformStorageKey === 'platform_github.com' -export const defaultConfigs: Config = { +export const getDefaultConfigs: () => Config = () => ({ sideBarWidth: 260, shortcut: undefined, accessToken: '', compressSingletonFolder: true, - copyFileButton: platformStorageKey !== 'platform_github.com', // false when on github.com, - copySnippetButton: platformStorageKey !== 'platform_github.com', // false when on github.com + copyFileButton: !isInGitHub, // disable on github.com + copySnippetButton: !isInGitHub, // disable on github.com intelligentToggle: null, icons: 'rich', toggleButtonVerticalDistance: 124, // align with GitHub's navbar items @@ -66,11 +70,13 @@ export const defaultConfigs: Config = { compactFileTree: false, restoreExpandedFolders: true, showDiffInText: false, -} + pjaxMode: platformName === 'GitHub' ? 'native' : 'pjax-api', // use native on GitHub +}) const configKeyArray = Object.values(configKeys) function applyDefaultConfigs(configs: Partial) { + const defaultConfigs = getDefaultConfigs() return configKeyArray.reduce((applied, key) => { Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] }) return applied @@ -79,9 +85,15 @@ function applyDefaultConfigs(configs: Partial) { export type VersionedConfig = Record & { configVersion: string } +export const configRef: Partial = {} +const updateConfigRef = async (config: Partial) => { + Object.assign(configRef, config) +} + const prepareConfig = new Promise(async resolve => { await migrateConfig() resolve() + updateConfigRef(await get()) }) async function get(): Promise { @@ -91,6 +103,7 @@ async function get(): Promise { } async function set(config: Config) { + updateConfigRef(config) return await storageHelper.set({ [platformStorageKey]: config }) } diff --git a/src/utils/hooks/usePJAX.ts b/src/utils/hooks/usePJAX.ts index 396dcaf..ba06191 100644 --- a/src/utils/hooks/usePJAX.ts +++ b/src/utils/hooks/usePJAX.ts @@ -1,4 +1,5 @@ -import { Config, Pjax } from 'pjax-api' +import { useConfigs } from 'containers/ConfigsContext' +import { Config } from 'pjax-api' import { platform } from 'platforms' import * as React from 'react' import { useEvent } from 'react-use' @@ -28,14 +29,18 @@ const config: Config = { } export function usePJAX() { + const { pjaxMode } = useConfigs().value // make history travel work React.useEffect(() => { - new Pjax({ - ...config, - filter() { - return false - }, - }) + if (pjaxMode === 'pjax-api') { + const { Pjax } = require('pjax-api') + new Pjax({ + ...config, + filter() { + return false + }, + }) + } }, []) // bindings for legacy support @@ -44,8 +49,7 @@ export function usePJAX() { } export const loadWithPJAX = (url: string, element: HTMLElement) => { - if (platform.loadWithPJAX) platform.loadWithPJAX(url, element) - else Pjax.assign(url, config) + platform.loadWithPJAX?.(url, element) || require('pjax-api').Pjax.assign(url, config) } export function useOnPJAXDone(callback: () => void) {