From 3a874583bce620dbb0448f4daec1a501a0e4e9cc Mon Sep 17 00:00:00 2001 From: muerwre Date: Thu, 28 Mar 2019 14:12:00 +0700 Subject: [PATCH] sliding up title dialog --- src/components/dialogs/TitleDialog.tsx | 70 +++++++++++++++++++++++--- src/components/panels/UserPanel.tsx | 3 +- src/styles/panel.less | 20 ++++++-- src/utils/dom.ts | 9 ++++ src/utils/geom.ts | 17 ++----- 5 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 src/utils/dom.ts diff --git a/src/components/dialogs/TitleDialog.tsx b/src/components/dialogs/TitleDialog.tsx index 91291c0..b7cd30e 100644 --- a/src/components/dialogs/TitleDialog.tsx +++ b/src/components/dialogs/TitleDialog.tsx @@ -3,36 +3,90 @@ import { bindActionCreators } from "redux"; import { connect } from 'react-redux'; import classnames from 'classnames'; +import { getStyle } from "$utils/dom"; +import { nearestInt } from "$utils/geom"; interface ITitleDialogProps { editing: boolean, title?: string, + minLines?: number, + maxLines?: number, } interface ITitleDialogState { raised: boolean; + height: number; + height_raised: number; } export class Component extends React.PureComponent { state = { raised: false, + height: 0, + height_raised: 0, }; onHover = () => this.setState({ raised: true }); onLeave = () => this.setState({ raised: false }); + componentDidMount() { + this.getMaxHeight(); + } + + getMaxHeight = (): number => { + if (!this.ref_sizer || !this.ref_title || !this.ref_text) return 0; + + const { height: sizer_height } = this.ref_sizer.getBoundingClientRect(); + const { height: title_height } = this.ref_title.getBoundingClientRect(); + const { height: text_height } = this.ref_text.getBoundingClientRect(); + + const title_margin = parseInt(getStyle(this.ref_title, 'margin-bottom'), 10) || 0; + const text_margins = (parseInt(getStyle(this.ref_text, 'margin-top'), 10) || 0) + + parseInt(getStyle(this.ref_text, 'margin-bottom'), 10) || 0;; + const text_line = parseInt(getStyle(this.ref_text, 'line-height'), 10) || 0; + + const container_height = sizer_height - title_height - title_margin - text_margins; + + console.log(this.ref_text.getBoundingClientRect()); + + const min_height = (this.props.minLines || 3) * text_line; + const max_height = (this.props.maxLines || 20) * text_line; + + const height = nearestInt(Math.min(container_height, Math.min(text_height, min_height)), text_line) + text_margins; + const height_raised = nearestInt(Math.min(container_height, Math.min(text_height, max_height)), text_line) + text_margins; + + console.log({ height, height_raised }); + this.setState({ height, height_raised }); + }; + render() { const { editing, title } = this.props; + const { raised, height, height_raised } = this.state; return (
-
{ this.sizer = el; }}> -
-
+
{ this.ref_sizer = el; }}> +
+
{ this.ref_title = el; }} + >

{title}

