mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: simple config fields
This commit is contained in:
parent
ff1bdd6f0f
commit
43aaa3874c
10 changed files with 159 additions and 106 deletions
19
src/components/Inputs/Checkbox.tsx
Normal file
19
src/components/Inputs/Checkbox.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { Checkbox as PrimerCheckbox, CheckboxProps, FormControl } from '@primer/react';
|
||||
import * as React from 'react';
|
||||
|
||||
export function Checkbox({
|
||||
label, value, onChange, checked = value, ...rest
|
||||
}: Override<CheckboxProps, { label: React.ReactNode; } & IO<boolean>>) {
|
||||
return (
|
||||
<FormControl>
|
||||
<PrimerCheckbox
|
||||
sx={{
|
||||
marginTop: '4px', // align label
|
||||
}}
|
||||
checked={checked}
|
||||
onChange={e => onChange(e.target.checked)}
|
||||
{...rest} />
|
||||
<FormControl.Label>{label}</FormControl.Label>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
|
|
@ -7,19 +7,18 @@ export type Option<T> = {
|
|||
value: T
|
||||
}
|
||||
|
||||
export type SelectInputProps<T> = Override<SelectProps, IO<T> & {
|
||||
label: React.ReactNode
|
||||
options: Option<T>[]
|
||||
}>
|
||||
|
||||
export function SelectInput<T>({
|
||||
value,
|
||||
onChange,
|
||||
label,
|
||||
options,
|
||||
...selectProps
|
||||
}: Override<
|
||||
SelectProps,
|
||||
IO<T> & {
|
||||
label: string
|
||||
options: Option<T>[]
|
||||
}
|
||||
>) {
|
||||
}: SelectInputProps<T>) {
|
||||
return (
|
||||
<FormControl
|
||||
sx={{
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import { Checkbox, FormControl } from '@primer/react'
|
||||
import { useConfigs } from 'containers/ConfigsContext'
|
||||
import * as React from 'react'
|
||||
import { Config, ConfigKeys } from 'utils/config/helper'
|
||||
|
||||
export type SimpleField<Key extends ConfigKeys> = {
|
||||
key: Key
|
||||
label: string
|
||||
wikiLink?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
overwrite?: {
|
||||
value: (value: Config[Key]) => boolean
|
||||
onChange: (checked: boolean) => Config[Key]
|
||||
}
|
||||
}
|
||||
|
||||
type Props<Key extends ConfigKeys> = {
|
||||
field: SimpleField<Key>
|
||||
}
|
||||
|
||||
export function SimpleToggleField<Key extends ConfigKeys>({ field }: Props<Key>) {
|
||||
const { overwrite } = field
|
||||
const configContext = useConfigs()
|
||||
const value = configContext.value[field.key]
|
||||
|
||||
const checked = React.useMemo(
|
||||
() => (overwrite ? overwrite.value(value) : Boolean(value)),
|
||||
[overwrite, value],
|
||||
)
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
(checked: boolean) => {
|
||||
const enabled = checked
|
||||
configContext.onChange({ [field.key]: overwrite ? overwrite.onChange(enabled) : enabled })
|
||||
},
|
||||
[field.key, overwrite, configContext],
|
||||
)
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
sx={{
|
||||
marginTop: '4px', // align label
|
||||
}}
|
||||
value={field.key}
|
||||
disabled={field.disabled}
|
||||
onChange={e => handleChange(e.target.checked)}
|
||||
checked={checked}
|
||||
/>
|
||||
<FormControl.Label>
|
||||
{field.label}
|
||||
{(field.wikiLink || field.tooltip) && ' '}
|
||||
{field.wikiLink ? (
|
||||
<a href={field.wikiLink} title={field.tooltip} target="_blank" rel="noopener noreferrer">
|
||||
(?)
|
||||
</a>
|
||||
) : (
|
||||
field.tooltip && (
|
||||
<span className={'help'} title={field.tooltip}>
|
||||
(?)
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</FormControl.Label>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { wikiLinks } from 'components/settings/SettingsBar'
|
||||
import { SimpleToggleField } from 'components/SimpleToggleField'
|
||||
import { useConfigs } from 'containers/ConfigsContext'
|
||||
import { SimpleConfigFieldCheckbox } from 'components/settings/SimpleConfigField/Checkbox'
|
||||
import * as React from 'react'
|
||||
import { Config } from 'utils/config/helper'
|
||||
import { Option, SelectInput } from '../SelectInput'
|
||||
import { Option } from '../Inputs/SelectInput'
|
||||
import { SettingsSection } from './SettingsSection'
|
||||
import { SimpleConfigFieldSelect } from './SimpleConfigField/SelectInput'
|
||||
|
||||
const iconOptions: Option<Config['icons']>[] = [
|
||||
{
|
||||
|
|
@ -38,32 +38,23 @@ const recursiveToggleFolderOptions: Option<Config['recursiveToggleFolder']>[] =
|
|||
]
|
||||
|
||||
export function FileTreeSettings() {
|
||||
const configContext = useConfigs()
|
||||
const { recursiveToggleFolder, icons } = configContext.value
|
||||
return (
|
||||
<SettingsSection title={'File Tree'}>
|
||||
<SelectInput
|
||||
label="Toggle folders recursively while holding"
|
||||
<SimpleConfigFieldSelect
|
||||
field={{
|
||||
key: 'recursiveToggleFolder',
|
||||
label: 'Toggle folders recursively while holding',
|
||||
}}
|
||||
options={recursiveToggleFolderOptions}
|
||||
onChange={v => {
|
||||
configContext.onChange({
|
||||
recursiveToggleFolder: v,
|
||||
})
|
||||
}}
|
||||
value={recursiveToggleFolder}
|
||||
/>
|
||||
|
||||
<SelectInput<Config['icons']>
|
||||
label="Icons"
|
||||
<SimpleConfigFieldSelect
|
||||
field={{
|
||||
key: 'icons',
|
||||
label: 'Icons',
|
||||
}}
|
||||
options={iconOptions}
|
||||
onChange={v => {
|
||||
configContext.onChange({
|
||||
icons: v,
|
||||
})
|
||||
}}
|
||||
value={icons}
|
||||
/>
|
||||
<SimpleToggleField
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'compressSingletonFolder',
|
||||
label: 'Compress singleton folder',
|
||||
|
|
@ -71,21 +62,21 @@ export function FileTreeSettings() {
|
|||
tooltip: 'Merge folders and their only child folder to make UI more compact.',
|
||||
}}
|
||||
/>
|
||||
<SimpleToggleField
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'restoreExpandedFolders',
|
||||
label: 'Restore expanded folders',
|
||||
tooltip: 'Folders will be expanded again when clear search input',
|
||||
}}
|
||||
/>
|
||||
<SimpleToggleField
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'commentToggle',
|
||||
label: 'Show PR file comments',
|
||||
tooltip: 'Show number of comments next to file names in Pull Requests.',
|
||||
}}
|
||||
/>
|
||||
<SimpleToggleField
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'compactFileTree',
|
||||
label: 'Compact file tree layout',
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import { platform } from 'platforms'
|
|||
import { GitHub } from 'platforms/GitHub'
|
||||
import * as React from 'react'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import { SimpleField, SimpleToggleField } from '../SimpleToggleField'
|
||||
import { AccessTokenSettings } from './AccessTokenSettings'
|
||||
import { FileTreeSettings } from './FileTreeSettings'
|
||||
import { SettingsSection } from './SettingsSection'
|
||||
import { SidebarSettings } from './SidebarSettings'
|
||||
import { SimpleConfigField } from './SimpleConfigField'
|
||||
import { SimpleConfigFieldCheckbox } from './SimpleConfigField/Checkbox'
|
||||
|
||||
const WIKI_HOME_LINK = 'https://github.com/EnixCoda/Gitako/wiki'
|
||||
export const wikiLinks = {
|
||||
|
|
@ -19,7 +20,7 @@ export const wikiLinks = {
|
|||
createAccessToken: `${WIKI_HOME_LINK}/Access-token-for-Gitako`,
|
||||
}
|
||||
|
||||
const moreFields: SimpleField<'copyFileButton' | 'copySnippetButton' | 'codeFolding'>[] =
|
||||
const moreFields: SimpleConfigField<'copyFileButton' | 'copySnippetButton' | 'codeFolding'>[] =
|
||||
platform === GitHub
|
||||
? [
|
||||
{
|
||||
|
|
@ -64,7 +65,7 @@ export function SettingsBarContent({ toggleShow }: { toggleShow: () => void }) {
|
|||
<SettingsSection title={'More'}>
|
||||
{moreFields.map(field => (
|
||||
<React.Fragment key={field.key}>
|
||||
<SimpleToggleField field={field} />
|
||||
<SimpleConfigFieldCheckbox field={field} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Box, Button, FormControl, TextInput } from '@primer/react'
|
||||
import { SimpleToggleField } from 'components/SimpleToggleField'
|
||||
import { SimpleConfigFieldCheckbox } from 'components/settings/SimpleConfigField/Checkbox'
|
||||
import { useConfigs } from 'containers/ConfigsContext'
|
||||
import * as React from 'react'
|
||||
import { friendlyFormatShortcut, noop } from 'utils/general'
|
||||
|
|
@ -13,7 +13,7 @@ export function SidebarSettings() {
|
|||
return (
|
||||
<SettingsSection title={'Sidebar'}>
|
||||
<ToggleSidebarShortcutSettings />
|
||||
<SimpleToggleField
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'intelligentToggle',
|
||||
label: 'Auto expand',
|
||||
|
|
|
|||
20
src/components/settings/SimpleConfigField/Checkbox.tsx
Normal file
20
src/components/settings/SimpleConfigField/Checkbox.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import * as React from 'react'
|
||||
import { ConfigKeys } from 'utils/config/helper'
|
||||
import { SimpleConfigFieldProps, useSimpleConfigFieldIO } from '.'
|
||||
import { Checkbox } from '../../Inputs/Checkbox'
|
||||
import { FieldLabel } from './FieldLabel'
|
||||
|
||||
export function SimpleConfigFieldCheckbox<Key extends ConfigKeys>({
|
||||
field,
|
||||
}: SimpleConfigFieldProps<Key>) {
|
||||
const { value, onChange } = useSimpleConfigFieldIO(field) as IO<boolean>
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
label={<FieldLabel {...field} />}
|
||||
disabled={field.disabled}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
27
src/components/settings/SimpleConfigField/FieldLabel.tsx
Normal file
27
src/components/settings/SimpleConfigField/FieldLabel.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import * as React from 'react'
|
||||
import { ConfigKeys } from 'utils/config/helper'
|
||||
import { SimpleConfigField } from '.'
|
||||
|
||||
export function FieldLabel<Key extends ConfigKeys>({
|
||||
label,
|
||||
wikiLink,
|
||||
tooltip,
|
||||
}: SimpleConfigField<Key>) {
|
||||
return (
|
||||
<>
|
||||
{label}
|
||||
{(wikiLink || tooltip) && ' '}
|
||||
{wikiLink ? (
|
||||
<a href={wikiLink} title={tooltip} target="_blank" rel="noopener noreferrer">
|
||||
(?)
|
||||
</a>
|
||||
) : (
|
||||
tooltip && (
|
||||
<span className={'help'} title={tooltip}>
|
||||
(?)
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
27
src/components/settings/SimpleConfigField/SelectInput.tsx
Normal file
27
src/components/settings/SimpleConfigField/SelectInput.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { SelectInput, SelectInputProps } from 'components/Inputs/SelectInput'
|
||||
import * as React from 'react'
|
||||
import { Config, ConfigKeys } from 'utils/config/helper'
|
||||
import {
|
||||
SimpleConfigFieldProps,
|
||||
useSimpleConfigFieldIO
|
||||
} from '.'
|
||||
import { FieldLabel } from './FieldLabel'
|
||||
|
||||
export function SimpleConfigFieldSelect<Key extends ConfigKeys>({
|
||||
field,
|
||||
options,
|
||||
}: SimpleConfigFieldProps<Key> & {
|
||||
options: SelectInputProps<Config[Key]>['options']
|
||||
}) {
|
||||
const { value, onChange } = useSimpleConfigFieldIO(field)
|
||||
|
||||
return (
|
||||
<SelectInput
|
||||
label={<FieldLabel {...field} />}
|
||||
disabled={field.disabled}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
/>
|
||||
)
|
||||
}
|
||||
37
src/components/settings/SimpleConfigField/index.tsx
Normal file
37
src/components/settings/SimpleConfigField/index.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { useConfigs } from 'containers/ConfigsContext'
|
||||
import React from 'react'
|
||||
import { Config, ConfigKeys } from 'utils/config/helper'
|
||||
|
||||
export type SimpleConfigField<Key extends ConfigKeys> = {
|
||||
label: string
|
||||
wikiLink?: string
|
||||
tooltip?: string
|
||||
key: Key
|
||||
disabled?: boolean
|
||||
overwrite?: {
|
||||
value: (value: Config[Key]) => Config[Key]
|
||||
onChange: (newValue: Config[Key]) => Config[Key]
|
||||
}
|
||||
}
|
||||
|
||||
export type SimpleConfigFieldProps<Key extends ConfigKeys> = {
|
||||
field: SimpleConfigField<Key>
|
||||
}
|
||||
|
||||
export function useSimpleConfigFieldIO<Key extends ConfigKeys>(
|
||||
field: SimpleConfigField<Key>,
|
||||
): IO<Config[Key]> {
|
||||
const { overwrite } = field
|
||||
const configContext = useConfigs()
|
||||
const value = configContext.value[field.key]
|
||||
|
||||
return {
|
||||
value: React.useMemo(() => (overwrite ? overwrite.value(value) : value), [overwrite, value]),
|
||||
onChange: React.useCallback(
|
||||
(newValue: Config[Key]) => {
|
||||
configContext.onChange({ [field.key]: overwrite ? overwrite.onChange(newValue) : newValue })
|
||||
},
|
||||
[field.key, overwrite, configContext],
|
||||
),
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue