mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
197 lines
4.6 KiB
TypeScript
197 lines
4.6 KiB
TypeScript
import {transition} from 'app/client/ui/transitions';
|
|
import {toggle} from 'app/client/ui2018/checkbox';
|
|
import {mediaSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
|
import {icon} from 'app/client/ui2018/icons';
|
|
import {dom, DomContents, IDisposableOwner, Observable, styled} from 'grainjs';
|
|
|
|
export function HidableToggle(owner: IDisposableOwner, value: Observable<boolean|null>) {
|
|
return toggle(value, dom.hide((use) => use(value) === null));
|
|
}
|
|
|
|
export function AdminSection(owner: IDisposableOwner, title: DomContents, items: DomContents[]) {
|
|
return cssSection(
|
|
cssSectionTitle(title),
|
|
...items,
|
|
);
|
|
}
|
|
|
|
export function AdminSectionItem(owner: IDisposableOwner, options: {
|
|
id: string,
|
|
name?: DomContents,
|
|
description?: DomContents,
|
|
value?: DomContents,
|
|
expandedContent?: DomContents,
|
|
}) {
|
|
const itemContent = (...prefix: DomContents[]) => [
|
|
cssItemName(
|
|
...prefix,
|
|
options.name,
|
|
testId(`admin-panel-item-name-${options.id}`),
|
|
prefix.length ? cssItemName.cls('-prefixed') : null,
|
|
),
|
|
cssItemDescription(options.description),
|
|
cssItemValue(options.value,
|
|
testId(`admin-panel-item-value-${options.id}`),
|
|
dom.on('click', ev => ev.stopPropagation())),
|
|
];
|
|
if (options.expandedContent) {
|
|
const isCollapsed = Observable.create(owner, true);
|
|
return cssItem(
|
|
cssItemShort(
|
|
itemContent(dom.domComputed(isCollapsed, (c) => cssCollapseIcon(c ? 'Expand' : 'Collapse'))),
|
|
cssItemShort.cls('-expandable'),
|
|
dom.on('click', () => isCollapsed.set(!isCollapsed.get())),
|
|
),
|
|
cssExpandedContentWrap(
|
|
transition(isCollapsed, {
|
|
prepare(elem, close) { elem.style.maxHeight = close ? elem.scrollHeight + 'px' : '0'; },
|
|
run(elem, close) { elem.style.maxHeight = close ? '0' : elem.scrollHeight + 'px'; },
|
|
finish(elem, close) { elem.style.maxHeight = close ? '0' : 'unset'; },
|
|
}),
|
|
cssExpandedContent(
|
|
options.expandedContent,
|
|
),
|
|
),
|
|
testId(`admin-panel-item-${options.id}`),
|
|
);
|
|
} else {
|
|
return cssItem(
|
|
cssItemShort(itemContent()),
|
|
testId(`admin-panel-item-${options.id}`),
|
|
);
|
|
}
|
|
}
|
|
|
|
const cssSection = styled('div', `
|
|
padding: 24px;
|
|
max-width: 600px;
|
|
width: 100%;
|
|
margin: 16px auto;
|
|
border: 1px solid ${theme.widgetBorder};
|
|
border-radius: 4px;
|
|
& > div + div {
|
|
margin-top: 8px;
|
|
}
|
|
|
|
@media ${mediaSmall} {
|
|
& {
|
|
width: auto;
|
|
padding: 12px;
|
|
margin: 8px;
|
|
}
|
|
}
|
|
`);
|
|
|
|
const cssSectionTitle = styled('div', `
|
|
height: 32px;
|
|
line-height: 32px;
|
|
margin-bottom: 8px;
|
|
font-size: ${vars.headerControlFontSize};
|
|
font-weight: ${vars.headerControlTextWeight};
|
|
`);
|
|
|
|
const cssItem = styled('div', `
|
|
margin-top: 8px;
|
|
container-type: inline-size;
|
|
container-name: line;
|
|
`);
|
|
|
|
const cssItemShort = styled('div', `
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
padding: 8px;
|
|
margin: 0 -8px;
|
|
border-radius: 4px;
|
|
&-expandable {
|
|
cursor: pointer;
|
|
}
|
|
&-expandable:hover {
|
|
background-color: ${theme.lightHover};
|
|
}
|
|
|
|
@container line (max-width: 500px) {
|
|
& {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 8px;
|
|
}
|
|
}
|
|
`);
|
|
|
|
const cssItemName = styled('div', `
|
|
width: 150px;
|
|
font-weight: bold;
|
|
display: flex;
|
|
align-items: center;
|
|
margin-right: 14px;
|
|
font-size: ${vars.largeFontSize};
|
|
padding-left: 24px;
|
|
&-prefixed {
|
|
padding-left: 0;
|
|
}
|
|
|
|
@container line (max-width: 500px) {
|
|
& {
|
|
padding-left: 0;
|
|
}
|
|
}
|
|
@media ${mediaSmall} {
|
|
& {
|
|
width: calc(100% - 28px);
|
|
padding-left: 0;
|
|
}
|
|
&:first-child {
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
`);
|
|
|
|
const cssItemDescription = styled('div', `
|
|
margin-right: auto;
|
|
margin-bottom: -1px; /* aligns with the value */
|
|
`);
|
|
|
|
const cssItemValue = styled('div', `
|
|
flex: none;
|
|
margin: -16px;
|
|
padding: 16px;
|
|
cursor: auto;
|
|
`);
|
|
|
|
const cssCollapseIcon = styled(icon, `
|
|
width: 24px;
|
|
height: 24px;
|
|
margin-right: 4px;
|
|
margin-left: -4px;
|
|
--icon-color: ${theme.lightText};
|
|
`);
|
|
|
|
const cssExpandedContentWrap = styled('div', `
|
|
transition: max-height 0.3s ease-in-out;
|
|
overflow: hidden;
|
|
max-height: 0;
|
|
`);
|
|
|
|
const cssExpandedContent = styled('div', `
|
|
margin-left: 24px;
|
|
padding: 18px 0;
|
|
border-bottom: 1px solid ${theme.widgetBorder};
|
|
.${cssItem.className}:last-child & {
|
|
padding-bottom: 0;
|
|
border-bottom: none;
|
|
}
|
|
@container line (max-width: 500px) {
|
|
& {
|
|
margin-left: 0px;
|
|
}
|
|
}
|
|
`);
|
|
|
|
export const cssValueLabel = styled('div', `
|
|
padding: 4px 8px;
|
|
color: ${theme.text};
|
|
border: 1px solid ${theme.inputBorder};
|
|
border-radius: ${vars.controlBorderRadius};
|
|
`);
|