-
- Давно выяснено, что при оценке дизайна и композиции читаемый текст мешает сосредоточиться. Lorem Ipsum используют потому, что тот обеспечивает более или менее стандартное заполнение шаблона, а также реальное распределение букв и пробелов в абзацах, которое не получается при простой дубликации "Здесь ваш текст.. Здесь ваш текст.. Здесь ваш текст.." Многие программы электронной вёрстки и редакторы HTML используют Lorem Ipsum в качестве текста по умолчанию, так что поиск по +
{ this.ref_overflow = el; }} + > +
{ this.ref_text = el; }} + > + Давно выяснено, что при оценке дизайна и композиции читаемый текст мешает сосредоточиться. Lorem Ipsum используют потому, что тот обеспечивает более или менее стандартное заполнение шаблона, а также реальное распределение букв и пробелов в абзацах, которое не получается при простой дубликации "Здесь ваш текст.. Здесь ваш текст.. Здесь ваш текст.." Многие программы электронной вёрстки и редакторы HTML используют Lorem Ipsum в качестве текста по умолчанию, так что поиск по +
@@ -40,8 +94,10 @@ export class Component extends React.PureComponent ({ editing, title }); diff --git a/src/components/panels/UserPanel.tsx b/src/components/panels/UserPanel.tsx index 25665f4..b3ad9dd 100644 --- a/src/components/panels/UserPanel.tsx +++ b/src/components/panels/UserPanel.tsx @@ -14,6 +14,7 @@ import { CLIENT } from '$config/frontend'; import { DIALOGS } from '$constants/dialogs'; import { IRootState } from "$redux/user/reducer"; import { Tooltip } from "$components/panels/Tooltip"; +import { TitleDialog } from "$components/dialogs/TitleDialog"; interface Props extends IRootState { userLogout: typeof userLogout, @@ -95,7 +96,7 @@ export class Component extends React.PureComponent { return (
{ - // + }
diff --git a/src/styles/panel.less b/src/styles/panel.less index ade2a81..a9b9654 100644 --- a/src/styles/panel.less +++ b/src/styles/panel.less @@ -641,19 +641,16 @@ .title-dialog { z-index: 2; - opacity: 0; transition: opacity 500ms, transform 1s; transform: translate(0, 68px); user-select: none; pointer-events: all; touch-action: auto; + display: flex; + flex-direction: column; &.active { - opacity: 0.5; transform: translate(0, 0); - &:hover { - opacity: 1; - } } .title-dialog-pane { @@ -662,6 +659,7 @@ background: #111111; color: fade(white, 50%); font-size: 13px; + box-sizing: border-box; h2 { margin: 0; @@ -671,4 +669,16 @@ color: white; } } + + .title-dialog-text { + overflow: hidden; + //display: flex; + transition: height 500ms; + line-height: 14px; + padding: 0; + + > div { + margin: 10px; + } + } } diff --git a/src/utils/dom.ts b/src/utils/dom.ts new file mode 100644 index 0000000..25eb73a --- /dev/null +++ b/src/utils/dom.ts @@ -0,0 +1,9 @@ +export const getStyle = (oElm: any, strCssRule: string): string => { + if(document.defaultView && document.defaultView.getComputedStyle){ + return document.defaultView.getComputedStyle(oElm, '').getPropertyValue(strCssRule); + } else if(oElm.currentStyle){ + return oElm.currentStyle[strCssRule.replace(/\-(\w)/g, (strMatch, p1) => p1.toUpperCase())]; + } + + return ''; +}; diff --git a/src/utils/geom.ts b/src/utils/geom.ts index 7c21275..6517084 100644 --- a/src/utils/geom.ts +++ b/src/utils/geom.ts @@ -90,25 +90,14 @@ const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => { }; export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => Math.sqrt(distToSegmentSquared(A, B, C)); -// if C between A and B + export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => (distToSegment(A, B, C) < 0.01); export const angleBetweenPoints = (A: Point, B: Point): number => parseFloat(((Math.atan2(B.y - A.y, B.x - A.x))* 180 / Math.PI).toFixed()); export const angleBetweenPointsRad = (A: Point, B: Point): number => ((Math.atan2(B.x - A.x, B.y - A.y))); -// export const pointOnDistance = (A: Point, B: Point, shift: number): Point => { -// const c = Math.sqrt((((B.x - A.x) ** 2) + ((B.y - A.y) ** 2))); -// const angle = angleBetweenPointsRad(A, B); -// -// // console.log({ angle, c, shift }); -// const x = Math.floor(B.x - c * Math.sin(angle) * shift); -// const y = Math.floor(B.y - c * Math.cos(angle) * shift); -// -// // console.log({ x, y }); -// -// return new Point(x, y); -// }; - export const allwaysPositiveAngleDeg = (angle: number): number => ( (angle >= -90 && angle <= 90) ? angle : (180 + angle) ); + +export const nearestInt = (value: number, parts: number): number => (value - (value % parts));