M: Improve layout for canvas - remove clipping top

This commit is contained in:
Ivan 2024-09-11 21:15:53 +03:00
parent 687f6e549e
commit 997021d628
14 changed files with 121 additions and 111 deletions

View File

@ -110,8 +110,14 @@ export const OptionsState = ({ children }: OptionsStateProps) => {
}, [setDarkMode]); }, [setDarkMode]);
const mainHeight = useMemo(() => { const mainHeight = useMemo(() => {
return !noNavigation ? 'calc(100dvh - 6.75rem)' : '100dvh'; if (noNavigation) {
}, [noNavigation]); return '100dvh';
} else if (noFooter) {
return 'calc(100dvh - 3rem)';
} else {
return 'calc(100dvh - 6.75rem)';
}
}, [noNavigation, noFooter]);
const viewportHeight = useMemo(() => { const viewportHeight = useMemo(() => {
return !noNavigation ? 'calc(100dvh - 3rem)' : '100dvh'; return !noNavigation ? 'calc(100dvh - 3rem)' : '100dvh';

View File

@ -49,7 +49,7 @@ function EditorOssCard({ isModified, onDestroy, setIsModified }: EditorOssCardPr
/> />
<AnimateFade <AnimateFade
onKeyDown={handleInput} onKeyDown={handleInput}
className={clsx('md:w-fit md:max-w-fit max-w-[32rem]', 'mx-auto ', 'flex flex-col md:flex-row px-6')} className={clsx('md:w-fit md:max-w-fit max-w-[32rem]', 'mx-auto pt-[1.9rem]', 'flex flex-col md:flex-row px-6')}
> >
<FlexColumn className='px-3'> <FlexColumn className='px-3'>
<FormOSS id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} /> <FormOSS id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />

View File

@ -40,7 +40,7 @@ interface OssFlowProps {
} }
function OssFlow({ isModified, setIsModified }: OssFlowProps) { function OssFlow({ isModified, setIsModified }: OssFlowProps) {
const { calculateHeight, colors } = useConceptOptions(); const { mainHeight, colors } = useConceptOptions();
const model = useOSS(); const model = useOSS();
const controller = useOssEdit(); const controller = useOssEdit();
const flow = useReactFlow(); const flow = useReactFlow();
@ -342,8 +342,6 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
} }
} }
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
const OssNodeTypes: NodeTypes = useMemo( const OssNodeTypes: NodeTypes = useMemo(
() => ({ () => ({
synthesis: OperationNode, synthesis: OperationNode,
@ -389,7 +387,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
return ( return (
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}> <AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}>
<Overlay position='top-0 pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'> <Overlay position='top-[1.9rem] pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
<ToolbarOssGraph <ToolbarOssGraph
isModified={isModified} isModified={isModified}
showGrid={showGrid} showGrid={showGrid}
@ -419,7 +417,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
{...menuProps} {...menuProps}
/> />
) : null} ) : null}
<div className='relative w-[100vw]' style={{ height: canvasHeight }}> <div className='relative w-[100vw]' style={{ height: mainHeight }}>
{graph} {graph}
</div> </div>
</AnimateFade> </AnimateFade>

View File

@ -9,6 +9,7 @@ import { toast } from 'react-toastify';
import { urls } from '@/app/urls'; import { urls } from '@/app/urls';
import InfoError, { ErrorData } from '@/components/info/InfoError'; import InfoError, { ErrorData } from '@/components/info/InfoError';
import Loader from '@/components/ui/Loader'; import Loader from '@/components/ui/Loader';
import Overlay from '@/components/ui/Overlay';
import TabLabel from '@/components/ui/TabLabel'; import TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL'; import TextURL from '@/components/ui/TextURL';
import AnimateFade from '@/components/wrap/AnimateFade'; import AnimateFade from '@/components/wrap/AnimateFade';
@ -37,7 +38,7 @@ function OssTabs() {
const activeTab = query.get('tab') ? (Number(query.get('tab')) as OssTabID) : OssTabID.GRAPH; const activeTab = query.get('tab') ? (Number(query.get('tab')) as OssTabID) : OssTabID.GRAPH;
const { user } = useAuth(); const { user } = useAuth();
const { calculateHeight, setNoFooter } = useConceptOptions(); const { setNoFooter } = useConceptOptions();
const { schema, loading, loadingError: errorLoading } = useOSS(); const { schema, loading, loadingError: errorLoading } = useOSS();
const { destroyItem } = useLibrary(); const { destroyItem } = useLibrary();
@ -107,8 +108,6 @@ function OssTabs() {
}); });
}, [schema, destroyItem, router]); }, [schema, destroyItem, router]);
const panelHeight = useMemo(() => calculateHeight('1.625rem + 2px'), [calculateHeight]);
const cardPanel = useMemo( const cardPanel = useMemo(
() => ( () => (
<TabPanel> <TabPanel>
@ -143,14 +142,16 @@ function OssTabs() {
selectedTabClassName='clr-selected' selectedTabClassName='clr-selected'
className='flex flex-col mx-auto min-w-fit' className='flex flex-col mx-auto min-w-fit'
> >
<TabList className={clsx('mx-auto w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2')}> <Overlay position='top-0 right-1/2 translate-x-1/2' layer='z-sticky'>
<TabList className={clsx('w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2')}>
<MenuOssTabs onDestroy={onDestroySchema} /> <MenuOssTabs onDestroy={onDestroySchema} />
<TabLabel label='Карточка' title={schema.title ?? ''} /> <TabLabel label='Карточка' title={schema.title ?? ''} />
<TabLabel label='Граф' /> <TabLabel label='Граф' />
</TabList> </TabList>
</Overlay>
<AnimateFade className='overflow-y-auto' style={{ maxHeight: panelHeight }}> <AnimateFade>
{cardPanel} {cardPanel}
{graphPanel} {graphPanel}
</AnimateFade> </AnimateFade>

View File

@ -28,7 +28,7 @@ interface EditorConstituentaProps {
function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }: EditorConstituentaProps) { function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }: EditorConstituentaProps) {
const controller = useRSEdit(); const controller = useRSEdit();
const windowSize = useWindowSize(); const windowSize = useWindowSize();
const { calculateHeight } = useConceptOptions(); const { mainHeight } = useConceptOptions();
const [showList, setShowList] = useLocalStorage(storage.rseditShowList, true); const [showList, setShowList] = useLocalStorage(storage.rseditShowList, true);
const [toggleReset, setToggleReset] = useState(false); const [toggleReset, setToggleReset] = useState(false);
@ -39,7 +39,6 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
); );
const isNarrow = useMemo(() => !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD, [windowSize]); const isNarrow = useMemo(() => !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD, [windowSize]);
const panelHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) { function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
if (disabled) { if (disabled) {
@ -79,7 +78,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
} }
return ( return (
<div className='overflow-y-auto min-h-[20rem]' style={{ maxHeight: panelHeight }}> <>
<ToolbarConstituenta <ToolbarConstituenta
activeCst={activeCst} activeCst={activeCst}
disabled={disabled} disabled={disabled}
@ -89,6 +88,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
onReset={() => setToggleReset(prev => !prev)} onReset={() => setToggleReset(prev => !prev)}
onToggleList={() => setShowList(prev => !prev)} onToggleList={() => setShowList(prev => !prev)}
/> />
<div className='pt-[1.9rem] overflow-y-auto min-h-[20rem]' style={{ maxHeight: mainHeight }}>
<div <div
tabIndex={-1} tabIndex={-1}
className={clsx( className={clsx(
@ -122,6 +122,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
</AnimatePresence> </AnimatePresence>
</div> </div>
</div> </div>
</>
); );
} }

View File

@ -50,7 +50,7 @@ function ToolbarConstituenta({
return ( return (
<Overlay <Overlay
position='top-1 right-1/2 translate-x-1/2 xs:right-4 xs:translate-x-0 md:right-1/2 md:translate-x-1/2' position='cc-tab-tools right-1/2 translate-x-1/2 xs:right-4 xs:translate-x-0 md:right-1/2 md:translate-x-1/2'
className='cc-icons outline-none transition-all duration-500' className='cc-icons outline-none transition-all duration-500'
> >
{controller.schema && controller.schema?.oss.length > 0 ? ( {controller.schema && controller.schema?.oss.length > 0 ? (

View File

@ -49,7 +49,7 @@ function EditorRSFormCard({ isModified, onDestroy, setIsModified }: EditorRSForm
/> />
<AnimateFade <AnimateFade
onKeyDown={handleInput} onKeyDown={handleInput}
className={clsx('md:w-fit md:max-w-fit max-w-[32rem] mx-auto', 'flex flex-col md:flex-row px-6')} className={clsx('md:w-fit md:max-w-fit max-w-[32rem] mx-auto', 'flex flex-col md:flex-row px-6 pt-[1.9rem]')}
> >
<FlexColumn className='flex-shrink'> <FlexColumn className='flex-shrink'>
<FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} /> <FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />

View File

@ -45,7 +45,7 @@ function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: Toolba
}, [controller]); }, [controller]);
return ( return (
<Overlay position='top-1 right-1/2 translate-x-1/2' className='cc-icons'> <Overlay position='cc-tab-tools' className='cc-icons'>
{ossSelector} {ossSelector}
{controller.isMutable || modified ? ( {controller.isMutable || modified ? (
<MiniButton <MiniButton

View File

@ -142,7 +142,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
return ( return (
<> <>
{controller.isContentEditable ? <ToolbarRSList /> : null} {controller.isContentEditable ? <ToolbarRSList /> : null}
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}> <AnimateFade tabIndex={-1} onKeyDown={handleKeyDown} className='pt-[1.9rem]'>
{controller.isContentEditable ? ( {controller.isContentEditable ? (
<div className='flex items-center border-b'> <div className='flex items-center border-b'>
<div className='px-2'> <div className='px-2'>

View File

@ -28,7 +28,7 @@ function ToolbarRSList() {
return ( return (
<Overlay <Overlay
position='top-1 right-4 translate-x-0 md:right-1/2 md:translate-x-1/2' position='cc-tab-tools right-4 translate-x-0 md:right-1/2 md:translate-x-1/2'
className='cc-icons items-start outline-none transition-all duration-500' className='cc-icons items-start outline-none transition-all duration-500'
> >
{controller.schema && controller.schema?.oss.length > 0 ? ( {controller.schema && controller.schema?.oss.length > 0 ? (

View File

@ -287,7 +287,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
); );
return ( return (
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}> <>
<AnimatePresence> <AnimatePresence>
{showParamsDialog ? ( {showParamsDialog ? (
<DlgGraphParams <DlgGraphParams
@ -298,10 +298,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
) : null} ) : null}
</AnimatePresence> </AnimatePresence>
<Overlay <Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'>
position='top-0 pt-1 right-1/2 translate-x-1/2'
className='flex flex-col items-center rounded-b-2xl cc-blur'
>
<ToolbarTermGraph <ToolbarTermGraph
is3D={is3D} is3D={is3D}
orbit={orbit} orbit={orbit}
@ -352,6 +349,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
) : null} ) : null}
</Overlay> </Overlay>
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}>
<SelectedCounter <SelectedCounter
hideZero hideZero
totalCount={controller.schema?.stats?.count_all ?? 0} totalCount={controller.schema?.stats?.count_all ?? 0}
@ -362,7 +360,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
{hoverCst && hoverCstDebounced && hoverCst === hoverCstDebounced ? ( {hoverCst && hoverCstDebounced && hoverCst === hoverCstDebounced ? (
<Overlay <Overlay
layer='z-tooltip' layer='z-tooltip'
position={clsx('top-[1.6rem]', { 'left-[2.6rem]': hoverLeft, 'right-[2.6rem]': !hoverLeft })} position={clsx('top-[3.5rem]', { 'left-[2.6rem]': hoverLeft, 'right-[2.6rem]': !hoverLeft })}
className={clsx( className={clsx(
'w-[25rem] max-h-[calc(100dvh-15rem)]', 'w-[25rem] max-h-[calc(100dvh-15rem)]',
'px-3', 'px-3',
@ -376,7 +374,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
</Overlay> </Overlay>
) : null} ) : null}
<Overlay position='top-[6.25rem] sm:top-[4rem] left-0' className='flex gap-1'> <Overlay position='top-[8.15rem] sm:top-[5.9rem] left-0' className='flex gap-1'>
<div className='flex flex-col ml-2 w-[13.5rem]'> <div className='flex flex-col ml-2 w-[13.5rem]'>
{selectors} {selectors}
{viewHidden} {viewHidden}
@ -385,6 +383,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
{graph} {graph}
</AnimateFade> </AnimateFade>
</>
); );
} }

View File

@ -53,7 +53,7 @@ function TermGraph({
onSelect, onSelect,
onDeselect onDeselect
}: TermGraphProps) { }: TermGraphProps) {
const { calculateHeight, darkMode } = useConceptOptions(); const { mainHeight, darkMode } = useConceptOptions();
const { selections, setSelections } = useSelection({ const { selections, setSelections } = useSelection({
ref: graphRef, ref: graphRef,
@ -111,10 +111,8 @@ function TermGraph({
return 'calc(100vw - 1rem)'; return 'calc(100vw - 1rem)';
}, []); }, []);
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
return ( return (
<div className='relative outline-none' style={{ width: canvasWidth, height: canvasHeight }}> <div className='relative outline-none' style={{ width: canvasWidth, height: mainHeight }}>
<GraphUI <GraphUI
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}

View File

@ -10,6 +10,7 @@ import { urls } from '@/app/urls';
import InfoError, { ErrorData } from '@/components/info/InfoError'; import InfoError, { ErrorData } from '@/components/info/InfoError';
import Divider from '@/components/ui/Divider'; import Divider from '@/components/ui/Divider';
import Loader from '@/components/ui/Loader'; import Loader from '@/components/ui/Loader';
import Overlay from '@/components/ui/Overlay';
import TabLabel from '@/components/ui/TabLabel'; import TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL'; import TextURL from '@/components/ui/TextURL';
import AnimateFade from '@/components/wrap/AnimateFade'; import AnimateFade from '@/components/wrap/AnimateFade';
@ -45,7 +46,7 @@ function RSTabs() {
const version = query.get('v') ? Number(query.get('v')) : undefined; const version = query.get('v') ? Number(query.get('v')) : undefined;
const cstQuery = query.get('active'); const cstQuery = query.get('active');
const { setNoFooter, calculateHeight } = useConceptOptions(); const { setNoFooter } = useConceptOptions();
const { schema, loading, errorLoading, isArchive, itemID } = useRSForm(); const { schema, loading, errorLoading, isArchive, itemID } = useRSForm();
const library = useLibrary(); const library = useLibrary();
const oss = useGlobalOss(); const oss = useGlobalOss();
@ -73,7 +74,7 @@ function RSTabs() {
}, [schema, schema?.title]); }, [schema, schema?.title]);
useLayoutEffect(() => { useLayoutEffect(() => {
setNoFooter(activeTab === RSTabID.CST_EDIT || activeTab === RSTabID.CST_LIST); setNoFooter(activeTab !== RSTabID.CARD);
setIsModified(false); setIsModified(false);
if (activeTab === RSTabID.CST_EDIT) { if (activeTab === RSTabID.CST_EDIT) {
const cstID = Number(cstQuery); const cstID = Number(cstQuery);
@ -189,8 +190,6 @@ function RSTabs() {
}); });
}, [schema, library, oss, router]); }, [schema, library, oss, router]);
const panelHeight = useMemo(() => calculateHeight('1.625rem + 2px'), [calculateHeight]);
const cardPanel = useMemo( const cardPanel = useMemo(
() => ( () => (
<TabPanel> <TabPanel>
@ -255,19 +254,23 @@ function RSTabs() {
selectedTabClassName='clr-selected' selectedTabClassName='clr-selected'
className='flex flex-col mx-auto min-w-fit' className='flex flex-col mx-auto min-w-fit'
> >
<Overlay position='top-0 right-1/2 translate-x-1/2' layer='z-sticky'>
<TabList className={clsx('mx-auto w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2')}> <TabList className={clsx('mx-auto w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2')}>
<MenuRSTabs onDestroy={onDestroySchema} /> <MenuRSTabs onDestroy={onDestroySchema} />
<TabLabel label='Карточка' titleHtml={`${schema.title ?? ''}<br />Версия: ${labelVersion(schema)}`} /> <TabLabel label='Карточка' titleHtml={`${schema.title ?? ''}<br />Версия: ${labelVersion(schema)}`} />
<TabLabel <TabLabel
label='Содержание' label='Содержание'
titleHtml={`Конституент: ${schema.stats?.count_all ?? 0}<br />Ошибок: ${schema.stats?.count_errors ?? 0}`} titleHtml={`Конституент: ${schema.stats?.count_all ?? 0}<br />Ошибок: ${
schema.stats?.count_errors ?? 0
}`}
/> />
<TabLabel label='Редактор' /> <TabLabel label='Редактор' />
<TabLabel label='Граф термов' /> <TabLabel label='Граф термов' />
</TabList> </TabList>
</Overlay>
<AnimateFade className='overflow-y-auto overflow-x-hidden' style={{ maxHeight: panelHeight }}> <AnimateFade className='overflow-x-hidden'>
{cardPanel} {cardPanel}
{listPanel} {listPanel}
{editorPanel} {editorPanel}

View File

@ -221,6 +221,10 @@
@apply clr-text-primary; @apply clr-text-primary;
} }
.cc-tab-tools {
@apply top-[1.9rem] pt-1 right-1/2 translate-x-1/2;
}
.cc-modal-blur { .cc-modal-blur {
opacity: 0.3; opacity: 0.3;
backdrop-filter: blur(2px); backdrop-filter: blur(2px);