feat-dev(wip): files table view (#2100)
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
||||
} from '@standardnotes/ui-services'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { PANEL_NAME_NOTES } from '@/Constants/Constants'
|
||||
import { FileItem, PrefKey, WebAppEvent } from '@standardnotes/snjs'
|
||||
import { FileItem, PrefKey, SystemViewId, WebAppEvent } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { forwardRef, useCallback, useEffect, useMemo } from 'react'
|
||||
import ContentList from '@/Components/ContentListView/ContentList'
|
||||
@@ -37,6 +37,9 @@ import { PanelResizedData } from '@/Types/PanelResizedData'
|
||||
import { useForwardedRef } from '@/Hooks/useForwardedRef'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
import FloatingAddButton from './FloatingAddButton'
|
||||
import FilesTableView from '../FilesTableView/FilesTableView'
|
||||
import { FeaturesController } from '@/Controllers/FeaturesController'
|
||||
import { featureTrunkEnabled, FeatureTrunkName } from '@/FeatureTrunk'
|
||||
|
||||
type Props = {
|
||||
accountMenuController: AccountMenuController
|
||||
@@ -49,6 +52,7 @@ type Props = {
|
||||
selectionController: SelectedItemsController
|
||||
searchOptionsController: SearchOptionsController
|
||||
linkingController: LinkingController
|
||||
featuresController: FeaturesController
|
||||
className?: string
|
||||
id: string
|
||||
children?: React.ReactNode
|
||||
@@ -68,6 +72,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
|
||||
selectionController,
|
||||
searchOptionsController,
|
||||
linkingController,
|
||||
featuresController,
|
||||
className,
|
||||
id,
|
||||
children,
|
||||
@@ -280,6 +285,9 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
|
||||
}
|
||||
}, [selectedUuids, innerRef, isCurrentNoteTemplate, renderedItems, panes])
|
||||
|
||||
const isFilesTableViewEnabled = featureTrunkEnabled(FeatureTrunkName.FilesTableView)
|
||||
const shouldShowFilesTableView = isFilesTableViewEnabled && selectedTag?.uuid === SystemViewId.Files
|
||||
|
||||
return (
|
||||
<div
|
||||
id={id}
|
||||
@@ -300,12 +308,16 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
|
||||
addButtonLabel={addButtonLabel}
|
||||
addNewItem={addNewItem}
|
||||
isFilesSmartView={isFilesSmartView}
|
||||
isFilesTableViewEnabled={isFilesTableViewEnabled}
|
||||
optionsSubtitle={optionsSubtitle}
|
||||
selectedTag={selectedTag}
|
||||
filesController={filesController}
|
||||
itemListController={itemListController}
|
||||
/>
|
||||
)}
|
||||
<SearchBar itemListController={itemListController} searchOptionsController={searchOptionsController} />
|
||||
{!isFilesTableViewEnabled && (
|
||||
<SearchBar itemListController={itemListController} searchOptionsController={searchOptionsController} />
|
||||
)}
|
||||
<NoAccountWarning
|
||||
accountMenuController={accountMenuController}
|
||||
noAccountWarningController={noAccountWarningController}
|
||||
@@ -324,13 +336,18 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
|
||||
{!dailyMode && completedFullSync && !renderedItems.length ? (
|
||||
<p className="empty-items-list opacity-50">No items.</p>
|
||||
) : null}
|
||||
|
||||
{!dailyMode && !completedFullSync && !renderedItems.length ? (
|
||||
<p className="empty-items-list opacity-50">Loading...</p>
|
||||
) : null}
|
||||
|
||||
{!dailyMode && renderedItems.length ? (
|
||||
<>
|
||||
shouldShowFilesTableView ? (
|
||||
<FilesTableView
|
||||
application={application}
|
||||
filesController={filesController}
|
||||
featuresController={featuresController}
|
||||
linkingController={linkingController}
|
||||
/>
|
||||
) : (
|
||||
<ContentList
|
||||
items={renderedItems}
|
||||
selectedUuids={selectedUuids}
|
||||
@@ -342,7 +359,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
|
||||
notesController={notesController}
|
||||
selectionController={selectionController}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
) : null}
|
||||
<div className="absolute bottom-0 h-safe-bottom w-full" />
|
||||
{children}
|
||||
|
||||
@@ -44,12 +44,8 @@ const AddItemMenuButton = ({
|
||||
<>
|
||||
<button
|
||||
className={classNames(
|
||||
'hidden md:flex',
|
||||
'h-8 w-8 hover:brightness-125',
|
||||
'z-editor-title-bar ml-3 cursor-pointer items-center',
|
||||
`justify-center rounded-full border border-solid border-transparent ${
|
||||
isDailyEntry ? 'bg-danger text-danger-contrast' : 'bg-info text-info-contrast'
|
||||
}`,
|
||||
'z-editor-title-bar hidden h-8 w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-transparent hover:brightness-125 md:flex',
|
||||
isDailyEntry ? 'bg-danger text-danger-contrast' : 'bg-info text-info-contrast',
|
||||
)}
|
||||
title={addButtonLabel}
|
||||
aria-label={addButtonLabel}
|
||||
|
||||
@@ -11,6 +11,8 @@ import { AnyTag } from '@/Controllers/Navigation/AnyTagType'
|
||||
import { MediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
import AddItemMenuButton from './AddItemMenuButton'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import SearchButton from './SearchButton'
|
||||
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -19,9 +21,11 @@ type Props = {
|
||||
addButtonLabel: string
|
||||
addNewItem: () => void
|
||||
isFilesSmartView: boolean
|
||||
isFilesTableViewEnabled: boolean
|
||||
optionsSubtitle?: string
|
||||
selectedTag: AnyTag
|
||||
filesController: FilesController
|
||||
itemListController: ItemListController
|
||||
}
|
||||
|
||||
const ContentListHeader = ({
|
||||
@@ -31,9 +35,11 @@ const ContentListHeader = ({
|
||||
addButtonLabel,
|
||||
addNewItem,
|
||||
isFilesSmartView,
|
||||
isFilesTableViewEnabled,
|
||||
optionsSubtitle,
|
||||
selectedTag,
|
||||
filesController,
|
||||
itemListController,
|
||||
}: Props) => {
|
||||
const displayOptionsContainerRef = useRef<HTMLDivElement>(null)
|
||||
const displayOptionsButtonRef = useRef<HTMLButtonElement>(null)
|
||||
@@ -98,6 +104,14 @@ const ContentListHeader = ({
|
||||
)
|
||||
}, [addButtonLabel, addNewItem, filesController, isDailyEntry, isFilesSmartView])
|
||||
|
||||
const SearchBarButton = useMemo(() => {
|
||||
if (!isFilesSmartView || !isFilesTableViewEnabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <SearchButton itemListController={itemListController} />
|
||||
}, [isFilesSmartView, isFilesTableViewEnabled, itemListController])
|
||||
|
||||
const FolderName = useMemo(() => {
|
||||
return (
|
||||
<div className="flex min-w-0 flex-grow flex-col break-words pt-1 lg:pt-0">
|
||||
@@ -125,13 +139,14 @@ const ContentListHeader = ({
|
||||
<div className={'flex w-full justify-between md:flex'}>
|
||||
<NavigationMenuButton />
|
||||
{FolderName}
|
||||
<div className="flex">
|
||||
<div className="flex items-center gap-3">
|
||||
{SearchBarButton}
|
||||
{OptionsMenu}
|
||||
{AddButton}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}, [OptionsMenu, AddButton, FolderName])
|
||||
}, [FolderName, SearchBarButton, OptionsMenu, AddButton])
|
||||
|
||||
const TabletLayout = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import RoundIconButton from '@/Components/Button/RoundIconButton'
|
||||
import ClearInputButton from '@/Components/ClearInputButton/ClearInputButton'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import DecoratedInput from '@/Components/Input/DecoratedInput'
|
||||
import { ElementIds } from '@/Constants/ElementIDs'
|
||||
import { ItemListController } from '@/Controllers/ItemList/ItemListController'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useState } from 'react'
|
||||
|
||||
type Props = {
|
||||
itemListController: ItemListController
|
||||
}
|
||||
|
||||
const SearchButton = ({ itemListController }: Props) => {
|
||||
const { noteFilterText, setNoteFilterText, clearFilterText } = itemListController
|
||||
|
||||
const [isSearchBarVisible, setIsSearchBarVisible] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
{isSearchBarVisible && (
|
||||
<DecoratedInput
|
||||
autocomplete={false}
|
||||
id={ElementIds.SearchBar}
|
||||
className={{
|
||||
container: 'px-1',
|
||||
input: 'text-base placeholder:text-passive-0 lg:text-sm',
|
||||
}}
|
||||
placeholder={'Search...'}
|
||||
value={noteFilterText}
|
||||
ref={(node) => {
|
||||
if (node && document.activeElement !== node) {
|
||||
node.focus()
|
||||
}
|
||||
}}
|
||||
onChange={(query) => setNoteFilterText(query)}
|
||||
left={[<Icon type="search" className="mr-1 h-4.5 w-4.5 flex-shrink-0 text-passive-1" />]}
|
||||
right={[noteFilterText && <ClearInputButton onClick={clearFilterText} />]}
|
||||
roundedFull
|
||||
/>
|
||||
)}
|
||||
<RoundIconButton
|
||||
onClick={() => {
|
||||
setIsSearchBarVisible(!isSearchBarVisible)
|
||||
}}
|
||||
icon={isSearchBarVisible ? 'close' : 'search'}
|
||||
label="Display options menu"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(SearchButton)
|
||||
Reference in New Issue
Block a user