1
0
Fork 0
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:
muerwre 2019-07-29 18:51:10 +07:00
parent e687a3f5f3
commit 14c5f67d49
15 changed files with 349 additions and 18 deletions

51
package-lock.json generated
View file

@ -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",

View file

@ -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"
}
}

View 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 };

View file

@ -0,0 +1,6 @@
.grid {
display: grid;
grid-auto-rows: 1fr;
grid-column-gap: $gap;
grid-row-gap: $gap;
}

View file

@ -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,
)}

View file

@ -39,4 +39,8 @@
&.wrap {
flex-wrap: wrap;
}
&.seamless > * {
margin: 0;
}
}

View 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 };

View file

@ -0,0 +1,3 @@
.panel {
@include outer_shadow();
}

View 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>
);
};

View 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;
}
}

View file

@ -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}
>
{
label &&
<div className={style.label}>{label}</div>
}
<div className={style.container}>
<div className={styles.container}>
{
label &&
<div className={styles.label}>{label}</div>
}
<input
placeholder={placeholder}
className={style.input}
className={styles.input}
type={type}
onChange={onChange}
value={value}

View file

@ -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();
}

View file

@ -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}>
panel
<Group>
<Card>
<Padder>
panel
</Padder>
</Card>
</Group>
</div>
</Group>
</Card>

View file

@ -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;
}

View file

@ -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;