mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Implement location selector button
This commit is contained in:
parent
a37fdf33e2
commit
edb3bb4f10
|
@ -1,40 +1,109 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback } from 'react';
|
import clsx from 'clsx';
|
||||||
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
||||||
import { FolderTree } from '@/models/FolderTree';
|
import { labelFolderNode } from '@/utils/labels';
|
||||||
|
|
||||||
import { IconFolderTree } from '../Icons';
|
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened } from '../Icons';
|
||||||
|
import { CProps } from '../props';
|
||||||
import MiniButton from '../ui/MiniButton';
|
import MiniButton from '../ui/MiniButton';
|
||||||
|
|
||||||
interface SelectLocationProps {
|
interface SelectLocationProps extends CProps.Styling {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (newValue: string) => void;
|
|
||||||
|
|
||||||
folderTree: FolderTree;
|
folderTree: FolderTree;
|
||||||
|
prefix: string;
|
||||||
|
dense?: boolean;
|
||||||
|
onClick: (event: CProps.EventMouse, target: FolderNode) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectLocation({ value, onChange, folderTree }: SelectLocationProps) {
|
function SelectLocation({ value, folderTree, dense, prefix, onClick, className, style }: SelectLocationProps) {
|
||||||
const menu = useDropdown();
|
const activeNode = useMemo(() => folderTree.at(value), [folderTree, value]);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const items = useMemo(() => folderTree.getTree(), [folderTree]);
|
||||||
(newValue: string) => {
|
const [folded, setFolded] = useState<FolderNode[]>(items);
|
||||||
console.log(folderTree.roots.size);
|
|
||||||
console.log(value);
|
useLayoutEffect(() => {
|
||||||
menu.hide();
|
setFolded(items.filter(item => item !== activeNode && (!activeNode || !activeNode.hasPredecessor(item))));
|
||||||
onChange(newValue);
|
}, [items, activeNode]);
|
||||||
|
|
||||||
|
const onFoldItem = useCallback(
|
||||||
|
(target: FolderNode, showChildren: boolean) => {
|
||||||
|
setFolded(prev =>
|
||||||
|
items.filter(item => {
|
||||||
|
if (item === target) {
|
||||||
|
return !showChildren;
|
||||||
|
}
|
||||||
|
if (!showChildren && item.hasPredecessor(target)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return prev.includes(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[menu, onChange, value, folderTree]
|
[items]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClickFold = useCallback(
|
||||||
|
(event: CProps.EventMouse, target: FolderNode, showChildren: boolean) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onFoldItem(target, showChildren);
|
||||||
|
},
|
||||||
|
[onFoldItem]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} className='h-full text-right'>
|
<div className={clsx('flex flex-col', 'cc-scroll-y', className)} style={style}>
|
||||||
|
{items.map((item, index) =>
|
||||||
|
!item.parent || !folded.includes(item.parent) ? (
|
||||||
|
<div
|
||||||
|
tabIndex={-1}
|
||||||
|
key={`${prefix}${index}`}
|
||||||
|
className={clsx(
|
||||||
|
!dense && 'min-h-[2.0825rem] sm:min-h-[2.3125rem]',
|
||||||
|
'pr-3 py-1 flex items-center gap-2',
|
||||||
|
'cc-scroll-row',
|
||||||
|
'clr-hover',
|
||||||
|
'cursor-pointer',
|
||||||
|
'leading-3 sm:leading-4',
|
||||||
|
activeNode === item && 'clr-selected'
|
||||||
|
)}
|
||||||
|
style={{ paddingLeft: `${(item.rank > 5 ? 5 : item.rank) * 0.5 + 0.5}rem` }}
|
||||||
|
onClick={event => onClick(event, item)}
|
||||||
|
>
|
||||||
|
{item.children.size > 0 ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Проводник...'
|
noPadding
|
||||||
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
noHover
|
||||||
onClick={() => handleChange('/U/test')}
|
icon={
|
||||||
|
folded.includes(item) ? (
|
||||||
|
item.filesInside ? (
|
||||||
|
<IconFolderClosed size='1rem' className='icon-primary' />
|
||||||
|
) : (
|
||||||
|
<IconFolderEmpty size='1rem' className='icon-primary' />
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<IconFolderOpened size='1rem' className='icon-green' />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={event => handleClickFold(event, item, folded.includes(item))}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
{item.filesInside ? (
|
||||||
|
<IconFolder size='1rem' className='clr-text-default' />
|
||||||
|
) : (
|
||||||
|
<IconFolderEmpty size='1rem' className='clr-text-controls' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className='self-center text-start'>{labelFolderNode(item)}</div>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
|
import { FolderTree } from '@/models/FolderTree';
|
||||||
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { IconFolderTree } from '../Icons';
|
||||||
|
import { CProps } from '../props';
|
||||||
|
import Dropdown from '../ui/Dropdown';
|
||||||
|
import MiniButton from '../ui/MiniButton';
|
||||||
|
import SelectLocation from './SelectLocation';
|
||||||
|
|
||||||
|
interface SelectLocationContextProps extends CProps.Styling {
|
||||||
|
value: string;
|
||||||
|
folderTree: FolderTree;
|
||||||
|
stretchTop?: boolean;
|
||||||
|
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectLocationContext({ value, folderTree, onChange, className, style }: SelectLocationContextProps) {
|
||||||
|
const menu = useDropdown();
|
||||||
|
|
||||||
|
const handleClick = useCallback(
|
||||||
|
(event: CProps.EventMouse, newValue: string) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
menu.hide();
|
||||||
|
onChange(newValue);
|
||||||
|
},
|
||||||
|
[menu, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={menu.ref} className='h-full text-right self-start mt-[-0.25rem] ml-[-1.5rem]'>
|
||||||
|
<MiniButton
|
||||||
|
title='Проводник...'
|
||||||
|
hideTitle={menu.isOpen}
|
||||||
|
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||||
|
onClick={() => menu.toggle()}
|
||||||
|
/>
|
||||||
|
<Dropdown
|
||||||
|
isOpen={menu.isOpen}
|
||||||
|
className={clsx('w-[20rem] h-[12.5rem] z-modalTooltip mt-0', className)}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<SelectLocation
|
||||||
|
folderTree={folderTree}
|
||||||
|
value={value}
|
||||||
|
prefix={prefixes.folders_list}
|
||||||
|
dense
|
||||||
|
onClick={(event, target) => handleClick(event, target.getPath())}
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectLocationContext;
|
|
@ -7,11 +7,12 @@ import { CProps } from '../props';
|
||||||
|
|
||||||
interface DropdownProps extends CProps.Styling {
|
interface DropdownProps extends CProps.Styling {
|
||||||
stretchLeft?: boolean;
|
stretchLeft?: boolean;
|
||||||
|
stretchTop?: boolean;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Dropdown({ isOpen, stretchLeft, className, children, ...restProps }: DropdownProps) {
|
function Dropdown({ isOpen, stretchLeft, stretchTop, className, children, ...restProps }: DropdownProps) {
|
||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<motion.div
|
<motion.div
|
||||||
|
@ -25,7 +26,8 @@ function Dropdown({ isOpen, stretchLeft, className, children, ...restProps }: Dr
|
||||||
'clr-input',
|
'clr-input',
|
||||||
{
|
{
|
||||||
'right-0': stretchLeft,
|
'right-0': stretchLeft,
|
||||||
'left-0': !stretchLeft
|
'left-0': !stretchLeft,
|
||||||
|
'bottom-[2rem]': stretchTop
|
||||||
},
|
},
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
import TextArea from '@/components/ui/TextArea';
|
import TextArea from '@/components/ui/TextArea';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { LocationHead } from '@/models/library';
|
import { LocationHead } from '@/models/library';
|
||||||
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||||
import { limits } from '@/utils/constants';
|
import { limits } from '@/utils/constants';
|
||||||
|
@ -22,9 +24,16 @@ function DlgChangeLocation({ hideWindow, initial, onChangeLocation }: DlgChangeL
|
||||||
const [head, setHead] = useState<LocationHead>(initial.substring(0, 2) as LocationHead);
|
const [head, setHead] = useState<LocationHead>(initial.substring(0, 2) as LocationHead);
|
||||||
const [body, setBody] = useState<string>(initial.substring(3));
|
const [body, setBody] = useState<string>(initial.substring(3));
|
||||||
|
|
||||||
|
const { folders } = useLibrary();
|
||||||
|
|
||||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
||||||
const isValid = useMemo(() => initial !== location && validateLocation(location), [initial, location]);
|
const isValid = useMemo(() => initial !== location && validateLocation(location), [initial, location]);
|
||||||
|
|
||||||
|
const handleSelectLocation = useCallback((newValue: string) => {
|
||||||
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
onChangeLocation(location);
|
onChangeLocation(location);
|
||||||
}
|
}
|
||||||
|
@ -41,13 +50,19 @@ function DlgChangeLocation({ hideWindow, initial, onChangeLocation }: DlgChangeL
|
||||||
className={clsx('w-[35rem]', 'pb-3 px-6 flex gap-3')}
|
className={clsx('w-[35rem]', 'pb-3 px-6 flex gap-3')}
|
||||||
>
|
>
|
||||||
<div className='flex flex-col gap-2 w-[7rem] h-min'>
|
<div className='flex flex-col gap-2 w-[7rem] h-min'>
|
||||||
<Label text='Корень' />
|
<Label className='select-none' text='Корень' />
|
||||||
<SelectLocationHead
|
<SelectLocationHead
|
||||||
value={head} // prettier: split-lines
|
value={head} // prettier: split-lines
|
||||||
onChange={setHead}
|
onChange={setHead}
|
||||||
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<SelectLocationContext
|
||||||
|
folderTree={folders}
|
||||||
|
value={location}
|
||||||
|
onChange={handleSelectLocation}
|
||||||
|
className='max-h-[9.2rem]'
|
||||||
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_body'
|
id='dlg_cst_body'
|
||||||
label='Путь'
|
label='Путь'
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import { VisibilityIcon } from '@/components/DomainIcons';
|
import { VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
|
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -44,10 +45,15 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
const [body, setBody] = useState(initialLocation.substring(3));
|
const [body, setBody] = useState(initialLocation.substring(3));
|
||||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
||||||
|
|
||||||
const { cloneItem } = useLibrary();
|
const { cloneItem, folders } = useLibrary();
|
||||||
|
|
||||||
const canSubmit = useMemo(() => title !== '' && alias !== '' && validateLocation(location), [title, alias, location]);
|
const canSubmit = useMemo(() => title !== '' && alias !== '' && validateLocation(location), [title, alias, location]);
|
||||||
|
|
||||||
|
const handleSelectLocation = useCallback((newValue: string) => {
|
||||||
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
const data: IRSFormCloneData = {
|
const data: IRSFormCloneData = {
|
||||||
item_type: base.item_type,
|
item_type: base.item_type,
|
||||||
|
@ -118,6 +124,7 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<SelectLocationContext folderTree={folders} value={location} onChange={handleSelectLocation} />
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_body'
|
id='dlg_cst_body'
|
||||||
label='Путь'
|
label='Путь'
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { IconDownload } from '@/components/Icons';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
import SelectItemType from '@/components/select/SelectItemType';
|
import SelectItemType from '@/components/select/SelectItemType';
|
||||||
import SelectLocation from '@/components/select/SelectLocation';
|
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -185,11 +185,7 @@ function FormCreateItem() {
|
||||||
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{user?.is_staff ? (
|
<SelectLocationContext folderTree={folders} value={location} onChange={handleSelectLocation} />
|
||||||
<div className='self-start mt-[-0.25rem] ml-[-1.5rem]'>
|
|
||||||
<SelectLocation folderTree={folders} value={location} onChange={handleSelectLocation} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_body'
|
id='dlg_cst_body'
|
||||||
label='Путь'
|
label='Путь'
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened, IconFolderTree } from '@/components/Icons';
|
import { IconFolderTree } from '@/components/Icons';
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
|
import SelectLocation from '@/components/select/SelectLocation';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { animateSideView } from '@/styling/animations';
|
import { animateSideView } from '@/styling/animations';
|
||||||
import { PARAMETER, prefixes } from '@/utils/constants';
|
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||||
import { information, labelFolderNode } from '@/utils/labels';
|
import { information } from '@/utils/labels';
|
||||||
|
|
||||||
interface LibraryTableProps {
|
interface LibraryTableProps {
|
||||||
folders: FolderTree;
|
folders: FolderTree;
|
||||||
|
@ -23,33 +22,6 @@ interface LibraryTableProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }: LibraryTableProps) {
|
function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }: LibraryTableProps) {
|
||||||
const activeNode = useMemo(() => folders.at(currentFolder), [folders, currentFolder]);
|
|
||||||
|
|
||||||
const items = useMemo(() => folders.getTree(), [folders]);
|
|
||||||
const [folded, setFolded] = useState<FolderNode[]>(items);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setFolded(items.filter(item => item !== activeNode && (!activeNode || !activeNode.hasPredecessor(item))));
|
|
||||||
}, [items, activeNode]);
|
|
||||||
|
|
||||||
const onFoldItem = useCallback(
|
|
||||||
(target: FolderNode, showChildren: boolean) => {
|
|
||||||
setFolded(prev =>
|
|
||||||
items.filter(item => {
|
|
||||||
if (item === target) {
|
|
||||||
return !showChildren;
|
|
||||||
}
|
|
||||||
if (!showChildren && item.hasPredecessor(target)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return prev.includes(item);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickFolder = useCallback(
|
const handleClickFolder = useCallback(
|
||||||
(event: CProps.EventMouse, target: FolderNode) => {
|
(event: CProps.EventMouse, target: FolderNode) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -66,18 +38,9 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
||||||
[setFolder]
|
[setFolder]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickFold = useCallback(
|
|
||||||
(event: CProps.EventMouse, target: FolderNode, showChildren: boolean) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
onFoldItem(target, showChildren);
|
|
||||||
},
|
|
||||||
[onFoldItem]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
className='flex flex-col select-none text:xs sm:text-sm'
|
className='flex flex-col select-none text:xs sm:text-sm max-w-[10rem] sm:max-w-[15rem] min-w-[10rem] sm:min-w-[15rem]'
|
||||||
initial={{ ...animateSideView.initial }}
|
initial={{ ...animateSideView.initial }}
|
||||||
animate={{ ...animateSideView.animate }}
|
animate={{ ...animateSideView.animate }}
|
||||||
exit={{ ...animateSideView.exit }}
|
exit={{ ...animateSideView.exit }}
|
||||||
|
@ -95,60 +58,12 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
||||||
onClick={toggleFolderMode}
|
onClick={toggleFolderMode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<SelectLocation
|
||||||
className={clsx(
|
value={currentFolder}
|
||||||
'max-w-[10rem] sm:max-w-[15rem] min-w-[10rem] sm:min-w-[15rem]',
|
folderTree={folders}
|
||||||
'flex flex-col',
|
prefix={prefixes.folders_list}
|
||||||
'cc-scroll-y'
|
onClick={handleClickFolder}
|
||||||
)}
|
|
||||||
>
|
|
||||||
{items.map((item, index) =>
|
|
||||||
!item.parent || !folded.includes(item.parent) ? (
|
|
||||||
<div
|
|
||||||
tabIndex={-1}
|
|
||||||
key={`${prefixes.folders_list}${index}`}
|
|
||||||
className={clsx(
|
|
||||||
'min-h-[2.0825rem] sm:min-h-[2.3125rem]',
|
|
||||||
'pr-3 flex items-center gap-2',
|
|
||||||
'cc-scroll-row',
|
|
||||||
'clr-hover',
|
|
||||||
'cursor-pointer',
|
|
||||||
activeNode === item && 'clr-selected'
|
|
||||||
)}
|
|
||||||
style={{ paddingLeft: `${(item.rank > 5 ? 5 : item.rank) * 0.5 + 0.5}rem` }}
|
|
||||||
onClick={event => handleClickFolder(event, item)}
|
|
||||||
>
|
|
||||||
{item.children.size > 0 ? (
|
|
||||||
<MiniButton
|
|
||||||
noPadding
|
|
||||||
noHover
|
|
||||||
icon={
|
|
||||||
folded.includes(item) ? (
|
|
||||||
item.filesInside ? (
|
|
||||||
<IconFolderClosed size='1rem' className='icon-primary' />
|
|
||||||
) : (
|
|
||||||
<IconFolderEmpty size='1rem' className='icon-primary' />
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<IconFolderOpened size='1rem' className='icon-green' />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClick={event => handleClickFold(event, item, folded.includes(item))}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
{item.filesInside ? (
|
|
||||||
<IconFolder size='1rem' className='clr-text-default' />
|
|
||||||
) : (
|
|
||||||
<IconFolderEmpty size='1rem' className='clr-text-controls' />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className='self-center'>{labelFolderNode(item)}</div>
|
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user