Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions src/cloud/components/Application.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import React, { useState, useCallback, useEffect, useMemo } from 'react'
import {
SidebarOrderedCategoriesDelimiter,
usePreferences,
} from '../lib/stores/preferences'
import { usePreferences } from '../lib/stores/preferences'
import { usePage } from '../lib/stores/pageStore'
import {
useGlobalKeyDownHandler,
Expand Down Expand Up @@ -147,6 +144,10 @@ import ButtonGroup from '../../shared/components/atoms/ButtonGroup'
import Button from '../../shared/components/atoms/Button'
import TemplatesModal from './organisms/Modal/contents/TemplatesModal'
import { CreateWorkspaceRequestBody } from '../api/teams/workspaces'
import {
cloudSidebaCategoryLabels,
cloudSidebarOrderedCategoriesDelimiter,
} from '../lib/sidebar'

interface ApplicationProps {
content: ContentLayoutProps
Expand Down Expand Up @@ -239,7 +240,15 @@ const Application = ({
}, [])

const getFoldEvents = useCallback(
(type: CollapsableType, key: string) => {
(type: CollapsableType, key: string, reversed?: boolean) => {
if (reversed) {
return {
fold: () => unfoldItem(type, key),
unfold: () => foldItem(type, key),
toggle: () => toggleItem(type, key),
}
}

return {
fold: () => foldItem(type, key),
unfold: () => unfoldItem(type, key),
Expand Down Expand Up @@ -346,8 +355,15 @@ const Application = ({
return undefined
}

const orderedCategories = preferences.sidebarOrderedCategories.split(
SidebarOrderedCategoriesDelimiter
const orderedCategories = Array.from(
new Set([
...preferences.sidebarOrderedCategories.split(
cloudSidebarOrderedCategoriesDelimiter
),
...cloudSidebaCategoryLabels,
])
).filter((item) =>
cloudSidebaCategoryLabels.find((categoryLabel) => categoryLabel === item)
)

const orderedTree = tree.sort((categoryA, categoryB) => {
Expand Down Expand Up @@ -393,7 +409,7 @@ const Application = ({

setPreferences({
sidebarOrderedCategories: reArrangedArray.join(
SidebarOrderedCategoriesDelimiter
cloudSidebarOrderedCategoriesDelimiter
),
})

Expand Down Expand Up @@ -917,7 +933,11 @@ function mapTree(
sideBarOpenedFolderIdsSet: Set<string>,
sideBarOpenedWorkspaceIdsSet: Set<string>,
toggleItem: (type: CollapsableType, id: string) => void,
getFoldEvents: (type: CollapsableType, key: string) => FoldingProps,
getFoldEvents: (
type: CollapsableType,
key: string,
reversed?: boolean
) => FoldingProps,
push: (url: string) => void,
openModal: (cmp: JSX.Element) => void,
toggleDocBookmark: (
Expand Down Expand Up @@ -1279,7 +1299,6 @@ function mapTree(
}
tree.push({
label: 'Workspaces',
shrink: 2,
rows: navTree,
controls: [
{
Expand All @@ -1292,7 +1311,6 @@ function mapTree(
if (!team.personal) {
tree.push({
label: 'Private',
shrink: 2,
rows:
personalWorkspace != null
? arrayItems
Expand Down Expand Up @@ -1425,7 +1443,7 @@ function mapTree(
const foldKey = `fold-${key}`
const hideKey = `hide-${key}`
category.folded = sideBarOpenedLinksIdsSet.has(foldKey)
category.folding = getFoldEvents('links', foldKey)
category.folding = getFoldEvents('links', foldKey, true)
category.hidden = sideBarOpenedLinksIdsSet.has(hideKey)
category.toggleHidden = () => toggleItem('links', hideKey)
})
Expand Down
9 changes: 9 additions & 0 deletions src/cloud/lib/sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const cloudSidebaCategoryLabels = [
'Bookmarks',
'Workspaces',
'Private',
'Labels',
'More',
]

export const cloudSidebarOrderedCategoriesDelimiter = '|'
8 changes: 7 additions & 1 deletion src/cloud/lib/stores/preferences/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { localLiteStorage } from 'ltstrg'
import { Preferences } from './types'
import { preferencesKey } from '../../localStorageKeys'
import { useSetState } from 'react-use'
import {
cloudSidebaCategoryLabels,
cloudSidebarOrderedCategoriesDelimiter,
} from '../../sidebar'

function savePreferencesToLocalStorage(preferences: Partial<Preferences>) {
localLiteStorage.setItem(preferencesKey, JSON.stringify(preferences))
Expand All @@ -20,7 +24,9 @@ const basePreferences: Preferences = {
sidebarBookmarksAreUnfolded: false,
workspaceManagerIsOpen: true,
lastSidebarState: 'tree',
sidebarOrderedCategories: 'Bookmarks|Workspaces|Private|Labels|More',
sidebarOrderedCategories: cloudSidebaCategoryLabels.join(
cloudSidebarOrderedCategoriesDelimiter
),
}

function getExistingPreferences() {
Expand Down
2 changes: 0 additions & 2 deletions src/cloud/lib/stores/preferences/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ export interface Preferences {
sidebarTreeSortingOrder: SidebarTreeSortingOrder
sidebarOrderedCategories: string
}

export const SidebarOrderedCategoriesDelimiter = '|'
36 changes: 36 additions & 0 deletions src/shared/components/atoms/VerticalScroller.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useCallback, useRef, useState } from 'react'
import { AppComponent } from '../../lib/types'
import cc from 'classcat'
import styled from '../../lib/styled'
import { scrollbarOverlay } from '../../lib/styled/styleFunctions'

const VerticalScroller: AppComponent<{}> = ({ children, className }) => {
const [inScroll, setInScroll] = useState(false)
const scrollTimer = useRef<any>()

const onScrollHandler: React.UIEventHandler<HTMLDivElement> = useCallback(() => {
setInScroll(true)
scrollTimer.current = setTimeout(() => {
setInScroll(false)
}, 600)
}, [])

return (
<Container
className={cc([
'vertical__scroller',
inScroll && 'vertical__scroller--scrolling',
className,
])}
onScroll={onScrollHandler}
>
{children}
</Container>
)
}

const Container = styled.div`
${(theme) => scrollbarOverlay(theme, 'y', 'vertical__scroller--scrolling')}
`

export default VerticalScroller
17 changes: 12 additions & 5 deletions src/shared/components/organisms/Sidebar/atoms/SidebarTreeItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface SidebarTreeItemProps {
controls?: ControlButtonProps[]
contextControls?: MenuItem[]
active?: boolean
isCategory?: boolean
}

interface SharedProps {
Expand All @@ -46,6 +47,7 @@ const SidebarItem: AppComponent<SidebarTreeItemProps & SharedProps> = ({
controls,
contextControls,
active,
isCategory,
}) => {
const { popup } = useContextMenu()
const LabelTag = labelHref != null ? 'a' : 'button'
Expand Down Expand Up @@ -75,6 +77,7 @@ const SidebarItem: AppComponent<SidebarTreeItemProps & SharedProps> = ({
className={cc([
className,
'sidebar__tree__item',
isCategory && 'sidebar__category',
focused && 'focused',
active && 'sidebar__tree__item--active',
])}
Expand Down Expand Up @@ -243,20 +246,24 @@ const Container = styled.div<{ depth: number }>`
}

&.sidebar__category {
.sidebar__tree__item__label {
font-weight: bold;
color: ${({ theme }) => theme.colors.text.subtle};
}

border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
.sidebar__tree__item__label {
text-transform: uppercase !important;
}

.sidebar__tree__item__icon {
color: currentColor !important;
}
&.focused {
background-color: ${({ theme }) => theme.colors.background.tertiary};
box-shadow: 0px 0px 0px 1px
${({ theme }) => theme.colors.variants.primary.base};
}
&:hover {
background-color: ${({ theme }) => theme.colors.background.quaternary};
box-shadow: 0px 0px 0px 1px
${({ theme }) => theme.colors.variants.primary.base};
}
}
`
Expand Down
77 changes: 29 additions & 48 deletions src/shared/components/organisms/Sidebar/molecules/SidebarTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import SidebarTreeForm from '../atoms/SidebarTreeForm'
import { DraggedTo, onDragLeaveCb, SidebarDragState } from '../../../../lib/dnd'
import { mdiDotsHorizontal } from '@mdi/js'
import Checkbox from '../../../molecules/Form/atoms/FormCheckbox'
import { scrollbarOverlay } from '../../../../lib/styled/styleFunctions'
import { useContextMenu } from '../../../../lib/stores/contextMenu'
import VerticalScroller from '../../../atoms/VerticalScroller'

interface SidebarTreeProps {
tree: SidebarNavCategory[]
Expand All @@ -37,7 +37,6 @@ export interface SidebarNavCategory {
toggleHidden: () => void
folding?: FoldingProps
rows: SidebarTreeChildRow[]
shrink?: 1 | 2 | 3
lastCategory?: boolean
drag?: {
onDragStart: () => void
Expand Down Expand Up @@ -136,23 +135,25 @@ const SidebarTree = ({
{topRows != null && (
<div className='sidebar__tree__rows--top'>{topRows}</div>
)}
{tree.map((category, i) => {
if (category.hidden) {
return null
}
<VerticalScroller className='sidebar__tree__scroller'>
{tree.map((category, i) => {
if (category.hidden) {
return null
}

return (
<SidebarCategory
category={{
...category,
lastCategory: i === tree.length - 1,
}}
draggingCategory={draggingCategory}
setDraggingCategory={setDraggingCategory}
key={`sidebar__category__${i}`}
/>
)
})}
return (
<SidebarCategory
category={{
...category,
lastCategory: i === tree.length - 1,
}}
draggingCategory={draggingCategory}
setDraggingCategory={setDraggingCategory}
key={`sidebar__category__${i}`}
/>
)
})}
</VerticalScroller>
</SidebarContextList>
</Container>
)
Expand All @@ -169,8 +170,6 @@ const SidebarCategory = ({
}) => {
const [creationFormIsOpened, setCreationFormIsOpened] = useState(false)
const [draggingItem, setDraggingItem] = useState(false)
const [inScroll, setInScroll] = useState(false)
const scrollTimer = useRef<any>()
const [showCreateForm, setShowCreateForm] = useState(false)
const [placeholder, setPlaceholder] = useState('')
const creationCallbackRef = useRef<((val: string) => Promise<void>) | null>(
Expand All @@ -179,13 +178,6 @@ const SidebarCategory = ({
const [draggedOver, setDraggedOver] = useState(false)
const dragRef = useRef<HTMLDivElement>(null)

const onScrollHandler: React.UIEventHandler<HTMLDivElement> = useCallback(() => {
setInScroll(true)
scrollTimer.current = setTimeout(() => {
setInScroll(false)
}, 600)
}, [])

const controls = useMemo(
() =>
(category.controls || []).map((control) => {
Expand Down Expand Up @@ -224,6 +216,7 @@ const SidebarCategory = ({
category.lastCategory && 'sidebar__category--last',
!category.folded && 'sidebar__category--open',
])}
isCategory={true}
id={`category-${category.label}`}
label={category.label}
labelClick={category.folding?.toggle}
Expand All @@ -236,11 +229,8 @@ const SidebarCategory = ({
<div
className={cc([
'sidebar__category__items',
`sidebar__category__items__shrink${category.shrink || '1'}`,
creationFormIsOpened && `sidebar__category__items--silenced`,
inScroll && 'sidebar__category__items--scrolling',
])}
onScroll={onScrollHandler}
>
{showCreateForm && (
<SidebarTreeForm
Expand Down Expand Up @@ -557,32 +547,23 @@ const Container = styled.div`
flex-direction: column;
}

.sidebar__tree__scroller {
padding: ${({ theme }) => theme.sizes.spaces.sm}px 0
${({ theme }) => theme.sizes.spaces.md}px 0;
flex: 1 1 auto;
}

.sidebar__category {
flex: 0 0 auto;
border: none;
}

.sidebar__category + .sidebar__category {
border-top: none;
.sidebar__category__wrapper + .sidebar__category__wrapper {
margin-top: ${({ theme }) => theme.sizes.spaces.sm}px;
}

.sidebar__category__items {
padding: 4px 0;
flex-shrink: 2;
${(theme) =>
scrollbarOverlay(theme, 'y', 'sidebar__category__items--scrolling')}
}

.sidebar__category__items__shrink1 {
flex-shrink: 1;
min-height: 50px;
}
.sidebar__category__items__shrink2 {
flex-shrink: 2;
min-height: 50px;
}
.sidebar__category__items__shrink3 {
flex-shrink: 3;
min-height: 50px;
}

.sidebar__category__items--silenced .sidebar__tree__item {
Expand Down