mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Fix layout for Ipad
This commit is contained in:
parent
2ead8e3a4a
commit
10d1da917d
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user