feat: redesign toggle show button

This commit is contained in:
EnixCoda 2020-08-02 17:33:45 +08:00
parent 02e3337037
commit 6d7610349e
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
6 changed files with 154 additions and 61 deletions

4
src/assets/icons/png.d.ts vendored Normal file
View file

@ -0,0 +1,4 @@
declare module '*.png' {
const content: string
export default content
}

View file

@ -17,6 +17,7 @@ import { cx } from 'utils/cx'
import { parseURLSearch } from 'utils/general'
import { usePJAX } from 'utils/hooks/usePJAX'
import * as keyHelper from 'utils/keyHelper'
import { Icon } from './Icon'
const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
const configContext = useConfigs()
@ -93,16 +94,22 @@ const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
return (
<div className={'gitako-side-bar'}>
<Portal into={logoContainerElement}>
<ToggleShowButton
error={error}
shouldShow={shouldShow}
toggleShowSideBar={toggleShowSideBar}
/>
{!shouldShow && (
<ToggleShowButton error={error} onClick={error ? undefined : toggleShowSideBar} />
)}
</Portal>
<Resizable className={cx({ hidden: error || !shouldShow })} baseSize={baseSize}>
<div className={'gitako-side-bar-body'}>
<div className={'gitako-side-bar-content'}>
{metaData && <MetaBar metaData={metaData} />}
<div className={'header'}>
{metaData ? <MetaBar metaData={metaData} /> : <div />}
<div className={'close-side-bar-button-position'}>
<button className={'close-side-bar-button'} onClick={toggleShowSideBar}>
<Icon className={'action-icon'} type={'x'} />
</button>
</div>
</div>
{errorDueToAuth ? (
<AccessDeniedError hasToken={Boolean(accessToken)} />
) : (

View file

@ -1,24 +1,67 @@
import { Icon } from 'components/Icon'
import iconSrc from 'assets/icons/Gitako.png'
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { useDebounce, useWindowSize } from 'react-use'
import { cx } from 'utils/cx'
type Props = {
error?: string
shouldShow: boolean
toggleShowSideBar: React.MouseEventHandler
}
} & Pick<React.HTMLAttributes<HTMLButtonElement>, 'onClick'>
export function ToggleShowButton({ error, onClick }: Props) {
const ref = React.useRef<HTMLButtonElement>(null)
const config = useConfigs()
const [distance, setDistance] = React.useState(config.val.toggleButtonVerticalDistance)
const { height } = useWindowSize()
const buttonHeight = 42
React.useEffect(() => {
// make sure it is inside viewport
if (height - buttonHeight < distance) {
setDistance(Math.max(0, height - buttonHeight))
}
}, [height, distance])
React.useLayoutEffect(() => {
if (ref.current) {
ref.current.style.top = distance + 'px'
}
}, [distance])
// updating context
useDebounce(
() => config.set({ toggleButtonVerticalDistance: distance }), // too slow
100,
[distance],
)
export function ToggleShowButton({ error, shouldShow, toggleShowSideBar }: Props) {
return (
<div
<button
ref={ref}
className={cx('gitako-toggle-show-button-wrapper', {
collapsed: !shouldShow || error,
error,
})}
onClick={error ? undefined : toggleShowSideBar}
onClick={onClick}
draggable
onDragStart={event => {
hideDragPreview(event)
}}
onDrag={e => {
if (e.clientY !== 0) {
// It will be 0 when release pointer
setDistance(e.clientY - buttonHeight / 2)
}
}}
title={'You can drag me'}
>
<Icon className={'action-icon'} type={shouldShow ? 'x' : 'octoface'} />
<img draggable={false} src={iconSrc} />
{error && <span className={'error-message'}>{error}</span>}
</div>
</button>
)
}
function hideDragPreview(event: React.DragEvent<HTMLButtonElement>) {
const img = new Image()
const EMPTY_IMAGE_BASE64 =
'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='
img.src = EMPTY_IMAGE_BASE64
event.dataTransfer.setDragImage(img, 0, 0)
}

View file

@ -139,54 +139,52 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
visibility: hidden;
}
.#{$name}-toggle-show-button-wrapper {
$animation-duration: 0.5s;
position: fixed;
top: 5px;
left: 0;
z-index: $minimal-z-index;
@mixin icon-button {
display: inline-flex;
justify-content: center;
align-items: center;
cursor: pointer;
padding: 4px;
border: 1px solid transparent;
will-change: transform;
transform: translate(calc(var(--gitako-width) - 30px));
padding: 0;
}
transition: transform $animation-duration ease;
// disable position transition when resizing sidebar
&.resizing {
transition: none;
@mixin button-color {
border: none;
background: $gray-000;
&:hover {
background: $gray-200;
}
&:active {
background: $gray-300;
}
}
&.collapsed {
border-color: $border-gray;
border-radius: 3px;
background: $bg-gray;
transform: translate(5px);
.action-icon {
color: $blue;
.#{$name}-toggle-show-button-wrapper {
@include icon-button;
width: 48px;
height: 48px;
position: fixed;
top: 80px;
left: -16px;
z-index: $minimal-z-index;
background: transparent;
border: none;
padding: 0;
transition: left ease 0.5s;
&:hover {
left: -12px;
img {
filter: drop-shadow(0 0 2px #888888);
width: 92%;
height: 92%;
}
}
.action-icon {
color: $gray;
width: 20px;
height: 20px;
text-align: center;
transition: all $animation-duration ease;
.octicon {
width: 100%;
height: 100%;
}
}
&.error {
.action-icon {
color: $red;
}
img {
filter: drop-shadow(0 0 1px #aaaaaa);
transition: all ease 0.3s;
width: 90%;
height: 90%;
object-fit: contain;
}
.error-message {
@ -286,13 +284,46 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
max-height: calc(100vh - 34px); // temporary fix for layout issue occurred since Chrome v76
min-height: 0; // make content shrinkable
.meta-bar {
position: relative; // prevent overlap by outline of other elements
min-height: 53px; // GitHub header height if login
flex-shrink: 0;
padding: 5px 10px;
padding-right: 30px; // space for toggle button
background: $bg-blue-light;
.header {
$button-size: 32px;
position: relative;
.meta-bar {
position: relative; // prevent overlap by outline of other elements
min-height: 53px; // GitHub header height if login
flex-shrink: 0;
padding: 5px 10px;
padding-right: $button-size; // space for toggle button
background: $gray-000;
}
.close-side-bar-button-position {
position: absolute;
right: 6px;
top: 0;
height: 100%;
display: inline-flex;
align-items: center;
.close-side-bar-button {
@include icon-button;
@include button-color;
width: $button-size;
height: $button-size;
border-radius: $button-size;
transition: background linear 0.3s;
.action-icon {
color: $gray;
width: 20px;
height: 20px;
text-align: center;
.octicon {
width: 100%;
height: 100%;
}
}
}
}
}
.description {

View file

@ -9,6 +9,7 @@ export type Config = {
copySnippetButton: boolean
intelligentToggle: boolean | null // `null` stands for intelligent, boolean for sidebar open status
icons: 'rich' | 'dim' | 'native'
toggleButtonVerticalDistance: number
}
export enum configKeys {
@ -20,6 +21,7 @@ export enum configKeys {
copySnippetButton = 'copySnippetButton',
intelligentToggle = 'intelligentToggle',
icons = 'icons',
toggleButtonVerticalDistance = 'toggleButtonVerticalDistance',
}
const defaultConfigs: Config = {
@ -31,6 +33,7 @@ const defaultConfigs: Config = {
copySnippetButton: true,
intelligentToggle: null,
icons: 'rich',
toggleButtonVerticalDistance: 80,
}
const configKeyArray = Object.values(configKeys)

View file

@ -104,6 +104,11 @@ module.exports = {
loader: ['json-loader'],
include: [srcPath],
},
{
test: /\.png$/,
loader: ['url-loader'],
include: [srcPath],
},
],
},
plugins,