diff --git a/src/assets/icons/png.d.ts b/src/assets/icons/png.d.ts new file mode 100644 index 0000000..02b2e89 --- /dev/null +++ b/src/assets/icons/png.d.ts @@ -0,0 +1,4 @@ +declare module '*.png' { + const content: string + export default content +} diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index d4c75f9..bcfb1bb 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -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 = function RawGitako(props) { const configContext = useConfigs() @@ -93,16 +94,22 @@ const RawGitako: React.FC = function RawGitako(props) { return (
- + {!shouldShow && ( + + )}
- {metaData && } +
+ {metaData ? :
} + +
+ +
+
{errorDueToAuth ? ( ) : ( diff --git a/src/components/ToggleShowButton.tsx b/src/components/ToggleShowButton.tsx index 219b06d..6fa5f9c 100644 --- a/src/components/ToggleShowButton.tsx +++ b/src/components/ToggleShowButton.tsx @@ -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, 'onClick'> + +export function ToggleShowButton({ error, onClick }: Props) { + const ref = React.useRef(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 ( -
{ + 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'} > - + {error && {error}} -
+ ) } + +function hideDragPreview(event: React.DragEvent) { + const img = new Image() + const EMPTY_IMAGE_BASE64 = + 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=' + img.src = EMPTY_IMAGE_BASE64 + event.dataTransfer.setDragImage(img, 0, 0) +} diff --git a/src/content.scss b/src/content.scss index 28767d7..d366d94 100644 --- a/src/content.scss +++ b/src/content.scss @@ -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 { diff --git a/src/utils/configHelper.ts b/src/utils/configHelper.ts index d0ac7f8..02968ac 100644 --- a/src/utils/configHelper.ts +++ b/src/utils/configHelper.ts @@ -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) diff --git a/webpack.config.js b/webpack.config.js index 1a57d65..b28b018 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -104,6 +104,11 @@ module.exports = { loader: ['json-loader'], include: [srcPath], }, + { + test: /\.png$/, + loader: ['url-loader'], + include: [srcPath], + }, ], }, plugins,