mirror of
https://github.com/magnum-opus-nn-cp/frontend.git
synced 2024-11-22 09:36:36 +03:00
feat(response): add response page layout
This commit is contained in:
parent
dbfd8e8b4f
commit
b2285e263b
|
@ -5,11 +5,10 @@ import {AppRoutes} from './routes';
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet title={"Pitch Deck"}>
|
<Helmet title={'Press-release analyzer'}>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { ChatPage } from '../../pages/chat';
|
||||||
import { HomePage } from '../../pages/home';
|
import { HomePage } from '../../pages/home';
|
||||||
import { DefaultLayout } from '../../pages/_layouts/DefaultLayout';
|
import { DefaultLayout } from '../../pages/_layouts/DefaultLayout';
|
||||||
import { TextPage } from '../../pages/text';
|
import { TextPage } from '../../pages/text';
|
||||||
import { CHAT_PAGE_ROUTE, HOME_PAGE_ROUTE, TEXT_PAGE_ROUTE } from './routes';
|
import { ResponsePage } from '../../pages/response';
|
||||||
|
import { CHAT_PAGE_ROUTE, HOME_PAGE_ROUTE, RESPONSE_PAGE_ROUTE, TEXT_PAGE_ROUTE } from './routes';
|
||||||
|
|
||||||
export const AppRoutes = () => {
|
export const AppRoutes = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -11,6 +12,7 @@ export const AppRoutes = () => {
|
||||||
<Route element={<DefaultLayout />}>
|
<Route element={<DefaultLayout />}>
|
||||||
<Route path={CHAT_PAGE_ROUTE} element={<ChatPage />} />
|
<Route path={CHAT_PAGE_ROUTE} element={<ChatPage />} />
|
||||||
<Route path={HOME_PAGE_ROUTE} element={<HomePage />} />
|
<Route path={HOME_PAGE_ROUTE} element={<HomePage />} />
|
||||||
|
<Route path={RESPONSE_PAGE_ROUTE} element={<ResponsePage />} />
|
||||||
<Route path={TEXT_PAGE_ROUTE} element={<TextPage />} />
|
<Route path={TEXT_PAGE_ROUTE} element={<TextPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
export const CHAT_PAGE_ROUTE = `/chat`;
|
export const CHAT_PAGE_ROUTE = `/chat`;
|
||||||
export const HOME_PAGE_ROUTE = `/`;
|
export const HOME_PAGE_ROUTE = `/`;
|
||||||
|
|
||||||
|
export const RESPONSE_PAGE_PARAM = 'processId';
|
||||||
|
export const RESPONSE_PAGE_ROUTE = `/response/:${RESPONSE_PAGE_PARAM}`;
|
||||||
|
|
||||||
export const TEXT_PAGE_PARAM = 'textId';
|
export const TEXT_PAGE_PARAM = 'textId';
|
||||||
export const TEXT_PAGE_ROUTE = `/text/:${TEXT_PAGE_PARAM}`;
|
export const TEXT_PAGE_ROUTE = `/text/:${TEXT_PAGE_PARAM}`;
|
||||||
|
|
|
@ -103,7 +103,7 @@ $line-height-67: 67px;
|
||||||
|
|
||||||
@mixin text-body-s-regular {
|
@mixin text-body-s-regular {
|
||||||
font-family: $font-family-inter, $font-family-default;
|
font-family: $font-family-inter, $font-family-default;
|
||||||
font-size: $font-size-12;
|
font-size: $font-size-14;
|
||||||
font-weight: $font-weight-400;
|
font-weight: $font-weight-400;
|
||||||
line-height: $line-height-18;
|
line-height: $line-height-18;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,3 +34,7 @@ a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scroll-prevented {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
67
src/components/Modal/Modal.module.scss
Normal file
67
src/components/Modal/Modal.module.scss
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.Modal {
|
||||||
|
position: fixed;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: $color-text-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal__overlay {
|
||||||
|
@include transition(opacity);
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
z-index: $z-index-overlay;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal__content {
|
||||||
|
@include transition(opacity);
|
||||||
|
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
border-radius: $radius-large;
|
||||||
|
background: var(--bg-color);
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
@include media-down(tablet-small) {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal_entering,
|
||||||
|
.Modal_entered {
|
||||||
|
.Modal__overlay {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal__content {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal_exiting,
|
||||||
|
.Modal_exited {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.Modal__overlay {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Modal__content {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
35
src/components/Modal/Modal.tsx
Normal file
35
src/components/Modal/Modal.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { ReactNode, useRef } from 'react';
|
||||||
|
import { Transition } from 'react-transition-group';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Portal } from '../Portal';
|
||||||
|
import { usePreventWindowScroll } from '../../hooks/usePreventWindowScroll';
|
||||||
|
import s from './Modal.module.scss';
|
||||||
|
|
||||||
|
export interface ModalProps {
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
isOpen?: boolean;
|
||||||
|
onClose?: () => void;
|
||||||
|
isClosing?: boolean;
|
||||||
|
preventWindowScroll?: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Modal = (props: ModalProps) => {
|
||||||
|
const { className, children, isOpen, onClose, isClosing, preventWindowScroll } = props;
|
||||||
|
|
||||||
|
const nodeRef = useRef(null);
|
||||||
|
usePreventWindowScroll(preventWindowScroll ?? isOpen);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Portal>
|
||||||
|
<Transition unmountOnExit nodeRef={nodeRef} timeout={200} in={isOpen && !isClosing}>
|
||||||
|
{(state) => (
|
||||||
|
<div ref={nodeRef} className={clsx(s.Modal, s[`Modal_${state}`], className)}>
|
||||||
|
<div onClick={onClose} className={s.Modal__overlay} />
|
||||||
|
<div className={s.Modal__content}>{isOpen && children}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
11
src/components/Modal/ModalBody/ModalBody.module.scss
Normal file
11
src/components/Modal/ModalBody/ModalBody.module.scss
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.ModalBody {
|
||||||
|
@include scrollbar;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
@include media-down(tablet-small) {
|
||||||
|
border-radius: 0 0 $radius-small $radius-small;
|
||||||
|
}
|
||||||
|
}
|
15
src/components/Modal/ModalBody/ModalBody.tsx
Normal file
15
src/components/Modal/ModalBody/ModalBody.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { memo } from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { ReactFCC } from '../../../utils/ReactFCC';
|
||||||
|
import s from './ModalBody.module.scss';
|
||||||
|
|
||||||
|
export interface ModalBodyProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModalBody: ReactFCC<ModalBodyProps> = memo((props) => {
|
||||||
|
const { children, className } = props;
|
||||||
|
|
||||||
|
return <div className={clsx(s.ModalBody, className)}>{children}</div>;
|
||||||
|
});
|
||||||
|
ModalBody.displayName = 'ModalBody';
|
1
src/components/Modal/ModalBody/index.ts
Normal file
1
src/components/Modal/ModalBody/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './ModalBody';
|
|
@ -0,0 +1,32 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.ModalContainer {
|
||||||
|
@include media-down(tablet-small) {
|
||||||
|
padding: $spacing-small $spacing-small-x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ModalContainer__wrapper {
|
||||||
|
display: flex;
|
||||||
|
width: 600px;
|
||||||
|
max-height: calc(100vh - $spacing-medium-x * 2);
|
||||||
|
background: $color-background-primary;
|
||||||
|
padding: $spacing-small;
|
||||||
|
|
||||||
|
&_borderRadius {
|
||||||
|
border-radius: $radius-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-down(tablet-small) {
|
||||||
|
width: 100%;
|
||||||
|
max-height: calc(100vh - $spacing-small * 2);
|
||||||
|
margin-top: auto;
|
||||||
|
background: $color-background-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ModalContainer__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
36
src/components/Modal/ModalContainer/ModalContainer.tsx
Normal file
36
src/components/Modal/ModalContainer/ModalContainer.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Modal } from '../Modal';
|
||||||
|
import s from './ModalContainer.module.scss';
|
||||||
|
|
||||||
|
export interface ModalContainerProps {
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onClose?: () => void;
|
||||||
|
isOpen: boolean;
|
||||||
|
isClosing?: boolean;
|
||||||
|
withBorderRadius?: boolean;
|
||||||
|
preventWindowScroll?: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModalContainer = (props: ModalContainerProps) => {
|
||||||
|
const { isClosing, className, children, isOpen, onClose, withBorderRadius = true, preventWindowScroll } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className={clsx(s.ModalContainer, {})}
|
||||||
|
onClose={onClose}
|
||||||
|
isClosing={isClosing}
|
||||||
|
isOpen={isOpen}
|
||||||
|
preventWindowScroll={preventWindowScroll}>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
s.ModalContainer__wrapper,
|
||||||
|
{ [s.ModalContainer__wrapper_borderRadius]: withBorderRadius },
|
||||||
|
className
|
||||||
|
)}>
|
||||||
|
<div className={s.ModalContainer__content}>{children}</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
1
src/components/Modal/ModalContainer/index.ts
Normal file
1
src/components/Modal/ModalContainer/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './ModalContainer';
|
5
src/components/Modal/index.ts
Normal file
5
src/components/Modal/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './Modal';
|
||||||
|
export * from './ModalContainer';
|
||||||
|
export * from './ModalBody';
|
||||||
|
export * from './useModal';
|
||||||
|
// export * from './ModalAlert';
|
72
src/components/Modal/useModal.ts
Normal file
72
src/components/Modal/useModal.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export interface UseModalProps {
|
||||||
|
onClose?: () => void;
|
||||||
|
isOpen?: boolean;
|
||||||
|
canClose?: boolean;
|
||||||
|
}
|
||||||
|
const ANIMATION_DURATION = 200;
|
||||||
|
|
||||||
|
export function useModal(props: UseModalProps) {
|
||||||
|
const { isOpen, canClose: canCloseProp = true, onClose } = props;
|
||||||
|
|
||||||
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
|
const [modalIsVisible, setModalIsVisible] = useState(false);
|
||||||
|
const [canClose, setCanClose] = useState(false);
|
||||||
|
|
||||||
|
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
if (canClose && canCloseProp && onClose) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}, [canClose, canCloseProp, onClose]);
|
||||||
|
|
||||||
|
const onKeyDown = useCallback(
|
||||||
|
(evt: KeyboardEvent) => {
|
||||||
|
if (evt.key === 'Escape') {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[close]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
setModalIsVisible(true);
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
setCanClose(true);
|
||||||
|
window.addEventListener('keydown', onKeyDown);
|
||||||
|
}, ANIMATION_DURATION);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', onKeyDown);
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOpen) {
|
||||||
|
setIsClosing(true);
|
||||||
|
setCanClose(false);
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
setModalIsVisible(false);
|
||||||
|
setIsClosing(false);
|
||||||
|
}, ANIMATION_DURATION);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [isOpen, onKeyDown]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isClosing,
|
||||||
|
close,
|
||||||
|
modalIsVisible,
|
||||||
|
ANIMATION_DURATION
|
||||||
|
};
|
||||||
|
}
|
16
src/components/Portal/Portal.tsx
Normal file
16
src/components/Portal/Portal.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
import { ReactFCC } from '../../utils/ReactFCC';
|
||||||
|
|
||||||
|
interface PortalProps {
|
||||||
|
element?: Element | DocumentFragment | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Portal: ReactFCC<PortalProps> = (props) => {
|
||||||
|
const { children, element = document.body } = props;
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createPortal(children, element);
|
||||||
|
};
|
1
src/components/Portal/index.ts
Normal file
1
src/components/Portal/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './Portal';
|
13
src/hooks/usePreventWindowScroll.ts
Normal file
13
src/hooks/usePreventWindowScroll.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
|
export const usePreventWindowScroll = (isPrevented?: boolean) => {
|
||||||
|
const preventScroll = useCallback((isPrevented: boolean) => {
|
||||||
|
document.body.classList.toggle('scroll-prevented', isPrevented);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
preventScroll(!!isPrevented);
|
||||||
|
}, [isPrevented, preventScroll]);
|
||||||
|
|
||||||
|
return preventScroll;
|
||||||
|
};
|
78
src/pages/response/ResponsePage.module.scss
Normal file
78
src/pages/response/ResponsePage.module.scss
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.ResponsePage {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResponsePage__title {
|
||||||
|
margin-bottom: $spacing-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResponsePage__container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
@include mobile-down {
|
||||||
|
@include flex-col;
|
||||||
|
row-gap: $spacing-small-2x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResponsePage__table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-radius: $radius-small;
|
||||||
|
border-style: hidden;
|
||||||
|
box-shadow: 0 0 0 1px $color-border-default;
|
||||||
|
|
||||||
|
tbody tr {
|
||||||
|
@include transition(background-color);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $color-background-secondary;
|
||||||
|
|
||||||
|
td {
|
||||||
|
border-color: $color-border-hover;
|
||||||
|
|
||||||
|
&, > span {
|
||||||
|
color: $color-text-brand !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResponsePage__tableSummary {
|
||||||
|
//opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: $color-button-secondary-hover-fill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: $spacing-small-3x $spacing-small-2x;
|
||||||
|
border: 1px solid $color-border-default;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
@include transition(border-color, color);
|
||||||
|
|
||||||
|
&.ResponsePage__tableSummary {
|
||||||
|
@include transition(opacity);
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
@include transition(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
src/pages/response/ResponsePage.tsx
Normal file
108
src/pages/response/ResponsePage.tsx
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { Heading, HeadingSize } from '../../components/Heading';
|
||||||
|
import { Link } from '../../components/Link';
|
||||||
|
import { getPercentageColor } from '../../utils/getPercentageColor';
|
||||||
|
import { EMDASH } from '../../utils/chars';
|
||||||
|
import { ModalBody, useModal, ModalContainer } from '../../components/Modal';
|
||||||
|
import { useIsMobile } from '../../hooks/useIsMobile';
|
||||||
|
import { TextItem } from './components';
|
||||||
|
import s from './ResponsePage.module.scss';
|
||||||
|
|
||||||
|
export const ResponsePage: FC = () => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
}, []);
|
||||||
|
const { modalIsVisible, isClosing, close } = useModal({ isOpen, onClose });
|
||||||
|
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.ResponsePage}>
|
||||||
|
<Heading size={HeadingSize.H2} className={s.ResponsePage__title}>
|
||||||
|
Результаты по запросу
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<div className={s.ResponsePage__container}>
|
||||||
|
{isMobile ? (
|
||||||
|
<>
|
||||||
|
<TextItem onClickSummary={() => setIsOpen(true)} />
|
||||||
|
<TextItem />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<table className={s.ResponsePage__table}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Имя</th>
|
||||||
|
<th>М. н-с.</th>
|
||||||
|
<th>М. стат.</th>
|
||||||
|
<th>М. п.</th>
|
||||||
|
<th>Рез.</th>
|
||||||
|
<th>Крат. сод.</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td>file.txt</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td className={s.ResponsePage__tableSummary}>
|
||||||
|
<Link standalone={false}>Открыть</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td>{EMDASH}</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
AA+ | <span style={{ color: getPercentageColor(0.95) }}>0.95</span>
|
||||||
|
</td>
|
||||||
|
<td className={s.ResponsePage__tableSummary}>
|
||||||
|
<Link
|
||||||
|
component={'button'}
|
||||||
|
standalone={false}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsOpen(true);
|
||||||
|
}}>
|
||||||
|
Открыть
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ModalContainer isOpen={modalIsVisible} onClose={close} isClosing={isClosing}>
|
||||||
|
<ModalBody>
|
||||||
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys
|
||||||
|
standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to
|
||||||
|
make a type specimen book.
|
||||||
|
</ModalBody>
|
||||||
|
</ModalContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
33
src/pages/response/components/TextItem/TextItem.module.scss
Normal file
33
src/pages/response/components/TextItem/TextItem.module.scss
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
@import 'src/app/styles/vars';
|
||||||
|
|
||||||
|
.TextItem {
|
||||||
|
background-color: $color-background-dark-100;
|
||||||
|
border-radius: $radius-medium;
|
||||||
|
padding: $spacing-small-2x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextItem__row {
|
||||||
|
margin-bottom: $spacing-small-4x;
|
||||||
|
|
||||||
|
&:not(.TextItem__row_name) {
|
||||||
|
> span {
|
||||||
|
font-size: $font-size-14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextItem__row_name {
|
||||||
|
margin-bottom: $spacing-small-3x;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextItem__name {
|
||||||
|
//font-size: $font-size-18;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: $font-weight-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextItem__row_link {
|
||||||
|
margin-top: $spacing-small-3x;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
62
src/pages/response/components/TextItem/TextItem.tsx
Normal file
62
src/pages/response/components/TextItem/TextItem.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { ReactFCC } from '../../../../utils/ReactFCC';
|
||||||
|
import { ETextVariants, Text } from '../../../../components/Text';
|
||||||
|
import { getPercentageColor } from '../../../../utils/getPercentageColor';
|
||||||
|
import { Link } from '../../../../components/Link';
|
||||||
|
import s from './TextItem.module.scss';
|
||||||
|
|
||||||
|
export interface TextItemProps {
|
||||||
|
/**
|
||||||
|
* Дополнительный css-класс
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
|
||||||
|
onClickSummary?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TextItem: ReactFCC<TextItemProps> = (props) => {
|
||||||
|
const { className, onClickSummary } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(s.TextItem, className)}>
|
||||||
|
<div className={clsx(s.TextItem__row, s.TextItem__row_name)}>
|
||||||
|
{/*<Text component={'span'} variant={ETextVariants.BODY_S_MEDIUM}>*/}
|
||||||
|
{/* Имя:*/}
|
||||||
|
{/*</Text>{' '}*/}
|
||||||
|
<Text className={s.TextItem__name} component={'span'} variant={ETextVariants.PROGRAMMING_CODE_REGULAR}>
|
||||||
|
file.txt #1
|
||||||
|
</Text>
|
||||||
|
{/*{' | '}*/}
|
||||||
|
{/*<Text component={'span'} variant={ETextVariants.BODY_S_REGULAR}>*/}
|
||||||
|
{/* file.txt*/}
|
||||||
|
{/*</Text>*/}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={s.TextItem__row}>
|
||||||
|
<Text component={'span'} variant={ETextVariants.PROGRAMMING_CODE_REGULAR}>
|
||||||
|
М. н-с: AA+ | <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
|
</Text>{' '}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={s.TextItem__row}>
|
||||||
|
<Text component={'span'} variant={ETextVariants.PROGRAMMING_CODE_REGULAR}>
|
||||||
|
М. стат: AA+ | <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
|
</Text>{' '}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={s.TextItem__row}>
|
||||||
|
<Text component={'span'} variant={ETextVariants.PROGRAMMING_CODE_REGULAR}>
|
||||||
|
М. п: AA+ | <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
|
</Text>{' '}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={clsx(s.TextItem__row, s.TextItem__row_link)}>
|
||||||
|
<Text component={'span'} variant={ETextVariants.BODY_S_REGULAR}>
|
||||||
|
<Link component={'button'} standalone={false} onClick={() => onClickSummary?.()}>
|
||||||
|
Краткое содержание
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
src/pages/response/components/TextItem/index.ts
Normal file
1
src/pages/response/components/TextItem/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './TextItem';
|
1
src/pages/response/components/index.ts
Normal file
1
src/pages/response/components/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './TextItem';
|
1
src/pages/response/index.ts
Normal file
1
src/pages/response/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './ResponsePage';
|
|
@ -42,7 +42,7 @@ export const TextPage: FC = () => {
|
||||||
Результат по методу{' '}
|
Результат по методу{' '}
|
||||||
<Tooltip className={s.TextPage__tooltip} content={'Berd + Annoy'}>
|
<Tooltip className={s.TextPage__tooltip} content={'Berd + Annoy'}>
|
||||||
<span className={s.TextPage__underline}>похожести</span>
|
<span className={s.TextPage__underline}>похожести</span>
|
||||||
</Tooltip>{' '}
|
</Tooltip>
|
||||||
: АА+ | Accuracy: <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
: АА+ | Accuracy: <span style={{ color: getPercentageColor(0.63) }}>0.63</span>
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
21
src/utils/chars.ts
Normal file
21
src/utils/chars.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// eslint-disable
|
||||||
|
export const LAQUO = '\u00AB'; // «
|
||||||
|
export const RAQUO = '\u00BB'; // »
|
||||||
|
export const EMDASH = '\u2014'; // —
|
||||||
|
export const THINSP = '\u2009'; //
|
||||||
|
export const QUARTERSP = '\u2005'; //
|
||||||
|
export const THIRDSP = '\u2004'; //
|
||||||
|
export const ENSP = '\u2002'; //
|
||||||
|
export const EMSP = '\u2001'; //
|
||||||
|
export const NBSP = '\u00A0'; //
|
||||||
|
export const HELLIP = '\u2026'; // …
|
||||||
|
export const LSAQUO = '\u2039'; // ‹
|
||||||
|
export const RSAQUO = '\u203A'; // ›
|
||||||
|
export const RUBLE = '\u20BD'; // ₽
|
||||||
|
export const LEQ = '\u2264'; // ≤
|
||||||
|
export const NEQ = '\u2260'; // ≠
|
||||||
|
export const GEQ = '\u2265'; // ≥
|
||||||
|
export const ARROW_LEFT = '\u2190'; // ←
|
||||||
|
export const ARROW_RIGHT = '\u2192'; // →
|
||||||
|
export const MAC_OPTION = '\u2325'; // ⌥
|
||||||
|
// eslint-enable
|
Loading…
Reference in New Issue
Block a user