mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-10 08:39:34 +00:00
refactor: param sections are collapsible
This commit is contained in:
committed by
Carlos Valente
parent
b4caec0644
commit
4503d1e411
@@ -25,39 +25,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.sectionList {
|
||||||
font-size: $inner-section-text-size;
|
|
||||||
color: $label-gray;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.25rem;
|
min-height: 100%;
|
||||||
}
|
gap: 2rem;
|
||||||
|
overflow-y: scroll;
|
||||||
.section {
|
padding-right: 0.5rem;
|
||||||
color: $ui-white;
|
|
||||||
font-size: 1rem;
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fieldSet {
|
|
||||||
display: flex;
|
|
||||||
padding: $section-spacing 0;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $element-spacing;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: $inner-section-text-size;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
font-size: $inner-section-text-size;
|
|
||||||
display: block;
|
|
||||||
color: $modal-note-color;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import { IoAlertCircle } from '@react-icons/all-files/io5/IoAlertCircle';
|
|||||||
|
|
||||||
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
||||||
|
|
||||||
import ParamInput from './ParamInput';
|
import { ViewOption } from './types';
|
||||||
import { isSection, ViewOption } from './types';
|
import ViewParamsSection from './ViewParamsSection';
|
||||||
|
|
||||||
import style from './ViewParamsEditor.module.scss';
|
import style from './ViewParamsEditor.module.scss';
|
||||||
|
|
||||||
@@ -40,15 +40,15 @@ const getURLSearchParamsFromObj = (paramsObj: ViewParamsObj, paramFields: ViewOp
|
|||||||
|
|
||||||
// Convert paramFields to an object that contains default values
|
// Convert paramFields to an object that contains default values
|
||||||
const defaultValues: Record<string, string> = {};
|
const defaultValues: Record<string, string> = {};
|
||||||
paramFields.forEach((option) => {
|
paramFields.forEach((section) => {
|
||||||
if (!isSection(option)) {
|
section.options.forEach((option) => {
|
||||||
defaultValues[option.id] = String(option.defaultValue);
|
defaultValues[option.id] = String(option.defaultValue);
|
||||||
}
|
|
||||||
|
|
||||||
// extract persisted values
|
// extract persisted values
|
||||||
if ('type' in option && option.type === 'persist') {
|
if ('type' in option && option.type === 'persist') {
|
||||||
newSearchParams.set(option.id, option.value);
|
newSearchParams.set(option.id, option.value);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// compare which values are different from the default values
|
// compare which values are different from the default values
|
||||||
@@ -138,30 +138,15 @@ export default function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) {
|
|||||||
This view style is being modified by a custom CSS file. <br />
|
This view style is being modified by a custom CSS file. <br />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<form id='edit-params-form' onSubmit={onParamsFormSubmit}>
|
<form id='edit-params-form' onSubmit={onParamsFormSubmit} className={style.sectionList}>
|
||||||
{viewOptions.map((option) => {
|
{viewOptions.map((section) => (
|
||||||
if (isSection(option)) {
|
<ViewParamsSection
|
||||||
return (
|
key={section.title}
|
||||||
<div key={option.section} className={style.section}>
|
title={section.title}
|
||||||
{option.section}
|
collapsible={section.collapsible}
|
||||||
</div>
|
options={section.options}
|
||||||
);
|
/>
|
||||||
}
|
))}
|
||||||
|
|
||||||
if (option.type === 'persist') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={option.title} className={style.fieldSet}>
|
|
||||||
<label className={style.label}>
|
|
||||||
<span className={style.title}>{option.title}</span>
|
|
||||||
<span className={style.description}>{option.description}</span>
|
|
||||||
<ParamInput key={option.title} paramField={option} />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</form>
|
</form>
|
||||||
</DrawerBody>
|
</DrawerBody>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
.section {
|
||||||
|
color: $ui-white;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionHeader {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 2rem;
|
||||||
|
|
||||||
|
&.collapsible {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom: 1px solid $white-10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-top: $section-spacing;
|
||||||
|
font-size: $inner-section-text-size;
|
||||||
|
color: $label-gray;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: $inner-section-text-size;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-size: $inner-section-text-size;
|
||||||
|
display: block;
|
||||||
|
color: $modal-note-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closed {
|
||||||
|
transition: rotate $transition-time-feedback;
|
||||||
|
rotate: 0deg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.open {
|
||||||
|
transition: rotate $transition-time-feedback;
|
||||||
|
rotate: 180deg;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { useLocalStorage } from '@mantine/hooks';
|
||||||
|
import { IoChevronDown } from '@react-icons/all-files/io5/IoChevronDown';
|
||||||
|
|
||||||
|
import { cx } from '../../utils/styleUtils';
|
||||||
|
|
||||||
|
import ParamInput from './ParamInput';
|
||||||
|
import { type ParamField } from './types';
|
||||||
|
|
||||||
|
import style from './ViewParamsSection.module.scss';
|
||||||
|
|
||||||
|
interface ViewParamsSectionProps {
|
||||||
|
title: string;
|
||||||
|
collapsible?: boolean;
|
||||||
|
options: ParamField[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ViewParamsSection(props: ViewParamsSectionProps) {
|
||||||
|
const { title, collapsible, options } = props;
|
||||||
|
|
||||||
|
const [collapsed, setCollapsed] = useLocalStorage({ key: `params-${title}`, defaultValue: false });
|
||||||
|
|
||||||
|
const handleCollapse = () => {
|
||||||
|
if (collapsible) {
|
||||||
|
setCollapsed((prev) => !prev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={style.section}>
|
||||||
|
<div className={cx([style.sectionHeader, collapsible && style.collapsible])} onClick={handleCollapse}>
|
||||||
|
{title}
|
||||||
|
{collapsible && <IoChevronDown className={cx([collapsed ? style.closed : style.open])} />}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!collapsed && (
|
||||||
|
<>
|
||||||
|
{options.map((option) => {
|
||||||
|
if (option.type === 'persist') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label key={option.title} className={style.label}>
|
||||||
|
<span className={style.title}>{option.title}</span>
|
||||||
|
<span className={style.description}>{option.description}</span>
|
||||||
|
<ParamInput paramField={option} />
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
type ParamSection = {
|
|
||||||
section: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type BaseField = {
|
type BaseField = {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
@@ -28,11 +24,9 @@ type PersistedField = { type: 'persist'; defaultValue?: string; value: string };
|
|||||||
|
|
||||||
export type ParamField = BaseField &
|
export type ParamField = BaseField &
|
||||||
(OptionsField | MultiOptionsField | StringField | NumberField | BooleanField | ColourField | PersistedField);
|
(OptionsField | MultiOptionsField | StringField | NumberField | BooleanField | ColourField | PersistedField);
|
||||||
export type ViewOption = ParamSection | ParamField;
|
|
||||||
|
|
||||||
/**
|
export type ViewOption = {
|
||||||
* Type assertion utility checks whether an entry is a section separator
|
title: string;
|
||||||
*/
|
options: ParamField[];
|
||||||
export function isSection(entry: ViewOption): entry is ParamSection {
|
collapsible?: boolean;
|
||||||
return 'section' in entry;
|
};
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user