Fix layout for Ipad

This commit is contained in:
IRBorisov 2024-06-04 14:20:43 +03:00
parent 2ead8e3a4a
commit 10d1da917d
6 changed files with 42 additions and 22 deletions

View File

@ -15,10 +15,11 @@ import DropdownButton from '../ui/DropdownButton';
interface SelectGraphFilterProps { interface SelectGraphFilterProps {
value: DependencyMode; value: DependencyMode;
dense?: boolean;
onChange: (value: DependencyMode) => void; onChange: (value: DependencyMode) => void;
} }
function SelectGraphFilter({ value, onChange }: SelectGraphFilterProps) { function SelectGraphFilter({ value, dense, onChange }: SelectGraphFilterProps) {
const menu = useDropdown(); const menu = useDropdown();
const size = useWindowSize(); const size = useWindowSize();
@ -39,7 +40,7 @@ function SelectGraphFilter({ value, onChange }: SelectGraphFilterProps) {
hideTitle={menu.isOpen} hideTitle={menu.isOpen}
className='h-full pr-2' className='h-full pr-2'
icon={DependencyIcon(value, '1rem', value !== DependencyMode.ALL ? 'icon-primary' : '')} icon={DependencyIcon(value, '1rem', value !== DependencyMode.ALL ? 'icon-primary' : '')}
text={size.isSmall ? undefined : labelCstSource(value)} text={dense || size.isSmall ? undefined : labelCstSource(value)}
onClick={menu.toggle} onClick={menu.toggle}
/> />
<Dropdown stretchLeft isOpen={menu.isOpen}> <Dropdown stretchLeft isOpen={menu.isOpen}>
@ -49,13 +50,17 @@ function SelectGraphFilter({ value, onChange }: SelectGraphFilterProps) {
const source = value as DependencyMode; const source = value as DependencyMode;
return ( return (
<DropdownButton <DropdownButton
className='w-[18rem]' className={!dense ? 'w-[18rem]' : undefined}
key={`${prefixes.cst_source_list}${index}`} key={`${prefixes.cst_source_list}${index}`}
onClick={() => handleChange(source)} onClick={() => handleChange(source)}
> >
<div className='inline-flex items-center gap-1'> <div className='inline-flex items-center gap-1'>
{DependencyIcon(source, '1rem')} {DependencyIcon(source, '1rem')}
<b>{labelCstSource(source)}:</b> {describeCstSource(source)} {!dense ? (
<span>
<b>{labelCstSource(source)}:</b> {describeCstSource(source)}
</span>
) : null}
</div> </div>
</DropdownButton> </DropdownButton>
); );

View File

@ -15,10 +15,11 @@ import DropdownButton from '../ui/DropdownButton';
interface SelectMatchModeProps { interface SelectMatchModeProps {
value: CstMatchMode; value: CstMatchMode;
dense?: boolean;
onChange: (value: CstMatchMode) => void; onChange: (value: CstMatchMode) => void;
} }
function SelectMatchMode({ value, onChange }: SelectMatchModeProps) { function SelectMatchMode({ value, dense, onChange }: SelectMatchModeProps) {
const menu = useDropdown(); const menu = useDropdown();
const size = useWindowSize(); const size = useWindowSize();
@ -38,7 +39,7 @@ function SelectMatchMode({ value, onChange }: SelectMatchModeProps) {
hideTitle={menu.isOpen} hideTitle={menu.isOpen}
className='h-full pr-2' className='h-full pr-2'
icon={MatchModeIcon(value, '1rem', value !== CstMatchMode.ALL ? 'icon-primary' : '')} icon={MatchModeIcon(value, '1rem', value !== CstMatchMode.ALL ? 'icon-primary' : '')}
text={size.isSmall ? undefined : labelCstMatchMode(value)} text={dense || size.isSmall ? undefined : labelCstMatchMode(value)}
onClick={menu.toggle} onClick={menu.toggle}
/> />
<Dropdown stretchLeft isOpen={menu.isOpen}> <Dropdown stretchLeft isOpen={menu.isOpen}>
@ -48,13 +49,17 @@ function SelectMatchMode({ value, onChange }: SelectMatchModeProps) {
const matchMode = value as CstMatchMode; const matchMode = value as CstMatchMode;
return ( return (
<DropdownButton <DropdownButton
className='w-[20rem]' className={!dense ? 'w-[20rem]' : undefined}
key={`${prefixes.cst_source_list}${index}`} key={`${prefixes.cst_source_list}${index}`}
onClick={() => handleChange(matchMode)} onClick={() => handleChange(matchMode)}
> >
<div className='inline-flex items-center gap-1'> <div className='inline-flex items-center gap-1'>
{MatchModeIcon(matchMode, '1rem')} {MatchModeIcon(matchMode, '1rem')}
<b>{labelCstMatchMode(matchMode)}:</b> {describeCstMatchMode(matchMode)} {!dense ? (
<span>
<b>{labelCstMatchMode(matchMode)}:</b> {describeCstMatchMode(matchMode)}
</span>
) : null}
</div> </div>
</DropdownButton> </DropdownButton>
); );

View File

@ -38,7 +38,7 @@ interface IOptionsContext {
showHelp: boolean; showHelp: boolean;
toggleShowHelp: () => void; toggleShowHelp: () => void;
calculateHeight: (offset: string) => string; calculateHeight: (offset: string, minimum?: string) => string;
} }
const OptionsContext = createContext<IOptionsContext | null>(null); const OptionsContext = createContext<IOptionsContext | null>(null);
@ -96,13 +96,13 @@ export const OptionsState = ({ children }: OptionsStateProps) => {
}, [noNavigation]); }, [noNavigation]);
const calculateHeight = useCallback( const calculateHeight = useCallback(
(offset: string) => { (offset: string, minimum: string = '0px') => {
if (noNavigation) { if (noNavigation) {
return `calc(100vh - (${offset}))`; return `max(calc(100vh - (${offset})), ${minimum})`;
} else if (noFooter) { } else if (noFooter) {
return `calc(100vh - 3rem - (${offset}))`; return `max(calc(100vh - 3rem - (${offset})), ${minimum})`;
} else { } else {
return `calc(100vh - 6.75rem - (${offset}))`; return `max(calc(100vh - 6.75rem - (${offset})), ${minimum})`;
} }
}, },
[noNavigation, noFooter] [noNavigation, noFooter]

View File

@ -4,6 +4,7 @@ import clsx from 'clsx';
import { AnimatePresence } from 'framer-motion'; import { AnimatePresence } from 'framer-motion';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useConceptOptions } from '@/context/OptionsContext';
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
import useWindowSize from '@/hooks/useWindowSize'; import useWindowSize from '@/hooks/useWindowSize';
import { ConstituentaID, IConstituenta } from '@/models/rsform'; import { ConstituentaID, IConstituenta } from '@/models/rsform';
@ -15,7 +16,7 @@ import ConstituentaToolbar from './ConstituentaToolbar';
import FormConstituenta from './FormConstituenta'; import FormConstituenta from './FormConstituenta';
// Threshold window width to switch layout. // Threshold window width to switch layout.
const SIDELIST_LAYOUT_THRESHOLD = 1100; // px const SIDELIST_LAYOUT_THRESHOLD = 1000; // px
interface EditorConstituentaProps { interface EditorConstituentaProps {
activeCst?: IConstituenta; activeCst?: IConstituenta;
@ -27,6 +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 [showList, setShowList] = useLocalStorage(storage.rseditShowList, true); const [showList, setShowList] = useLocalStorage(storage.rseditShowList, true);
const [toggleReset, setToggleReset] = useState(false); const [toggleReset, setToggleReset] = useState(false);
@ -37,6 +39,7 @@ 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) {
@ -76,7 +79,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
} }
return ( return (
<> <div className='overflow-y-auto' style={{ maxHeight: panelHeight }}>
{controller.isContentEditable ? ( {controller.isContentEditable ? (
<ConstituentaToolbar <ConstituentaToolbar
disabled={disabled} disabled={disabled}
@ -123,7 +126,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
) : null} ) : null}
</AnimatePresence> </AnimatePresence>
</div> </div>
</> </div>
); );
} }

View File

@ -15,12 +15,13 @@ import { storage } from '@/utils/constants';
interface ConstituentsSearchProps { interface ConstituentsSearchProps {
schema?: IRSForm; schema?: IRSForm;
dense?: boolean;
activeID?: ConstituentaID; activeID?: ConstituentaID;
activeExpression: string; activeExpression: string;
setFiltered: React.Dispatch<React.SetStateAction<IConstituenta[]>>; setFiltered: React.Dispatch<React.SetStateAction<IConstituenta[]>>;
} }
function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }: ConstituentsSearchProps) { function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFiltered }: ConstituentsSearchProps) {
const [filterMatch, setFilterMatch] = useLocalStorage(storage.cstFilterMatch, CstMatchMode.ALL); const [filterMatch, setFilterMatch] = useLocalStorage(storage.cstFilterMatch, CstMatchMode.ALL);
const [filterSource, setFilterSource] = useLocalStorage(storage.cstFilterGraph, DependencyMode.ALL); const [filterSource, setFilterSource] = useLocalStorage(storage.cstFilterGraph, DependencyMode.ALL);
const [filterText, setFilterText] = useState(''); const [filterText, setFilterText] = useState('');
@ -51,13 +52,13 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }:
}, [filterText, setFiltered, filterSource, activeExpression, schema?.items, schema, filterMatch, activeID]); }, [filterText, setFiltered, filterSource, activeExpression, schema?.items, schema, filterMatch, activeID]);
const selectGraph = useMemo( const selectGraph = useMemo(
() => <SelectGraphFilter value={filterSource} onChange={newValue => setFilterSource(newValue)} />, () => <SelectGraphFilter value={filterSource} onChange={newValue => setFilterSource(newValue)} dense={dense} />,
[filterSource, setFilterSource] [filterSource, setFilterSource, dense]
); );
const selectMatchMode = useMemo( const selectMatchMode = useMemo(
() => <SelectMatchMode value={filterMatch} onChange={newValue => setFilterMatch(newValue)} />, () => <SelectMatchMode value={filterMatch} onChange={newValue => setFilterMatch(newValue)} dense={dense} />,
[filterMatch, setFilterMatch] [filterMatch, setFilterMatch, dense]
); );
return ( return (

View File

@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useConceptOptions } from '@/context/OptionsContext'; import { useConceptOptions } from '@/context/OptionsContext';
import useWindowSize from '@/hooks/useWindowSize';
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform'; import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
import { animateSideView } from '@/styling/animations'; import { animateSideView } from '@/styling/animations';
@ -14,6 +15,9 @@ import ConstituentsTable from './ConstituentsTable';
// Window width cutoff for expression show // Window width cutoff for expression show
const COLUMN_EXPRESSION_HIDE_THRESHOLD = 1500; const COLUMN_EXPRESSION_HIDE_THRESHOLD = 1500;
// Window width cutoff for dense search bar
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
interface ViewConstituentsProps { interface ViewConstituentsProps {
expression: string; expression: string;
isBottom?: boolean; isBottom?: boolean;
@ -24,13 +28,14 @@ interface ViewConstituentsProps {
function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit }: ViewConstituentsProps) { function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit }: ViewConstituentsProps) {
const { calculateHeight } = useConceptOptions(); const { calculateHeight } = useConceptOptions();
const windowSize = useWindowSize();
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []); const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
const table = useMemo( const table = useMemo(
() => ( () => (
<ConstituentsTable <ConstituentsTable
maxHeight={isBottom ? calculateHeight('42rem') : calculateHeight('8.2rem')} maxHeight={isBottom ? calculateHeight('42rem', '10rem') : calculateHeight('8.2rem')}
items={filteredData} items={filteredData}
activeCst={activeCst} activeCst={activeCst}
onOpenEdit={onOpenEdit} onOpenEdit={onOpenEdit}
@ -54,6 +59,7 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit
exit={{ ...animateSideView.exit }} exit={{ ...animateSideView.exit }}
> >
<ConstituentsSearch <ConstituentsSearch
dense={windowSize.width && windowSize.width < COLUMN_DENSE_SEARCH_THRESHOLD ? true : undefined}
schema={schema} schema={schema}
activeID={activeCst?.id} activeID={activeCst?.id}
activeExpression={expression} activeExpression={expression}