From 5b82dfda4b49c4c88005818c4bc3f40c60d27f04 Mon Sep 17 00:00:00 2001 From: ditsemto Date: Wed, 7 Jul 2021 07:46:37 +0200 Subject: [PATCH] GH-629 - Property Popover in Kanban view (#643) --- .../src/components/gallery/galleryCard.scss | 3 + webapp/src/components/gallery/galleryCard.tsx | 18 ++- webapp/src/components/kanban/kanbanCard.tsx | 17 ++- webapp/src/widgets/tooltip.scss | 120 ++++++++++++++++++ webapp/src/widgets/tooltip.tsx | 29 +++++ 5 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 webapp/src/widgets/tooltip.scss create mode 100644 webapp/src/widgets/tooltip.tsx diff --git a/webapp/src/components/gallery/galleryCard.scss b/webapp/src/components/gallery/galleryCard.scss index e339cc09f..cf652f0e4 100644 --- a/webapp/src/components/gallery/galleryCard.scss +++ b/webapp/src/components/gallery/galleryCard.scss @@ -76,6 +76,9 @@ } .gallery-props { + display: flex; + flex-direction: column; + align-items: flex-start; flex-grow: 0; margin: 0; padding: 5px 10px; diff --git a/webapp/src/components/gallery/galleryCard.tsx b/webapp/src/components/gallery/galleryCard.tsx index 413faf74c..1e3ddb975 100644 --- a/webapp/src/components/gallery/galleryCard.tsx +++ b/webapp/src/components/gallery/galleryCard.tsx @@ -20,6 +20,7 @@ import {useSortable} from '../../hooks/sortable' import ImageElement from '../content/imageElement' import ContentElement from '../content/contentElement' import PropertyValueElement from '../propertyValueElement' +import Tooltip from '../../widgets/tooltip' import './galleryCard.scss' @@ -108,13 +109,18 @@ const GalleryCard = React.memo((props: Props) => { {visiblePropertyTemplates.length > 0 &&
{visiblePropertyTemplates.map((template) => ( - + title={template.name} + placement='top' + > + + ))}
} diff --git a/webapp/src/components/kanban/kanbanCard.tsx b/webapp/src/components/kanban/kanbanCard.tsx index f90b428b1..8feb8fbd0 100644 --- a/webapp/src/components/kanban/kanbanCard.tsx +++ b/webapp/src/components/kanban/kanbanCard.tsx @@ -16,6 +16,7 @@ import {useSortable} from '../../hooks/sortable' import './kanbanCard.scss' import PropertyValueElement from '../propertyValueElement' +import Tooltip from '../../widgets/tooltip' type Props = { card: Card @@ -86,13 +87,17 @@ const KanbanCard = React.memo((props: Props) => {
{card.title || intl.formatMessage({id: 'KanbanCard.untitled', defaultMessage: 'Untitled'})}
{visiblePropertyTemplates.map((template) => ( - + title={template.name} + > + + ))} ) diff --git a/webapp/src/widgets/tooltip.scss b/webapp/src/widgets/tooltip.scss new file mode 100644 index 000000000..13c878eac --- /dev/null +++ b/webapp/src/widgets/tooltip.scss @@ -0,0 +1,120 @@ + +// Tooltip arrow width +$tooltip-arrow-width: 6px; +// Space between element after transform +$tooltop-horizontal-offset: 2px; +$tooltop-vertical-offset: 2px; + +%hover_tooltip_body { + position: absolute; + content: attr(data-tooltip); + line-height: 16px; + padding: 2px 4px; + line-height: 1; + font-size: 1.0em; + text-align: center; + color: rgb(255, 255, 255); + background: rgb(0, 0, 0); + // opacity: 0.8; + border: 4px solid rgb(0, 0, 0); + border-radius: 4px; + text-shadow: rgba(0, 0, 0, 0.098) 1px 1px 1px; + box-shadow: rgba(0, 0, 0, 0.1) 1px 1px 2px 0px; + min-width: 2em; + max-width: 21em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + z-index: 100; +} + +%hover_tooltip_arrow { + content: ""; + position: absolute; + width: 0; + height: 0; + border-width: $tooltip-arrow-width; + border-style: solid; + border-color: #000000 transparent transparent transparent; + z-index: 99; +} + +.octo-tooltip { + display: inline; + // Tooltip itself needs to be relative so + // content and arrow can be absolute to it + position: relative; + // Arrow gets added before content + &:hover:before { + @extend %hover_tooltip_arrow + } + // Tooltip message gets added after content + &:hover:after { + @extend %hover_tooltip_body + } + + // Top tooltip arrow style + &.tooltip-top:hover:before { + left: 50%; + bottom: calc(100% - 2px); + -webkit-transform: translate(-50%, #{$tooltop-horizontal-offset}); + transform: translate(-50%, #{$tooltop-horizontal-offset}); + } + // Top tooltip body style + &.tooltip-top:hover:after { + bottom: calc(100% + 10px); + left: 50%; + -webkit-transform: translate(-50%, #{$tooltop-horizontal-offset}); + transform: translate(-50%, #{$tooltop-horizontal-offset}); + } + + // Right tooltip arrow style + &.tooltip-right:hover:before { + border-color: transparent #000000 transparent transparent; + top: 50%; + right: calc(0em - 2px); + -webkit-transform: translate(#{$tooltop-vertical-offset}, -50%); + transform: translate(#{$tooltop-vertical-offset}, -50%); + } + // Right tooltip body style + &.tooltip-right:hover:after { + top: 50%; + left: calc(100% + 2px); + -webkit-transform: translate(#{$tooltop-vertical-offset}, -50%); + transform: translate(#{$tooltop-vertical-offset}, -50%); + } + + // Left tooltip arrow style + &.tooltip-left:hover:before { + top: 50%; + left: calc(0em - 2px); + border-color: transparent transparent transparent #000000; + -webkit-transform: translate(-#{$tooltop-vertical-offset}, -50%); + transform: translate(-#{$tooltop-vertical-offset}, -50%); + } + // Left tooltip body style + &.tooltip-left:hover:after { + left: undefined; + top: 50%; + right: calc(100% + 2px); + -webkit-transform: translate(-#{$tooltop-vertical-offset}, -50%); + transform: translate(-#{$tooltop-vertical-offset}, -50%); + } + + // Bottom tooltip arrow style + &.tooltip-bottom:hover:before { + left: 50%; + top: calc(100% - 8px); + border-color: transparent transparent #000000 transparent ; + -webkit-transform: translate(-50%, -#{$tooltop-horizontal-offset}); + transform: translate(-50%, -#{$tooltop-horizontal-offset}); + } + // Bottom tooltip body style + &.tooltip-bottom:hover:after { + left: 50%; + top: calc(100% + 4px); + -webkit-transform: translate(-50%, -#{$tooltop-horizontal-offset}); + transform: translate(-50%, -#{$tooltop-horizontal-offset}); + } +} diff --git a/webapp/src/widgets/tooltip.tsx b/webapp/src/widgets/tooltip.tsx new file mode 100644 index 000000000..b7f53ad7b --- /dev/null +++ b/webapp/src/widgets/tooltip.tsx @@ -0,0 +1,29 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import React from 'react' + +import './tooltip.scss' + +type Props = { + title: string + children: React.ReactNode + placement?: 'top'|'left'|'right'|'bottom' +} + +// Adds tooltip div over children elements, the popup will +// be positioned based on the specified placement +// Default position is 'top' +function Tooltip(props: Props): JSX.Element { + const placement = props.placement || 'top' + const className = `octo-tooltip tooltip-${placement}` + return ( +
+ {props.children} +
+ ) +} + +export default React.memo(Tooltip)