2024-04-25 16:31:18 +02:00
|
|
|
import * as React from 'react';
|
|
|
|
|
|
|
|
import { FolderIcon, FolderIconType } from '@joplin/lib/services/database/types';
|
|
|
|
import ExpandLink from './ExpandLink';
|
2024-10-15 18:59:51 +02:00
|
|
|
import { StyledListItemAnchor, StyledShareIcon, StyledSpanFix } from '../styles';
|
2024-04-25 16:31:18 +02:00
|
|
|
import { ItemClickListener, ItemContextMenuListener, ItemDragListener } from '../types';
|
|
|
|
import FolderIconBox from '../../FolderIconBox';
|
|
|
|
import { getTrashFolderIcon, getTrashFolderId } from '@joplin/lib/services/trash';
|
|
|
|
import Folder from '@joplin/lib/models/Folder';
|
|
|
|
import { ModelType } from '@joplin/lib/BaseModel';
|
2024-07-28 15:53:32 +02:00
|
|
|
import { _ } from '@joplin/lib/locale';
|
|
|
|
import NoteCount from './NoteCount';
|
2024-10-15 18:59:51 +02:00
|
|
|
import ListItemWrapper, { ListItemRef } from './ListItemWrapper';
|
2024-04-25 16:31:18 +02:00
|
|
|
|
|
|
|
const renderFolderIcon = (folderIcon: FolderIcon) => {
|
|
|
|
if (!folderIcon) {
|
|
|
|
const defaultFolderIcon: FolderIcon = {
|
|
|
|
dataUrl: '',
|
|
|
|
emoji: '',
|
|
|
|
name: 'far fa-folder',
|
|
|
|
type: FolderIconType.FontAwesome,
|
|
|
|
};
|
|
|
|
return <div style={{ marginRight: 7, display: 'flex' }}><FolderIconBox opacity={0.7} folderIcon={defaultFolderIcon}/></div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
return <div style={{ marginRight: 7, display: 'flex' }}><FolderIconBox folderIcon={folderIcon}/></div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
interface FolderItemProps {
|
2024-10-15 18:59:51 +02:00
|
|
|
anchorRef: ListItemRef;
|
2024-04-25 16:31:18 +02:00
|
|
|
hasChildren: boolean;
|
|
|
|
showFolderIcon: boolean;
|
|
|
|
isExpanded: boolean;
|
|
|
|
parentId: string;
|
|
|
|
depth: number;
|
|
|
|
folderId: string;
|
|
|
|
folderTitle: string;
|
|
|
|
folderIcon: FolderIcon;
|
|
|
|
noteCount: number;
|
|
|
|
onFolderDragStart_: ItemDragListener;
|
|
|
|
onFolderDragOver_: ItemDragListener;
|
|
|
|
onFolderDrop_: ItemDragListener;
|
|
|
|
itemContextMenu: ItemContextMenuListener;
|
|
|
|
folderItem_click: (folderId: string)=> void;
|
|
|
|
onFolderToggleClick_: ItemClickListener;
|
|
|
|
shareId: string;
|
|
|
|
selected: boolean;
|
2024-10-15 18:59:51 +02:00
|
|
|
|
|
|
|
index: number;
|
|
|
|
itemCount: number;
|
2024-04-25 16:31:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function FolderItem(props: FolderItemProps) {
|
|
|
|
const { hasChildren, showFolderIcon, isExpanded, parentId, depth, selected, folderId, folderTitle, folderIcon, noteCount, onFolderDragStart_, onFolderDragOver_, onFolderDrop_, itemContextMenu, folderItem_click, onFolderToggleClick_, shareId } = props;
|
|
|
|
|
2024-07-28 15:53:32 +02:00
|
|
|
const shareTitle = _('Shared');
|
|
|
|
const shareIcon = shareId && !parentId ? <StyledShareIcon aria-label={shareTitle} title={shareTitle} className="fas fa-share-alt"/> : null;
|
2024-04-25 16:31:18 +02:00
|
|
|
const draggable = ![getTrashFolderId(), Folder.conflictFolderId()].includes(folderId);
|
|
|
|
|
|
|
|
const doRenderFolderIcon = () => {
|
|
|
|
if (folderId === getTrashFolderId()) {
|
|
|
|
return renderFolderIcon(getTrashFolderIcon(FolderIconType.FontAwesome));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!showFolderIcon) return null;
|
|
|
|
return renderFolderIcon(folderIcon);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2024-10-15 18:59:51 +02:00
|
|
|
<ListItemWrapper
|
|
|
|
containerRef={props.anchorRef}
|
|
|
|
// Folders are contained within the "Notebooks" section (which has depth 0):
|
|
|
|
depth={depth + 1}
|
|
|
|
selected={selected}
|
|
|
|
itemIndex={props.index}
|
|
|
|
itemCount={props.itemCount}
|
|
|
|
expanded={hasChildren ? props.isExpanded : undefined}
|
|
|
|
className={`list-item-container list-item-depth-${depth} ${selected ? 'selected' : ''}`}
|
|
|
|
highlightOnHover={true}
|
|
|
|
onDragStart={onFolderDragStart_}
|
|
|
|
onDragOver={onFolderDragOver_}
|
|
|
|
onDrop={onFolderDrop_}
|
|
|
|
onContextMenu={itemContextMenu}
|
|
|
|
draggable={draggable}
|
|
|
|
data-folder-id={folderId}
|
|
|
|
data-id={folderId}
|
|
|
|
data-type={ModelType.Folder}
|
|
|
|
>
|
2024-04-25 16:31:18 +02:00
|
|
|
<StyledListItemAnchor
|
|
|
|
className="list-item"
|
|
|
|
isConflictFolder={folderId === Folder.conflictFolderId()}
|
|
|
|
selected={selected}
|
|
|
|
shareId={shareId}
|
2024-10-15 18:59:51 +02:00
|
|
|
onDoubleClick={onFolderToggleClick_}
|
|
|
|
|
2024-04-25 16:31:18 +02:00
|
|
|
onClick={() => {
|
|
|
|
folderItem_click(folderId);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{doRenderFolderIcon()}<StyledSpanFix className="title">{folderTitle}</StyledSpanFix>
|
2024-07-28 15:53:32 +02:00
|
|
|
{shareIcon} <NoteCount count={noteCount}/>
|
2024-04-25 16:31:18 +02:00
|
|
|
</StyledListItemAnchor>
|
2024-10-15 18:59:51 +02:00
|
|
|
<ExpandLink
|
|
|
|
// The ExpandLink is included after the title so that the screen reader reads the
|
|
|
|
// title first.
|
|
|
|
className='toggle'
|
|
|
|
hasChildren={hasChildren}
|
|
|
|
folderTitle={folderTitle}
|
|
|
|
folderId={folderId}
|
|
|
|
onClick={onFolderToggleClick_}
|
|
|
|
isExpanded={isExpanded}
|
|
|
|
/>
|
|
|
|
</ListItemWrapper>
|
2024-04-25 16:31:18 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FolderItem;
|