mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: resize side bar when window is wide enough
This commit is contained in:
parent
5ac46e0b2a
commit
560a64d768
4 changed files with 319 additions and 205 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import preact from 'preact'
|
||||
/** @jsx preact.h */
|
||||
|
||||
import Grabber from '../assets/icons/octicons/grabber.svg?svgr'
|
||||
import Octoface from '../assets/icons/octicons/octoface.svg?svgr'
|
||||
import ChevronDown from '../assets/icons/octicons/chevron-down.svg?svgr'
|
||||
import TriangleRight from '../assets/icons/octicons/triangle-right.svg?svgr'
|
||||
|
|
@ -21,6 +22,8 @@ import cx from '../utils/cx'
|
|||
|
||||
function getSVGIconComponent(type) {
|
||||
switch (type) {
|
||||
case 'grabber':
|
||||
return Grabber
|
||||
case 'octoface':
|
||||
return Octoface
|
||||
case 'chevron-down':
|
||||
|
|
|
|||
60
src/components/ResizeHandler.js
Normal file
60
src/components/ResizeHandler.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import preact from 'preact'
|
||||
/** @jsx preact.h */
|
||||
|
||||
import Icon from './Icon'
|
||||
|
||||
export default class ResizeHandler extends preact.Component {
|
||||
pointerDown = false
|
||||
startX = 0
|
||||
delta = 0
|
||||
baseSize = this.props.baseSize
|
||||
|
||||
subscribeEvents = () => {
|
||||
window.addEventListener('mousemove', this.onPointerMove)
|
||||
window.addEventListener('mouseup', this.onPointerUp)
|
||||
}
|
||||
|
||||
unsubscribeEvents = () => {
|
||||
window.removeEventListener('mousemove', this.onPointerMove)
|
||||
window.removeEventListener('mouseup', this.onPointerUp)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MouseEvent} e
|
||||
* @memberof ResizeHandler
|
||||
*/
|
||||
onPointerDown = e => {
|
||||
this.pointerDown = true
|
||||
const { clientX } = e
|
||||
this.startX = clientX
|
||||
this.subscribeEvents()
|
||||
}
|
||||
|
||||
onPointerMove = e => {
|
||||
if (!this.pointerDown) return
|
||||
const { clientX } = e
|
||||
const { onResize } = this.props
|
||||
this.delta = this.startX - clientX
|
||||
onResize(this.delta + this.baseSize)
|
||||
}
|
||||
|
||||
onPointerUp = () => {
|
||||
this.pointerDown = false
|
||||
this.baseSize += this.delta
|
||||
this.unsubscribeEvents()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { style } = this.props
|
||||
return (
|
||||
<div
|
||||
className={'gitako-resize-handler'}
|
||||
onMouseDown={this.onPointerDown}
|
||||
style={style}
|
||||
>
|
||||
<Icon type={'grabber'} className={'grabber-icon'} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import FileExplorer from './FileExplorer'
|
|||
import ToggleShowButton from './ToggleShowButton'
|
||||
import MetaBar from './MetaBar'
|
||||
import SettingsBar from './SettingsBar'
|
||||
import ResizeHandler from './ResizeHandler'
|
||||
|
||||
import cx from '../utils/cx'
|
||||
import DOMHelper, { REPO_TYPE_PRIVATE } from '../utils/DOMHelper'
|
||||
|
|
@ -15,8 +16,12 @@ import storageHelper from '../utils/storageHelper'
|
|||
import URLHelper from '../utils/URLHelper'
|
||||
import keyHelper from '../utils/keyHelper'
|
||||
|
||||
// initial width of side bar
|
||||
const baseSize = 260
|
||||
export default class SideBar extends preact.Component {
|
||||
state = {
|
||||
// current width of side bar
|
||||
size: 260,
|
||||
// whether Gitako side bar should be shown
|
||||
shouldShow: false,
|
||||
// whether show settings pane
|
||||
|
|
@ -127,6 +132,12 @@ export default class SideBar extends preact.Component {
|
|||
this.setState({ toggleShowSideBarShortcut: shortcut })
|
||||
}
|
||||
|
||||
onResize = size => {
|
||||
this.setState({
|
||||
size,
|
||||
})
|
||||
}
|
||||
|
||||
renderAccessDeniedError() {
|
||||
return (
|
||||
<div className={'description'}>
|
||||
|
|
@ -155,6 +166,7 @@ export default class SideBar extends preact.Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
size,
|
||||
shouldShow,
|
||||
showSettings,
|
||||
hasAccessToken,
|
||||
|
|
@ -166,16 +178,19 @@ export default class SideBar extends preact.Component {
|
|||
<Portal into={this.logoContainerElement}>
|
||||
<ToggleShowButton shouldShow={shouldShow} toggleShowSideBar={this.toggleShowSideBar} />
|
||||
</Portal>
|
||||
<div className={'gitako-side-bar'}>
|
||||
{this.renderContent()}
|
||||
<SettingsBar
|
||||
toggleShowSettings={this.toggleShowSettings}
|
||||
onShortcutChange={this.onShortcutChange}
|
||||
onHasAccessTokenChange={this.onHasAccessTokenChange}
|
||||
activated={showSettings}
|
||||
hasAccessToken={hasAccessToken}
|
||||
toggleShowSideBarShortcut={toggleShowSideBarShortcut}
|
||||
/>
|
||||
<div className={'gitako-position-wrapper'}>
|
||||
<ResizeHandler onResize={this.onResize} baseSize={baseSize} style={{ right: size }} />
|
||||
<div className={'gitako-side-bar'} style={{ width: size }}>
|
||||
{this.renderContent()}
|
||||
<SettingsBar
|
||||
toggleShowSettings={this.toggleShowSettings}
|
||||
onShortcutChange={this.onShortcutChange}
|
||||
onHasAccessTokenChange={this.onHasAccessTokenChange}
|
||||
activated={showSettings}
|
||||
hasAccessToken={hasAccessToken}
|
||||
toggleShowSideBarShortcut={toggleShowSideBarShortcut}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
426
src/content.less
426
src/content.less
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
@name: gitako;
|
||||
|
||||
@side-bar-width: 260px;
|
||||
@github-content-width: 1280px;
|
||||
@content-width: (@side-bar-width + @github-content-width);
|
||||
@min-screen-width: 1280px;
|
||||
@github-content-width: 1020px;
|
||||
@side-bar-base-width: (@min-screen-width - @github-content-width);
|
||||
@width-with-gitako: (@min-screen-width + @side-bar-base-width);
|
||||
|
||||
.with-@{name}-spacing {
|
||||
margin-left: @side-bar-width;
|
||||
@media (min-width: @github-content-width) and (max-width: @content-width) {
|
||||
margin-left: ~'calc(' @content-width ~' - 100vw)';
|
||||
margin-left: @side-bar-base-width;
|
||||
@media (min-width: @min-screen-width) and (max-width: @width-with-gitako) {
|
||||
margin-left: ~'calc(' @width-with-gitako ~' - 100vw)';
|
||||
}
|
||||
@media (min-width: @content-width) {
|
||||
@media (min-width: @width-with-gitako) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -68,10 +69,11 @@
|
|||
}
|
||||
|
||||
.@{name}-toggle-show-button-wrapper {
|
||||
@animation-duration: 0.8s;
|
||||
@animation-duration: 0.5s;
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
transform: translate((@side-bar-base-width - 30px));
|
||||
z-index: 2;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
|
@ -80,20 +82,23 @@
|
|||
width: 30px;
|
||||
height: 30px;
|
||||
will-change: transform;
|
||||
transform: translateX(225px);
|
||||
transition: all @animation-duration ease;
|
||||
border: 1px solid transparent;
|
||||
@media screen and (min-width: @content-width) {
|
||||
transform: translateX(~'calc((100vw - ' @content-width ~') / 2 + ' 225px ~')');
|
||||
|
||||
@media screen and (max-width: @width-with-gitako) {
|
||||
transition: all @animation-duration ease;
|
||||
}
|
||||
@media screen and (min-width: @width-with-gitako) {
|
||||
transition: border-color, border-radius, background @animation-duration ease;
|
||||
transform: translate(~'calc(50vw - (' @github-content-width ~') / 2 - 30px)');
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
border-color: #999999;
|
||||
background: #f5f5f5;
|
||||
border-radius: 3px;
|
||||
background: #f5f5f5;
|
||||
|
||||
@media screen and (max-width: @content-width) {
|
||||
transform: translateX(5px);
|
||||
@media screen and (max-width: @width-with-gitako) {
|
||||
transform: translate(5px);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
|
|
@ -110,198 +115,229 @@
|
|||
}
|
||||
|
||||
.@{name} {
|
||||
.@{name}-side-bar {
|
||||
.@{name}-position-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: @side-bar-width;
|
||||
height: 100vh;
|
||||
z-index: 2;
|
||||
background: #fafbfc;
|
||||
border-right: 1px solid #e1e4e8;
|
||||
overflow: hidden;
|
||||
min-width: @side-bar-base-width;
|
||||
@media screen and (min-width: @min-screen-width) {
|
||||
width: ~'calc((100vw - ' @github-content-width ~') / 2)';
|
||||
}
|
||||
|
||||
@media screen and (min-width: @content-width) {
|
||||
.@{name}-resize-handler {
|
||||
@resize-handler-width: 16px;
|
||||
@side-bar-and-handler-width: (@min-screen-width + @resize-handler-width);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: none;
|
||||
width: @resize-handler-width;
|
||||
height: 100vh;
|
||||
background: #fafbfc;
|
||||
cursor: ew-resize;
|
||||
user-select: none;
|
||||
border-left: 1px solid #e1e4e8;
|
||||
left: ~'calc((100vw - ' @content-width ~') / 2)';
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
.hidden;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
transition: 0.3s ease;
|
||||
color: rgba(3, 47, 98, 0.55);
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.octicon-wrapper {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.octicon-color {
|
||||
color: rgba(3, 47, 98, 0.55);
|
||||
}
|
||||
|
||||
.@{name}-side-bar-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
.meta-bar {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-right: 30px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #586069;
|
||||
background-color: #f1f8ff;
|
||||
border-bottom: 1px solid #c8e1ff;
|
||||
|
||||
a {
|
||||
// fix a weird bug:
|
||||
// when gitako failed loading repo, cursor hovering <a> in meta bar will be 'text'
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repo-name {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.file-explorer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
@media screen and (min-width: @min-screen-width) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
&.freeze {
|
||||
filter: blur(1.5px) opacity(0.6) grayscale(0.9);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* search input */
|
||||
.search-input-wrapper {
|
||||
input[type='text'].form-control {
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.no-results {
|
||||
padding: 0px 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.files {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.node-item-row {
|
||||
background: #fff;
|
||||
&:hover {
|
||||
background: #f6f8fa;
|
||||
}
|
||||
&.focused {
|
||||
background: #f0f0f6;
|
||||
}
|
||||
|
||||
.node-item {
|
||||
word-wrap: normal;
|
||||
word-break: break-all;
|
||||
margin: 0;
|
||||
color: #0366d6;
|
||||
line-height: 20px;
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid #eaecef;
|
||||
transition: all 0.5s ease;
|
||||
|
||||
// folder icon rotate when expand
|
||||
&.expanded .octicon.octicon-triangle-right {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.node-item-name {
|
||||
padding-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.node-item:hover .node-item-name {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{name}-settings-bar {
|
||||
border-top: 1px solid #eaecef;
|
||||
&-content {
|
||||
padding: 0 10px;
|
||||
&-section {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.access-token {
|
||||
border-bottom: none; // prevent overwrite by github style
|
||||
.hint {
|
||||
color: #6a737d;
|
||||
}
|
||||
}
|
||||
.access-token-input-control {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
.access-token-input {
|
||||
flex: 1;
|
||||
box-shadow: none;
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
.toggle-shortcut {
|
||||
.hint {
|
||||
color: #6a737d;
|
||||
}
|
||||
}
|
||||
.toggle-shortcut-input-control {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
.toggle-shortcut-input {
|
||||
flex: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.placeholder-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.show-settings-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
.grabber-icon {
|
||||
transform: rotate(90deg);
|
||||
width: 12px;
|
||||
}
|
||||
}
|
||||
.@{name}-side-bar {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: @side-bar-base-width;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fafbfc;
|
||||
border-right: 1px solid #e1e4e8;
|
||||
overflow: hidden;
|
||||
will-change: transform;
|
||||
border-left: 1px solid #e1e4e8;
|
||||
|
||||
&.hidden {
|
||||
.hidden;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
transition: 0.3s ease;
|
||||
color: rgba(3, 47, 98, 0.55);
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.octicon-wrapper {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.octicon-color {
|
||||
color: rgba(3, 47, 98, 0.55);
|
||||
}
|
||||
|
||||
.@{name}-side-bar-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
.meta-bar {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-right: 30px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #586069;
|
||||
background-color: #f1f8ff;
|
||||
border-bottom: 1px solid #c8e1ff;
|
||||
|
||||
a {
|
||||
// fix a weird bug:
|
||||
// when gitako failed loading repo, cursor hovering <a> in meta bar will be 'text'
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repo-name {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
.hide-settings-icon {
|
||||
width: 15px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
.description {
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.file-explorer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
&.freeze {
|
||||
filter: blur(1.5px) opacity(0.6) grayscale(0.9);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* search input */
|
||||
.search-input-wrapper {
|
||||
input[type='text'].form-control {
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.no-results {
|
||||
padding: 0px 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.files {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.node-item-row {
|
||||
background: #fff;
|
||||
&:hover {
|
||||
background: #f6f8fa;
|
||||
}
|
||||
&.focused {
|
||||
background: #f0f0f6;
|
||||
}
|
||||
|
||||
.node-item {
|
||||
word-wrap: normal;
|
||||
word-break: break-all;
|
||||
margin: 0;
|
||||
color: #0366d6;
|
||||
line-height: 20px;
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid #eaecef;
|
||||
transition: all 0.5s ease;
|
||||
|
||||
// folder icon rotate when expand
|
||||
&.expanded .octicon.octicon-triangle-right {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.node-item-name {
|
||||
padding-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.node-item:hover .node-item-name {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{name}-settings-bar {
|
||||
border-top: 1px solid #eaecef;
|
||||
&-content {
|
||||
padding: 0 10px;
|
||||
&-section {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.access-token {
|
||||
border-bottom: none; // prevent overwrite by github style
|
||||
.hint {
|
||||
color: #6a737d;
|
||||
}
|
||||
}
|
||||
.access-token-input-control {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
.access-token-input {
|
||||
flex: 1;
|
||||
box-shadow: none;
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
.toggle-shortcut {
|
||||
.hint {
|
||||
color: #6a737d;
|
||||
}
|
||||
}
|
||||
.toggle-shortcut-input-control {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
.toggle-shortcut-input {
|
||||
flex: 1;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.placeholder-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6px 10px;
|
||||
|
||||
.show-settings-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.hide-settings-icon {
|
||||
width: 15px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue