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

View File

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

View File

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

View File

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

View File

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

View File

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