F: Improve Sidepanel UI
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
Frontend CI / notify-failure (push) Blocked by required conditions

This commit is contained in:
Ivan 2025-07-30 10:38:04 +03:00
parent 176ad744fe
commit 1af6f87824
4 changed files with 68 additions and 8 deletions

View File

@ -23,6 +23,7 @@ export function ApplicationLayout() {
const viewportHeight = useViewportHeight();
const noNavigationAnimation = useAppLayoutStore(state => state.noNavigationAnimation);
const noNavigation = useAppLayoutStore(state => state.noNavigation);
const toastBottom = useAppLayoutStore(state => state.toastBottom);
const noFooter = useAppLayoutStore(state => state.noFooter);
const activeDialog = useDialogsStore(state => state.active);
@ -35,6 +36,8 @@ export function ApplicationLayout() {
autoClose={3000}
draggable={false}
pauseOnFocusLoss={false}
position={toastBottom ? 'bottom-right' : 'top-right'}
newestOnTop={toastBottom}
/>
<Suspense fallback={<ModalLoader />}>

View File

@ -1,4 +1,4 @@
import { Suspense } from 'react';
import { Suspense, useEffect } from 'react';
import clsx from 'clsx';
import { useDebounce } from 'use-debounce';
@ -23,6 +23,7 @@ interface SidePanelProps {
export function SidePanel({ isMounted, className }: SidePanelProps) {
const noNavigationAnimation = useAppLayoutStore(state => state.noNavigationAnimation);
const setToastBottom = useAppLayoutStore(state => state.setToastBottom);
const { schema, isMutable, selectedItems } = useOssEdit();
const selectedOperation =
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.OPERATION ? selectedItems[0] : null;
@ -32,8 +33,14 @@ export function SidePanel({ isMounted, className }: SidePanelProps) {
const [debouncedMounted] = useDebounce(isMounted, PARAMETER.moveDuration);
const closePanel = usePreferencesStore(state => state.toggleShowOssSidePanel);
const showPanel = usePreferencesStore(state => state.showOssSidePanel);
const sidePanelHeight = useMainHeight();
useEffect(() => {
setToastBottom(showPanel);
return () => setToastBottom(false);
}, [setToastBottom, showPanel]);
return (
<aside
className={cn(

View File

@ -4,18 +4,23 @@ import { CstType, type IConstituentaBasicsDTO, type ICreateConstituentaDTO } fro
import { useCreateConstituenta } from '@/features/rsform/backend/use-create-constituenta';
import { useMoveConstituents } from '@/features/rsform/backend/use-move-constituents';
import { useMutatingRSForm } from '@/features/rsform/backend/use-mutating-rsform';
import { useResetAliases } from '@/features/rsform/backend/use-reset-aliases';
import { useRestoreOrder } from '@/features/rsform/backend/use-restore-order';
import { generateAlias } from '@/features/rsform/models/rsform-api';
import { useCstSearchStore } from '@/features/rsform/stores/cst-search';
import { MiniButton } from '@/components/control';
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
import {
IconClone,
IconDestroy,
IconEdit2,
IconGenerateNames,
IconMoveDown,
IconMoveUp,
IconNewItem,
IconRSForm,
IconSortList,
IconTree,
IconTypeGraph
} from '@/components/icons';
@ -43,6 +48,7 @@ export function ToolbarSchema({
isMutable,
className
}: ToolbarSchemaProps) {
const menuSchema = useDropdown();
const router = useConceptNavigation();
const isProcessing = useMutatingRSForm();
const searchText = useCstSearchStore(state => state.query);
@ -54,6 +60,8 @@ export function ToolbarSchema({
const showTermGraph = useDialogsStore(state => state.showShowTermGraph);
const { moveConstituents } = useMoveConstituents();
const { createConstituenta } = useCreateConstituenta();
const { resetAliases } = useResetAliases();
const { restoreOrder } = useRestoreOrder();
function navigateRSForm() {
router.push({ path: urls.schema(schema.id) });
@ -181,14 +189,50 @@ export function ToolbarSchema({
showTermGraph({ schema: schema });
}
function handleReindex() {
menuSchema.hide();
void resetAliases({ itemID: schema.id });
}
function handleRestoreOrder() {
menuSchema.hide();
void restoreOrder({ itemID: schema.id });
}
return (
<div className={cn('flex gap-0.5', className)}>
<MiniButton
title='Перейти к концептуальной схеме'
icon={<IconRSForm size='1rem' className='icon-primary' />}
onClick={navigateRSForm}
/>
<div ref={menuSchema.ref} onBlur={menuSchema.handleBlur} className='flex relative items-center'>
<MiniButton
title='Редактирование концептуальной схемы'
hideTitle={menuSchema.isOpen}
icon={<IconRSForm size='1rem' className='icon-primary' />}
onClick={menuSchema.toggle}
/>
<Dropdown isOpen={menuSchema.isOpen} margin='mt-0.5'>
<DropdownButton
text='Упорядочить список'
titleHtml='Упорядочить список, исходя из <br/>логики типов и связей конституент'
aria-label='Упорядочить список, исходя из логики типов и связей конституент'
icon={<IconSortList size='1rem' className='icon-primary' />}
onClick={handleRestoreOrder}
disabled={!isMutable || isProcessing}
/>
<DropdownButton
text='Порядковые имена'
titleHtml='Присвоить порядковые имена <br/>и обновить выражения'
aria-label='Присвоить порядковые имена и обновить выражения'
icon={<IconGenerateNames size='1rem' className='icon-primary' />}
onClick={handleReindex}
disabled={!isMutable || isProcessing}
/>
<DropdownButton
title='Перейти к концептуальной схеме'
text='перейти к схеме'
icon={<IconRSForm size='1rem' className='icon-primary' />}
onClick={navigateRSForm}
/>
</Dropdown>
</div>
<MiniButton
title='Редактировать конституенту'
icon={<IconEdit2 size='1rem' className='icon-primary' />}

View File

@ -10,6 +10,9 @@ interface AppLayoutStore {
noFooter: boolean;
hideFooter: (value?: boolean) => void;
toastBottom: boolean;
setToastBottom: (value: boolean) => void;
}
export const useAppLayoutStore = create<AppLayoutStore>()(set => ({
@ -26,7 +29,10 @@ export const useAppLayoutStore = create<AppLayoutStore>()(set => ({
}),
noFooter: false,
hideFooter: value => set({ noFooter: value ?? true })
hideFooter: value => set({ noFooter: value ?? true }),
toastBottom: false,
setToastBottom: value => set({ toastBottom: value })
}));
/** Utility function that returns the height of the main area. */