mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-28 22:26:41 +07:00
Compare commits
No commits in common. "9e79cba7bffb1cf340c871c77613e63f56e9302a" and "f0606a894a3291b3beb399ba4a14e9c973b04b24" have entirely different histories.
9e79cba7bf
...
f0606a894a
21 changed files with 243 additions and 250 deletions
|
@ -27,8 +27,8 @@
|
||||||
&.new {
|
&.new {
|
||||||
&::after {
|
&::after {
|
||||||
content: ' ';
|
content: ' ';
|
||||||
width: 8px;
|
width: 12px;
|
||||||
height: 8px;
|
height: 12px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
background: $color_danger;
|
background: $color_danger;
|
||||||
box-shadow: $content_bg 0 0 0 5px;
|
box-shadow: $content_bg 0 0 0 5px;
|
||||||
|
|
|
@ -13,11 +13,9 @@ interface Props extends DivProps {
|
||||||
|
|
||||||
const SubTitle: FC<Props> = ({ isLoading, children, ...rest }) => (
|
const SubTitle: FC<Props> = ({ isLoading, children, ...rest }) => (
|
||||||
<div {...rest} className={classNames(styles.title, rest.className)}>
|
<div {...rest} className={classNames(styles.title, rest.className)}>
|
||||||
<span className={styles.name}>
|
|
||||||
<Placeholder active={isLoading} loading>
|
<Placeholder active={isLoading} loading>
|
||||||
{children}
|
{children}
|
||||||
</Placeholder>
|
</Placeholder>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,7 @@
|
||||||
@import 'src/styles/variables.scss';
|
@import "src/styles/variables.scss";
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font: $font_12_semibold;
|
font: $font_12_semibold;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
display: flex;
|
opacity: 0.3;
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: $gap / 2;
|
|
||||||
color: var(--gray_75);
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: ' ';
|
|
||||||
display: flex;
|
|
||||||
height: 2px;
|
|
||||||
background-color: var(--gray_90);
|
|
||||||
flex: 1;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
|
@ -5,5 +5,3 @@ export const isTablet = () => {
|
||||||
|
|
||||||
return window.innerWidth < 599;
|
return window.innerWidth < 599;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const headerHeight = 64; // px
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ interface Props {
|
||||||
|
|
||||||
const FlowCellMenu: FC<Props> = ({
|
const FlowCellMenu: FC<Props> = ({
|
||||||
onClose,
|
onClose,
|
||||||
currentView,
|
|
||||||
hasDescription,
|
hasDescription,
|
||||||
toggleViewDescription,
|
toggleViewDescription,
|
||||||
descriptionEnabled,
|
descriptionEnabled,
|
||||||
|
@ -60,7 +59,7 @@ const FlowCellMenu: FC<Props> = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasDescription && currentView !== 'single' && (
|
{hasDescription && (
|
||||||
<Group
|
<Group
|
||||||
className={styles.description}
|
className={styles.description}
|
||||||
horizontal
|
horizontal
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { FC, ReactElement } from 'react';
|
import { FC, ReactElement } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { transparentize, darken, desaturate, getLuminance } from 'color2k';
|
|
||||||
|
|
||||||
import { Markdown } from '~/components/common/Markdown';
|
import { Markdown } from '~/components/common/Markdown';
|
||||||
import { formatText } from '~/utils/dom';
|
import { formatText } from '~/utils/dom';
|
||||||
|
@ -12,29 +11,13 @@ import styles from './styles.module.scss';
|
||||||
interface Props extends DivProps {
|
interface Props extends DivProps {
|
||||||
children: string;
|
children: string;
|
||||||
heading: string | ReactElement;
|
heading: string | ReactElement;
|
||||||
color?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FlowCellText: FC<Props> = ({ children, heading, color, ...rest }) => {
|
const FlowCellText: FC<Props> = ({ children, heading, ...rest }) => (
|
||||||
const colorIsBright = !!color && getLuminance(color) > 0.4;
|
<div {...rest} className={classNames(styles.text, rest.className)}>
|
||||||
|
|
||||||
const textColor = colorIsBright
|
|
||||||
? desaturate(darken(color, 0.5), 0.1)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
{...rest}
|
|
||||||
className={classNames(styles.text, rest.className)}
|
|
||||||
style={{
|
|
||||||
backgroundColor: color && transparentize(color, 0.5),
|
|
||||||
color: textColor,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{heading && <div className={styles.heading}>{heading}</div>}
|
{heading && <div className={styles.heading}>{heading}</div>}
|
||||||
<Markdown className={styles.description}>{formatText(children)}</Markdown>
|
<Markdown className={styles.description}>{formatText(children)}</Markdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export { FlowCellText };
|
export { FlowCellText };
|
||||||
|
|
|
@ -1,24 +1,10 @@
|
||||||
@import 'src/styles/variables';
|
@import "src/styles/variables";
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
@include blur;
|
padding: $gap;
|
||||||
|
|
||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
mask-image: linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
rgba(255, 255, 255, 1) 50%,
|
|
||||||
rgba(0, 0, 0, 0) 95%
|
|
||||||
);
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
margin-bottom: 0.25em;
|
margin-bottom: 0.4em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FC, useCallback, useMemo } from 'react';
|
import { FC, useMemo } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ import { useWindowSize } from '~/hooks/dom/useWindowSize';
|
||||||
import { useFlowCellControls } from '~/hooks/flow/useFlowCellControls';
|
import { useFlowCellControls } from '~/hooks/flow/useFlowCellControls';
|
||||||
import { FlowDisplay, INode } from '~/types';
|
import { FlowDisplay, INode } from '~/types';
|
||||||
|
|
||||||
import { isFullyVisible } from '../../../../../utils/dom';
|
|
||||||
|
|
||||||
import { CellShade } from './components/CellShade';
|
import { CellShade } from './components/CellShade';
|
||||||
import { FlowCellImage } from './components/FlowCellImage';
|
import { FlowCellImage } from './components/FlowCellImage';
|
||||||
import { FlowCellMenu } from './components/FlowCellMenu';
|
import { FlowCellMenu } from './components/FlowCellMenu';
|
||||||
|
@ -27,7 +25,7 @@ interface Props {
|
||||||
text?: string;
|
text?: string;
|
||||||
flow: FlowDisplay;
|
flow: FlowDisplay;
|
||||||
canEdit?: boolean;
|
canEdit?: boolean;
|
||||||
onChange: (id: INode['id'], flow: FlowDisplay) => void;
|
onChangeCellView: (id: INode['id'], flow: FlowDisplay) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FlowCell: FC<Props> = ({
|
const FlowCell: FC<Props> = ({
|
||||||
|
@ -39,7 +37,7 @@ const FlowCell: FC<Props> = ({
|
||||||
text,
|
text,
|
||||||
title,
|
title,
|
||||||
canEdit = false,
|
canEdit = false,
|
||||||
onChange,
|
onChangeCellView,
|
||||||
}) => {
|
}) => {
|
||||||
const { isTablet } = useWindowSize();
|
const { isTablet } = useWindowSize();
|
||||||
|
|
||||||
|
@ -47,30 +45,6 @@ const FlowCell: FC<Props> = ({
|
||||||
((!!flow.display && flow.display !== 'single') || !image) &&
|
((!!flow.display && flow.display !== 'single') || !image) &&
|
||||||
flow.show_description &&
|
flow.show_description &&
|
||||||
!!text;
|
!!text;
|
||||||
|
|
||||||
const {
|
|
||||||
isActive: isMenuActive,
|
|
||||||
activate,
|
|
||||||
ref,
|
|
||||||
deactivate,
|
|
||||||
} = useClickOutsideFocus();
|
|
||||||
|
|
||||||
const onChangeWithScroll = useCallback<typeof onChange>(
|
|
||||||
(...args) => {
|
|
||||||
onChange(...args);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!isFullyVisible(ref.current)) {
|
|
||||||
ref.current?.scrollIntoView({
|
|
||||||
behavior: 'auto',
|
|
||||||
block: 'center',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
},
|
|
||||||
[onChange, ref],
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hasDescription,
|
hasDescription,
|
||||||
setViewHorizontal,
|
setViewHorizontal,
|
||||||
|
@ -78,7 +52,13 @@ const FlowCell: FC<Props> = ({
|
||||||
setViewQuadro,
|
setViewQuadro,
|
||||||
setViewSingle,
|
setViewSingle,
|
||||||
toggleViewDescription,
|
toggleViewDescription,
|
||||||
} = useFlowCellControls(id, text, flow, onChangeWithScroll);
|
} = useFlowCellControls(id, text, flow, onChangeCellView);
|
||||||
|
const {
|
||||||
|
isActive: isMenuActive,
|
||||||
|
activate,
|
||||||
|
ref,
|
||||||
|
deactivate,
|
||||||
|
} = useClickOutsideFocus();
|
||||||
|
|
||||||
const shadeSize = useMemo(() => {
|
const shadeSize = useMemo(() => {
|
||||||
const min = isTablet ? 10 : 15;
|
const min = isTablet ? 10 : 15;
|
||||||
|
@ -131,9 +111,8 @@ const FlowCell: FC<Props> = ({
|
||||||
<FlowCellText
|
<FlowCellText
|
||||||
className={styles.text}
|
className={styles.text}
|
||||||
heading={<h4 className={styles.title}>{title}</h4>}
|
heading={<h4 className={styles.title}>{title}</h4>}
|
||||||
color={color}
|
|
||||||
>
|
>
|
||||||
{text}
|
{text!}
|
||||||
</FlowCellText>
|
</FlowCellText>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -145,7 +124,7 @@ const FlowCell: FC<Props> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!!title && !withText && (
|
{!!title && (
|
||||||
<CellShade
|
<CellShade
|
||||||
color={color}
|
color={color}
|
||||||
className={styles.shade}
|
className={styles.shade}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
@import 'src/styles/variables';
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
$compact_size: 200px;
|
|
||||||
|
|
||||||
.cell {
|
.cell {
|
||||||
@include inner_shadow;
|
@include inner_shadow;
|
||||||
|
|
||||||
|
@ -11,7 +9,6 @@ $compact_size: 200px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: $content_bg;
|
background: $content_bg;
|
||||||
container: cell / inline-size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
|
@ -36,17 +33,20 @@ $compact_size: 200px;
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
left: 5px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
|
max-height: calc(100% - 10px);
|
||||||
|
max-width: calc(100% - 10px);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
inset: 50% 0 0 0;
|
font: $font_16_regular;
|
||||||
padding: $gap $gap * 1.5 0 $gap * 1.5;
|
|
||||||
font: $font_14_medium;
|
|
||||||
line-height: 1.25em;
|
|
||||||
|
|
||||||
@container (max-width: $compact_size) {
|
@include tablet {
|
||||||
padding: $gap / 2 $gap 0 $gap;
|
font: $font_14_regular;
|
||||||
|
left: 5px;
|
||||||
|
bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& :global(.grey) {
|
& :global(.grey) {
|
||||||
|
@ -54,34 +54,14 @@ $compact_size: 200px;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: #{$compact_size}) {
|
.quadro &,
|
||||||
padding: $gap / 2 $gap 0 $gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.horizontal &,
|
|
||||||
.quadro & {
|
|
||||||
@container (max-width: #{$compact_size * 2}) {
|
|
||||||
padding: $gap / 2 $gap 0 $gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.horizontal & {
|
.horizontal & {
|
||||||
inset: 0 calc(50% + $gap / 2) 0 0;
|
max-width: calc(50% - 15px);
|
||||||
border-radius: $radius 0 0 $radius;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quadro &,
|
||||||
.vertical & {
|
.vertical & {
|
||||||
inset: calc(50% + $gap / 2) 0 0 0;
|
max-height: calc(50% - 15px);
|
||||||
border-radius: 0 0 $radius $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quadro & {
|
|
||||||
inset: calc(50% + $gap / 2) calc(50% + $gap / 2) 0 0;
|
|
||||||
border-radius: 0 $radius 0 $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin-bottom: 0.1em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,21 +76,11 @@ $compact_size: 200px;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font: $font_cell_title;
|
font: $font_cell_title;
|
||||||
line-height: 1.2em;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
color: inherit;
|
|
||||||
margin-bottom: -0.125em;
|
|
||||||
|
|
||||||
@container (max-width: #{$compact_size}) {
|
@include tablet {
|
||||||
font: $font_cell_title_compact;
|
font: $font_18_semibold;
|
||||||
}
|
|
||||||
|
|
||||||
.horizontal &,
|
|
||||||
.quadro & {
|
|
||||||
@container (max-width: #{$compact_size * 2}) {
|
|
||||||
font: $font_cell_title_compact;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +107,12 @@ $compact_size: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.display_modal {
|
.display_modal {
|
||||||
|
@include appear;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const FlowGrid: FC<Props> = observer(
|
||||||
text={node.description}
|
text={node.description}
|
||||||
title={node.title}
|
title={node.title}
|
||||||
canEdit={fetched && isUser && canEditNode(node, user)}
|
canEdit={fetched && isUser && canEditNode(node, user)}
|
||||||
onChange={onChangeCellView}
|
onChangeCellView={onChangeCellView}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
@import 'src/styles/variables';
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
|
@mixin mobile {
|
||||||
|
@media (max-width: $cell * 2) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cell {
|
.cell {
|
||||||
&.horizontal,
|
&.horizontal,
|
||||||
&.quadro {
|
&.quadro {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
import { NodeHorizontalCard } from '~/components/common/NodeHorizontalCard';
|
||||||
|
import { IFlowNode } from '~/types';
|
||||||
|
|
||||||
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
recent: IFlowNode[];
|
||||||
|
updated: IFlowNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlowRecent: FC<Props> = ({ recent, updated }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.updates}>
|
||||||
|
{updated &&
|
||||||
|
updated.map((node) => (
|
||||||
|
<NodeHorizontalCard node={node} key={node.id} hasNew />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.recent}>
|
||||||
|
{recent &&
|
||||||
|
recent.map((node) => (
|
||||||
|
<NodeHorizontalCard node={node} key={node.id} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { FlowRecent };
|
|
@ -0,0 +1,7 @@
|
||||||
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
|
.recent {
|
||||||
|
@container sizer (width < #{$flow_hide_recents}) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,15 +2,17 @@ import { FC, FormEvent, useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { Card } from '~/components/common/Card';
|
import { Group } from '~/components/common/Group';
|
||||||
import { Icon } from '~/components/common/Icon';
|
import { Icon } from '~/components/common/Icon';
|
||||||
import { NodeHorizontalCard } from '~/components/common/NodeHorizontalCard';
|
import { Superpower } from '~/components/common/Superpower';
|
||||||
import { SubTitle } from '~/components/common/SubTitle';
|
|
||||||
import { InputText } from '~/components/input/InputText';
|
import { InputText } from '~/components/input/InputText';
|
||||||
|
import { Toggle } from '~/components/input/Toggle';
|
||||||
|
import { experimentalFeatures } from '~/constants/features';
|
||||||
import styles from '~/containers/flow/FlowStamp/styles.module.scss';
|
import styles from '~/containers/flow/FlowStamp/styles.module.scss';
|
||||||
import { useFlowContext } from '~/utils/providers/FlowProvider';
|
import { useFlowContext } from '~/utils/providers/FlowProvider';
|
||||||
import { useSearchContext } from '~/utils/providers/SearchProvider';
|
import { useSearchContext } from '~/utils/providers/SearchProvider';
|
||||||
|
|
||||||
|
import { FlowRecent } from './components/FlowRecent';
|
||||||
import { FlowSearchResults } from './components/FlowSearchResults';
|
import { FlowSearchResults } from './components/FlowSearchResults';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -62,8 +64,7 @@ const FlowStamp: FC<Props> = ({ isFluid, onToggleLayout }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrap}>
|
<div className={styles.wrap}>
|
||||||
<Card className={styles.search}>
|
<form className={styles.search} onSubmit={onSearchSubmit}>
|
||||||
<form onSubmit={onSearchSubmit}>
|
|
||||||
<InputText
|
<InputText
|
||||||
title="Поиск"
|
title="Поиск"
|
||||||
value={searchText}
|
value={searchText}
|
||||||
|
@ -72,11 +73,14 @@ const FlowStamp: FC<Props> = ({ isFluid, onToggleLayout }) => {
|
||||||
onKeyUp={onKeyUp}
|
onKeyUp={onKeyUp}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</Card>
|
|
||||||
|
|
||||||
{searchText ? (
|
{searchText ? (
|
||||||
<Card className={styles.grid}>
|
<div className={styles.search_results}>
|
||||||
<SubTitle>Результаты поиска</SubTitle>
|
<div className={styles.grid}>
|
||||||
|
<div className={styles.label}>
|
||||||
|
<span className={styles.label_text}>Результаты поиска</span>
|
||||||
|
<span className="line" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className={styles.items}>
|
<div className={styles.items}>
|
||||||
<FlowSearchResults
|
<FlowSearchResults
|
||||||
|
@ -86,31 +90,34 @@ const FlowStamp: FC<Props> = ({ isFluid, onToggleLayout }) => {
|
||||||
onLoadMore={onSearchLoadMore}
|
onLoadMore={onSearchLoadMore}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Card
|
<div className={styles.grid}>
|
||||||
className={classNames(styles.grid, {
|
<div className={classNames(styles.label, styles.whatsnew)}>
|
||||||
[styles.noUpdates]: !updates.length,
|
<span className={styles.label_text}>Что нового?</span>
|
||||||
})}
|
<span className="line" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.items}>
|
||||||
|
<FlowRecent updated={updates} recent={recent} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{experimentalFeatures.liquidFlow && (
|
||||||
|
<Superpower>
|
||||||
|
<div className={styles.toggles}>
|
||||||
|
<Group
|
||||||
|
horizontal
|
||||||
|
onClick={onToggleLayout}
|
||||||
|
className={styles.fluid_toggle}
|
||||||
>
|
>
|
||||||
<SubTitle>Что нового?</SubTitle>
|
<Toggle value={isFluid} />
|
||||||
|
<div className={styles.toggles__label}>Жидкое течение</div>
|
||||||
{updates.length > 0 && (
|
</Group>
|
||||||
<div className={classNames(styles.items, styles.updates)}>
|
|
||||||
{updates.map((node) => (
|
|
||||||
<NodeHorizontalCard node={node} key={node.id} hasNew />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</Superpower>
|
||||||
|
|
||||||
{recent.length > 0 && (
|
|
||||||
<div className={classNames(styles.items, styles.recent)}>
|
|
||||||
{recent.map((node) => (
|
|
||||||
<NodeHorizontalCard node={node} key={node.id} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
@import '~/styles/variables';
|
@import '../../../styles/variables';
|
||||||
|
|
||||||
.wrap {
|
.wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: $gap;
|
border-radius: $radius;
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
background-color: var(--content_bg_lighter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
|
@include outer_shadow();
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
border-radius: $radius;
|
||||||
|
position: relative;
|
||||||
|
background: $content_bg;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
gap: $gap;
|
|
||||||
padding: $gap;
|
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -35,25 +33,49 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.noUpdates {
|
|
||||||
@container sizer (width < #{$flow_hide_recents}) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.items.recent {
|
|
||||||
@container sizer (width < #{$flow_hide_recents}) {
|
|
||||||
display: none;
|
|
||||||
background-color: red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.items {
|
.items {
|
||||||
|
padding: 0 $gap 0 $gap;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
min-width: 0;
|
||||||
|
padding: $gap;
|
||||||
|
border-radius: $radius;
|
||||||
|
|
||||||
|
@include title_with_line();
|
||||||
|
|
||||||
|
color: transparentize(white, $amount: 0.8);
|
||||||
|
|
||||||
|
&_search {
|
||||||
|
color: white;
|
||||||
|
padding-left: $gap * 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :global(.line) {
|
||||||
|
margin-right: $gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label_text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
@include outer_shadow();
|
||||||
|
|
||||||
|
background: $content_bg_lighter;
|
||||||
|
padding: $gap;
|
||||||
|
border-radius: $radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search_icon {
|
.search_icon {
|
||||||
|
@ -67,3 +89,34 @@
|
||||||
stroke-width: 0.5;
|
stroke-width: 0.5;
|
||||||
transition: opacity 0.25s;
|
transition: opacity 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggles {
|
||||||
|
& > div {
|
||||||
|
padding: $gap;
|
||||||
|
font: $font_14_semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fluid_toggle {
|
||||||
|
@include desktop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.whatsnew {
|
||||||
|
@container sizer (width < #{$flow_hide_recents}) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_results {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
@include tablet {
|
||||||
|
margin-top: $gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ $cols: math.div($content_width, $cell);
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
|
|
||||||
@include flow_grid() {
|
@include flow_grid() {
|
||||||
grid-template-rows: min(50vh, 33cqw);
|
grid-template-rows: 40vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include flow_breakpoint(5);
|
@include flow_breakpoint(5);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
$bold: 700;
|
$bold: 700;
|
||||||
$semibold: 600;
|
$semibold: 600;
|
||||||
$regular: 400;
|
$regular: 400;
|
||||||
|
@ -5,20 +6,10 @@ $medium: 500;
|
||||||
$light: 300;
|
$light: 300;
|
||||||
$extra_light: 200;
|
$extra_light: 200;
|
||||||
|
|
||||||
$font:
|
|
||||||
Montserrat,
|
$font: Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
||||||
-apple-system,
|
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||||
BlinkMacSystemFont,
|
'Noto Color Emoji';
|
||||||
'Segoe UI',
|
|
||||||
Roboto,
|
|
||||||
'Helvetica Neue',
|
|
||||||
Arial,
|
|
||||||
'Noto Sans',
|
|
||||||
sans-serif,
|
|
||||||
'Apple Color Emoji',
|
|
||||||
'Segoe UI Emoji',
|
|
||||||
'Segoe UI Symbol',
|
|
||||||
'Noto Color Emoji';
|
|
||||||
|
|
||||||
$font_48_semibold: $semibold 48px $font;
|
$font_48_semibold: $semibold 48px $font;
|
||||||
$font_48_bold: $bold 48px $font;
|
$font_48_bold: $bold 48px $font;
|
||||||
|
@ -48,6 +39,5 @@ $font_8_regular: $regular 8px $font;
|
||||||
$font_8_semibold: $semibold 8px $font;
|
$font_8_semibold: $semibold 8px $font;
|
||||||
|
|
||||||
$font_cell_title: $font_24_semibold;
|
$font_cell_title: $font_24_semibold;
|
||||||
$font_cell_title_compact: $font_18_semibold;
|
|
||||||
$font_hero_title: $bold 40px $font;
|
$font_hero_title: $bold 40px $font;
|
||||||
$font_boris: $bold 72px $font;
|
$font_boris: $bold 72px $font;
|
||||||
|
|
|
@ -63,8 +63,10 @@ $_brown: #23201f;
|
||||||
--content_bg_success: #{transparentize($_wisegreen, 0.7)};
|
--content_bg_success: #{transparentize($_wisegreen, 0.7)};
|
||||||
--content_bg_info: #{transparentize($_blue, 0.5)};
|
--content_bg_info: #{transparentize($_blue, 0.5)};
|
||||||
--content_bg_danger: #{transparentize($_red, 0.5)};
|
--content_bg_danger: #{transparentize($_red, 0.5)};
|
||||||
--content_bg_backdrop: url('/images/noise.png')
|
--content_bg_backdrop: url('/images/noise.png') #{transparentize(
|
||||||
#{transparentize($_brown, 0.3)};
|
$_brown,
|
||||||
|
0.3
|
||||||
|
)};
|
||||||
--content_bg_hero: url('/images/noise.png') #{transparentize($_brown, 0.6)};
|
--content_bg_hero: url('/images/noise.png') #{transparentize($_brown, 0.6)};
|
||||||
|
|
||||||
// white shades (move to --vars)
|
// white shades (move to --vars)
|
||||||
|
|
|
@ -85,8 +85,10 @@ $_ocean: #25b0bc;
|
||||||
--gray_90: #{transparentize(white, 0.95)};
|
--gray_90: #{transparentize(white, 0.95)};
|
||||||
|
|
||||||
// page background
|
// page background
|
||||||
--page-background: 50% 50% / cover no-repeat url('/images/horizon_bg.svg')
|
--page-background: 50% 50% / cover no-repeat url('/images/horizon_bg.svg') #{darken(
|
||||||
#{darken($_cold, 4%)} fixed;
|
$_cold,
|
||||||
|
4%
|
||||||
|
)} fixed;
|
||||||
--page-background-top: linear-gradient(
|
--page-background-top: linear-gradient(
|
||||||
#{$_accent} -150%,
|
#{$_accent} -150%,
|
||||||
#{transparentize($_ocean, 0.99)} 100px,
|
#{transparentize($_ocean, 0.99)} 100px,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
COMMENT_BLOCK_TYPES,
|
COMMENT_BLOCK_TYPES,
|
||||||
ICommentBlock,
|
ICommentBlock,
|
||||||
} from '~/constants/comment';
|
} from '~/constants/comment';
|
||||||
import { headerHeight } from '~/constants/dom';
|
|
||||||
import { IFile, ValueOf } from '~/types';
|
import { IFile, ValueOf } from '~/types';
|
||||||
import { CONFIG } from '~/utils/config';
|
import { CONFIG } from '~/utils/config';
|
||||||
import {
|
import {
|
||||||
|
@ -214,14 +213,3 @@ export const sizeOf = (bytes: number): string => {
|
||||||
(bytes / Math.pow(1024, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'B'
|
(bytes / Math.pow(1024, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'B'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Tells if element is in view */
|
|
||||||
export const isFullyVisible = (element?: HTMLElement): boolean => {
|
|
||||||
if (!element) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rect = element.getBoundingClientRect();
|
|
||||||
|
|
||||||
return rect?.top > headerHeight && rect?.bottom < window.innerHeight;
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue