mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
editor scrollbars
This commit is contained in:
parent
e687a3f5f3
commit
14c5f67d49
15 changed files with 349 additions and 18 deletions
51
package-lock.json
generated
51
package-lock.json
generated
|
@ -2820,6 +2820,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"add-px-to-style": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/add-px-to-style/-/add-px-to-style-1.0.0.tgz",
|
||||
"integrity": "sha1-0ME1RB+oAUqBN5BFMQlvZ/KPJjo="
|
||||
},
|
||||
"adjust-sourcemap-loader": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz",
|
||||
|
@ -6632,6 +6637,16 @@
|
|||
"utila": "~0.4"
|
||||
}
|
||||
},
|
||||
"dom-css": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-css/-/dom-css-2.1.0.tgz",
|
||||
"integrity": "sha1-/bwtWgFdCj4YcuEUcrvQ57nmogI=",
|
||||
"requires": {
|
||||
"add-px-to-style": "1.0.0",
|
||||
"prefix-style": "2.0.1",
|
||||
"to-camel-case": "1.0.0"
|
||||
}
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
|
@ -13106,6 +13121,11 @@
|
|||
"uniqs": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"prefix-style": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prefix-style/-/prefix-style-2.0.1.tgz",
|
||||
"integrity": "sha1-ZrupqHDP2jCKXcIOhekSCTLJWgY="
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
|
@ -15963,12 +15983,25 @@
|
|||
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
|
||||
"dev": true
|
||||
},
|
||||
"to-camel-case": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-camel-case/-/to-camel-case-1.0.0.tgz",
|
||||
"integrity": "sha1-GlYFSy+daWKYzmamCJcyK29CPkY=",
|
||||
"requires": {
|
||||
"to-space-case": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
|
||||
"integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
|
||||
"dev": true
|
||||
},
|
||||
"to-no-case": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz",
|
||||
"integrity": "sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo="
|
||||
},
|
||||
"to-object-path": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
|
||||
|
@ -16011,6 +16044,14 @@
|
|||
"repeat-string": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"to-space-case": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz",
|
||||
"integrity": "sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=",
|
||||
"requires": {
|
||||
"to-no-case": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"toposort": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
|
||||
|
@ -16082,6 +16123,16 @@
|
|||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tt-react-custom-scrollbars": {
|
||||
"version": "4.2.1-tt2",
|
||||
"resolved": "https://registry.npmjs.org/tt-react-custom-scrollbars/-/tt-react-custom-scrollbars-4.2.1-tt2.tgz",
|
||||
"integrity": "sha512-gMEVHHOClNJXM1d/p4PrLdXtCU2JzWRtcZdzUkXgck8sgzkxwFwSDNc3scnTk21sSKG2GSgf7G54sboXwsMVlg==",
|
||||
"requires": {
|
||||
"dom-css": "^2.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"raf": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
"sass-loader": "^7.1.0",
|
||||
"sass-resources-loader": "^2.0.0",
|
||||
"scrypt": "^6.0.3",
|
||||
"throttle-debounce": "^2.1.0"
|
||||
"throttle-debounce": "^2.1.0",
|
||||
"tt-react-custom-scrollbars": "latest"
|
||||
}
|
||||
}
|
||||
|
|
25
src/components/containers/CellGrid/index.tsx
Normal file
25
src/components/containers/CellGrid/index.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import React, { FC, HTMLAttributes, ReactChild, ReactChildren } from 'react';
|
||||
import * as styles from './styles.scss';
|
||||
import classNames = require("classnames");
|
||||
|
||||
type IProps = HTMLAttributes<HTMLDivElement> & {
|
||||
children: any;
|
||||
size: number;
|
||||
}
|
||||
|
||||
const CellGrid: FC<IProps> = ({
|
||||
children,
|
||||
size,
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
<div
|
||||
className={classNames(styles.grid, className)}
|
||||
style={{ gridTemplateColumns: `repeat(auto-fit, minmax(${size}px, 1fr))` }}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export { CellGrid };
|
6
src/components/containers/CellGrid/styles.scss
Normal file
6
src/components/containers/CellGrid/styles.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
.grid {
|
||||
display: grid;
|
||||
grid-auto-rows: 1fr;
|
||||
grid-column-gap: $gap;
|
||||
grid-row-gap: $gap;
|
||||
}
|
|
@ -7,6 +7,7 @@ type IProps = React.HTMLAttributes<HTMLDivElement> & {
|
|||
top?: boolean;
|
||||
bottom?: boolean;
|
||||
wrap?: boolean;
|
||||
seamless?: boolean;
|
||||
};
|
||||
|
||||
const Group: FC<IProps> = ({
|
||||
|
@ -16,6 +17,7 @@ const Group: FC<IProps> = ({
|
|||
top = false,
|
||||
bottom = false,
|
||||
wrap = false,
|
||||
seamless = false,
|
||||
...props
|
||||
}) => (
|
||||
<div
|
||||
|
@ -27,6 +29,7 @@ const Group: FC<IProps> = ({
|
|||
[styles.top]: top,
|
||||
[styles.bottom]: bottom,
|
||||
[styles.wrap]: wrap,
|
||||
[styles.seamless]: seamless,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
|
|
|
@ -39,4 +39,8 @@
|
|||
&.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&.seamless > * {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
|
19
src/components/containers/Panel/index.tsx
Normal file
19
src/components/containers/Panel/index.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React, { FC, HTMLAttributes } from 'react';
|
||||
import * as styles from './styles.scss';
|
||||
import classNames = require("classnames");
|
||||
|
||||
type IProps = HTMLAttributes<HTMLDivElement> & {
|
||||
|
||||
}
|
||||
|
||||
const Panel: FC<IProps> = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => (
|
||||
<div className={classNames(styles.panel, className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export { Panel };
|
3
src/components/containers/Panel/styles.scss
Normal file
3
src/components/containers/Panel/styles.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
.panel {
|
||||
@include outer_shadow();
|
||||
}
|
45
src/components/containers/Scroll/index.tsx
Normal file
45
src/components/containers/Scroll/index.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
import React, { MouseEventHandler, useEffect, useState } from 'react';
|
||||
import * as styles from './styles.scss';
|
||||
import { Scrollbars } from 'tt-react-custom-scrollbars';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface IProps {
|
||||
children: Element | React.ReactChild;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
autoHeight?: boolean;
|
||||
autoHeightMax?: number;
|
||||
onRef?: (el: any) => void;
|
||||
onScroll?: MouseEventHandler;
|
||||
onScrollStop?: MouseEventHandler;
|
||||
}
|
||||
|
||||
export const Scroll = ({
|
||||
children,
|
||||
className = '',
|
||||
onRef = null,
|
||||
...props
|
||||
}: IProps) => {
|
||||
const [ref, setRef] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (onRef && ref) return onRef(ref);
|
||||
}, [ref, onRef]);
|
||||
|
||||
return (
|
||||
<Scrollbars
|
||||
className={classNames(styles.container, className)}
|
||||
renderTrackHorizontal={data => <div className={styles.track_horizontal} {...data} />}
|
||||
renderTrackVertical={data => <div className={styles.track_vertical} {...data} />}
|
||||
renderThumbHorizontal={data => <div className={styles.thumb_horizontal} {...data} />}
|
||||
renderThumbVertical={data => <div className={styles.thumb_vertical} {...data} />}
|
||||
renderView = {data => <div className={styles.view} {...data} />}
|
||||
hideTracksWhenNotNeeded
|
||||
universal
|
||||
ref={setRef}
|
||||
{ ...props }
|
||||
>
|
||||
{children}
|
||||
</Scrollbars>
|
||||
);
|
||||
};
|
107
src/components/containers/Scroll/styles.scss
Normal file
107
src/components/containers/Scroll/styles.scss
Normal file
|
@ -0,0 +1,107 @@
|
|||
.container {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.track_vertical {
|
||||
height: 100%;
|
||||
width: 20px !important;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
opacity: $scroll_inactive_opacity;
|
||||
transition: opacity 0.25s;
|
||||
padding: $gap 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
|
||||
&:hover, &:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
width: 1px;
|
||||
background: $scroll_color;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.thumb_vertical {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
width: 5px;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
background: $scroll_color;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.track_horizontal {
|
||||
height: 20px !important;
|
||||
width: 100% !important;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
opacity: 0.3;
|
||||
transition: opacity 0.25s;
|
||||
padding: 0 $gap;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
|
||||
&:hover, &:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
height: 1px;
|
||||
background: $scroll_color;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 0.5;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.thumb_horizontal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
height: 5px;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
background: $scroll_color;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const style = require('./style.scss');
|
||||
import * as styles from './styles.scss';
|
||||
|
||||
interface ITextInputProps {
|
||||
type?: 'text' | 'password',
|
||||
|
@ -19,16 +18,16 @@ export const TextInput: React.FunctionComponent<ITextInputProps> = ({
|
|||
value='',
|
||||
}) => (
|
||||
<div
|
||||
className={style.wrapper}
|
||||
className={styles.wrapper}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
{
|
||||
label &&
|
||||
<div className={style.label}>{label}</div>
|
||||
<div className={styles.label}>{label}</div>
|
||||
}
|
||||
<div className={style.container}>
|
||||
<input
|
||||
placeholder={placeholder}
|
||||
className={style.input}
|
||||
className={styles.input}
|
||||
type={type}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
.wrapper {
|
||||
height: $input_height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
height: $input_height;
|
||||
}
|
||||
|
||||
.label {
|
||||
background: $input_bg_color;
|
||||
font-size: 10px;
|
||||
background: transparentize(black, 0.8);
|
||||
font: $font_14_medium;
|
||||
// color: transparentize(white, 0.5);
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
padding: 2px $gap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
border-radius: $radius 0 0 $radius;
|
||||
@include input_shadow();
|
||||
}
|
||||
|
||||
.container {
|
||||
|
@ -20,7 +27,7 @@
|
|||
flex: 1 0;
|
||||
display: flex;
|
||||
align-self: stretch;
|
||||
align-items: center;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
@include input_shadow();
|
||||
}
|
|
@ -2,18 +2,47 @@ import React, { FC } from 'react';
|
|||
import { Card } from "~/components/containers/Card";
|
||||
import * as styles from './styles.scss';
|
||||
import { Group } from "~/components/containers/Group";
|
||||
import { Padder } from "~/components/containers/Padder";
|
||||
import { CellGrid } from "~/components/containers/CellGrid";
|
||||
import { Panel } from "~/components/containers/Panel";
|
||||
import { TextInput } from "~/components/input/TextInput";
|
||||
import classNames = require("classnames");
|
||||
import { Scroll } from "~/components/containers/Scroll";
|
||||
|
||||
interface IProps {}
|
||||
|
||||
const EditorExample: FC<IProps> = () => (
|
||||
<Card className={styles.wrap}>
|
||||
<Group horizontal className={styles.group}>
|
||||
<Group horizontal className={styles.group} seamless>
|
||||
<div className={styles.editor}>
|
||||
editor
|
||||
<Panel className={styles.editor_panel}>
|
||||
<TextInput onChange={console.log} label="Название" />
|
||||
</Panel>
|
||||
|
||||
<Panel className={classNames(styles.editor_panel, styles.editor_image_panel)}>
|
||||
<Scroll>
|
||||
<CellGrid className={styles.editor_image_container} size={200}>
|
||||
<div className={styles.editor_image} />
|
||||
<div className={styles.editor_image} />
|
||||
<div className={styles.editor_image} />
|
||||
<div className={styles.editor_image} />
|
||||
</CellGrid>
|
||||
</Scroll>
|
||||
</Panel>
|
||||
|
||||
<Panel className={styles.editor_panel}>
|
||||
Cover panel
|
||||
</Panel>
|
||||
</div>
|
||||
|
||||
<div className={styles.panel}>
|
||||
<Group>
|
||||
<Card>
|
||||
<Padder>
|
||||
panel
|
||||
</Padder>
|
||||
</Card>
|
||||
</Group>
|
||||
</div>
|
||||
</Group>
|
||||
</Card>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
align-items: stretch;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
background: $editor_bg;
|
||||
}
|
||||
|
||||
.group {
|
||||
|
@ -13,10 +14,35 @@
|
|||
}
|
||||
|
||||
.panel {
|
||||
background: red;
|
||||
background: $editor_panel_bg;
|
||||
flex: 0 0 33%;
|
||||
border-radius: 0 $radius $radius 0;
|
||||
padding: $gap;
|
||||
box-sizing: border-box;
|
||||
@include outer_shadow();
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.editor_panel {
|
||||
padding: $gap;
|
||||
}
|
||||
|
||||
.editor_image_panel {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.editor_image_container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.editor_image {
|
||||
background: lighten($main_bg_color, 20%);
|
||||
padding-bottom: 100%;
|
||||
border-radius: $radius;
|
||||
}
|
||||
|
|
|
@ -36,3 +36,9 @@ $panel_bg: #191919;
|
|||
$node_bg: #111111;
|
||||
$node_image_bg: #131313;
|
||||
$node_title_background: #191919;
|
||||
|
||||
$editor_panel_bg: lighten($main_bg_color, 5%);
|
||||
$editor_bg: lighten($main_bg_color, 10%);
|
||||
|
||||
$scroll_color: $red_gradient;
|
||||
$scroll_inactive_opacity: 0.5;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue