Compare commits
4 Commits
f3f9c419d4
...
d7ee1db6a9
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d7ee1db6a9 | ||
![]() |
7d41953a8d | ||
![]() |
fdbb05df70 | ||
![]() |
142f3882bb |
|
@ -32,9 +32,10 @@ export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri';
|
|||
export { LuMoon as IconDarkTheme } from 'react-icons/lu';
|
||||
export { LuSun as IconLightTheme } from 'react-icons/lu';
|
||||
export { LuFolderTree as IconFolderTree } from 'react-icons/lu';
|
||||
export { FaRegFolder as IconFolder } from 'react-icons/fa6';
|
||||
export { FaRegFolderOpen as IconFolderOpened } from 'react-icons/fa6';
|
||||
export { FaRegFolderClosed as IconFolderClosed } from 'react-icons/fa6';
|
||||
export { LuFolder as IconFolder } from 'react-icons/lu';
|
||||
export { LuFolderOpen as IconFolderOpened } from 'react-icons/lu';
|
||||
export { LuFolderClosed as IconFolderClosed } from 'react-icons/lu';
|
||||
export { LuFolderDot as IconFolderEmpty } from 'react-icons/lu';
|
||||
export { LuLightbulb as IconHelp } from 'react-icons/lu';
|
||||
export { LuLightbulbOff as IconHelpOff } from 'react-icons/lu';
|
||||
export { RiPushpinFill as IconPin } from 'react-icons/ri';
|
||||
|
|
|
@ -77,11 +77,12 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
|||
const [cachedTemplates, setCachedTemplates] = useState<IRSForm[]>([]);
|
||||
|
||||
const folders = useMemo(() => {
|
||||
const result = new FolderTree(items.map(item => item.location));
|
||||
const result = new FolderTree();
|
||||
result.addPath(LocationHead.USER, 0);
|
||||
result.addPath(LocationHead.COMMON, 0);
|
||||
result.addPath(LocationHead.LIBRARY, 0);
|
||||
result.addPath(LocationHead.PROJECTS, 0);
|
||||
items.forEach(item => result.addPath(item.location));
|
||||
return result;
|
||||
}, [items]);
|
||||
|
||||
|
|
|
@ -102,7 +102,9 @@ export class FolderTree {
|
|||
|
||||
private visitNode(target: FolderNode, result: FolderNode[]) {
|
||||
result.push(target);
|
||||
target.children.forEach(child => this.visitNode(child, result));
|
||||
[...target.children.keys()]
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.forEach(key => this.visitNode(target.children.get(key)!, result));
|
||||
}
|
||||
|
||||
addPath(path: string, filesCount: number = 1): FolderNode {
|
||||
|
|
|
@ -4,12 +4,14 @@ import clsx from 'clsx';
|
|||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { IconFolder, IconFolderClosed, IconFolderOpened, IconFolderTree } from '@/components/Icons';
|
||||
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened, IconFolderTree } from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import { CProps } from '@/components/props';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { animateSideAppear, animateSideView } from '@/styling/animations';
|
||||
import { globals, prefixes } from '@/utils/constants';
|
||||
import { globals, PARAMETER, prefixes } from '@/utils/constants';
|
||||
import { describeFolderNode, labelFolderNode } from '@/utils/labels';
|
||||
|
||||
interface LibraryTableProps {
|
||||
|
@ -72,10 +74,16 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
|||
animate={{ ...animateSideView.animate }}
|
||||
exit={{ ...animateSideView.exit }}
|
||||
>
|
||||
<div className='h-[2.08rem] flex justify-end pr-1'>
|
||||
<div className='h-[2.08rem] flex justify-between items-center pr-1'>
|
||||
<BadgeHelp
|
||||
topic={HelpTopic.UI_LIBRARY}
|
||||
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'text-sm')}
|
||||
offset={5}
|
||||
place='right-start'
|
||||
/>
|
||||
<MiniButton
|
||||
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||
title='Режим: проводник'
|
||||
title='Переключение в режим Поиск'
|
||||
onClick={toggleFolderMode}
|
||||
/>
|
||||
</div>
|
||||
|
@ -114,7 +122,11 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
|||
noHover
|
||||
icon={
|
||||
folded.includes(item) ? (
|
||||
<IconFolderClosed size='1rem' className='icon-primary' />
|
||||
item.filesInside ? (
|
||||
<IconFolderClosed size='1rem' className='icon-primary' />
|
||||
) : (
|
||||
<IconFolderEmpty size='1rem' className='icon-primary' />
|
||||
)
|
||||
) : (
|
||||
<IconFolderOpened size='1rem' className='icon-green' />
|
||||
)
|
||||
|
@ -123,7 +135,11 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
|||
/>
|
||||
) : (
|
||||
<div>
|
||||
<IconFolder size='1rem' />
|
||||
{item.filesInside ? (
|
||||
<IconFolder size='1rem' className='clr-text-default' />
|
||||
) : (
|
||||
<IconFolderEmpty size='1rem' className='clr-text-controls' />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className='self-center'>{labelFolderNode(item)}</div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
|||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { urls } from '@/app/urls';
|
||||
import { IconFolder } from '@/components/Icons';
|
||||
import { IconFolderTree } from '@/components/Icons';
|
||||
import BadgeLocation from '@/components/info/BadgeLocation';
|
||||
import { CProps } from '@/components/props';
|
||||
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
||||
|
@ -56,11 +56,9 @@ function LibraryTable({ items, resetQuery, folderMode, toggleFolderMode }: Libra
|
|||
|
||||
const handleToggleFolder = useCallback(
|
||||
(event: CProps.EventMouse) => {
|
||||
if (event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleFolderMode();
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleFolderMode();
|
||||
},
|
||||
[toggleFolderMode]
|
||||
);
|
||||
|
@ -74,12 +72,12 @@ function LibraryTable({ items, resetQuery, folderMode, toggleFolderMode }: Libra
|
|||
id: 'location',
|
||||
header: () => (
|
||||
<MiniButton
|
||||
noHover
|
||||
noPadding
|
||||
noHover
|
||||
className='pl-2 max-h-[1rem] translate-y-[-0.125rem]'
|
||||
onClick={handleToggleFolder}
|
||||
titleHtml='Ctrl + клик для переключения </br>в режим папок'
|
||||
icon={<IconFolder size='1.25rem' className='clr-text-controls' />}
|
||||
titleHtml='Переключение в режим Проводник'
|
||||
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
|
||||
/>
|
||||
),
|
||||
size: 50,
|
||||
|
|
|
@ -176,6 +176,12 @@ function SearchPanel({
|
|||
/>
|
||||
|
||||
<Dropdown isOpen={headMenu.isOpen} stretchLeft className='z-modalTooltip'>
|
||||
<DropdownButton className='w-[10rem]' title='Переключение в режим Проводник' onClick={handleToggleFolder}>
|
||||
<div className='inline-flex items-center gap-3'>
|
||||
<IconFolderTree size='1rem' className='clr-text-controls' />
|
||||
<span>проводник...</span>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
<DropdownButton className='w-[10rem]' onClick={() => handleChange(undefined)}>
|
||||
<div className='inline-flex items-center gap-3'>
|
||||
<IconFolder size='1rem' className='clr-text-controls' />
|
||||
|
@ -197,16 +203,6 @@ function SearchPanel({
|
|||
</DropdownButton>
|
||||
);
|
||||
})}
|
||||
<DropdownButton
|
||||
className='w-[10rem]'
|
||||
title='переключение в режим выбора папок'
|
||||
onClick={handleToggleFolder}
|
||||
>
|
||||
<div className='inline-flex items-center gap-3'>
|
||||
<IconFolderTree size='1rem' className='clr-text-controls' />
|
||||
<span>проводник...</span>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
</Dropdown>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
import { IconFolder, IconSearch, IconShow, IconSortAsc, IconSortDesc } from '@/components/Icons';
|
||||
import {
|
||||
IconFolder,
|
||||
IconFolderClosed,
|
||||
IconFolderEmpty,
|
||||
IconFolderOpened,
|
||||
IconFolderTree,
|
||||
IconSearch,
|
||||
IconShow,
|
||||
IconSortAsc,
|
||||
IconSortDesc
|
||||
} from '@/components/Icons';
|
||||
|
||||
function HelpLibrary() {
|
||||
return (
|
||||
|
@ -21,6 +31,28 @@ function HelpLibrary() {
|
|||
<li>
|
||||
<IconFolder size='1rem' className='inline-icon' /> фильтр по расположению
|
||||
</li>
|
||||
|
||||
<h2>Проводник</h2>
|
||||
<li>клик по папке отображает справа файлы в ней</li>
|
||||
<li>клик по иконке сворачивает/разворачивает вложенные</li>
|
||||
<li>
|
||||
<IconFolderTree size='1rem' className='inline-icon' /> переключение между Проводник и Поиск
|
||||
</li>
|
||||
<li>
|
||||
<IconFolderEmpty size='1rem' className='inline-icon clr-text-default' /> папка без файлов
|
||||
</li>
|
||||
<li>
|
||||
<IconFolderEmpty size='1rem' className='inline-icon' /> папка с вложенными без файлов
|
||||
</li>
|
||||
<li>
|
||||
<IconFolder size='1rem' className='inline-icon' /> папка без вложенных
|
||||
</li>
|
||||
<li>
|
||||
<IconFolderClosed size='1rem' className='inline-icon' /> папка с вложенными и файлами
|
||||
</li>
|
||||
<li>
|
||||
<IconFolderOpened size='1rem' className='inline-icon icon-green' /> развернутая папка
|
||||
</li>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ function FormConstituenta({
|
|||
}
|
||||
|
||||
return (
|
||||
<AnimateFade>
|
||||
<AnimateFade className='mx-0 md:mx-auto'>
|
||||
<ControlsOverlay
|
||||
disabled={disabled}
|
||||
modified={isModified}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { GraphLayout } from '@/components/ui/GraphUI';
|
|||
import { FolderNode } from '@/models/FolderTree';
|
||||
import { GramData, Grammeme, ReferenceType } from '@/models/language';
|
||||
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||
import { validateLocation } from '@/models/libraryAPI';
|
||||
import { CstMatchMode, DependencyMode, GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous';
|
||||
import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from '@/models/rsform';
|
||||
import {
|
||||
|
@ -271,10 +272,10 @@ export function describeCstSource(mode: DependencyMode): string {
|
|||
export function labelLocationHead(head: LocationHead): string {
|
||||
// prettier-ignore
|
||||
switch (head) {
|
||||
case LocationHead.USER: return 'личные (/U)';
|
||||
case LocationHead.COMMON: return 'общие (/S)';
|
||||
case LocationHead.LIBRARY: return 'примеры (/L)';
|
||||
case LocationHead.PROJECTS: return 'проекты (/P)';
|
||||
case LocationHead.USER: return '/U : личные';
|
||||
case LocationHead.COMMON: return '/S : общие';
|
||||
case LocationHead.LIBRARY: return '/L : примеры';
|
||||
case LocationHead.PROJECTS: return '/P : проекты';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -825,7 +826,11 @@ export function describeAccessMode(mode: UserLevel): string {
|
|||
* Retrieves label for {@link FolderNode}.
|
||||
*/
|
||||
export function labelFolderNode(node: FolderNode): string {
|
||||
return node.text;
|
||||
if (node.parent || !validateLocation('/' + node.text)) {
|
||||
return node.text;
|
||||
} else {
|
||||
return labelLocationHead(('/' + node.text) as LocationHead);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user