mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-28 19:08:01 +00:00
parent
9874c47cf2
commit
1f7f1b05cf
@ -15,20 +15,20 @@
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import type { AnySvelteComponent, TooltipAligment } from '../types'
|
||||
|
||||
import Icon from './Icon.svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let direction: string = 'top'
|
||||
export let direction: TooltipAligment | undefined
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let action: () => Promise<void>
|
||||
export let invisible: boolean = false
|
||||
</script>
|
||||
|
||||
<Tooltip label={label} direction={direction}>
|
||||
<Tooltip {label} {direction}>
|
||||
<button class="button {size}" on:click|stopPropagation={action}>
|
||||
<div class="icon {size}" class:invisible={invisible}>
|
||||
{#if typeof (icon) === 'string'}
|
||||
|
@ -48,7 +48,7 @@
|
||||
<svelte:component this={component} {...item.props}/>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="icon"><ActionIcon label={'Remove'} direction={'top'} icon={Close} size={'small'} action={async () => { item.selected = false }}/></div>
|
||||
<div class="icon"><ActionIcon label={'Remove'} icon={Close} size={'small'} action={async () => { item.selected = false }}/></div>
|
||||
</button>
|
||||
{#if byTitle }
|
||||
<PopupItem bind:title={item.title} selectable bind:selected={item.selected}/>
|
||||
|
@ -15,108 +15,24 @@
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
import type { TooltipAligment } from '..'
|
||||
import { showTooltip, closeTooltip } from '..'
|
||||
|
||||
export let label: IntlString
|
||||
export let direction: 'top' | 'bottom' | 'left' | 'right' = 'top'
|
||||
export let direction: TooltipAligment | undefined
|
||||
|
||||
let triggerHTML: HTMLElement
|
||||
</script>
|
||||
|
||||
<div class="flex-center container">
|
||||
<div class="trigger"><slot/></div>
|
||||
<div class="tooltip {direction}">
|
||||
<Label label={label}/>
|
||||
</div>
|
||||
<div
|
||||
class="tooltip-trigger"
|
||||
bind:this={triggerHTML}
|
||||
on:mouseenter={(ev) => {
|
||||
showTooltip(label, triggerHTML, direction)
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
closeTooltip()
|
||||
}}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
position: relative;
|
||||
|
||||
.trigger:hover + .tooltip {
|
||||
opacity: 1;
|
||||
&.top {
|
||||
transform: translateY(-.625rem);
|
||||
}
|
||||
&.bottom {
|
||||
transform: translateY(.625rem);
|
||||
}
|
||||
&.right {
|
||||
transform: translateX(.625rem);
|
||||
}
|
||||
&.left {
|
||||
transform: translateX(-.625rem);
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
padding: .5rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: .5rem;
|
||||
box-shadow: 0px .5rem 1.25rem rgba(0, 0, 0, .25);
|
||||
opacity: 0;
|
||||
transition: transform .3s ease, opacity .2s ease-in-out;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
transition-delay: .2s;
|
||||
z-index: 10;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: .875rem;
|
||||
height: .875rem;
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 0 0 .25rem;
|
||||
mask-image: linear-gradient(-45deg, rgba(0, 0, 0, 1) .655rem, rgba(0, 0, 0, 0) .656rem);
|
||||
}
|
||||
|
||||
&.top::after, &.bottom::after {
|
||||
left: 50%;
|
||||
margin-left: -.5rem;
|
||||
}
|
||||
&.top {
|
||||
bottom: 100%;
|
||||
box-shadow: 0px -.5rem 1.25rem rgba(0, 0, 0, .25);
|
||||
&::after {
|
||||
bottom: -.5rem;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
&.bottom {
|
||||
top: 100%;
|
||||
box-shadow: 0px -.5rem 1.25rem rgba(0, 0, 0, .25);
|
||||
&::after {
|
||||
top: -.5rem;
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.right::after, &.left::after {
|
||||
top: 50%;
|
||||
margin-top: -.5rem;
|
||||
}
|
||||
&.right {
|
||||
left: 100%;
|
||||
box-shadow: -.5rem 0px 1.25rem rgba(0, 0, 0, .25);
|
||||
&::after {
|
||||
left: -.4rem;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
&.left {
|
||||
right: 100%;
|
||||
box-shadow: .5rem 0px 1.25rem rgba(0, 0, 0, .25);
|
||||
&::after {
|
||||
right: -.4rem;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
146
packages/ui/src/components/TooltipInstance.svelte
Normal file
146
packages/ui/src/components/TooltipInstance.svelte
Normal file
@ -0,0 +1,146 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { tooltipstore as tooltip } from '..'
|
||||
import type { TooltipAligment } from '..'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
let tooltipHTML: HTMLElement
|
||||
let dir: TooltipAligment
|
||||
|
||||
$: {
|
||||
if ($tooltip.label && tooltipHTML) {
|
||||
if ($tooltip.element) {
|
||||
const rect = $tooltip.element.getBoundingClientRect()
|
||||
const doc = document.body.getBoundingClientRect()
|
||||
|
||||
if (!$tooltip.direction) {
|
||||
if (rect.right < doc.width / 5) dir = 'right'
|
||||
else if (rect.left > doc.width - doc.width / 5) dir = 'left'
|
||||
else if (rect.top < tooltipHTML.clientHeight) dir = 'bottom'
|
||||
else dir = 'top'
|
||||
} else dir = $tooltip.direction
|
||||
|
||||
if (dir === 'right') {
|
||||
tooltipHTML.style.top = rect.y + rect.height / 2 + 'px'
|
||||
tooltipHTML.style.left = `calc(${rect.right}px + .75rem)`
|
||||
tooltipHTML.style.transform = 'translateY(-50%)'
|
||||
} else if (dir === 'left') {
|
||||
tooltipHTML.style.top = rect.y + rect.height / 2 + 'px'
|
||||
tooltipHTML.style.right = `calc(${doc.width - rect.x}px + .75rem)`
|
||||
tooltipHTML.style.transform = 'translateY(-50%)'
|
||||
} else if (dir === 'bottom') {
|
||||
tooltipHTML.style.top = `calc(${rect.bottom}px + .5rem)`
|
||||
tooltipHTML.style.left = rect.x + rect.width / 2 + 'px'
|
||||
tooltipHTML.style.transform = 'translateX(-50%)'
|
||||
} else if (dir === 'top') {
|
||||
tooltipHTML.style.bottom = `calc(${doc.height - rect.y}px + .75rem)`
|
||||
tooltipHTML.style.left = rect.x + rect.width / 2 + 'px'
|
||||
tooltipHTML.style.transform = 'translateX(-50%)'
|
||||
}
|
||||
tooltipHTML.classList.remove('no-arrow')
|
||||
} else {
|
||||
tooltipHTML.style.top = '50%'
|
||||
tooltipHTML.style.left = '50%'
|
||||
tooltipHTML.style.width = 'min-content'
|
||||
tooltipHTML.style.height = 'min-content'
|
||||
tooltipHTML.style.transform = 'translate(-50%, -50%)'
|
||||
tooltipHTML.classList.add('no-arrow')
|
||||
}
|
||||
tooltipHTML.style.visibility = 'visible'
|
||||
} else if (tooltipHTML) tooltipHTML.style.visibility = 'hidden'
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $tooltip.label}
|
||||
<div class="tooltip {dir}" bind:this={tooltipHTML}>
|
||||
<Label label={$tooltip.label} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.tooltip {
|
||||
position: fixed;
|
||||
padding: .5rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: .5rem;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
z-index: 10;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: .875rem;
|
||||
height: .875rem;
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 0 0 3px;
|
||||
clip-path: polygon(100% 25%, 100% 100%, 25% 100%);
|
||||
}
|
||||
|
||||
&.top::after,
|
||||
&.bottom::after {
|
||||
left: 50%;
|
||||
margin-left: -.5rem;
|
||||
}
|
||||
&.top {
|
||||
bottom: 100%;
|
||||
box-shadow: 0px 8px 20px rgba(0, 0, 0, .35);
|
||||
&::after {
|
||||
bottom: -.3125rem;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
&.bottom {
|
||||
top: 100%;
|
||||
box-shadow: 0px -8px 20px rgba(0, 0, 0, .35);
|
||||
&::after {
|
||||
top: -.3125rem;
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.right::after,
|
||||
&.left::after {
|
||||
top: 50%;
|
||||
margin-top: -.5rem;
|
||||
}
|
||||
&.right {
|
||||
left: 100%;
|
||||
box-shadow: -8px 0px 20px rgba(0, 0, 0, .35);
|
||||
&::after {
|
||||
left: -.3125rem;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
&.left {
|
||||
right: 100%;
|
||||
box-shadow: 8px 0px 20px rgba(0, 0, 0, .35);
|
||||
&::after {
|
||||
right: -.3125rem;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.no-arrow {
|
||||
box-shadow: 0px 0px 20px rgba(0, 0, 0, .75);
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -14,10 +14,12 @@
|
||||
//
|
||||
|
||||
import { SvelteComponent } from 'svelte'
|
||||
import type { AnySvelteComponent, AnyComponent, PopupAlignment, LabelAndProps, TooltipAligment } from './types'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
|
||||
import Root from './components/internal/Root.svelte'
|
||||
|
||||
export type { AnyComponent, AnySvelteComponent, Action } from './types'
|
||||
export type { AnyComponent, AnySvelteComponent, Action, LabelAndProps, TooltipAligment } from './types'
|
||||
// export { applicationShortcutKey } from './utils'
|
||||
export { getCurrentLocation, navigate, location } from './location'
|
||||
|
||||
@ -32,6 +34,7 @@ export { default as Toggle } from './components/Toggle.svelte'
|
||||
export { default as Dialog } from './components/Dialog.svelte'
|
||||
export { default as ToggleWithLabel } from './components/ToggleWithLabel.svelte'
|
||||
export { default as Tooltip } from './components/Tooltip.svelte'
|
||||
export { default as TooltipInstance } from './components/TooltipInstance.svelte'
|
||||
export { default as CheckBox } from './components/CheckBox.svelte'
|
||||
export { default as Progress } from './components/Progress.svelte'
|
||||
export { default as Tabs } from './components/Tabs.svelte'
|
||||
@ -66,7 +69,6 @@ export { default as IconThread } from './components/icons/Thread.svelte'
|
||||
|
||||
export * from './utils'
|
||||
|
||||
import type { AnySvelteComponent, AnyComponent, PopupAlignment } from './types'
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
export function createApp (target: HTMLElement): SvelteComponent {
|
||||
@ -100,3 +102,17 @@ export function closePopup (): void {
|
||||
return popups
|
||||
})
|
||||
}
|
||||
|
||||
export const tooltipstore = writable<LabelAndProps>({
|
||||
label: undefined,
|
||||
element: undefined,
|
||||
direction: undefined
|
||||
})
|
||||
|
||||
export function showTooltip (label: IntlString, element: HTMLElement, direction?: TooltipAligment): void {
|
||||
tooltipstore.set({ label: label, element: element, direction: direction })
|
||||
}
|
||||
|
||||
export function closeTooltip (): void {
|
||||
tooltipstore.set({ label: undefined, element: undefined, direction: undefined })
|
||||
}
|
||||
|
@ -55,3 +55,11 @@ export interface Tab {
|
||||
export type TabModel = Tab[]
|
||||
|
||||
export type PopupAlignment = HTMLElement | 'right' | 'float'
|
||||
|
||||
export type TooltipAligment = 'top' | 'bottom' | 'left' | 'right'
|
||||
|
||||
export interface LabelAndProps {
|
||||
label: IntlString | undefined
|
||||
element: HTMLElement | undefined
|
||||
direction?: TooltipAligment
|
||||
}
|
||||
|
@ -48,10 +48,10 @@
|
||||
</div>
|
||||
{#if !thread}
|
||||
<div class="buttons">
|
||||
<div class="tool"><ActionIcon icon={IconMoreH} size={'medium'} direction={'left'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Bookmark} size={'medium'} direction={'left'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Share} size={'medium'} direction={'left'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Emoji} size={'medium'} direction={'left'}/></div>
|
||||
<div class="tool"><ActionIcon icon={IconMoreH} size={'medium'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Bookmark} size={'medium'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Share} size={'medium'}/></div>
|
||||
<div class="tool"><ActionIcon icon={Emoji} size={'medium'}/></div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -24,16 +24,14 @@
|
||||
export let notify: boolean
|
||||
</script>
|
||||
|
||||
<button class="app" class:selected={selected} on:click={action}>
|
||||
<Tooltip label={label} direction="right">
|
||||
<Tooltip {label}>
|
||||
<button class="app" class:selected={selected} on:click={action}>
|
||||
<div class="icon-container" class:noty={notify}>
|
||||
<Icon icon={icon} size={'large'}/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{#if notify}
|
||||
<div class="marker"/>
|
||||
{/if}
|
||||
</button>
|
||||
{#if notify}<div class="marker"/>{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<style lang="scss">
|
||||
.app {
|
||||
|
@ -29,7 +29,7 @@
|
||||
import SpaceHeader from './SpaceHeader.svelte'
|
||||
import SpaceView from './SpaceView.svelte'
|
||||
|
||||
import { AnyComponent, location, Popup, showPopup } from '@anticrm/ui'
|
||||
import { AnyComponent, location, Popup, showPopup, TooltipInstance } from '@anticrm/ui'
|
||||
import core from '@anticrm/core'
|
||||
import CreateUser from './CreateUser.svelte'
|
||||
|
||||
@ -92,6 +92,7 @@
|
||||
<!-- <div class="aside"><Chat thread/></div> -->
|
||||
</div>
|
||||
<Popup />
|
||||
<TooltipInstance />
|
||||
{:else}
|
||||
No client
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user