mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactor Checkbox and add Tristate
This commit is contained in:
parent
c58743bdb0
commit
75fd9a855c
|
@ -1,5 +1,6 @@
|
|||
import { useRef } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { CheckboxChecked } from '../Icons';
|
||||
import Label from './Label';
|
||||
|
||||
export interface CheckboxProps {
|
||||
|
@ -9,51 +10,52 @@ export interface CheckboxProps {
|
|||
disabled?: boolean
|
||||
widthClass?: string
|
||||
tooltip?: string
|
||||
value?: boolean
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
|
||||
value: boolean
|
||||
setValue?: (newValue: boolean) => void
|
||||
}
|
||||
|
||||
function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-fit', value, onChange }: CheckboxProps) {
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const cursor = disabled ? 'cursor-not-allowed' : 'cursor-pointer';
|
||||
function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-fit', value, setValue }: CheckboxProps) {
|
||||
const cursor = useMemo(
|
||||
() => {
|
||||
if (disabled) {
|
||||
return 'cursor-not-allowed';
|
||||
} else if (setValue) {
|
||||
return 'cursor-pointer';
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}, [disabled, setValue]);
|
||||
const bgColor = useMemo(
|
||||
() => {
|
||||
return value !== false ? 'clr-primary' : 'clr-app'
|
||||
}, [value]);
|
||||
|
||||
function handleClick(event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void {
|
||||
event.preventDefault();
|
||||
if (!disabled) {
|
||||
inputRef.current?.click();
|
||||
if (disabled || !setValue) {
|
||||
return;
|
||||
}
|
||||
setValue(!value);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className={'flex [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ' + widthClass}
|
||||
id={id}
|
||||
className={`flex items-center [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ${widthClass}`}
|
||||
title={tooltip}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<input id={id} type='checkbox' ref={inputRef}
|
||||
className={`relative peer w-4 h-4 shrink-0 mt-0.5 border rounded-sm appearance-none clr-checkbox ${cursor}`}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
checked={value}
|
||||
onChange={onChange}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<div className={`relative peer w-4 h-4 shrink-0 mt-0.5 border rounded-sm appearance-none ${bgColor} ${cursor}`} />
|
||||
{ label &&
|
||||
<Label
|
||||
className={`${cursor} px-2`}
|
||||
className={`${cursor} px-2 text-start`}
|
||||
text={label}
|
||||
required={required}
|
||||
htmlFor={id}
|
||||
/>}
|
||||
<svg
|
||||
className='absolute hidden w-3 h-3 mt-1 ml-0.5 text-white pointer-events-none peer-checked:block'
|
||||
viewBox='0 0 512 512'
|
||||
fill='currentColor'
|
||||
>
|
||||
<path d='M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7l233.4-233.3c12.5-12.5 32.8-12.5 45.3 0z' />
|
||||
</svg>
|
||||
{value && <CheckboxChecked />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import Checkbox from './Checkbox';
|
||||
|
||||
interface DropdownCheckboxProps {
|
||||
value: boolean
|
||||
label?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
value?: boolean
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
setValue?: (newValue: boolean) => void
|
||||
}
|
||||
|
||||
function DropdownCheckbox({ tooltip, onChange, disabled, ...props }: DropdownCheckboxProps) {
|
||||
const behavior = (onChange && !disabled ? 'clr-hover' : '');
|
||||
function DropdownCheckbox({ tooltip, setValue, disabled, ...props }: DropdownCheckboxProps) {
|
||||
const behavior = (setValue && !disabled ? 'clr-hover' : '');
|
||||
return (
|
||||
<div
|
||||
title={tooltip}
|
||||
|
@ -18,7 +18,7 @@ function DropdownCheckbox({ tooltip, onChange, disabled, ...props }: DropdownChe
|
|||
<Checkbox
|
||||
widthClass='w-full'
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
setValue={setValue}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -4,18 +4,22 @@ import { UploadIcon } from '../Icons';
|
|||
import Button from './Button';
|
||||
import Label from './Label';
|
||||
|
||||
interface FileInputProps {
|
||||
id?: string
|
||||
required?: boolean
|
||||
interface FileInputProps
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title' | 'style' | 'accept' | 'type'> {
|
||||
label: string
|
||||
tooltip?: string
|
||||
acceptType?: string
|
||||
widthClass?: string
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
||||
function FileInput({ id, required, label, acceptType, widthClass = 'w-full', onChange }: FileInputProps) {
|
||||
function FileInput({
|
||||
label, acceptType, tooltip,
|
||||
widthClass = 'w-fit', onChange,
|
||||
...props
|
||||
}: FileInputProps) {
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [labelText, setLabelText] = useState('');
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
const handleUploadClick = () => {
|
||||
inputRef.current?.click();
|
||||
|
@ -23,9 +27,9 @@ function FileInput({ id, required, label, acceptType, widthClass = 'w-full', onC
|
|||
|
||||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
setLabelText(event.target.files[0].name)
|
||||
setFileName(event.target.files[0].name)
|
||||
} else {
|
||||
setLabelText('')
|
||||
setFileName('')
|
||||
}
|
||||
if (onChange) {
|
||||
onChange(event);
|
||||
|
@ -33,21 +37,22 @@ function FileInput({ id, required, label, acceptType, widthClass = 'w-full', onC
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col gap-2 py-2 [&:not(:first-child)]:mt-3 items-start ' + widthClass}>
|
||||
<input id={id} type='file'
|
||||
<div className={`flex flex-col gap-2 py-2 mt-3 items-start ${widthClass}`}>
|
||||
<input type='file'
|
||||
ref={inputRef}
|
||||
required={required}
|
||||
style={{ display: 'none' }}
|
||||
accept={acceptType}
|
||||
onChange={handleFileChange}
|
||||
{...props}
|
||||
/>
|
||||
<Button
|
||||
text={label}
|
||||
icon={<UploadIcon/>}
|
||||
onClick={handleUploadClick}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<Label
|
||||
text={labelText}
|
||||
text={fileName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ function SubmitButton({
|
|||
return (
|
||||
<button type='submit'
|
||||
title={tooltip}
|
||||
className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-bold select-none disabled:cursor-not-allowed border rounded clr-btn-primary ${widthClass} ${loading ? ' cursor-progress' : ''}`}
|
||||
className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-semibold select-none disabled:cursor-not-allowed border rounded clr-btn-primary ${widthClass} ${loading ? ' cursor-progress' : ''}`}
|
||||
disabled={disabled ?? loading}
|
||||
>
|
||||
{icon && <span>{icon}</span>}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { type InputHTMLAttributes } from 'react';
|
||||
|
||||
import Label from './Label';
|
||||
|
||||
interface TextInputProps
|
||||
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'> {
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'> {
|
||||
id: string
|
||||
label: string
|
||||
tooltip?: string
|
||||
|
|
64
rsconcept/frontend/src/components/Common/Tristate.tsx
Normal file
64
rsconcept/frontend/src/components/Common/Tristate.tsx
Normal file
|
@ -0,0 +1,64 @@
|
|||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { CheckboxChecked, CheckboxNull } from '../Icons';
|
||||
import { CheckboxProps } from './Checkbox';
|
||||
import Label from './Label';
|
||||
|
||||
export interface TristateProps
|
||||
extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
||||
value: boolean | null
|
||||
setValue?: (newValue: boolean | null) => void
|
||||
}
|
||||
|
||||
function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-fit', value, setValue }: TristateProps) {
|
||||
const cursor = useMemo(
|
||||
() => {
|
||||
if (disabled) {
|
||||
return 'cursor-not-allowed';
|
||||
} else if (setValue) {
|
||||
return 'cursor-pointer';
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}, [disabled, setValue]);
|
||||
const bgColor = useMemo(
|
||||
() => {
|
||||
return value !== false ? 'clr-primary' : 'clr-app'
|
||||
}, [value]);
|
||||
|
||||
function handleClick(event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void {
|
||||
event.preventDefault();
|
||||
if (disabled || !setValue) {
|
||||
return;
|
||||
}
|
||||
if (value === false) {
|
||||
setValue(null);
|
||||
} else {
|
||||
setValue(!value);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
id={id}
|
||||
className={`flex items-center [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ${widthClass}`}
|
||||
title={tooltip}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className={`relative peer w-4 h-4 shrink-0 mt-0.5 border rounded-sm appearance-none ${bgColor} ${cursor}`} />
|
||||
{ label &&
|
||||
<Label
|
||||
className={`${cursor} px-2 text-start`}
|
||||
text={label}
|
||||
required={required}
|
||||
htmlFor={id}
|
||||
/>}
|
||||
{value && <CheckboxChecked />}
|
||||
{value === null && <CheckboxNull />}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Checkbox;
|
|
@ -317,3 +317,27 @@ export function InDoor(props: IconProps) {
|
|||
</IconSVG>
|
||||
);
|
||||
}
|
||||
|
||||
export function CheckboxChecked() {
|
||||
return (
|
||||
<svg
|
||||
className='absolute w-3 h-3 mt-1 ml-0.5'
|
||||
viewBox='0 0 512 512'
|
||||
fill='#ffffff'
|
||||
>
|
||||
<path d='M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7l233.4-233.3c12.5-12.5 32.8-12.5 45.3 0z' />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function CheckboxNull() {
|
||||
return (
|
||||
<svg
|
||||
className='absolute w-3 h-3 mt-1 ml-0.5'
|
||||
viewBox='0 0 512 512'
|
||||
fill='#ffffff'
|
||||
>
|
||||
<path d='M2 7.75A.75.75 0 012.75 7h10a.75.75 0 010 1.5h-10A.75.75 0 012 7.75z' />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
.clr-footer,
|
||||
.clr-modal-backdrop,
|
||||
.clr-btn-nav,
|
||||
.clr-checkbox,
|
||||
.clr-input:disabled
|
||||
) {
|
||||
background-color: var(--cl-bg-100);
|
||||
|
@ -168,8 +167,7 @@
|
|||
|
||||
:is(.clr-primary,
|
||||
.clr-btn-primary:hover,
|
||||
.clr-btn-primary:focus,
|
||||
.clr-checkbox:checked
|
||||
.clr-btn-primary:focus
|
||||
) {
|
||||
color: var(--cl-prim-fg-100);
|
||||
background-color: var(--cl-prim-bg-100);
|
||||
|
|
|
@ -93,7 +93,7 @@ function CreateRSFormPage() {
|
|||
/>
|
||||
<Checkbox id='common' label='Общедоступная схема'
|
||||
value={common}
|
||||
onChange={event => setCommon(event.target.checked)}
|
||||
setValue={value => setCommon(value ?? false)}
|
||||
/>
|
||||
<FileInput id='trs' label='Загрузить из Экстеор'
|
||||
acceptType='.trs'
|
||||
|
|
|
@ -36,38 +36,38 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) {
|
|||
{ pickerMenu.isActive &&
|
||||
<Dropdown>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.MANUAL)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.MANUAL)}
|
||||
value={value === LibraryFilterStrategy.MANUAL}
|
||||
label='Отображать все'
|
||||
/>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.COMMON)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.COMMON)}
|
||||
value={value === LibraryFilterStrategy.COMMON}
|
||||
label='Общедоступные'
|
||||
tooltip='Отображать только общедоступные схемы'
|
||||
/>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.CANONICAL)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.CANONICAL)}
|
||||
value={value === LibraryFilterStrategy.CANONICAL}
|
||||
label='Неизменные'
|
||||
tooltip='Отображать только стандартные схемы'
|
||||
/>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.PERSONAL)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.PERSONAL)}
|
||||
value={value === LibraryFilterStrategy.PERSONAL}
|
||||
label='Личные'
|
||||
disabled={!user}
|
||||
tooltip='Отображать только подписки и владеемые схемы'
|
||||
/>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.SUBSCRIBE)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.SUBSCRIBE)}
|
||||
value={value === LibraryFilterStrategy.SUBSCRIBE}
|
||||
label='Подписки'
|
||||
disabled={!user}
|
||||
tooltip='Отображать только подписки'
|
||||
/>
|
||||
<DropdownCheckbox
|
||||
onChange={() => handleChange(LibraryFilterStrategy.OWNED)}
|
||||
setValue={() => handleChange(LibraryFilterStrategy.OWNED)}
|
||||
value={value === LibraryFilterStrategy.OWNED}
|
||||
disabled={!user}
|
||||
label='Я - Владелец!'
|
||||
|
|
|
@ -79,7 +79,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
|
|||
/>
|
||||
<Checkbox id='common' label='Общедоступная схема'
|
||||
value={common}
|
||||
onChange={event => setCommon(event.target.checked)}
|
||||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
@ -52,7 +52,7 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
|
|||
<Checkbox
|
||||
label='Удалить зависимые конституенты'
|
||||
value={expandOut}
|
||||
onChange={data => setExpandOut(data.target.checked)}
|
||||
setValue={value => setExpandOut(value)}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
@ -81,25 +81,25 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
|
|||
label='Скрыть текст'
|
||||
tooltip='Не отображать термины'
|
||||
value={noTerms}
|
||||
onChange={ event => setNoTerms(event.target.checked) }
|
||||
setValue={ value => setNoTerms(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label='Скрыть несвязанные'
|
||||
tooltip='Неиспользуемые конституенты'
|
||||
value={noHermits}
|
||||
onChange={ event => setNoHermits(event.target.checked) }
|
||||
setValue={ value => setNoHermits(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label='Скрыть шаблоны'
|
||||
tooltip='Терм-функции и предикат-функции с параметризованными аргументами'
|
||||
value={noTemplates}
|
||||
onChange={ event => setNoTemplates(event.target.checked) }
|
||||
setValue={ value => setNoTemplates(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label='Транзитивная редукция'
|
||||
tooltip='Удалить связи, образующие транзитивные пути в графе'
|
||||
value={noTransitive}
|
||||
onChange={ event => setNoTransitive(event.target.checked) }
|
||||
setValue={ value => setNoTransitive(value) }
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
|
@ -107,42 +107,42 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
|
|||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.BASE)}
|
||||
value={allowBase}
|
||||
onChange={ event => setAllowBase(event.target.checked) }
|
||||
setValue={ value => setAllowBase(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.STRUCTURED)}
|
||||
value={allowStruct}
|
||||
onChange={ event => setAllowStruct(event.target.checked) }
|
||||
setValue={ value => setAllowStruct(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.TERM)}
|
||||
value={allowTerm}
|
||||
onChange={ event => setAllowTerm(event.target.checked) }
|
||||
setValue={ value => setAllowTerm(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.AXIOM)}
|
||||
value={allowAxiom}
|
||||
onChange={ event => setAllowAxiom(event.target.checked) }
|
||||
setValue={ value => setAllowAxiom(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.FUNCTION)}
|
||||
value={allowFunction}
|
||||
onChange={ event => setAllowFunction(event.target.checked) }
|
||||
setValue={ value => setAllowFunction(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.PREDICATE)}
|
||||
value={allowPredicate}
|
||||
onChange={ event => setAllowPredicate(event.target.checked) }
|
||||
setValue={ value => setAllowPredicate(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.CONSTANT)}
|
||||
value={allowConstant}
|
||||
onChange={ event => setAllowConstant(event.target.checked) }
|
||||
setValue={ value => setAllowConstant(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label={getCstTypeLabel(CstType.THEOREM)}
|
||||
value={allowTheorem}
|
||||
onChange={ event => setAllowTheorem(event.target.checked) }
|
||||
setValue ={ value => setAllowTheorem(value) }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -44,7 +44,7 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
|
|||
onSubmit={handleSubmit}
|
||||
submitText='Загрузить'
|
||||
>
|
||||
<div className='max-w-[20rem]'>
|
||||
<div className='flex flex-col items-center'>
|
||||
<FileInput
|
||||
label='Выбрать файл'
|
||||
acceptType='.trs'
|
||||
|
@ -53,7 +53,8 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
|
|||
<Checkbox
|
||||
label='Загружать название и комментарий'
|
||||
value={loadMetadata}
|
||||
onChange={event => setLoadMetadata(event.target.checked)}
|
||||
setValue={value => setLoadMetadata(value)}
|
||||
widthClass='w-fit pb-2'
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
@ -136,14 +136,14 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
|
|||
value={common}
|
||||
widthClass='w-fit mt-3'
|
||||
disabled={!isEditable}
|
||||
onChange={event => setCommon(event.target.checked)}
|
||||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
<Checkbox id='canonical' label='Неизменная схема'
|
||||
widthClass='w-fit'
|
||||
value={canonical}
|
||||
tooltip='Только администраторы могут присваивать схемам неизменный статус'
|
||||
disabled={!isEditable || !isForceAdmin}
|
||||
onChange={event => setCanonical(event.target.checked)}
|
||||
setValue={value => setCanonical(value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -415,18 +415,18 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
|||
<Checkbox
|
||||
label='Скрыть текст'
|
||||
value={noTerms}
|
||||
onChange={ event => setNoTerms(event.target.checked) }
|
||||
setValue={ value => setNoTerms(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
label='Транзитивная редукция'
|
||||
value={noTransitive}
|
||||
onChange={ event => setNoTransitive(event.target.checked) }
|
||||
setValue={ value => setNoTransitive(value) }
|
||||
/>
|
||||
<Checkbox
|
||||
disabled={!is3D}
|
||||
label='Анимация вращения'
|
||||
value={orbit}
|
||||
onChange={ event => setOrbit(event.target.checked) }
|
||||
setValue={ value => setOrbit(value) }
|
||||
/>
|
||||
|
||||
<Divider margins='mt-3 mb-2' />
|
||||
|
|
|
@ -146,14 +146,14 @@ function RSTabsMenu({
|
|||
{(isOwned || user?.is_staff) &&
|
||||
<DropdownCheckbox
|
||||
value={isReadonly}
|
||||
onChange={toggleReadonly}
|
||||
setValue={toggleReadonly}
|
||||
label='Я — читатель!'
|
||||
tooltip='Режим чтения'
|
||||
/>}
|
||||
{user?.is_staff &&
|
||||
<DropdownCheckbox
|
||||
value={isForceAdmin}
|
||||
onChange={toggleForceAdmin}
|
||||
setValue={toggleForceAdmin}
|
||||
label='Я — администратор!'
|
||||
tooltip='Режим редактирования для администраторов'
|
||||
/>}
|
||||
|
|
Loading…
Reference in New Issue
Block a user