feat: enhance settings UI

This commit is contained in:
EnixCoda 2020-03-08 15:40:46 +08:00
parent 916d718d4c
commit 6b40ad2ef7
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
7 changed files with 117 additions and 105 deletions

View file

@ -13,12 +13,11 @@ export function SearchBar({ onSearch, onFocus, searchKey }: Props) {
<input
onFocus={onFocus}
tabIndex={0}
className={cx('form-control search-input', {
className={cx('form-control', 'search-input', {
error: !isValidRegexpSource(searchKey),
})}
aria-label="search files"
placeholder="Search files (use RegExp)"
type="text"
onChange={({ target: { value } }) => onSearch(value)}
value={searchKey}
/>

View file

@ -4,8 +4,8 @@ import * as React from 'react'
import { Config } from 'utils/configHelper'
import { useStates } from 'utils/hooks/useStates'
import { AccessTokenSettings } from './settings/AccessTokenSettings'
import { FileTreeIconSettings } from './settings/FileTreeIconSettings'
import { ShortcutSettings } from './settings/ShortcutSettings'
import { FileTreeSettings } from './settings/FileTreeSettings'
import { SidebarSettings } from './settings/SidebarSettings'
import { SimpleToggleField } from './SimpleToggleField'
const WIKI_HOME_LINK = 'https://github.com/EnixCoda/Gitako/wiki'
@ -34,30 +34,16 @@ export type SimpleField = {
}
const moreFields: SimpleField[] = [
{
key: 'compressSingletonFolder',
label: 'Compress singleton folder',
wikiLink: wikiLinks.compressSingletonFolder,
},
{
key: 'copyFileButton',
label: 'Copy File Shortcut',
label: 'Copy file shortcut',
wikiLink: wikiLinks.copyFileButton,
},
{
key: 'copySnippetButton',
label: 'Copy Snippet Shortcut',
label: 'Copy snippet shortcut',
wikiLink: wikiLinks.copySnippet,
},
{
key: 'intelligentToggle',
label: 'Intelligent Toggle',
description: `Gitako will open/close automatically according to page content when this is enabled.`,
overwrite: {
value: enabled => enabled === null,
onChange: checked => (checked ? null : true),
},
},
]
function SettingsBarContent() {
@ -70,14 +56,13 @@ function SettingsBarContent() {
<div className={'gitako-settings-bar-content'}>
<div className={'shadow-shelter'} />
<AccessTokenSettings />
<ShortcutSettings />
<FileTreeIconSettings />
<SidebarSettings />
<FileTreeSettings />
<div className={'gitako-settings-bar-content-section others'}>
<h4>More</h4>
{moreFields.map(field => (
<React.Fragment key={field.key}>
<SimpleToggleField field={field} />
<br />
</React.Fragment>
))}

View file

@ -12,8 +12,9 @@ export function SimpleToggleField({ field, onChange }: Props) {
const configContext = useConfigs()
const value = configContext.val[field.key]
return (
<label htmlFor={field.key}>
<div className={'form-checkbox'}>
<input
className={'form-control'}
id={field.key}
name={field.key}
type={'checkbox'}
@ -24,18 +25,16 @@ export function SimpleToggleField({ field, onChange }: Props) {
}}
checked={overwrite ? overwrite.value(value) : Boolean(value)}
/>
&nbsp;{field.label}&nbsp;
{field.wikiLink ? (
<a href={field.wikiLink} target={'_blank'}>
(?)
</a>
) : (
field.description && (
<span className={'description'} title={field.description}>
<label htmlFor={field.key}>
{field.label}{' '}
{field.wikiLink ? (
<a href={field.wikiLink} target={'_blank'}>
(?)
</span>
)
)}
</label>
</a>
) : (
field.description && <p className={'note'}>{field.description}</p>
)}
</label>
</div>
)
}

View file

@ -1,3 +1,5 @@
import { wikiLinks } from 'components/SettingsBar'
import { SimpleToggleField } from 'components/SimpleToggleField'
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { Config } from 'utils/configHelper'
@ -26,21 +28,23 @@ const options: {
type Props = {}
export function FileTreeIconSettings(props: React.PropsWithChildren<Props>) {
export function FileTreeSettings(props: React.PropsWithChildren<Props>) {
const configContext = useConfigs()
return (
<div className={'gitako-settings-bar-content-section toggle-shortcut'}>
<h4>File Tree Icons</h4>
<span>Icons can make a difference.</span>
<br />
<div className={'toggle-shortcut-input-control'}>
<div className={'gitako-settings-bar-content-section'}>
<h4>File Tree</h4>
<label className="form-label" htmlFor="file-tree-icons">
Icons
</label>
<div>
<select
id="file-tree-icons"
onChange={e => {
configContext.set({
icons: e.target.value as Config['icons'],
})
}}
className={'toggle-shortcut-input form-control'}
className={'file-tree-input form-control'}
placeholder={'focus here and press the shortcut keys'}
value={configContext.val.icons}
>
@ -51,6 +55,13 @@ export function FileTreeIconSettings(props: React.PropsWithChildren<Props>) {
))}
</select>
</div>
<SimpleToggleField
field={{
key: 'compressSingletonFolder',
label: 'Compress singleton folder',
wikiLink: wikiLinks.compressSingletonFolder,
}}
/>
</div>
)
}

View file

@ -1,56 +0,0 @@
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { friendlyFormatShortcut } from 'utils/general'
import { useStates } from 'utils/hooks/useStates'
import * as keyHelper from 'utils/keyHelper'
type Props = {}
export function ShortcutSettings(props: React.PropsWithChildren<Props>) {
const configContext = useConfigs()
const useShortcutHint = useStates('')
const useToggleShowSideBarShortcut = useStates(configContext.val.shortcut)
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
const { val: shortcutHint } = useShortcutHint
React.useEffect(() => {
useToggleShowSideBarShortcut.set(configContext.val.shortcut)
}, [configContext.val.shortcut])
const saveShortcut = React.useCallback(async () => {
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
configContext.set({ shortcut: toggleShowSideBarShortcut })
if (typeof toggleShowSideBarShortcut === 'string') {
useShortcutHint.set('Shortcut is saved!')
}
}, [useToggleShowSideBarShortcut.val])
const onShortCutInputKeyDown = React.useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
e.preventDefault()
e.stopPropagation()
// Clear shortcut with backspace
const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e)
useToggleShowSideBarShortcut.set(shortcut)
}, [])
return (
<div className={'gitako-settings-bar-content-section toggle-shortcut'}>
<h4>Toggle Shortcut</h4>
<span>Set a combination of keys for toggling Gitako sidebar.</span>
<br />
<div className={'toggle-shortcut-input-control'}>
<input
className={'toggle-shortcut-input form-control'}
placeholder={'focus here and press the shortcut keys'}
value={friendlyFormatShortcut(toggleShowSideBarShortcut)}
onKeyDown={onShortCutInputKeyDown}
readOnly
/>
<button className={'btn'} onClick={saveShortcut}>
Save
</button>
</div>
{shortcutHint && <span className={'hint'}>{shortcutHint}</span>}
</div>
)
}

View file

@ -0,0 +1,64 @@
import { SimpleToggleField } from 'components/SimpleToggleField'
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { friendlyFormatShortcut } from 'utils/general'
import { useStates } from 'utils/hooks/useStates'
import * as keyHelper from 'utils/keyHelper'
type Props = {}
export function SidebarSettings(props: React.PropsWithChildren<Props>) {
const configContext = useConfigs()
const useToggleShowSideBarShortcut = useStates(configContext.val.shortcut)
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
React.useEffect(() => {
useToggleShowSideBarShortcut.set(configContext.val.shortcut)
}, [configContext.val.shortcut])
return (
<div className={'gitako-settings-bar-content-section toggle-shortcut'}>
<h4>Toggle Sidebar</h4>
<label className="form-label" htmlFor="toggle-sidebar-shortcut">
Keyboard Shortcut
</label>
<div className={'toggle-shortcut-input-control'}>
<input
id="toggle-sidebar-shortcut"
className={'toggle-shortcut-input form-control'}
placeholder={'focus here and press the shortcut keys'}
value={friendlyFormatShortcut(toggleShowSideBarShortcut)}
onKeyDown={React.useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
e.preventDefault()
e.stopPropagation()
// Clear shortcut with backspace
const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e)
useToggleShowSideBarShortcut.set(shortcut)
}, [])}
readOnly
/>
<button
className={'btn'}
disabled={toggleShowSideBarShortcut === configContext.val.shortcut}
onClick={() => {
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
if (typeof toggleShowSideBarShortcut !== 'string') return
configContext.set({ shortcut: toggleShowSideBarShortcut })
}}
>
Save
</button>
</div>
<SimpleToggleField
field={{
key: 'intelligentToggle',
label: 'Auto toggle according to page content.',
overwrite: {
value: enabled => enabled === null,
onChange: checked => (checked ? null : true),
},
}}
/>
</div>
)
}

View file

@ -310,8 +310,7 @@
/* search input */
.search-input-wrapper {
input[type='text'].form-control {
box-shadow: none;
input.form-control {
width: 100%;
&.error {
@ -448,7 +447,9 @@
z-index: 1;
}
&-section {
padding-bottom: 16px;
&:not(:last-of-type) {
padding-bottom: 16px;
}
.description:hover {
cursor: help;
@ -459,10 +460,18 @@
input.form-control {
min-width: 100px;
}
.form-checkbox {
margin: 0;
}
}
select {
-moz-appearance: none;
}
.form-label {
margin-bottom: 2px;
display: inline-block;
}
.access-token {
border-bottom: none; // prevent overwrite by github style
.link-button {
@ -477,7 +486,6 @@
margin-top: 8px;
.access-token-input {
flex: 1;
box-shadow: none;
&:disabled {
cursor: not-allowed;
@ -491,10 +499,8 @@
}
.toggle-shortcut-input-control {
display: flex;
margin-top: 8px;
.toggle-shortcut-input {
flex: 1;
box-shadow: none;
}
}
.singleton {
@ -524,6 +530,10 @@
cursor: pointer;
}
}
input.form-control:not(:last-child) {
margin-right: 5px;
}
}
}
}