feat: optimize icons

This commit is contained in:
EnixCoda 2022-06-03 23:34:09 +08:00
parent c558eaf35c
commit 10668b6606
11 changed files with 109 additions and 142 deletions

View file

@ -1,7 +1,22 @@
import {
DiffAddedIcon,
DiffIgnoredIcon,
DiffModifiedIcon,
DiffRemovedIcon,
DiffRenamedIcon
} from '@primer/octicons-react'
import * as React from 'react'
import { resolveDiffGraphMeta } from 'utils/general'
import { Icon } from '../Icon'
const iconMap = {
added: DiffAddedIcon,
ignored: DiffIgnoredIcon,
modified: DiffModifiedIcon,
removed: DiffRemovedIcon,
renamed: DiffRenamedIcon,
}
export function DiffStatGraph({
diff: { status, changes, additions, deletions },
}: {
@ -19,18 +34,7 @@ export function DiffStatGraph({
return (
<span className={'diff-stat-graph'}>
<Icon
className={status}
type={
{
added: 'diffAdded',
ignored: 'diffIgnored',
modified: 'diffModified',
removed: 'diffRemoved',
renamed: 'diffRenamed',
}[status]
}
/>
<Icon className={status} IconComponent={iconMap[status]} />
{children}
</span>
)

View file

@ -77,17 +77,18 @@ const NodeItemIcon = React.memo(function NodeItemIcon({
() => (node.type === 'tree' ? getFolderIconURL(node, open) : getFileIconURL(node)),
[node, open],
)
const iconType = React.useMemo(() => getIconType(node), [node])
if (icons === 'native') return <Icon type={getIconType(node)} />
if (icons === 'native') return <Icon type={iconType} />
return (
<>
<Icon
className={'node-item-type-icon'}
placeholder={node.type !== 'tree'}
type={loading ? 'loading' : getIconType(node)}
type={loading ? 'loading' : iconType}
/>
{node.type === 'commit' ? (
<Icon type={getIconType(node)} />
<Icon type={iconType} />
) : (
<img alt={node.name} className={cx('node-item-icon', { dim: icons === 'dim' })} src={src} />
)}

View file

@ -1,3 +1,4 @@
import { CommentIcon } from '@primer/octicons-react'
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { isNotFalsy } from 'utils/general'
@ -42,7 +43,7 @@ export function useRenderFileCommentAmounts() {
node.comments.active
} active, ${node.comments.resolved} resolved`}
>
<Icon type={'comment'} /> {node.comments.active > 9 ? '9+' : node.comments.active}
<Icon IconComponent={CommentIcon} /> {node.comments.active > 9 ? '9+' : node.comments.active}
</span>
) : null
}

View file

@ -1,8 +1,9 @@
import { GearIcon } from '@primer/octicons-react'
import { Link } from '@primer/react'
import { Icon } from 'components/Icon'
import { VERSION } from 'env'
import * as React from 'react'
import { wikiLinks } from './SettingsBar'
import { RoundIconButton } from './RoundIconButton'
import { wikiLinks } from './settings/SettingsBar'
type Props = {
toggleShowSettings: () => void
@ -21,9 +22,12 @@ export function Footer(props: Props) {
>
{VERSION}
</Link>
<button className={'settings-button'} onClick={toggleShowSettings}>
<Icon type={'gear'} className={'show-settings-icon'} />
</button>
<RoundIconButton
aria-label={'settings'}
icon={GearIcon}
iconColor="fg.muted"
onClick={toggleShowSettings}
/>
</div>
)
}

View file

@ -61,14 +61,7 @@ const typeToIconComponentMap: {
} = {
search: 'Search',
loading: 'Clock',
hourglass: 'Hourglass',
submodule: 'Submodule',
grabber: 'Grabber',
comment: 'Comment',
x: 'X',
pin: 'Pin',
tab: 'Tab',
gear: 'Gear',
diff: 'Diff',
diffAdded: 'DiffAdded',
diffIgnored: 'DiffIgnored',
@ -76,7 +69,6 @@ const typeToIconComponentMap: {
diffRemoved: 'DiffRemoved',
diffRenamed: 'DiffRenamed',
folder: 'ChevronRight',
'chevron-down': 'ChevronDown',
'go-to': 'Reply',
'.zip': 'FileZip',
'.rar': 'FileZip',
@ -99,7 +91,9 @@ const typeToIconComponentMap: {
}
type Props = {
type: string
type?: keyof typeof typeToIconComponentMap
name?: keyof typeof iconToComponentMap
IconComponent?: React.ComponentType<IconProps>
className?: string
placeholder?: boolean
onClick?: (event: React.MouseEvent<HTMLElement>) => void
@ -107,19 +101,15 @@ type Props = {
export const Icon = React.memo(function Icon({
type,
className = undefined,
placeholder,
className = undefined,
name = (type && typeToIconComponentMap[type]) || defaultIcon,
IconComponent = iconToComponentMap[name],
...otherProps
}: Props) {
let children: React.ReactNode = null
if (!placeholder) {
const name = typeToIconComponentMap[type] || defaultIcon
const IconComponent = iconToComponentMap[name]
children = <IconComponent className={cx('octicon', name)} {...otherProps} />
}
return (
<div className={cx('octicon-wrapper', className)} {...otherProps}>
{children}
</div>
<span className={cx('octicon-wrapper', className)} {...otherProps}>
{placeholder ? null : <IconComponent className={cx('octicon', name)} {...otherProps} />}
</span>
)
})

View file

@ -1,4 +1,4 @@
import { Icon } from 'components/Icon'
import { HourglassIcon } from '@primer/octicons-react'
import * as React from 'react'
type Props = {
@ -8,7 +8,7 @@ export function LoadingIndicator({ text }: Props) {
return (
<div className={'loading-indicator-container'}>
<div className={'loading-indicator'}>
<Icon className={'loading-indicator-icon'} type={'hourglass'} />
<HourglassIcon className={'loading-indicator-icon'} />
{text}
</div>
</div>

View file

@ -1,3 +1,4 @@
import { GrabberIcon } from '@primer/octicons-react'
import { Icon } from 'components/Icon'
import * as React from 'react'
import { ResizeState, useResizeHandler } from '../utils/hooks/useResizeHandler'
@ -21,7 +22,7 @@ export function ResizeHandler({ onResize, onResetSize, onResizeStateChange, size
onDoubleClick={onResetSize}
style={style}
>
<Icon type={'grabber'} className={'grabber-icon'} size={20} />
<Icon IconComponent={GrabberIcon} />
</div>
)
}

View file

@ -1,8 +1,9 @@
import { PinIcon, TabIcon } from '@primer/octicons-react'
import { AccessDeniedDescription } from 'components/AccessDeniedDescription'
import { FileExplorer } from 'components/FileExplorer'
import { Footer } from 'components/Footer'
import { MetaBar } from 'components/MetaBar'
import { Portal } from 'components/Portal'
import { Footer } from 'components/settings/Footer'
import { SideBarBodyWrapper } from 'components/SideBarBodyWrapper'
import { ToggleShowButton } from 'components/ToggleShowButton'
import { useConfigs } from 'containers/ConfigsContext'
@ -19,8 +20,8 @@ import { RepoContext } from '../containers/RepoContext'
import { SideBarStateContext } from '../containers/SideBarState'
import { Theme } from '../containers/Theme'
import { useToggleSideBarWithKeyboard } from '../utils/hooks/useToggleSideBarWithKeyboard'
import { Icon } from './Icon'
import { LoadingIndicator } from './LoadingIndicator'
import { RoundIconButton } from './RoundIconButton'
import { SettingsBarContent } from './settings/SettingsBar'
export function SideBar() {
@ -151,27 +152,29 @@ export function SideBar() {
<div className={'header'}>
<div className={'close-side-bar-button-position'}>
{sidebarToggleMode === 'persistent' && (
<button
title={'Collapse sidebar'}
className={'close-side-bar-button'}
<RoundIconButton
icon={TabIcon}
aria-label={'Collapse sidebar'}
sx={{
transform: 'rotateY(180deg)',
}}
onClick={toggleShowSideBar}
>
<Icon className={'action-icon'} type={'tab'} />
</button>
/>
)}
<button
title={'Toggle sidebar dock mode between float and persistent'}
className={cx('close-side-bar-button', {
active: sidebarToggleMode === 'persistent',
})}
<RoundIconButton
icon={PinIcon}
aria-label={'Toggle sidebar dock mode between float and persistent'}
iconColor={sidebarToggleMode === 'persistent' ? 'fg.default' : undefined}
sx={{
transform: 'rotateY(180deg)',
}}
onClick={() =>
configContext.onChange({
sidebarToggleMode: sidebarToggleMode === 'float' ? 'persistent' : 'float',
sidebarToggleMode:
sidebarToggleMode === 'persistent' ? 'float' : 'persistent',
})
}
>
<Icon className={'action-icon'} type={'pin'} />
</button>
/>
</div>
{metaData && <MetaBar metaData={metaData} />}
</div>

View file

@ -1,5 +1,6 @@
import { ChevronDownIcon } from '@primer/octicons-react'
import { Box } from '@primer/react'
import { Icon } from 'components/Icon'
import { RoundIconButton } from 'components/RoundIconButton'
import { platform } from 'platforms'
import { GitHub } from 'platforms/GitHub'
import * as React from 'react'
@ -53,9 +54,13 @@ export function SettingsBarContent({ toggleShow }: { toggleShow: () => void }) {
<div className={'gitako-settings-bar'}>
<div className={'gitako-settings-bar-header'}>
<h2 className={'gitako-settings-bar-title'}>Settings</h2>
<button className={'settings-button'} onClick={toggleShow}>
<Icon type={'chevron-down'} className={'hide-settings-icon'} />
</button>
<RoundIconButton
aria-label="Close settings"
onClick={toggleShow}
size="medium"
icon={ChevronDownIcon}
color="fg.default"
/>
</div>
<Box display="grid" gridGap={4} className={'gitako-settings-bar-content'}>
<div className={'shadow-shelter'} />

View file

@ -1,3 +1,5 @@
import { InfoIcon, LinkExternalIcon } from '@primer/octicons-react'
import { Box } from '@primer/react'
import * as React from 'react'
import { ConfigKeys } from 'utils/config/helper'
import { SimpleConfigField } from '.'
@ -12,14 +14,29 @@ export function FieldLabel<Key extends ConfigKeys>({
{label}
{(wikiLink || tooltip) && ' '}
{wikiLink ? (
<a href={wikiLink} title={tooltip} target="_blank" rel="noopener noreferrer">
(?)
<a
className={'help'}
href={wikiLink}
title={tooltip}
target="_blank"
rel="noopener noreferrer"
>
<LinkExternalIcon size="small" />
</a>
) : (
tooltip && (
<span className={'help'} title={tooltip}>
(?)
</span>
<Box
as="span"
sx={{
'.octicon': {
color: 'fg.subtle',
},
}}
className={'help'}
title={tooltip}
>
<InfoIcon size="small" />
</Box>
)
)}
</>

View file

@ -220,7 +220,12 @@ $minimal-z-index: max(
padding-top: 0;
.#{$name}-side-bar {
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
}
@ -409,14 +414,7 @@ $minimal-z-index: max(
background: var(--color-bg-subtle);
border-left: 1px solid var(--color-border-default);
}
.octicon.Grabber {
margin-left: -2px;
width: 20px;
font-size: 0;
}
}
.#{$name}-side-bar-body {
$button-size: 32px;
position: relative;
@ -426,20 +424,9 @@ $minimal-z-index: max(
flex-direction: column;
background: var(--color-bg-subtle);
border-left: 1px solid var(--color-border-default);
.octicon {
transition: transform 0.3s ease;
color: var(--color-fg-subtle);
width: 100%;
height: 100%;
}
.octicon-color {
color: var(--color-fg-subtle);
}
.octicon-wrapper {
display: inline-block;
color: var(--color-fg-subtle);
width: 16px;
min-width: 16px; // prevent shrink when sidebar is narrow
text-align: center;
@ -478,41 +465,6 @@ $minimal-z-index: max(
.close-side-bar-button-position {
float: right;
z-index: 1; // prevent being covered by following elements
.close-side-bar-button {
@include icon-button;
width: $button-size;
height: $button-size;
border-radius: $button-size;
// feedback to click should be instant
&:not(:active) {
transition: background linear 0.3s;
}
&.active .octicon {
color: var(--color-fg-default);
}
.action-icon {
color: var(--color-fg-subtle);
width: 20px;
height: 20px;
text-align: center;
.octicon {
width: 100%;
height: 100%;
}
.Pin,
.Tab {
transform: rotateY(180deg);
}
}
}
.close-side-bar-button + .close-side-bar-button {
margin-left: 4px;
}
}
}
@ -536,11 +488,7 @@ $minimal-z-index: max(
height: 20px;
margin-right: 4px;
.octicon {
width: 20px;
height: 20px;
animation: pulse-rotate 1.8s infinite ease;
}
animation: pulse-rotate 1.8s infinite ease;
}
}
}
@ -755,6 +703,9 @@ $minimal-z-index: max(
height: 10px;
margin: 0 1px;
border-radius: 2px;
}
.diff-stat-graph-no-change {
background: var(--color-neutral-emphasis);
}
@ -861,6 +812,9 @@ $minimal-z-index: max(
.hint {
color: var(--color-fg-subtle);
}
.help {
cursor: help;
}
.access-token-input-control {
display: flex;
.access-token-input {
@ -881,19 +835,6 @@ $minimal-z-index: max(
color: var(--color-fg-muted);
}
}
.settings-button {
@include icon-button();
$size: 32px;
width: $size;
height: $size;
border-radius: $size;
user-select: none;
.octicon-wrapper {
width: 18px;
}
}
}
}