mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Merge with shadcn styling
Revert "F: Merge with shadcn styling" This reverts commit b9f8143b3e0a7f4726ab7751757b31532b0834f9. F: Merge with shadcn styling
This commit is contained in:
parent
3a54bf7108
commit
c5e41acc31
|
@ -10,7 +10,7 @@ export function Footer() {
|
||||||
'z-navigation',
|
'z-navigation',
|
||||||
'mx-auto',
|
'mx-auto',
|
||||||
'px-3 py-2 flex flex-col items-center gap-1',
|
'px-3 py-2 flex flex-col items-center gap-1',
|
||||||
'text-xs sm:text-sm select-none whitespace-nowrap text-prim-600 bg-prim-100'
|
'text-xs sm:text-sm select-none whitespace-nowrap text-inert-foreground bg-background'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<nav className='flex gap-3' aria-label='Вторичная навигация'>
|
<nav className='flex gap-3' aria-label='Вторичная навигация'>
|
||||||
|
|
|
@ -18,7 +18,7 @@ export function GlobalLoader() {
|
||||||
return (
|
return (
|
||||||
<div className='cc-modal-wrapper'>
|
<div className='cc-modal-wrapper'>
|
||||||
<ModalBackdrop />
|
<ModalBackdrop />
|
||||||
<div className='z-pop cc-fade-in px-10 border rounded-xl bg-prim-100'>
|
<div className='z-pop cc-fade-in px-10 border rounded-xl bg-background'>
|
||||||
<Loader scale={6} />
|
<Loader scale={6} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,9 +20,9 @@ export function MutationErrors() {
|
||||||
return (
|
return (
|
||||||
<div className='cc-modal-wrapper'>
|
<div className='cc-modal-wrapper'>
|
||||||
<ModalBackdrop onHide={resetErrors} />
|
<ModalBackdrop onHide={resetErrors} />
|
||||||
<div className='z-pop px-10 py-3 flex flex-col items-center border rounded-xl bg-prim-100' role='alertdialog'>
|
<div className='z-pop px-10 py-3 flex flex-col items-center border rounded-xl bg-background' role='alertdialog'>
|
||||||
<h1 className='py-2 select-none'>Ошибка при обработке</h1>
|
<h1 className='py-2 select-none'>Ошибка при обработке</h1>
|
||||||
<div className='px-3 flex flex-col text-warn-600 text-sm font-semibold select-text'>
|
<div className='px-3 flex flex-col text-destructive text-sm font-semibold select-text'>
|
||||||
<DescribeError error={mutationErrors[0]} />
|
<DescribeError error={mutationErrors[0]} />
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={resetErrors} className='w-fit' text='Закрыть' />
|
<Button onClick={resetErrors} className='w-fit' text='Закрыть' />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
interface NavigationButtonProps extends Styling {
|
interface NavigationButtonProps extends Styling {
|
||||||
|
@ -21,7 +20,7 @@ export function NavigationButton({ icon, title, hideTitle, className, style, onC
|
||||||
data-tooltip-hidden={hideTitle}
|
data-tooltip-hidden={hideTitle}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={clsx('p-2 flex items-center gap-1', 'cc-btn-nav', 'font-controls focus-outline', className)}
|
className={cn('p-2 flex items-center gap-1', 'cc-btn-nav', 'font-controls focus-outline', className)}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
{icon ? icon : null}
|
{icon ? icon : null}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function Navigation() {
|
||||||
push({ path: urls.create_schema, newTab: event.ctrlKey || event.metaKey });
|
push({ path: urls.create_schema, newTab: event.ctrlKey || event.metaKey });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className='z-navigation sticky top-0 left-0 right-0 select-none bg-prim-100' inert={activeDialog !== null}>
|
<nav className='z-navigation sticky top-0 left-0 right-0 select-none bg-background' inert={activeDialog !== null}>
|
||||||
<ToggleNavigation />
|
<ToggleNavigation />
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Styling } from '../props';
|
import { type Styling } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface DividerProps extends Styling {
|
interface DividerProps extends Styling {
|
||||||
/** Indicates whether the divider is vertical. */
|
/** Indicates whether the divider is vertical. */
|
||||||
|
@ -16,7 +15,7 @@ interface DividerProps extends Styling {
|
||||||
export function Divider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
|
export function Divider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
vertical ? 'border-x' : 'border-y', //
|
vertical ? 'border-x' : 'border-y', //
|
||||||
margins,
|
margins,
|
||||||
className
|
className
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
import { type ReactNode } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { type ITooltip, Tooltip as TooltipImpl } from 'react-tooltip';
|
import { type ITooltip, Tooltip as TooltipImpl } from 'react-tooltip';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
export type { PlacesType } from 'react-tooltip';
|
export type { PlacesType } from 'react-tooltip';
|
||||||
|
|
||||||
interface TooltipProps extends Omit<ITooltip, 'variant'> {
|
interface TooltipProps extends Omit<ITooltip, 'variant'> {
|
||||||
|
@ -37,7 +38,7 @@ export function Tooltip({
|
||||||
delayShow={750}
|
delayShow={750}
|
||||||
delayHide={100}
|
delayHide={100}
|
||||||
opacity={1}
|
opacity={1}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'relative',
|
'relative',
|
||||||
'py-0.5! px-2!',
|
'py-0.5! px-2!',
|
||||||
'max-h-[calc(100svh-6rem)]',
|
'max-h-[calc(100svh-6rem)]',
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
import { type Button as ButtonStyle, type Control } from '../props';
|
import { type Button as ButtonStyle, type Control } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface ButtonProps extends Control, ButtonStyle {
|
interface ButtonProps extends Control, ButtonStyle {
|
||||||
/** Icon to display first. */
|
/** Icon to display first. */
|
||||||
|
@ -38,10 +37,10 @@ export function Button({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className={clsx(
|
className={cn(
|
||||||
'inline-flex gap-2 items-center justify-center',
|
'inline-flex gap-2 items-center justify-center',
|
||||||
'font-medium select-none disabled:cursor-auto',
|
'font-medium select-none disabled:cursor-auto disabled:opacity-75',
|
||||||
'clr-btn-default cc-animate-color',
|
'bg-secondary text-secondary-foreground cc-hover cc-animate-color',
|
||||||
dense ? 'px-1' : 'px-3 py-1',
|
dense ? 'px-1' : 'px-3 py-1',
|
||||||
loading ? 'cursor-progress' : 'cursor-pointer',
|
loading ? 'cursor-progress' : 'cursor-pointer',
|
||||||
noOutline ? 'outline-hidden' : 'focus-outline',
|
noOutline ? 'outline-hidden' : 'focus-outline',
|
||||||
|
|
|
@ -39,9 +39,9 @@ export function MiniButton({
|
||||||
tabIndex={tabIndex ?? -1}
|
tabIndex={tabIndex ?? -1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-lg',
|
'rounded-lg',
|
||||||
'clr-text-controls cc-animate-background',
|
'cc-controls cc-animate-background',
|
||||||
'cursor-pointer disabled:cursor-auto',
|
'cursor-pointer disabled:cursor-auto',
|
||||||
noHover ? 'outline-hidden' : 'clr-hover',
|
noHover ? 'outline-hidden' : 'cc-hover',
|
||||||
!noPadding && 'px-1 py-1',
|
!noPadding && 'px-1 py-1',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
import { type Button } from '../props';
|
import { type Button } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface SelectorButtonProps extends Button {
|
interface SelectorButtonProps extends Button {
|
||||||
/** Text to display in the button. */
|
/** Text to display in the button. */
|
||||||
|
@ -10,9 +9,6 @@ interface SelectorButtonProps extends Button {
|
||||||
|
|
||||||
/** Icon to display in the button. */
|
/** Icon to display in the button. */
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
|
||||||
/** Indicates if button background should be transparent. */
|
|
||||||
transparent?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +20,6 @@ export function SelectorButton({
|
||||||
title,
|
title,
|
||||||
titleHtml,
|
titleHtml,
|
||||||
className,
|
className,
|
||||||
transparent,
|
|
||||||
hideTitle,
|
hideTitle,
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectorButtonProps) {
|
}: SelectorButtonProps) {
|
||||||
|
@ -32,13 +27,12 @@ export function SelectorButton({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'px-1 flex flex-start items-center gap-1',
|
'px-1 flex flex-start items-center gap-1',
|
||||||
'text-sm font-controls select-none',
|
'text-sm font-controls select-none',
|
||||||
'text-btn clr-text-controls',
|
'text-btn cc-controls',
|
||||||
'disabled:cursor-auto cursor-pointer',
|
'disabled:cursor-auto cursor-pointer',
|
||||||
'cc-animate-color',
|
'cc-hover cc-animate-color',
|
||||||
transparent ? 'clr-hover' : 'clr-btn-default border',
|
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Button } from '../props';
|
import { type Button } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface SubmitButtonProps extends Button {
|
interface SubmitButtonProps extends Button {
|
||||||
/** Text to display in the button. */
|
/** Text to display in the button. */
|
||||||
|
@ -20,11 +19,11 @@ export function SubmitButton({ text = 'ОК', icon, disabled, loading, className
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='submit'
|
type='submit'
|
||||||
className={clsx(
|
className={cn(
|
||||||
'px-3 py-1 flex gap-2 items-center justify-center',
|
'px-3 py-1 flex gap-2 items-center justify-center',
|
||||||
'border',
|
'border',
|
||||||
'font-medium',
|
'font-medium',
|
||||||
'clr-btn-primary cc-animate-color',
|
'cc-btn-primary disabled:opacity-50 cc-animate-color',
|
||||||
'select-none cursor-pointer disabled:cursor-auto',
|
'select-none cursor-pointer disabled:cursor-auto',
|
||||||
loading && 'cursor-progress',
|
loading && 'cursor-progress',
|
||||||
className
|
className
|
||||||
|
|
|
@ -20,7 +20,7 @@ interface TextURLProps {
|
||||||
/**
|
/**
|
||||||
* Displays a text with a clickable link.
|
* Displays a text with a clickable link.
|
||||||
*/
|
*/
|
||||||
export function TextURL({ text, href, title, color = 'text-sec-600', onClick }: TextURLProps) {
|
export function TextURL({ text, href, title, color = 'text-primary', onClick }: TextURLProps) {
|
||||||
const design = `cursor-pointer hover:underline ${color}`;
|
const design = `cursor-pointer hover:underline ${color}`;
|
||||||
if (href) {
|
if (href) {
|
||||||
return (
|
return (
|
||||||
|
@ -38,4 +38,3 @@ export function TextURL({ text, href, title, color = 'text-sec-600', onClick }:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ import {
|
||||||
type TableOptions,
|
type TableOptions,
|
||||||
type VisibilityState
|
type VisibilityState
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Styling } from '../props';
|
import { type Styling } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { DefaultNoData } from './default-no-data';
|
import { DefaultNoData } from './default-no-data';
|
||||||
import { PaginationTools } from './pagination-tools';
|
import { PaginationTools } from './pagination-tools';
|
||||||
|
@ -157,7 +157,7 @@ export function DataTable<TData extends RowData>({
|
||||||
<div
|
<div
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
id={id}
|
id={id}
|
||||||
className={clsx('table-auto', className)}
|
className={cn('table-auto', className)}
|
||||||
style={{ minHeight: fixedSize, maxHeight: fixedSize, ...style }}
|
style={{ minHeight: fixedSize, maxHeight: fixedSize, ...style }}
|
||||||
>
|
>
|
||||||
<table className='w-full' style={{ ...columnSizeVars }}>
|
<table className='w-full' style={{ ...columnSizeVars }}>
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function PaginationTools<TData>({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-end items-center my-2 text-sm clr-text-controls select-none'>
|
<div className='flex justify-end items-center my-2 text-sm cc-controls select-none'>
|
||||||
<span className='mr-3'>
|
<span className='mr-3'>
|
||||||
{`${table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}
|
{`${table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}
|
||||||
-
|
-
|
||||||
|
@ -46,7 +46,7 @@ export function PaginationTools<TData>({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
aria-label='Первая страница'
|
aria-label='Первая страница'
|
||||||
className='clr-hover clr-text-controls cc-animate-color focus-outline'
|
className='cc-hover cc-controls cc-animate-color focus-outline'
|
||||||
onClick={() => table.setPageIndex(0)}
|
onClick={() => table.setPageIndex(0)}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -55,7 +55,7 @@ export function PaginationTools<TData>({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
aria-label='Предыдущая страница'
|
aria-label='Предыдущая страница'
|
||||||
className='clr-hover clr-text-controls cc-animate-color focus-outline'
|
className='cc-hover cc-controls cc-animate-color focus-outline'
|
||||||
onClick={() => table.previousPage()}
|
onClick={() => table.previousPage()}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -65,7 +65,7 @@ export function PaginationTools<TData>({
|
||||||
id={id ? `${id}__page` : undefined}
|
id={id ? `${id}__page` : undefined}
|
||||||
title='Номер страницы. Выделите для ручного ввода'
|
title='Номер страницы. Выделите для ручного ввода'
|
||||||
aria-label='Номер страницы'
|
aria-label='Номер страницы'
|
||||||
className='w-6 text-center bg-prim-100 focus-outline'
|
className='w-6 text-center bg-transparent focus-outline'
|
||||||
value={table.getState().pagination.pageIndex + 1}
|
value={table.getState().pagination.pageIndex + 1}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
const page = event.target.value ? Number(event.target.value) - 1 : 0;
|
const page = event.target.value ? Number(event.target.value) - 1 : 0;
|
||||||
|
@ -77,7 +77,7 @@ export function PaginationTools<TData>({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
aria-label='Следующая страница'
|
aria-label='Следующая страница'
|
||||||
className='clr-hover clr-text-controls cc-animate-color focus-outline'
|
className='cc-hover cc-controls cc-animate-color focus-outline'
|
||||||
onClick={() => table.nextPage()}
|
onClick={() => table.nextPage()}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -86,7 +86,7 @@ export function PaginationTools<TData>({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
aria-label='Последняя страница'
|
aria-label='Последняя страница'
|
||||||
className='clr-hover clr-text-controls cc-animate-color focus-outline'
|
className='cc-hover cc-controls cc-animate-color focus-outline'
|
||||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -98,7 +98,7 @@ export function PaginationTools<TData>({
|
||||||
aria-label='Выбор количества строчек на странице'
|
aria-label='Выбор количества строчек на странице'
|
||||||
value={table.getState().pagination.pageSize}
|
value={table.getState().pagination.pageSize}
|
||||||
onChange={handlePaginationOptionsChange}
|
onChange={handlePaginationOptionsChange}
|
||||||
className='mx-2 cursor-pointer bg-prim-100 focus-outline'
|
className='mx-2 cursor-pointer bg-transparent focus-outline'
|
||||||
>
|
>
|
||||||
{paginationOptions.map(pageSize => (
|
{paginationOptions.map(pageSize => (
|
||||||
<option key={`${prefixes.page_size}${pageSize}`} value={pageSize} aria-label={`${pageSize} на страницу`}>
|
<option key={`${prefixes.page_size}${pageSize}`} value={pageSize} aria-label={`${pageSize} на страницу`}>
|
||||||
|
|
|
@ -75,11 +75,11 @@ export function TableBody<TData>({
|
||||||
key={row.id}
|
key={row.id}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'cc-scroll-row',
|
'cc-scroll-row',
|
||||||
'clr-hover cc-animate-background duration-(--duration-fade)',
|
'cc-hover cc-animate-background duration-(--duration-fade)',
|
||||||
!noHeader && 'scroll-mt-[calc(2px+2rem)]',
|
!noHeader && 'scroll-mt-[calc(2px+2rem)]',
|
||||||
table.options.enableRowSelection && row.getIsSelected()
|
table.options.enableRowSelection && row.getIsSelected()
|
||||||
? 'clr-selected'
|
? 'cc-selected'
|
||||||
: 'odd:bg-prim-200 even:bg-prim-100'
|
: 'odd:bg-secondary even:bg-background'
|
||||||
)}
|
)}
|
||||||
style={{ ...(conditionalRowStyles ? getRowStyles(row) : []) }}
|
style={{ ...(conditionalRowStyles ? getRowStyles(row) : []) }}
|
||||||
onClick={event => handleRowClicked(row, event)}
|
onClick={event => handleRowClicked(row, event)}
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface TableHeaderProps<TData> {
|
||||||
|
|
||||||
export function TableHeader<TData>({ table, headPosition, resetLastSelected }: TableHeaderProps<TData>) {
|
export function TableHeader<TData>({ table, headPosition, resetLastSelected }: TableHeaderProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<thead className='sticky bg-prim-100 cc-shadow-border' style={{ top: headPosition }}>
|
<thead className='sticky bg-background cc-shadow-border' style={{ top: headPosition }}>
|
||||||
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
|
{table.getHeaderGroups().map((headerGroup: HeaderGroup<TData>) => (
|
||||||
<tr key={headerGroup.id}>
|
<tr key={headerGroup.id}>
|
||||||
{table.options.enableRowSelection ? (
|
{table.options.enableRowSelection ? (
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Button } from '@/components/props';
|
import { type Button } from '@/components/props';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface DropdownButtonProps extends Button {
|
interface DropdownButtonProps extends Button {
|
||||||
/** Icon to display first (not used if children are provided). */
|
/** Icon to display first (not used if children are provided). */
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
@ -33,12 +33,12 @@ export function DropdownButton({
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'px-3 py-1 inline-flex items-center gap-2',
|
'px-3 py-1 inline-flex items-center gap-2',
|
||||||
'text-left text-sm text-ellipsis whitespace-nowrap',
|
'text-left text-sm text-ellipsis whitespace-nowrap',
|
||||||
'disabled:clr-text-controls',
|
'disabled:cc-controls disabled:opacity-75',
|
||||||
'cc-animate-background',
|
'cc-animate-background',
|
||||||
!!onClick ? 'clr-hover cursor-pointer disabled:cursor-auto' : 'clr-btn-default',
|
!!onClick ? 'cc-hover cursor-pointer disabled:cursor-auto' : 'bg-secondary text-secondary-foreground',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Styling } from '../props';
|
import { type Styling } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface DropdownProps extends Styling {
|
interface DropdownProps extends Styling {
|
||||||
/** Reference to the dropdown element. */
|
/** Reference to the dropdown element. */
|
||||||
|
@ -39,8 +37,8 @@ export function Dropdown({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'cc-dropdown isolate z-topmost absolute grid bg-prim-0 border rounded-md shadow-lg text-sm',
|
'cc-dropdown isolate z-topmost absolute grid bg-popover border rounded-md shadow-lg text-sm',
|
||||||
stretchLeft ? 'right-0' : 'left-0',
|
stretchLeft ? 'right-0' : 'left-0',
|
||||||
stretchTop ? 'bottom-0' : 'top-full',
|
stretchTop ? 'bottom-0' : 'top-full',
|
||||||
isOpen && 'open',
|
isOpen && 'open',
|
||||||
|
|
|
@ -81,11 +81,11 @@ export function InfoError({ error }: InfoErrorProps) {
|
||||||
'cc-fade-in',
|
'cc-fade-in',
|
||||||
'min-w-100',
|
'min-w-100',
|
||||||
'px-3 py-2 flex flex-col',
|
'px-3 py-2 flex flex-col',
|
||||||
'text-warn-600 text-sm font-semibold',
|
'text-destructive text-sm font-semibold',
|
||||||
'select-text'
|
'select-text'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className='font-normal clr-text-default mb-6'>
|
<div className='font-normal text-foreground mb-6'>
|
||||||
<p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p>
|
<p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p>
|
||||||
<br />
|
<br />
|
||||||
<p>Для продолжения работы перезагрузите страницу</p>
|
<p>Для продолжения работы перезагрузите страницу</p>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import clsx from 'clsx';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
import { CheckboxChecked, CheckboxNull } from '../icons';
|
import { CheckboxChecked, CheckboxNull } from '../icons';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { type CheckboxProps } from './checkbox';
|
import { type CheckboxProps } from './checkbox';
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ export function CheckboxTristate({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className={clsx(
|
className={cn(
|
||||||
'flex items-center gap-2', //
|
'flex items-center gap-2', //
|
||||||
'outline-hidden',
|
'outline-hidden',
|
||||||
'focus-frame',
|
'focus-frame',
|
||||||
|
@ -67,7 +68,7 @@ export function CheckboxTristate({
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-4 h-4', //
|
'w-4 h-4', //
|
||||||
'border rounded-sm',
|
'border rounded-sm',
|
||||||
value === false ? 'bg-prim-100' : 'bg-sec-600 text-sec-0'
|
value === false ? 'bg-background text-foreground' : 'bg-primary text-primary-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{value ? <CheckboxChecked /> : null}
|
{value ? <CheckboxChecked /> : null}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
import { CheckboxChecked } from '../icons';
|
import { CheckboxChecked } from '../icons';
|
||||||
import { type Button } from '../props';
|
import { type Button } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
export interface CheckboxProps extends Omit<Button, 'value' | 'onClick' | 'onChange'> {
|
export interface CheckboxProps extends Omit<Button, 'value' | 'onClick' | 'onChange'> {
|
||||||
/** Label to display next to the checkbox. */
|
/** Label to display next to the checkbox. */
|
||||||
|
@ -47,7 +48,7 @@ export function Checkbox({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className={clsx(
|
className={cn(
|
||||||
'flex items-center gap-2', //
|
'flex items-center gap-2', //
|
||||||
'outline-hidden',
|
'outline-hidden',
|
||||||
'focus-frame',
|
'focus-frame',
|
||||||
|
@ -66,7 +67,7 @@ export function Checkbox({
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-4 h-4', //
|
'w-4 h-4', //
|
||||||
'border rounded-sm',
|
'border rounded-sm',
|
||||||
value === false ? 'bg-prim-100' : 'bg-sec-600 text-sec-0'
|
value === false ? 'bg-background text-foreground' : 'bg-primary text-primary-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{value ? <CheckboxChecked /> : null}
|
{value ? <CheckboxChecked /> : null}
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function ErrorField({ error, className, ...restProps }: ErrorFieldProps):
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className={clsx('text-sm text-warn-600 select-none', className)} {...restProps}>
|
<div className={clsx('text-sm text-destructive select-none', className)} {...restProps}>
|
||||||
{error.message}
|
{error.message}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,9 @@ import clsx from 'clsx';
|
||||||
|
|
||||||
import { IconSearch } from '@/components/icons';
|
import { IconSearch } from '@/components/icons';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
interface SearchBarProps extends Styling {
|
interface SearchBarProps extends Styling {
|
||||||
/** Id of the search bar. */
|
/** Id of the search bar. */
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -36,7 +39,7 @@ export function SearchBar({
|
||||||
...restProps
|
...restProps
|
||||||
}: SearchBarProps) {
|
}: SearchBarProps) {
|
||||||
return (
|
return (
|
||||||
<div className={clsx('relative flex items-center grow', className)} {...restProps}>
|
<div className={cn('relative flex items-center grow', className)} {...restProps}>
|
||||||
{!noIcon ? (
|
{!noIcon ? (
|
||||||
<IconSearch className='absolute -top-0.5 left-2 translate-y-1/2 cc-search-icon' size='1.25rem' />
|
<IconSearch className='absolute -top-0.5 left-2 translate-y-1/2 cc-search-icon' size='1.25rem' />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -89,9 +89,9 @@ export function SelectTree<ItemType>({
|
||||||
<div
|
<div
|
||||||
key={`${prefix}${index}`}
|
key={`${prefix}${index}`}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'cc-tree-item relative cc-scroll-row clr-hover',
|
'cc-tree-item relative cc-scroll-row cc-hover',
|
||||||
isActive ? 'max-h-7 py-1 border-b' : 'max-h-0 opacity-0 pointer-events-none',
|
isActive ? 'max-h-7 py-1 border-b' : 'max-h-0 opacity-0 pointer-events-none',
|
||||||
value === item && 'clr-selected'
|
value === item && 'cc-selected'
|
||||||
)}
|
)}
|
||||||
data-tooltip-id={globalIDs.tooltip}
|
data-tooltip-id={globalIDs.tooltip}
|
||||||
data-tooltip-html={getDescription(item)}
|
data-tooltip-html={getDescription(item)}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Editor, type ErrorProcessing, type Titled } from '../props';
|
import { type Editor, type ErrorProcessing, type Titled } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { ErrorField } from './error-field';
|
import { ErrorField } from './error-field';
|
||||||
import { Label } from './label';
|
import { Label } from './label';
|
||||||
|
@ -25,21 +24,20 @@ interface TextAreaProps extends Editor, ErrorProcessing, Titled, React.Component
|
||||||
export function TextArea({
|
export function TextArea({
|
||||||
id,
|
id,
|
||||||
label,
|
label,
|
||||||
required,
|
|
||||||
transparent,
|
transparent,
|
||||||
rows,
|
|
||||||
dense,
|
dense,
|
||||||
noBorder,
|
noBorder,
|
||||||
noOutline,
|
noOutline,
|
||||||
noResize,
|
noResize,
|
||||||
className,
|
className,
|
||||||
fitContent,
|
fitContent,
|
||||||
|
disabled,
|
||||||
error,
|
error,
|
||||||
...restProps
|
...restProps
|
||||||
}: TextAreaProps) {
|
}: TextAreaProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
'w-full', //
|
'w-full', //
|
||||||
dense ? 'flex grow items-center gap-3' : 'flex flex-col',
|
dense ? 'flex grow items-center gap-3' : 'flex flex-col',
|
||||||
dense && className
|
dense && className
|
||||||
|
@ -48,21 +46,20 @@ export function TextArea({
|
||||||
<Label text={label} htmlFor={id} />
|
<Label text={label} htmlFor={id} />
|
||||||
<textarea
|
<textarea
|
||||||
id={id}
|
id={id}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'px-3 py-2',
|
'px-3 py-2',
|
||||||
'leading-tight',
|
'leading-tight',
|
||||||
'overflow-x-hidden overflow-y-auto',
|
'overflow-x-hidden overflow-y-auto',
|
||||||
!noBorder && 'border',
|
!noBorder && 'border',
|
||||||
fitContent && 'field-sizing-content',
|
fitContent && 'field-sizing-content',
|
||||||
noResize && 'resize-none',
|
noResize && 'resize-none',
|
||||||
transparent ? 'bg-transparent' : 'clr-input',
|
transparent || disabled ? 'bg-transparent' : 'bg-input',
|
||||||
!noOutline && 'focus-outline',
|
!noOutline && 'focus-outline',
|
||||||
dense && 'grow max-w-full',
|
dense && 'grow max-w-full',
|
||||||
!dense && !!label && 'mt-2',
|
!dense && !!label && 'mt-2',
|
||||||
!dense && className
|
!dense && className
|
||||||
)}
|
)}
|
||||||
rows={rows}
|
disabled={disabled}
|
||||||
required={required}
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
<ErrorField className='mt-1' error={error} />
|
<ErrorField className='mt-1' error={error} />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type Editor, type ErrorProcessing, type Titled } from '../props';
|
import { type Editor, type ErrorProcessing, type Titled } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { ErrorField } from './error-field';
|
import { ErrorField } from './error-field';
|
||||||
import { Label } from './label';
|
import { Label } from './label';
|
||||||
|
@ -41,7 +40,7 @@ export function TextInput({
|
||||||
}: TextInputProps) {
|
}: TextInputProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
dense ? 'flex items-center gap-3' : 'flex flex-col', //
|
dense ? 'flex items-center gap-3' : 'flex flex-col', //
|
||||||
dense && className
|
dense && className
|
||||||
)}
|
)}
|
||||||
|
@ -49,10 +48,10 @@ export function TextInput({
|
||||||
<Label text={label} htmlFor={id} />
|
<Label text={label} htmlFor={id} />
|
||||||
<input
|
<input
|
||||||
id={id}
|
id={id}
|
||||||
className={clsx(
|
className={cn(
|
||||||
'min-w-0 py-2',
|
'min-w-0 py-2',
|
||||||
'leading-tight truncate hover:text-clip',
|
'leading-tight truncate hover:text-clip',
|
||||||
transparent ? 'bg-transparent' : 'clr-input',
|
transparent || disabled ? 'bg-transparent' : 'bg-input',
|
||||||
!noBorder && 'border',
|
!noBorder && 'border',
|
||||||
!noOutline && 'focus-outline',
|
!noOutline && 'focus-outline',
|
||||||
(!noBorder || !disabled) && 'px-3',
|
(!noBorder || !disabled) && 'px-3',
|
||||||
|
|
|
@ -8,7 +8,7 @@ export function ModalBackdrop({ onHide }: ModalBackdropProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='z-bottom fixed inset-0 backdrop-blur-[3px] opacity-50' />
|
<div className='z-bottom fixed inset-0 backdrop-blur-[3px] opacity-50' />
|
||||||
<div className='z-bottom fixed inset-0 bg-prim-0 opacity-25' onClick={onHide} />
|
<div className='z-bottom fixed inset-0 bg-popover opacity-25' onClick={onHide} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type HelpTopic } from '@/features/help';
|
import { type HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
|
|
||||||
|
@ -12,6 +10,7 @@ import { prepareTooltip } from '@/utils/utils';
|
||||||
import { Button, MiniButton, SubmitButton } from '../control';
|
import { Button, MiniButton, SubmitButton } from '../control';
|
||||||
import { IconClose } from '../icons';
|
import { IconClose } from '../icons';
|
||||||
import { type Styling } from '../props';
|
import { type Styling } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { ModalBackdrop } from './modal-backdrop';
|
import { ModalBackdrop } from './modal-backdrop';
|
||||||
|
|
||||||
|
@ -90,7 +89,7 @@ export function ModalForm({
|
||||||
<div className='cc-modal-wrapper'>
|
<div className='cc-modal-wrapper'>
|
||||||
<ModalBackdrop onHide={handleCancel} />
|
<ModalBackdrop onHide={handleCancel} />
|
||||||
<form
|
<form
|
||||||
className='cc-animate-modal relative grid border rounded-xl bg-prim-100'
|
className='cc-animate-modal relative grid border rounded-xl bg-background'
|
||||||
role='dialog'
|
role='dialog'
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
aria-labelledby='modal-title'
|
aria-labelledby='modal-title'
|
||||||
|
@ -120,7 +119,7 @@ export function ModalForm({
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
'@container/modal',
|
'@container/modal',
|
||||||
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
|
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
|
||||||
'overscroll-contain outline-hidden',
|
'overscroll-contain outline-hidden',
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function ModalLoader() {
|
||||||
return (
|
return (
|
||||||
<div className='cc-modal-wrapper'>
|
<div className='cc-modal-wrapper'>
|
||||||
<ModalBackdrop />
|
<ModalBackdrop />
|
||||||
<div className='cc-animate-modal p-20 border rounded-xl bg-prim-100'>
|
<div className='cc-animate-modal p-20 border rounded-xl bg-background'>
|
||||||
<Loader circular scale={6} />
|
<Loader circular scale={6} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { prepareTooltip } from '@/utils/utils';
|
||||||
|
|
||||||
import { Button, MiniButton } from '../control';
|
import { Button, MiniButton } from '../control';
|
||||||
import { IconClose } from '../icons';
|
import { IconClose } from '../icons';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { ModalBackdrop } from './modal-backdrop';
|
import { ModalBackdrop } from './modal-backdrop';
|
||||||
import { type ModalProps } from './modal-form';
|
import { type ModalProps } from './modal-form';
|
||||||
|
@ -38,7 +39,7 @@ export function ModalView({
|
||||||
return (
|
return (
|
||||||
<div className='cc-modal-wrapper'>
|
<div className='cc-modal-wrapper'>
|
||||||
<ModalBackdrop onHide={hideDialog} />
|
<ModalBackdrop onHide={hideDialog} />
|
||||||
<div className='cc-animate-modal relative grid border rounded-xl bg-prim-100' role='dialog'>
|
<div className='cc-animate-modal relative grid border rounded-xl bg-background' role='dialog'>
|
||||||
{helpTopic && !hideHelpWhen?.() ? (
|
{helpTopic && !hideHelpWhen?.() ? (
|
||||||
<BadgeHelp
|
<BadgeHelp
|
||||||
topic={helpTopic}
|
topic={helpTopic}
|
||||||
|
@ -61,7 +62,8 @@ export function ModalView({
|
||||||
<h1
|
<h1
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-12 py-2 select-none',
|
'px-12 py-2 select-none',
|
||||||
fullScreen && 'z-pop absolute top-0 right-1/2 translate-x-1/2 backdrop-blur-xs bg-prim-100/90 rounded-2xl'
|
fullScreen &&
|
||||||
|
'z-pop absolute top-0 right-1/2 translate-x-1/2 backdrop-blur-xs bg-background/90 rounded-2xl'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{header}
|
{header}
|
||||||
|
@ -69,7 +71,7 @@ export function ModalView({
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
'@container/modal',
|
'@container/modal',
|
||||||
'max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
|
'max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
|
||||||
'overscroll-contain outline-hidden',
|
'overscroll-contain outline-hidden',
|
||||||
|
@ -93,7 +95,7 @@ export function ModalView({
|
||||||
onClick={hideDialog}
|
onClick={hideDialog}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className='z-pop absolute bottom-0 right-1/2 translate-x-1/2 p-3 rounded-xl bg-prim-100/90 backdrop-blur-xs'>
|
<div className='z-pop absolute bottom-0 right-1/2 translate-x-1/2 p-3 rounded-xl bg-background/90 backdrop-blur-xs'>
|
||||||
{' '}
|
{' '}
|
||||||
<Button text='Закрыть' aria-label='Закрыть' className='text-sm min-w-28' onClick={hideDialog} />
|
<Button text='Закрыть' aria-label='Закрыть' className='text-sm min-w-28' onClick={hideDialog} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function TabLabel({
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'min-w-20 h-full',
|
'min-w-20 h-full',
|
||||||
'px-2 py-1 flex justify-center',
|
'px-2 py-1 flex justify-center',
|
||||||
'clr-hover cc-animate-color duration-150',
|
'cc-hover cc-animate-color duration-150',
|
||||||
'text-sm whitespace-nowrap font-controls',
|
'text-sm whitespace-nowrap font-controls',
|
||||||
'select-none hover:cursor-pointer',
|
'select-none hover:cursor-pointer',
|
||||||
'outline-hidden',
|
'outline-hidden',
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { ChevronDownIcon } from 'lucide-react';
|
import { ChevronDownIcon } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
import { IconRemove } from '../icons';
|
import { IconRemove } from '../icons';
|
||||||
import { type Styling } from '../props';
|
import { type Styling } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command';
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
||||||
|
@ -77,7 +76,11 @@ export function ComboBox<Option>({
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative h-9',
|
'relative h-9',
|
||||||
'inline-flex gap-2 px-3 py-2 items-center justify-between bg-input cursor-pointer disabled:cursor-auto whitespace-nowrap outline-none focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px] aria-invalid:ring-destructive aria-invalid:border-destructive',
|
'flex gap-2 px-3 py-2 items-center justify-between',
|
||||||
|
'bg-input disabled:opacity-50',
|
||||||
|
'cursor-pointer disabled:cursor-auto',
|
||||||
|
'whitespace-nowrap',
|
||||||
|
'focus-outline',
|
||||||
"[&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
|
"[&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
|
||||||
open && 'cursor-auto',
|
open && 'cursor-auto',
|
||||||
!noBorder && 'border',
|
!noBorder && 'border',
|
||||||
|
@ -94,7 +97,7 @@ export function ComboBox<Option>({
|
||||||
<IconRemove
|
<IconRemove
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
size='1rem'
|
size='1rem'
|
||||||
className='absolute pointer-events-auto right-3 text-muted-foreground hover:text-warn-600'
|
className='absolute pointer-events-auto right-3 text-muted-foreground hover:text-destructive'
|
||||||
onClick={handleClear}
|
onClick={handleClear}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { Command as CommandPrimitive } from 'cmdk';
|
||||||
import { SearchIcon } from 'lucide-react';
|
import { SearchIcon } from 'lucide-react';
|
||||||
|
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
|
function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||||
import { XIcon } from 'lucide-react';
|
import { XIcon } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '../utils';
|
||||||
|
|
||||||
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
||||||
return <DialogPrimitive.Root data-slot='dialog' {...props} />;
|
return <DialogPrimitive.Root data-slot='dialog' {...props} />;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '../utils';
|
||||||
|
|
||||||
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||||
return <PopoverPrimitive.Root data-slot='popover' {...props} />;
|
return <PopoverPrimitive.Root data-slot='popover' {...props} />;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as SelectPrimitive from '@radix-ui/react-select';
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
||||||
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
|
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '../utils';
|
||||||
|
|
||||||
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||||
return <SelectPrimitive.Root data-slot='select' {...props} />;
|
return <SelectPrimitive.Root data-slot='select' {...props} />;
|
||||||
|
@ -19,29 +19,26 @@ function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.V
|
||||||
|
|
||||||
function SelectTrigger({
|
function SelectTrigger({
|
||||||
className,
|
className,
|
||||||
size = 'default',
|
|
||||||
children,
|
children,
|
||||||
noBorder,
|
noBorder,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
size?: 'sm' | 'default';
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
data-slot='select-trigger'
|
data-slot='select-trigger'
|
||||||
data-size={size}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
'data-[size=default]:h-9 data-[size=sm]:h-8',
|
'h-9',
|
||||||
'flex items-center justify-between gap-2 px-3 py-2',
|
'flex gap-2 px-3 py-2 items-center justify-between',
|
||||||
'bg-input disabled:opacity-50',
|
'bg-input disabled:opacity-50',
|
||||||
'cursor-pointer disabled:cursor-auto',
|
'cursor-pointer disabled:cursor-auto',
|
||||||
'data-[placeholder]:text-muted-foreground',
|
|
||||||
'whitespace-nowrap',
|
'whitespace-nowrap',
|
||||||
'outline-none focus-visible:ring-[2px] focus-visible:border-ring focus-visible:ring-ring aria-invalid:ring-destructive',
|
'focus-outline',
|
||||||
|
'data-[placeholder]:text-muted-foreground',
|
||||||
'*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2',
|
'*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2',
|
||||||
"[&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"[&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
!noBorder && 'border aria-invalid:border-destructive',
|
!noBorder && 'border',
|
||||||
noBorder && 'rounded-md',
|
noBorder && 'rounded-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export function Indicator({ icon, title, titleHtml, hideTitle, noPadding, classN
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'clr-text-controls', //
|
'cc-controls', //
|
||||||
'outline-hidden',
|
'outline-hidden',
|
||||||
!noPadding && 'px-1 py-1',
|
!noPadding && 'px-1 py-1',
|
||||||
className
|
className
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function ExpectedAnonymous() {
|
||||||
<span> | </span>
|
<span> | </span>
|
||||||
<TextURL text='Справка' href='/manuals' />
|
<TextURL text='Справка' href='/manuals' />
|
||||||
<span> | </span>
|
<span> | </span>
|
||||||
<span className='cursor-pointer hover:underline text-sec-600' onClick={logoutAndRedirect}>
|
<span className='cursor-pointer hover:underline text-primary' aria-label='Выйти' onClick={logoutAndRedirect}>
|
||||||
Выйти
|
Выйти
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -95,7 +95,7 @@ export function LoginPage() {
|
||||||
function ServerError({ error }: { error: ErrorData }): React.ReactElement | null {
|
function ServerError({ error }: { error: ErrorData }): React.ReactElement | null {
|
||||||
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
||||||
return (
|
return (
|
||||||
<div className='text-sm select-text text-warn-600'>
|
<div className='text-sm select-text text-destructive'>
|
||||||
На Портале отсутствует такое сочетание имени пользователя и пароля
|
На Портале отсутствует такое сочетание имени пользователя и пароля
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -88,7 +88,7 @@ export function Component() {
|
||||||
// ====== Internals =========
|
// ====== Internals =========
|
||||||
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
||||||
if (isAxiosError(error) && error.response && error.response.status === 404) {
|
if (isAxiosError(error) && error.response && error.response.status === 404) {
|
||||||
return <div className='mx-auto mt-6 text-sm select-text text-warn-600'>Данная ссылка не действительна</div>;
|
return <div className='mx-auto mt-6 text-sm select-text text-destructive'>Данная ссылка не действительна</div>;
|
||||||
}
|
}
|
||||||
return <InfoError error={error} />;
|
return <InfoError error={error} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export function Component() {
|
||||||
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
||||||
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
||||||
return (
|
return (
|
||||||
<div className='mx-auto mt-6 text-sm select-text text-warn-600'>Данный email не используется на Портале.</div>
|
<div className='mx-auto mt-6 text-sm select-text text-destructive'>Данный email не используется на Портале.</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw error as Error;
|
throw error as Error;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { Suspense } from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type PlacesType, Tooltip } from '@/components/container';
|
import { type PlacesType, Tooltip } from '@/components/container';
|
||||||
import { TextURL } from '@/components/control';
|
import { TextURL } from '@/components/control';
|
||||||
import { IconHelp } from '@/components/icons';
|
import { IconHelp } from '@/components/icons';
|
||||||
import { Loader } from '@/components/loader';
|
import { Loader } from '@/components/loader';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
|
||||||
import { type HelpTopic } from '../models/help-topic';
|
import { type HelpTopic } from '../models/help-topic';
|
||||||
|
@ -41,17 +41,17 @@ export function BadgeHelp({ topic, padding = 'p-1', className, contentClass, sty
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} id={`help-${topic}`} className={clsx(padding, className)} style={style}>
|
<div tabIndex={-1} id={`help-${topic}`} className={cn(padding, className)} style={style}>
|
||||||
<IconHelp size='1.25rem' className='icon-primary' />
|
<IconHelp size='1.25rem' className='icon-primary' />
|
||||||
<Tooltip
|
<Tooltip
|
||||||
clickable
|
clickable
|
||||||
anchorSelect={`#help-${topic}`}
|
anchorSelect={`#help-${topic}`}
|
||||||
layer='z-topmost'
|
layer='z-topmost'
|
||||||
className={clsx('max-w-120', contentClass)}
|
className={cn('max-w-120', contentClass)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<Loader />}>
|
<Suspense fallback={<Loader />}>
|
||||||
<div className='absolute right-1 text-sm top-2 clr-input' onClick={event => event.stopPropagation()}>
|
<div className='absolute right-1 text-sm top-2 bg-input' onClick={event => event.stopPropagation()}>
|
||||||
<TextURL text='Справка...' href={`/manuals?topic=${topic}`} />
|
<TextURL text='Справка...' href={`/manuals?topic=${topic}`} />
|
||||||
</div>
|
</div>
|
||||||
<TopicPage topic={topic} />
|
<TopicPage topic={topic} />
|
||||||
|
|
|
@ -81,7 +81,7 @@ export function HelpLibrary() {
|
||||||
<kbd>клик</kbd> по иконке сворачивает/разворачивает вложенные
|
<kbd>клик</kbd> по иконке сворачивает/разворачивает вложенные
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconFolderEmpty size='1rem' className='inline-icon clr-text-default' /> папка без схем
|
<IconFolderEmpty size='1rem' className='inline-icon text-foreground' /> папка без схем
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconFolderEmpty size='1rem' className='inline-icon' /> папка с вложенными без схем
|
<IconFolderEmpty size='1rem' className='inline-icon' /> папка с вложенными без схем
|
||||||
|
|
|
@ -68,7 +68,7 @@ export function HelpRSEditor() {
|
||||||
<IconChild className='inline-icon' /> отображение наследованных
|
<IconChild className='inline-icon' /> отображение наследованных
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className='bg-sec-200'>текущая конституента</span>
|
<span className='bg-selected'>текущая конституента</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className='bg-(--acc-bg-green50)'>
|
<span className='bg-(--acc-bg-green50)'>
|
||||||
|
|
|
@ -137,14 +137,14 @@ export function EditorLibraryItem({ schema, isAttachedToOSS }: EditorLibraryItem
|
||||||
<ValueIcon
|
<ValueIcon
|
||||||
title='Дата обновления'
|
title='Дата обновления'
|
||||||
dense
|
dense
|
||||||
icon={<IconDateUpdate size='1.25rem' className='text-ok-600' />}
|
icon={<IconDateUpdate size='1.25rem' className='text-constructive' />}
|
||||||
value={new Date(schema.time_update).toLocaleString(intl.locale)}
|
value={new Date(schema.time_update).toLocaleString(intl.locale)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValueIcon
|
<ValueIcon
|
||||||
title='Дата создания'
|
title='Дата создания'
|
||||||
dense
|
dense
|
||||||
icon={<IconDateCreate size='1.25rem' className='text-ok-600' />}
|
icon={<IconDateCreate size='1.25rem' className='text-constructive' />}
|
||||||
value={new Date(schema.time_create).toLocaleString(intl.locale, {
|
value={new Date(schema.time_create).toLocaleString(intl.locale, {
|
||||||
year: '2-digit',
|
year: '2-digit',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
|
|
|
@ -6,10 +6,10 @@ import { AccessPolicy } from '../backend/types';
|
||||||
export function IconAccessPolicy({ value, size = '1.25rem', className }: DomIconProps<AccessPolicy>) {
|
export function IconAccessPolicy({ value, size = '1.25rem', className }: DomIconProps<AccessPolicy>) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case AccessPolicy.PRIVATE:
|
case AccessPolicy.PRIVATE:
|
||||||
return <IconPrivate size={size} className={className ?? 'text-warn-600'} />;
|
return <IconPrivate size={size} className={className ?? 'text-destructive'} />;
|
||||||
case AccessPolicy.PROTECTED:
|
case AccessPolicy.PROTECTED:
|
||||||
return <IconProtected size={size} className={className ?? 'text-sec-600'} />;
|
return <IconProtected size={size} className={className ?? 'text-primary'} />;
|
||||||
case AccessPolicy.PUBLIC:
|
case AccessPolicy.PUBLIC:
|
||||||
return <IconPublic size={size} className={className ?? 'text-ok-600'} />;
|
return <IconPublic size={size} className={className ?? 'text-constructive'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { type DomIconProps, IconHide, IconShow } from '@/components/icons';
|
||||||
/** Icon for visibility. */
|
/** Icon for visibility. */
|
||||||
export function IconItemVisibility({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
export function IconItemVisibility({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
||||||
if (value) {
|
if (value) {
|
||||||
return <IconShow size={size} className={className ?? 'text-ok-600'} />;
|
return <IconShow size={size} className={className ?? 'text-constructive'} />;
|
||||||
} else {
|
} else {
|
||||||
return <IconHide size={size} className={className ?? 'text-warn-600'} />;
|
return <IconHide size={size} className={className ?? 'text-destructive'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { LibraryItemType } from '../backend/types';
|
||||||
export function IconLibraryItemType({ value, size = '1.25rem', className }: DomIconProps<LibraryItemType>) {
|
export function IconLibraryItemType({ value, size = '1.25rem', className }: DomIconProps<LibraryItemType>) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case LibraryItemType.RSFORM:
|
case LibraryItemType.RSFORM:
|
||||||
return <IconRSForm size={size} className={className ?? 'text-sec-600'} />;
|
return <IconRSForm size={size} className={className ?? 'text-primary'} />;
|
||||||
case LibraryItemType.OSS:
|
case LibraryItemType.OSS:
|
||||||
return <IconOSS size={size} className={className ?? 'text-ok-600'} />;
|
return <IconOSS size={size} className={className ?? 'text-constructive'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ import { LocationHead } from '../models/library';
|
||||||
export function IconLocationHead({ value, size = '1.25rem', className }: DomIconProps<string>) {
|
export function IconLocationHead({ value, size = '1.25rem', className }: DomIconProps<string>) {
|
||||||
switch (value.substring(0, 2) as LocationHead) {
|
switch (value.substring(0, 2) as LocationHead) {
|
||||||
case LocationHead.COMMON:
|
case LocationHead.COMMON:
|
||||||
return <IconPublic size={size} className={className ?? 'text-sec-600'} />;
|
return <IconPublic size={size} className={className ?? 'text-primary'} />;
|
||||||
case LocationHead.LIBRARY:
|
case LocationHead.LIBRARY:
|
||||||
return <IconTemplates size={size} className={className ?? 'text-warn-600'} />;
|
return <IconTemplates size={size} className={className ?? 'text-destructive'} />;
|
||||||
case LocationHead.PROJECTS:
|
case LocationHead.PROJECTS:
|
||||||
return <IconBusiness size={size} className={className ?? 'text-sec-600'} />;
|
return <IconBusiness size={size} className={className ?? 'text-primary'} />;
|
||||||
case LocationHead.USER:
|
case LocationHead.USER:
|
||||||
return <IconUser size={size} className={className ?? 'text-ok-600'} />;
|
return <IconUser size={size} className={className ?? 'text-constructive'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { type DomIconProps, IconSubfolders } from '@/components/icons';
|
||||||
/** Icon for subfolders. */
|
/** Icon for subfolders. */
|
||||||
export function IconShowSubfolders({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
export function IconShowSubfolders({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
||||||
if (value) {
|
if (value) {
|
||||||
return <IconSubfolders size={size} className={className ?? 'text-ok-600'} />;
|
return <IconSubfolders size={size} className={className ?? 'text-constructive'} />;
|
||||||
} else {
|
} else {
|
||||||
return <IconSubfolders size={size} className={className ?? 'text-sec-600'} />;
|
return <IconSubfolders size={size} className={className ?? 'text-primary'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { MiniButton } from '@/components/control';
|
import { MiniButton } from '@/components/control';
|
||||||
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
||||||
|
@ -8,6 +7,7 @@ import { Dropdown, useDropdown } from '@/components/dropdown';
|
||||||
import { IconClose, IconFolderTree } from '@/components/icons';
|
import { IconClose, IconFolderTree } from '@/components/icons';
|
||||||
import { SearchBar } from '@/components/input';
|
import { SearchBar } from '@/components/input';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { APP_COLORS } from '@/styling/colors';
|
import { APP_COLORS } from '@/styling/colors';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -103,11 +103,11 @@ export function PickSchema({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('border divide-y', className)} {...restProps}>
|
<div className={cn('border divide-y', className)} {...restProps}>
|
||||||
<div className='flex justify-between clr-input items-center pr-1 rounded-t-md'>
|
<div className='flex justify-between bg-input items-center pr-1 rounded-t-md'>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
id={id ? `${id}__search` : undefined}
|
id={id ? `${id}__search` : undefined}
|
||||||
className='clr-input grow rounded-t-md'
|
className='grow rounded-t-md'
|
||||||
noBorder
|
noBorder
|
||||||
query={filterText}
|
query={filterText}
|
||||||
onChangeQuery={newValue => setFilterText(newValue)}
|
onChangeQuery={newValue => setFilterText(newValue)}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { SelectorButton } from '@/components/control';
|
import { SelectorButton } from '@/components/control';
|
||||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
import { LibraryItemType } from '../backend/types';
|
import { LibraryItemType } from '../backend/types';
|
||||||
|
@ -37,9 +36,8 @@ export function SelectItemType({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} onBlur={menu.handleBlur} className={clsx('relative', className)} {...restProps}>
|
<div ref={menu.ref} onBlur={menu.handleBlur} className={cn('relative', className)} {...restProps}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
|
||||||
title={describeLibraryItemType(value)}
|
title={describeLibraryItemType(value)}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full px-2 py-1 rounded-lg'
|
className='h-full px-2 py-1 rounded-lg'
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { SelectorButton } from '@/components/control';
|
import { SelectorButton } from '@/components/control';
|
||||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
import { describeLocationHead, labelLocationHead } from '../labels';
|
import { describeLocationHead, labelLocationHead } from '../labels';
|
||||||
|
@ -36,11 +35,10 @@ export function SelectLocationHead({
|
||||||
<div
|
<div
|
||||||
ref={menu.ref} //
|
ref={menu.ref} //
|
||||||
onBlur={menu.handleBlur}
|
onBlur={menu.handleBlur}
|
||||||
className={clsx('text-right relative', className)}
|
className={cn('text-right relative', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title={describeLocationHead(value)}
|
title={describeLocationHead(value)}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import clsx from 'clsx';
|
||||||
import { MiniButton } from '@/components/control';
|
import { MiniButton } from '@/components/control';
|
||||||
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened } from '@/components/icons';
|
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened } from '@/components/icons';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
|
|
||||||
import { useFolders } from '../backend/use-folders';
|
import { useFolders } from '../backend/use-folders';
|
||||||
import { labelFolderNode } from '../labels';
|
import { labelFolderNode } from '../labels';
|
||||||
|
@ -51,7 +52,7 @@ export function SelectLocation({ value, dense, prefix, onClick, className, style
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col cc-scroll-y', className)} style={style}>
|
<div className={cn('flex flex-col cc-scroll-y', className)} style={style}>
|
||||||
{items.map((item, index) =>
|
{items.map((item, index) =>
|
||||||
!item.parent || !folded.includes(item.parent) ? (
|
!item.parent || !folded.includes(item.parent) ? (
|
||||||
<div
|
<div
|
||||||
|
@ -61,10 +62,10 @@ export function SelectLocation({ value, dense, prefix, onClick, className, style
|
||||||
!dense && 'h-7 sm:h-8',
|
!dense && 'h-7 sm:h-8',
|
||||||
'pr-3 py-1 flex items-center gap-2',
|
'pr-3 py-1 flex items-center gap-2',
|
||||||
'cc-scroll-row',
|
'cc-scroll-row',
|
||||||
'clr-hover cc-animate-color',
|
'cc-hover cc-animate-color',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
'leading-3 sm:leading-4',
|
'leading-3 sm:leading-4',
|
||||||
activeNode === item && 'clr-selected'
|
activeNode === item && 'cc-selected'
|
||||||
)}
|
)}
|
||||||
style={{ paddingLeft: `${(item.rank > 5 ? 5 : item.rank) * 0.5 + 0.5}rem` }}
|
style={{ paddingLeft: `${(item.rank > 5 ? 5 : item.rank) * 0.5 + 0.5}rem` }}
|
||||||
onClick={event => onClick(event, item)}
|
onClick={event => onClick(event, item)}
|
||||||
|
@ -90,9 +91,9 @@ export function SelectLocation({ value, dense, prefix, onClick, className, style
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
{item.filesInside ? (
|
{item.filesInside ? (
|
||||||
<IconFolder size='1rem' className='clr-text-default' />
|
<IconFolder size='1rem' className='text-foreground' />
|
||||||
) : (
|
) : (
|
||||||
<IconFolderEmpty size='1rem' className='clr-text-controls' />
|
<IconFolderEmpty size='1rem' className='cc-controls' />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/components/utils';
|
||||||
|
|
||||||
import { labelVersion } from '../../rsform/labels';
|
import { labelVersion } from '../../rsform/labels';
|
||||||
import { type IVersionInfo } from '../backend/types';
|
import { type IVersionInfo } from '../backend/types';
|
||||||
|
|
|
@ -66,9 +66,9 @@ export function ToolbarItemAccess({
|
||||||
aria-label='Переключатель режима изменения'
|
aria-label='Переключатель режима изменения'
|
||||||
icon={
|
icon={
|
||||||
readOnly ? (
|
readOnly ? (
|
||||||
<IconImmutable size='1.25rem' className='text-sec-600' />
|
<IconImmutable size='1.25rem' className='text-primary' />
|
||||||
) : (
|
) : (
|
||||||
<IconMutable size='1.25rem' className='text-ok-600' />
|
<IconMutable size='1.25rem' className='text-constructive' />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={toggleReadOnly}
|
onClick={toggleReadOnly}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { urls, useConceptNavigation } from '@/app';
|
import { urls, useConceptNavigation } from '@/app';
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
|
@ -10,6 +8,7 @@ import { useRoleStore, UserRole } from '@/features/users';
|
||||||
|
|
||||||
import { MiniButton } from '@/components/control';
|
import { MiniButton } from '@/components/control';
|
||||||
import { IconDestroy, IconSave, IconShare } from '@/components/icons';
|
import { IconDestroy, IconSave, IconShare } from '@/components/icons';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { useModificationStore } from '@/stores/modification';
|
import { useModificationStore } from '@/stores/modification';
|
||||||
import { tooltipText } from '@/utils/labels';
|
import { tooltipText } from '@/utils/labels';
|
||||||
import { prepareTooltip, sharePage } from '@/utils/utils';
|
import { prepareTooltip, sharePage } from '@/utils/utils';
|
||||||
|
@ -51,7 +50,7 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('cc-icons', className)}>
|
<div className={cn('cc-icons', className)}>
|
||||||
{ossSelector}
|
{ossSelector}
|
||||||
{isMutable || isModified ? (
|
{isMutable || isModified ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
IconUserSearch
|
IconUserSearch
|
||||||
} from '@/components/icons';
|
} from '@/components/icons';
|
||||||
import { SearchBar } from '@/components/input';
|
import { SearchBar } from '@/components/input';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
import { tripleToggleColor } from '@/utils/utils';
|
import { tripleToggleColor } from '@/utils/utils';
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex gap-3 border-b text-sm clr-input items-center', className)}>
|
<div className={cn('flex gap-3 border-b text-sm bg-input items-center', className)}>
|
||||||
<div className='ml-3 min-w-18 sm:min-w-30 select-none whitespace-nowrap'>
|
<div className='ml-3 min-w-18 sm:min-w-30 select-none whitespace-nowrap'>
|
||||||
{filtered} из {total}
|
{filtered} из {total}
|
||||||
</div>
|
</div>
|
||||||
|
@ -143,7 +144,6 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
||||||
className='relative flex items-center h-full select-none'
|
className='relative flex items-center h-full select-none'
|
||||||
>
|
>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
|
||||||
className='rounded-lg py-1'
|
className='rounded-lg py-1'
|
||||||
titleHtml={
|
titleHtml={
|
||||||
(head ? describeLocationHead(head) : 'Выберите каталог') + '<br/><kbd>Ctrl + клик</kbd> - Проводник'
|
(head ? describeLocationHead(head) : 'Выберите каталог') + '<br/><kbd>Ctrl + клик</kbd> - Проводник'
|
||||||
|
@ -153,7 +153,7 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
||||||
head ? (
|
head ? (
|
||||||
<IconLocationHead value={head} size='1.25rem' />
|
<IconLocationHead value={head} size='1.25rem' />
|
||||||
) : (
|
) : (
|
||||||
<IconFolderSearch size='1.25rem' className='clr-text-controls' />
|
<IconFolderSearch size='1.25rem' className='cc-controls' />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={handleFolderClick}
|
onClick={handleFolderClick}
|
||||||
|
@ -164,13 +164,13 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='проводник...'
|
text='проводник...'
|
||||||
title='Переключение в режим Проводник'
|
title='Переключение в режим Проводник'
|
||||||
icon={<IconFolderTree size='1rem' className='clr-text-controls' />}
|
icon={<IconFolderTree size='1rem' className='cc-controls' />}
|
||||||
onClick={handleToggleFolder}
|
onClick={handleToggleFolder}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='отображать все'
|
text='отображать все'
|
||||||
title='Очистить фильтр по расположению'
|
title='Очистить фильтр по расположению'
|
||||||
icon={<IconFolder size='1rem' className='clr-text-controls' />}
|
icon={<IconFolder size='1rem' className='cc-controls' />}
|
||||||
onClick={() => handleChange(null)}
|
onClick={() => handleChange(null)}
|
||||||
/>
|
/>
|
||||||
{Object.values(LocationHead).map((head, index) => {
|
{Object.values(LocationHead).map((head, index) => {
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function useLibraryColumns() {
|
||||||
noHover
|
noHover
|
||||||
className='pl-2 max-h-4 -translate-y-0.5'
|
className='pl-2 max-h-4 -translate-y-0.5'
|
||||||
onClick={handleToggleFolder}
|
onClick={handleToggleFolder}
|
||||||
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
|
icon={<IconFolderTree size='1.25rem' className='cc-controls' />}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
size: 50,
|
size: 50,
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { type DomIconProps, IconMoveDown, IconMoveUp } from '@/components/icons'
|
||||||
/** Icon for relocation direction. */
|
/** Icon for relocation direction. */
|
||||||
export function IconRelocationUp({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
export function IconRelocationUp({ value, size = '1.25rem', className }: DomIconProps<boolean>) {
|
||||||
if (value) {
|
if (value) {
|
||||||
return <IconMoveUp size={size} className={className ?? 'text-sec-600'} />;
|
return <IconMoveUp size={size} className={className ?? 'text-primary'} />;
|
||||||
} else {
|
} else {
|
||||||
return <IconMoveDown size={size} className={className ?? 'text-sec-600'} />;
|
return <IconMoveDown size={size} className={className ?? 'text-primary'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { MiniButton } from '@/components/control';
|
import { MiniButton } from '@/components/control';
|
||||||
import { createColumnHelper, DataTable } from '@/components/data-table';
|
import { createColumnHelper, DataTable } from '@/components/data-table';
|
||||||
import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/icons';
|
import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/icons';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { NoData } from '@/components/view';
|
import { NoData } from '@/components/view';
|
||||||
|
|
||||||
import { type IOperation } from '../models/oss';
|
import { type IOperation } from '../models/oss';
|
||||||
|
@ -107,7 +107,7 @@ export function PickMultiOperation({ rows, items, value, onChange, className, ..
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col gap-1 border-t border-x rounded-md clr-input', className)} {...restProps}>
|
<div className={cn('flex flex-col gap-1 border-t border-x rounded-md bg-input', className)} {...restProps}>
|
||||||
<SelectOperation
|
<SelectOperation
|
||||||
noBorder
|
noBorder
|
||||||
items={nonSelectedItems} //
|
items={nonSelectedItems} //
|
||||||
|
|
|
@ -99,7 +99,7 @@ export function DlgCreateOperation() {
|
||||||
helpTopic={HelpTopic.CC_OSS}
|
helpTopic={HelpTopic.CC_OSS}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='grid'
|
className='grid'
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={(index, last) => handleSelectTab(index as TabID, last as TabID)}
|
onSelect={(index, last) => handleSelectTab(index as TabID, last as TabID)}
|
||||||
|
|
|
@ -71,7 +71,7 @@ export function DlgEditOperation() {
|
||||||
hideHelpWhen={() => activeTab !== TabID.SUBSTITUTION}
|
hideHelpWhen={() => activeTab !== TabID.SUBSTITUTION}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='grid'
|
className='grid'
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={index => setActiveTab(index as TabID)}
|
onSelect={index => setActiveTab(index as TabID)}
|
||||||
|
|
|
@ -119,7 +119,7 @@ export function DlgRelocateConstituents() {
|
||||||
helpTopic={HelpTopic.UI_RELOCATE_CST}
|
helpTopic={HelpTopic.UI_RELOCATE_CST}
|
||||||
>
|
>
|
||||||
<div className='flex flex-col border'>
|
<div className='flex flex-col border'>
|
||||||
<div className='flex gap-1 items-center clr-input border-b rounded-t-md'>
|
<div className='flex gap-1 items-center bg-input border-b rounded-t-md'>
|
||||||
<SelectLibraryItem
|
<SelectLibraryItem
|
||||||
noBorder
|
noBorder
|
||||||
className='w-1/2'
|
className='w-1/2'
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { IconDownload, IconRSForm, IconRSFormImported, IconRSFormOwned, IconSynthesis } from '@/components/icons';
|
import { IconDownload, IconRSForm, IconRSFormImported, IconRSFormOwned, IconSynthesis } from '@/components/icons';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { ValueStats } from '@/components/view';
|
import { ValueStats } from '@/components/view';
|
||||||
|
|
||||||
import { type IOperationSchemaStats } from '../../../models/oss';
|
import { type IOperationSchemaStats } from '../../../models/oss';
|
||||||
|
@ -12,7 +11,7 @@ interface OssStatsProps {
|
||||||
|
|
||||||
export function OssStats({ className, stats }: OssStatsProps) {
|
export function OssStats({ className, stats }: OssStatsProps) {
|
||||||
return (
|
return (
|
||||||
<div className={clsx('grid grid-cols-3 gap-1 justify-items-end', className)}>
|
<div className={cn('grid grid-cols-3 gap-1 justify-items-end', className)}>
|
||||||
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
||||||
<span>Всего</span>
|
<span>Всего</span>
|
||||||
<span>{stats.count_operations}</span>
|
<span>{stats.count_operations}</span>
|
||||||
|
@ -20,32 +19,32 @@ export function OssStats({ className, stats }: OssStatsProps) {
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_inputs'
|
id='count_inputs'
|
||||||
title='Загрузка'
|
title='Загрузка'
|
||||||
icon={<IconDownload size='1.25rem' className='text-sec-600' />}
|
icon={<IconDownload size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_inputs}
|
value={stats.count_inputs}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_synthesis'
|
id='count_synthesis'
|
||||||
title='Синтез'
|
title='Синтез'
|
||||||
icon={<IconSynthesis size='1.25rem' className='text-sec-600' />}
|
icon={<IconSynthesis size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_synthesis}
|
value={stats.count_synthesis}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_schemas'
|
id='count_schemas'
|
||||||
title='Прикрепленные схемы'
|
title='Прикрепленные схемы'
|
||||||
icon={<IconRSForm size='1.25rem' className='text-sec-600' />}
|
icon={<IconRSForm size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_schemas}
|
value={stats.count_schemas}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_owned'
|
id='count_owned'
|
||||||
title='Собственные'
|
title='Собственные'
|
||||||
icon={<IconRSFormOwned size='1.25rem' className='text-sec-600' />}
|
icon={<IconRSFormOwned size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_owned}
|
value={stats.count_owned}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_imported'
|
id='count_imported'
|
||||||
title='Внешние'
|
title='Внешние'
|
||||||
icon={<IconRSFormImported size='1.25rem' className='text-sec-600' />}
|
icon={<IconRSFormImported size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_schemas - stats.count_owned}
|
value={stats.count_schemas - stats.count_owned}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,13 +34,13 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
<Indicator
|
<Indicator
|
||||||
noPadding
|
noPadding
|
||||||
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
|
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
|
||||||
icon={<IconRSForm className={hasFile ? 'text-ok-600' : 'text-warn-600'} size='12px' />}
|
icon={<IconRSForm className={hasFile ? 'text-constructive' : 'text-destructive'} size='12px' />}
|
||||||
/>
|
/>
|
||||||
{node.data.operation.is_consolidation ? (
|
{node.data.operation.is_consolidation ? (
|
||||||
<Indicator
|
<Indicator
|
||||||
noPadding
|
noPadding
|
||||||
titleHtml='<b>Внимание!</b><br />Ромбовидный синтез</br/>Возможны дубликаты конституент'
|
titleHtml='<b>Внимание!</b><br />Ромбовидный синтез</br/>Возможны дубликаты конституент'
|
||||||
icon={<IconConsolidation className='text-sec-600' size='12px' />}
|
icon={<IconConsolidation className='text-primary' size='12px' />}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,7 +50,7 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!node.data.operation.is_owned ? (
|
{!node.data.operation.is_owned ? (
|
||||||
<div className='absolute left-[2px] top-[6px] border-r rounded-none clr-input h-[22px]' />
|
<div className='absolute left-[2px] top-[6px] border-r rounded-none bg-input h-[22px]' />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useReactFlow } from 'reactflow';
|
import { useReactFlow } from 'reactflow';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
|
@ -24,6 +23,7 @@ import {
|
||||||
IconSave
|
IconSave
|
||||||
} from '@/components/icons';
|
} from '@/components/icons';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { prepareTooltip } from '@/utils/utils';
|
import { prepareTooltip } from '@/utils/utils';
|
||||||
|
@ -119,10 +119,10 @@ export function ToolbarOssGraph({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={cn(
|
||||||
'flex flex-col items-center pt-1',
|
'flex flex-col items-center pt-1',
|
||||||
'rounded-b-2xl',
|
'rounded-b-2xl',
|
||||||
'hover:bg-prim-100 hover:bg-opacity-50 backdrop-blur-xs',
|
'hover:bg-background backdrop-blur-xs',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export function MenuMain() {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title='Меню'
|
title='Меню'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
icon={<IconMenu size='1.25rem' className='clr-text-controls' />}
|
icon={<IconMenu size='1.25rem' className='cc-controls' />}
|
||||||
className='h-full pl-2'
|
className='h-full pl-2'
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -58,7 +58,7 @@ export function OssTabs({ activeTab }: OssTabsProps) {
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={onSelectTab}
|
onSelect={onSelectTab}
|
||||||
defaultFocus
|
defaultFocus
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='relative flex flex-col mx-auto min-w-fit items-center'
|
className='relative flex flex-col mx-auto min-w-fit items-center'
|
||||||
>
|
>
|
||||||
<TabList className='absolute z-sticky flex border-b-2 border-x-2 divide-x-2 bg-prim-200'>
|
<TabList className='absolute z-sticky flex border-b-2 border-x-2 divide-x-2 bg-prim-200'>
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface BadgeGrammemeProps {
|
||||||
export function BadgeGrammeme({ grammeme }: BadgeGrammemeProps) {
|
export function BadgeGrammeme({ grammeme }: BadgeGrammemeProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='min-w-12 px-1 border rounded-md text-sm font-medium text-center whitespace-nowrap bg-prim-0'
|
className='min-w-12 px-1 border rounded-md text-sm font-medium text-center whitespace-nowrap bg-card'
|
||||||
style={{
|
style={{
|
||||||
borderColor: colorFgGrammeme(grammeme),
|
borderColor: colorFgGrammeme(grammeme),
|
||||||
color: colorFgGrammeme(grammeme)
|
color: colorFgGrammeme(grammeme)
|
||||||
|
|
|
@ -8,12 +8,12 @@ export function IconCstMatchMode({ value, size = '1.25rem', className }: DomIcon
|
||||||
case CstMatchMode.ALL:
|
case CstMatchMode.ALL:
|
||||||
return <IconFilter size={size} className={className} />;
|
return <IconFilter size={size} className={className} />;
|
||||||
case CstMatchMode.TEXT:
|
case CstMatchMode.TEXT:
|
||||||
return <IconText size={size} className={className ?? 'text-sec-600'} />;
|
return <IconText size={size} className={className ?? 'text-primary'} />;
|
||||||
case CstMatchMode.EXPR:
|
case CstMatchMode.EXPR:
|
||||||
return <IconFormula size={size} className={className ?? 'text-sec-600'} />;
|
return <IconFormula size={size} className={className ?? 'text-primary'} />;
|
||||||
case CstMatchMode.TERM:
|
case CstMatchMode.TERM:
|
||||||
return <IconTerm size={size} className={className ?? 'text-sec-600'} />;
|
return <IconTerm size={size} className={className ?? 'text-primary'} />;
|
||||||
case CstMatchMode.NAME:
|
case CstMatchMode.NAME:
|
||||||
return <IconAlias size={size} className={className ?? 'text-sec-600'} />;
|
return <IconAlias size={size} className={className ?? 'text-primary'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,20 @@ import { CstType } from '../backend/types';
|
||||||
export function IconCstType({ value, size = '1.25rem', className }: DomIconProps<CstType>) {
|
export function IconCstType({ value, size = '1.25rem', className }: DomIconProps<CstType>) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case CstType.BASE:
|
case CstType.BASE:
|
||||||
return <IconCstBaseSet size={size} className={className ?? 'text-ok-600'} />;
|
return <IconCstBaseSet size={size} className={className ?? 'text-constructive'} />;
|
||||||
case CstType.CONSTANT:
|
case CstType.CONSTANT:
|
||||||
return <IconCstConstSet size={size} className={className ?? 'text-ok-600'} />;
|
return <IconCstConstSet size={size} className={className ?? 'text-constructive'} />;
|
||||||
case CstType.STRUCTURED:
|
case CstType.STRUCTURED:
|
||||||
return <IconCstStructured size={size} className={className ?? 'text-ok-600'} />;
|
return <IconCstStructured size={size} className={className ?? 'text-constructive'} />;
|
||||||
case CstType.TERM:
|
case CstType.TERM:
|
||||||
return <IconCstTerm size={size} className={className ?? 'text-sec-600'} />;
|
return <IconCstTerm size={size} className={className ?? 'text-primary'} />;
|
||||||
case CstType.AXIOM:
|
case CstType.AXIOM:
|
||||||
return <IconCstAxiom size={size} className={className ?? 'text-warn-600'} />;
|
return <IconCstAxiom size={size} className={className ?? 'text-destructive'} />;
|
||||||
case CstType.FUNCTION:
|
case CstType.FUNCTION:
|
||||||
return <IconCstFunction size={size} className={className ?? 'text-sec-600'} />;
|
return <IconCstFunction size={size} className={className ?? 'text-primary'} />;
|
||||||
case CstType.PREDICATE:
|
case CstType.PREDICATE:
|
||||||
return <IconCstPredicate size={size} className={className ?? 'text-warn-600'} />;
|
return <IconCstPredicate size={size} className={className ?? 'text-destructive'} />;
|
||||||
case CstType.THEOREM:
|
case CstType.THEOREM:
|
||||||
return <IconCstTheorem size={size} className={className ?? 'text-warn-600'} />;
|
return <IconCstTheorem size={size} className={className ?? 'text-destructive'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ export function IconDependencyMode({ value, size = '1.25rem', className }: DomIc
|
||||||
case DependencyMode.ALL:
|
case DependencyMode.ALL:
|
||||||
return <IconSettings size={size} className={className} />;
|
return <IconSettings size={size} className={className} />;
|
||||||
case DependencyMode.OUTPUTS:
|
case DependencyMode.OUTPUTS:
|
||||||
return <IconGraphOutputs size={size} className={className ?? 'text-sec-600'} />;
|
return <IconGraphOutputs size={size} className={className ?? 'text-primary'} />;
|
||||||
case DependencyMode.INPUTS:
|
case DependencyMode.INPUTS:
|
||||||
return <IconGraphInputs size={size} className={className ?? 'text-sec-600'} />;
|
return <IconGraphInputs size={size} className={className ?? 'text-primary'} />;
|
||||||
case DependencyMode.EXPAND_OUTPUTS:
|
case DependencyMode.EXPAND_OUTPUTS:
|
||||||
return <IconGraphExpand size={size} className={className ?? 'text-sec-600'} />;
|
return <IconGraphExpand size={size} className={className ?? 'text-primary'} />;
|
||||||
case DependencyMode.EXPAND_INPUTS:
|
case DependencyMode.EXPAND_INPUTS:
|
||||||
return <IconGraphCollapse size={size} className={className ?? 'text-sec-600'} />;
|
return <IconGraphCollapse size={size} className={className ?? 'text-primary'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
||||||
import { SearchBar } from '@/components/input';
|
import { SearchBar } from '@/components/input';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { NoData } from '@/components/view';
|
import { NoData } from '@/components/view';
|
||||||
import { APP_COLORS } from '@/styling/colors';
|
import { APP_COLORS } from '@/styling/colors';
|
||||||
|
|
||||||
|
@ -73,10 +73,10 @@ export function PickConstituenta({
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('border', className)} {...restProps}>
|
<div className={cn('border', className)} {...restProps}>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
id={id ? `${id}__search` : undefined}
|
id={id ? `${id}__search` : undefined}
|
||||||
className='clr-input border-b rounded-t-md'
|
className='bg-input border-b rounded-t-md'
|
||||||
noBorder
|
noBorder
|
||||||
query={filterText}
|
query={filterText}
|
||||||
onChangeQuery={newValue => setFilterText(newValue)}
|
onChangeQuery={newValue => setFilterText(newValue)}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { createColumnHelper, DataTable, type RowSelectionState } from '@/components/data-table';
|
import { createColumnHelper, DataTable, type RowSelectionState } from '@/components/data-table';
|
||||||
import { SearchBar } from '@/components/input';
|
import { SearchBar } from '@/components/input';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { NoData } from '@/components/view';
|
import { NoData } from '@/components/view';
|
||||||
import { Graph } from '@/models/graph';
|
import { Graph } from '@/models/graph';
|
||||||
|
|
||||||
|
@ -98,8 +98,8 @@ export function PickMultiConstituenta({
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(!noBorder && 'border', className)} {...restProps}>
|
<div className={cn(!noBorder && 'border', className)} {...restProps}>
|
||||||
<div className='px-3 flex justify-between items-center clr-input border-b rounded-t-md'>
|
<div className='px-3 flex justify-between items-center bg-input border-b rounded-t-md'>
|
||||||
<div className='w-[24ch] select-none whitespace-nowrap'>
|
<div className='w-[24ch] select-none whitespace-nowrap'>
|
||||||
{items.length > 0 ? `Выбраны ${value.length} из ${items.length}` : 'Конституенты'}
|
{items.length > 0 ? `Выбраны ${value.length} из ${items.length}` : 'Конституенты'}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { type ILibraryItem } from '@/features/library';
|
import { type ILibraryItem } from '@/features/library';
|
||||||
import { SelectLibraryItem } from '@/features/library/components';
|
import { SelectLibraryItem } from '@/features/library/components';
|
||||||
|
@ -11,6 +10,7 @@ import { MiniButton } from '@/components/control';
|
||||||
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
import { createColumnHelper, DataTable, type IConditionalStyle } from '@/components/data-table';
|
||||||
import { IconAccept, IconPageLeft, IconPageRight, IconRemove, IconReplace } from '@/components/icons';
|
import { IconAccept, IconPageLeft, IconPageRight, IconRemove, IconReplace } from '@/components/icons';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { NoData } from '@/components/view';
|
import { NoData } from '@/components/view';
|
||||||
import { APP_COLORS } from '@/styling/colors';
|
import { APP_COLORS } from '@/styling/colors';
|
||||||
import { errorMsg } from '@/utils/labels';
|
import { errorMsg } from '@/utils/labels';
|
||||||
|
@ -229,9 +229,9 @@ export function PickSubstitutions({
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col', className)} {...restProps}>
|
<div className={cn('flex flex-col', className)} {...restProps}>
|
||||||
<div className='flex items-center gap-3'>
|
<div className='flex items-center gap-3'>
|
||||||
<div className='w-60 grow flex flex-col basis-1/2 gap-1 border-x border-t clr-input rounded-t-md'>
|
<div className='w-60 grow flex flex-col basis-1/2 gap-1 border-x border-t bg-input rounded-t-md'>
|
||||||
<SelectLibraryItem
|
<SelectLibraryItem
|
||||||
id='substitute-left-schema'
|
id='substitute-left-schema'
|
||||||
noBorder
|
noBorder
|
||||||
|
@ -248,9 +248,9 @@ export function PickSubstitutions({
|
||||||
onClick={toggleDelete}
|
onClick={toggleDelete}
|
||||||
icon={
|
icon={
|
||||||
deleteRight ? (
|
deleteRight ? (
|
||||||
<IconPageRight size='1.5rem' className='text-sec-600' />
|
<IconPageRight size='1.5rem' className='text-primary' />
|
||||||
) : (
|
) : (
|
||||||
<IconPageLeft size='1.5rem' className='text-sec-600' />
|
<IconPageLeft size='1.5rem' className='text-primary' />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -263,7 +263,7 @@ export function PickSubstitutions({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-60 grow basis-1/2 flex flex-col gap-1 border-x border-t clr-input rounded-t-md'>
|
<div className='w-60 grow basis-1/2 flex flex-col gap-1 border-x border-t bg-input rounded-t-md'>
|
||||||
<SelectLibraryItem
|
<SelectLibraryItem
|
||||||
id='substitute-right-schema'
|
id='substitute-right-schema'
|
||||||
noBorder
|
noBorder
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/components/utils';
|
||||||
|
|
||||||
import { CstType } from '../backend/types';
|
import { CstType } from '../backend/types';
|
||||||
import { labelCstType } from '../labels';
|
import { labelCstType } from '../labels';
|
||||||
|
|
|
@ -21,8 +21,8 @@ export function WordformButton({ text, example, grams, onSelectGrams, isSelected
|
||||||
'p-1',
|
'p-1',
|
||||||
'border rounded-none',
|
'border rounded-none',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
'clr-text-controls clr-hover cc-animate-color',
|
'cc-controls cc-hover cc-animate-color',
|
||||||
isSelected && 'clr-selected'
|
isSelected && 'cc-selected'
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -124,7 +124,7 @@ export function FormCreateCst({ schema }: FormCreateCstProps) {
|
||||||
id='dlg_cst_show_comment'
|
id='dlg_cst_show_comment'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
type='button'
|
type='button'
|
||||||
className='self-start cc-label text-sec-600 hover:underline select-none'
|
className='self-start cc-label text-primary hover:underline select-none'
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
>
|
>
|
||||||
Добавить комментарий
|
Добавить комментарий
|
||||||
|
|
|
@ -71,7 +71,7 @@ export function DlgCstTemplate() {
|
||||||
helpTopic={HelpTopic.RSL_TEMPLATES}
|
helpTopic={HelpTopic.RSL_TEMPLATES}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='grid'
|
className='grid'
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={index => setActiveTab(index as TabID)}
|
onSelect={index => setActiveTab(index as TabID)}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export function TabTemplate() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in'>
|
<div className='cc-fade-in'>
|
||||||
<div className='flex gap-1 border-t border-x rounded-t-md clr-input'>
|
<div className='flex gap-1 border-t border-x rounded-t-md bg-input'>
|
||||||
<ComboBox
|
<ComboBox
|
||||||
value={selectedTemplate ?? null}
|
value={selectedTemplate ?? null}
|
||||||
items={templates}
|
items={templates}
|
||||||
|
|
|
@ -105,7 +105,7 @@ export function DlgEditReference() {
|
||||||
className='w-160 px-6 h-128'
|
className='w-160 px-6 h-128'
|
||||||
helpTopic={HelpTopic.TERM_CONTROL}
|
helpTopic={HelpTopic.TERM_CONTROL}
|
||||||
>
|
>
|
||||||
<Tabs selectedTabClassName='clr-selected' className='grid' selectedIndex={activeTab} onSelect={handleChangeTab}>
|
<Tabs selectedTabClassName='cc-selected' className='grid' selectedIndex={activeTab} onSelect={handleChangeTab}>
|
||||||
<TabList className='mb-3 mx-auto flex border divide-x rounded-none bg-prim-200'>
|
<TabList className='mb-3 mx-auto flex border divide-x rounded-none bg-prim-200'>
|
||||||
<TabLabel title='Отсылка на термин в заданной словоформе' label={labelReferenceType(ReferenceType.ENTITY)} />
|
<TabLabel title='Отсылка на термин в заданной словоформе' label={labelReferenceType(ReferenceType.ENTITY)} />
|
||||||
<TabLabel
|
<TabLabel
|
||||||
|
|
|
@ -59,7 +59,7 @@ export function DlgInlineSynthesis() {
|
||||||
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
|
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='grid'
|
className='grid'
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={index => setActiveTab(index as TabID)}
|
onSelect={index => setActiveTab(index as TabID)}
|
||||||
|
|
|
@ -39,7 +39,7 @@ export function DlgShowAST() {
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'absolute z-pop top-2 right-1/2 translate-x-1/2 max-w-[60ch]',
|
'absolute z-pop top-2 right-1/2 translate-x-1/2 max-w-[60ch]',
|
||||||
'px-2 rounded-2xl',
|
'px-2 rounded-2xl',
|
||||||
'backdrop-blur-xs bg-prim-100/90',
|
'backdrop-blur-xs bg-background/90',
|
||||||
'text-lg text-center'
|
'text-lg text-center'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -47,7 +47,7 @@ export function DlgShowAST() {
|
||||||
{!isDragging && hoverNodeDebounced ? (
|
{!isDragging && hoverNodeDebounced ? (
|
||||||
<div key={hoverNodeDebounced.uid}>
|
<div key={hoverNodeDebounced.uid}>
|
||||||
<span>{expression.slice(0, hoverNodeDebounced.start)}</span>
|
<span>{expression.slice(0, hoverNodeDebounced.start)}</span>
|
||||||
<span className='bg-sec-200 cc-animate-background starting:bg-prim-100 duration-500'>
|
<span className='bg-selected cc-animate-background starting:bg-background duration-500'>
|
||||||
{expression.slice(hoverNodeDebounced.start, hoverNodeDebounced.finish)}
|
{expression.slice(hoverNodeDebounced.start, hoverNodeDebounced.finish)}
|
||||||
</span>
|
</span>
|
||||||
<span>{expression.slice(hoverNodeDebounced.finish)}</span>
|
<span>{expression.slice(hoverNodeDebounced.finish)}</span>
|
||||||
|
|
|
@ -194,7 +194,7 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
readOnly
|
readOnly
|
||||||
label='Типизация'
|
label='Типизация'
|
||||||
value={typification}
|
value={typification}
|
||||||
className='clr-text-default cursor-default'
|
className='cursor-default'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!!activeCst.definition_formal || !isElementary ? (
|
{!!activeCst.definition_formal || !isElementary ? (
|
||||||
|
@ -266,7 +266,7 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className='self-start cc-label text-sec-600 hover:underline select-none'
|
className='self-start cc-label text-primary hover:underline select-none'
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
>
|
>
|
||||||
Добавить комментарий
|
Добавить комментарий
|
||||||
|
@ -283,13 +283,13 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
<div className='absolute z-pop top-1/2 -translate-y-1/2 left-full cc-icons'>
|
<div className='absolute z-pop top-1/2 -translate-y-1/2 left-full cc-icons'>
|
||||||
{activeCst.has_inherited_children && !activeCst.is_inherited ? (
|
{activeCst.has_inherited_children && !activeCst.is_inherited ? (
|
||||||
<Indicator
|
<Indicator
|
||||||
icon={<IconPredecessor size='1.25rem' className='text-sec-600' />}
|
icon={<IconPredecessor size='1.25rem' className='text-primary' />}
|
||||||
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
|
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{activeCst.is_inherited ? (
|
{activeCst.is_inherited ? (
|
||||||
<Indicator
|
<Indicator
|
||||||
icon={<IconChild size='1.25rem' className='text-sec-600' />}
|
icon={<IconChild size='1.25rem' className='text-primary' />}
|
||||||
titleHtml='Внимание!</br> Конституента является наследником<br/>'
|
titleHtml='Внимание!</br> Конституента является наследником<br/>'
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -25,7 +25,7 @@ export function ParsingResult({ isOpen, data, disabled, onShowError }: ParsingRe
|
||||||
<p
|
<p
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
key={`error-${index}`}
|
key={`error-${index}`}
|
||||||
className={`text-warn-600 break-all ${disabled ? '' : 'cursor-pointer'}`}
|
className={`text-destructive break-all ${disabled ? '' : 'cursor-pointer'}`}
|
||||||
onClick={disabled ? undefined : () => onShowError(error)}
|
onClick={disabled ? undefined : () => onShowError(error)}
|
||||||
>
|
>
|
||||||
<span className='mr-1 font-semibold underline'>
|
<span className='mr-1 font-semibold underline'>
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function RSLocalButton({
|
||||||
'w-7 sm:w-8 h-5 sm:h-6',
|
'w-7 sm:w-8 h-5 sm:h-6',
|
||||||
'cursor-pointer disabled:cursor-default',
|
'cursor-pointer disabled:cursor-default',
|
||||||
'rounded-none',
|
'rounded-none',
|
||||||
'clr-hover clr-text-controls cc-animate-color',
|
'cc-hover cc-controls cc-animate-color',
|
||||||
'font-math',
|
'font-math',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -22,7 +22,7 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
|
||||||
'h-5 sm:h-6',
|
'h-5 sm:h-6',
|
||||||
'px-1',
|
'px-1',
|
||||||
'outline-hidden',
|
'outline-hidden',
|
||||||
'clr-hover clr-text-controls cc-animate-color',
|
'cc-hover cc-controls cc-animate-color',
|
||||||
'font-math',
|
'font-math',
|
||||||
'cursor-pointer disabled:cursor-default',
|
'cursor-pointer disabled:cursor-default',
|
||||||
label.length > 3 ? 'w-14.5 md:w-18' : 'w-7.25 md:w-9'
|
label.length > 3 ? 'w-14.5 md:w-18' : 'w-7.25 md:w-9'
|
||||||
|
|
|
@ -39,12 +39,12 @@ export function RSFormStats({ className, stats, isArchive }: RSFormStatsProps) {
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_owned'
|
id='count_owned'
|
||||||
title='Собственные'
|
title='Собственные'
|
||||||
icon={<IconPredecessor size='1.25rem' className='text-sec-600' />}
|
icon={<IconPredecessor size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_all - stats.count_inherited}
|
value={stats.count_all - stats.count_inherited}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_inherited'
|
id='count_inherited'
|
||||||
icon={<IconChild size='1.25rem' className='text-sec-600' />}
|
icon={<IconChild size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_inherited}
|
value={stats.count_inherited}
|
||||||
titleHtml={isArchive ? 'Архивные схемы не хранят<br/> информацию о наследовании' : 'Наследованные'}
|
titleHtml={isArchive ? 'Архивные схемы не хранят<br/> информацию о наследовании' : 'Наследованные'}
|
||||||
/>
|
/>
|
||||||
|
@ -53,94 +53,94 @@ export function RSFormStats({ className, stats, isArchive }: RSFormStatsProps) {
|
||||||
id='count_ok'
|
id='count_ok'
|
||||||
title='Корректные'
|
title='Корректные'
|
||||||
className='col-start-1'
|
className='col-start-1'
|
||||||
icon={<IconStatusOK size='1.25rem' className='text-ok-600' />}
|
icon={<IconStatusOK size='1.25rem' className='text-constructive' />}
|
||||||
value={stats.count_all - stats.count_errors - stats.count_property - stats.count_incalculable}
|
value={stats.count_all - stats.count_errors - stats.count_property - stats.count_incalculable}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_property'
|
id='count_property'
|
||||||
title='Неразмерные'
|
title='Неразмерные'
|
||||||
icon={<IconStatusProperty size='1.25rem' className='text-sec-600' />}
|
icon={<IconStatusProperty size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_errors}
|
value={stats.count_errors}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_incalculable'
|
id='count_incalculable'
|
||||||
title='Невычислимые'
|
title='Невычислимые'
|
||||||
icon={<IconStatusIncalculable size='1.25rem' className='text-warn-600' />}
|
icon={<IconStatusIncalculable size='1.25rem' className='text-destructive' />}
|
||||||
value={stats.count_incalculable}
|
value={stats.count_incalculable}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_errors'
|
id='count_errors'
|
||||||
title='Некорректные'
|
title='Некорректные'
|
||||||
icon={<IconStatusError size='1.25rem' className='text-warn-600' />}
|
icon={<IconStatusError size='1.25rem' className='text-destructive' />}
|
||||||
value={stats.count_errors}
|
value={stats.count_errors}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_base'
|
id='count_base'
|
||||||
title='Базисные множества'
|
title='Базисные множества'
|
||||||
icon={<IconCstBaseSet size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstBaseSet size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_base}
|
value={stats.count_base}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_constant'
|
id='count_constant'
|
||||||
title='Константные множества'
|
title='Константные множества'
|
||||||
icon={<IconCstConstSet size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstConstSet size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_constant}
|
value={stats.count_constant}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_structured'
|
id='count_structured'
|
||||||
title='Родовые структуры'
|
title='Родовые структуры'
|
||||||
icon={<IconCstStructured size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstStructured size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_structured}
|
value={stats.count_structured}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_axiom'
|
id='count_axiom'
|
||||||
title='Аксиомы'
|
title='Аксиомы'
|
||||||
icon={<IconCstAxiom size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstAxiom size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_axiom}
|
value={stats.count_axiom}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_term'
|
id='count_term'
|
||||||
title='Термы'
|
title='Термы'
|
||||||
icon={<IconCstTerm size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstTerm size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_term}
|
value={stats.count_term}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_function'
|
id='count_function'
|
||||||
title='Терм-функции'
|
title='Терм-функции'
|
||||||
icon={<IconCstFunction size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstFunction size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_function}
|
value={stats.count_function}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_predicate'
|
id='count_predicate'
|
||||||
title='Предикат-функции'
|
title='Предикат-функции'
|
||||||
icon={<IconCstPredicate size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstPredicate size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_predicate}
|
value={stats.count_predicate}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_theorem'
|
id='count_theorem'
|
||||||
title='Теоремы'
|
title='Теоремы'
|
||||||
icon={<IconCstTheorem size='1.25rem' className='clr-text-controls' />}
|
icon={<IconCstTheorem size='1.25rem' className='cc-controls' />}
|
||||||
value={stats.count_theorem}
|
value={stats.count_theorem}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_text_term'
|
id='count_text_term'
|
||||||
title='Термины'
|
title='Термины'
|
||||||
icon={<IconTerminology size='1.25rem' className='text-sec-600' />}
|
icon={<IconTerminology size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_text_term}
|
value={stats.count_text_term}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_definition'
|
id='count_definition'
|
||||||
title='Определения'
|
title='Определения'
|
||||||
icon={<IconDefinition size='1.25rem' className='text-sec-600' />}
|
icon={<IconDefinition size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_definition}
|
value={stats.count_definition}
|
||||||
/>
|
/>
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_convention'
|
id='count_convention'
|
||||||
title='Конвенции'
|
title='Конвенции'
|
||||||
icon={<IconConvention size='1.25rem' className='text-sec-600' />}
|
icon={<IconConvention size='1.25rem' className='text-primary' />}
|
||||||
value={stats.count_convention}
|
value={stats.count_convention}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function TGNode(node: TGNodeInternal) {
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-full h-full cursor-default flex items-center justify-center rounded-full',
|
'w-full h-full cursor-default flex items-center justify-center rounded-full',
|
||||||
isFocused && 'border-2 border-sec-200',
|
isFocused && 'border-2 border-selected',
|
||||||
label.length > LABEL_THRESHOLD ? 'text-[12px]/[16px]' : 'text-[14px]/[20px]'
|
label.length > LABEL_THRESHOLD ? 'text-[12px]/[16px]' : 'text-[14px]/[20px]'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function SelectColoring() {
|
||||||
const setColoring = useTermGraphStore(state => state.setColoring);
|
const setColoring = useTermGraphStore(state => state.setColoring);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative border rounded-b-none select-none clr-input rounded-t-md pointer-events-auto'>
|
<div className='relative border rounded-b-none select-none bg-input rounded-t-md pointer-events-auto'>
|
||||||
<div className='absolute z-pop right-10 h-9 flex items-center'>
|
<div className='absolute z-pop right-10 h-9 flex items-center'>
|
||||||
{coloring === 'status' ? <BadgeHelp topic={HelpTopic.UI_CST_STATUS} contentClass='min-w-100' /> : null}
|
{coloring === 'status' ? <BadgeHelp topic={HelpTopic.UI_CST_STATUS} contentClass='min-w-100' /> : null}
|
||||||
{coloring === 'type' ? <BadgeHelp topic={HelpTopic.UI_CST_CLASS} contentClass='min-w-100' /> : null}
|
{coloring === 'type' ? <BadgeHelp topic={HelpTopic.UI_CST_CLASS} contentClass='min-w-100' /> : null}
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function ViewHidden({ items }: ViewHiddenProps) {
|
||||||
onClick={toggleFolded}
|
onClick={toggleFolded}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={clsx('py-2 clr-input border-x', isFolded && 'border-b rounded-b-md')}>
|
<div className={clsx('py-2 bg-input border-x', isFolded && 'border-b rounded-b-md')}>
|
||||||
<div className={clsx('w-fit select-none cc-view-hidden-header', !isFolded && 'open')}>
|
<div className={clsx('w-fit select-none cc-view-hidden-header', !isFolded && 'open')}>
|
||||||
{`Скрытые [${localSelected.length} | ${items.length}]`}
|
{`Скрытые [${localSelected.length} | ${items.length}]`}
|
||||||
</div>
|
</div>
|
||||||
|
@ -65,7 +65,7 @@ export function ViewHidden({ items }: ViewHiddenProps) {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'cc-view-hidden-list flex flex-wrap gap-2 justify-center py-2 -mt-2',
|
'cc-view-hidden-list flex flex-wrap gap-2 justify-center py-2 -mt-2',
|
||||||
'border-x border-b rounded-b-md bg-prim-0',
|
'border-x border-b rounded-b-md bg-popover',
|
||||||
'text-sm',
|
'text-sm',
|
||||||
'cc-scroll-y',
|
'cc-scroll-y',
|
||||||
!isFolded && 'open'
|
!isFolded && 'open'
|
||||||
|
|
|
@ -121,7 +121,7 @@ export function MenuMain() {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title='Меню'
|
title='Меню'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
icon={<IconMenu size='1.25rem' className='clr-text-controls' />}
|
icon={<IconMenu size='1.25rem' className='cc-controls' />}
|
||||||
className='h-full pl-2'
|
className='h-full pl-2'
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -76,7 +76,7 @@ export function RSTabs({ activeID, activeTab }: RSTabsProps) {
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
onSelect={onSelectTab}
|
onSelect={onSelectTab}
|
||||||
defaultFocus
|
defaultFocus
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='cc-selected'
|
||||||
className='relative flex flex-col min-w-fit items-center'
|
className='relative flex flex-col min-w-fit items-center'
|
||||||
>
|
>
|
||||||
<TabList className='absolute z-sticky flex border-b-2 border-x-2 divide-x-2 bg-prim-200'>
|
<TabList className='absolute z-sticky flex border-b-2 border-x-2 divide-x-2 bg-prim-200'>
|
||||||
|
|
|
@ -27,7 +27,7 @@ export function ConstituentsSearch({ dense }: ConstituentsSearchProps) {
|
||||||
const schema = useRSEdit().schema;
|
const schema = useRSEdit().schema;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex border-b clr-input rounded-t-md'>
|
<div className='flex border-b bg-input rounded-t-md'>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
id='constituents_search'
|
id='constituents_search'
|
||||||
noBorder
|
noBorder
|
||||||
|
@ -42,7 +42,7 @@ export function ConstituentsSearch({ dense }: ConstituentsSearchProps) {
|
||||||
noHover
|
noHover
|
||||||
titleHtml={`Наследованные: <b>${includeInherited ? 'отображать' : 'скрывать'}</b>`}
|
titleHtml={`Наследованные: <b>${includeInherited ? 'отображать' : 'скрывать'}</b>`}
|
||||||
aria-label={`Отображение наследованных: ${includeInherited ? 'отображать' : 'скрывать'}`}
|
aria-label={`Отображение наследованных: ${includeInherited ? 'отображать' : 'скрывать'}`}
|
||||||
icon={<IconChild size='1rem' className={includeInherited ? 'icon-primary' : 'clr-text-controls'} />}
|
icon={<IconChild size='1rem' className={includeInherited ? 'icon-primary' : 'cc-controls'} />}
|
||||||
className='h-fit self-center'
|
className='h-fit self-center'
|
||||||
onClick={toggleInherited}
|
onClick={toggleInherited}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { SelectorButton } from '@/components/control';
|
import { SelectorButton } from '@/components/control';
|
||||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { useWindowSize } from '@/hooks/use-window-size';
|
import { useWindowSize } from '@/hooks/use-window-size';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -28,9 +27,8 @@ export function SelectGraphFilter({ value, dense, className, onChange, ...restPr
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} onBlur={menu.handleBlur} className={clsx('relative', className)} {...restProps}>
|
<div ref={menu.ref} onBlur={menu.handleBlur} className={cn('relative', className)} {...restProps}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
titleHtml='Настройка фильтрации <br/>по графу термов'
|
titleHtml='Настройка фильтрации <br/>по графу термов'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { SelectorButton } from '@/components/control';
|
import { SelectorButton } from '@/components/control';
|
||||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
import { useWindowSize } from '@/hooks/use-window-size';
|
import { useWindowSize } from '@/hooks/use-window-size';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -28,9 +27,8 @@ export function SelectMatchMode({ value, dense, className, onChange, ...restProp
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} onBlur={menu.handleBlur} className={clsx('relative', className)} {...restProps}>
|
<div ref={menu.ref} onBlur={menu.handleBlur} className={cn('relative', className)} {...restProps}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
|
||||||
titleHtml='Настройка фильтрации <br/>по проверяемым атрибутам'
|
titleHtml='Настройка фильтрации <br/>по проверяемым атрибутам'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
|
|
|
@ -156,16 +156,16 @@ function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
||||||
if ('email' in error.response.data) {
|
if ('email' in error.response.data) {
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
<div className='mx-auto text-sm select-text text-warn-600'>{error.response.data.email}</div>
|
<div className='mx-auto text-sm select-text text-destructive'>{error.response.data.email}</div>
|
||||||
);
|
);
|
||||||
} else if ('username' in error.response.data) {
|
} else if ('username' in error.response.data) {
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
<div className='mx-auto text-sm select-text text-warn-600'>{error.response.data.username}</div>
|
<div className='mx-auto text-sm select-text text-destructive'>{error.response.data.username}</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className='mx-auto text-sm select-text text-warn-600'>
|
<div className='mx-auto text-sm select-text text-destructive'>
|
||||||
<PrettyJson data={error.response} />
|
<PrettyJson data={error.response} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -77,7 +77,7 @@ export function EditorPassword() {
|
||||||
// ====== Internals =========
|
// ====== Internals =========
|
||||||
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
function ServerError({ error }: { error: ErrorData }): React.ReactElement {
|
||||||
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
if (isAxiosError(error) && error.response && error.response.status === 400) {
|
||||||
return <div className='text-sm select-text text-warn-600'>Неверно введен старый пароль</div>;
|
return <div className='text-sm select-text text-destructive'>Неверно введен старый пароль</div>;
|
||||||
}
|
}
|
||||||
throw error as Error;
|
throw error as Error;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user