mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #903 from appwrite/fix-tooltip-arrow
fix: tooltip arrows
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
export let wrapperFullWidth = false;
|
||||
export let fixed = false;
|
||||
export let display = 'block';
|
||||
export let arrowSize = 10;
|
||||
export let isPopover = false;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
blur: undefined;
|
||||
@@ -33,13 +35,14 @@
|
||||
{
|
||||
name: 'arrow',
|
||||
options: {
|
||||
element: arrow
|
||||
element: arrow,
|
||||
padding: arrowSize * 1.75
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, noArrow ? 0 : 6]
|
||||
offset: [-arrowSize, noArrow ? 0 : arrowSize / 1.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -113,10 +116,15 @@
|
||||
|
||||
<div
|
||||
class="drop-tooltip"
|
||||
class:u-width-full-line={fullWidth}
|
||||
bind:this={tooltip}
|
||||
class:u-width-full-line={fullWidth}
|
||||
style:--arrow-size={`${arrowSize}px`}
|
||||
style:z-index="10">
|
||||
<div class="drop-arrow" class:u-hide={!show || (show && noArrow)} bind:this={arrow} />
|
||||
<div
|
||||
class="drop-arrow"
|
||||
class:is-popover={isPopover}
|
||||
class:u-hide={!show || (show && noArrow)}
|
||||
bind:this={arrow} />
|
||||
{#if show}
|
||||
<slot name="list" />
|
||||
{/if}
|
||||
@@ -124,36 +132,50 @@
|
||||
|
||||
<!-- svelte-ignore css-unused-selector -->
|
||||
<style global lang="scss">
|
||||
.drop-tooltip[data-popper-placement^='top'] > .drop-arrow {
|
||||
bottom: -4px;
|
||||
}
|
||||
|
||||
.drop-tooltip[data-popper-placement^='bottom'] > .drop-arrow {
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.drop-tooltip[data-popper-placement^='left'] > .drop-arrow {
|
||||
right: -4px;
|
||||
}
|
||||
|
||||
.drop-tooltip[data-popper-placement^='right'] > .drop-arrow {
|
||||
left: -4px;
|
||||
.drop-arrow.is-popover {
|
||||
--drop-arrow-pop-over-bg-color: var(--color-neutral-90);
|
||||
body.theme-light & {
|
||||
--drop-arrow-pop-over-bg-color: var(--color-neutral-0);
|
||||
}
|
||||
}
|
||||
.drop-arrow,
|
||||
.drop-arrow::before {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
z-index: -1;
|
||||
width: var(--arrow-size);
|
||||
height: var(--arrow-size);
|
||||
z-index: 1;
|
||||
|
||||
--drop-arrow-border: 1px solid hsl(var(--color-neutral-85));
|
||||
--drop-arrow-bg-color: hsl(var(--drop-arrow-pop-over-bg-color, var(--color-neutral-105)));
|
||||
body.theme-light & {
|
||||
--drop-arrow-border: 1px solid hsl(var(--color-neutral-10));
|
||||
--drop-arrow-bg-color: hsl(var(--drop-arrow-pop-over-bg-color, var(--color-neutral-0)));
|
||||
}
|
||||
}
|
||||
|
||||
.drop-arrow::before {
|
||||
content: '';
|
||||
transform: rotate(45deg);
|
||||
background: hsl(var(--color-neutral-85));
|
||||
background: var(--drop-arrow-bg-color);
|
||||
}
|
||||
|
||||
body.theme-light & {
|
||||
background: hsl(var(--color-neutral-10));
|
||||
.drop-tooltip[data-popper-placement^='top'] > .drop-arrow {
|
||||
bottom: calc(var(--arrow-size) / -2);
|
||||
|
||||
&::before {
|
||||
border-bottom: var(--drop-arrow-border);
|
||||
border-right: var(--drop-arrow-border);
|
||||
border-bottom-right-radius: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.drop-tooltip[data-popper-placement^='bottom'] > .drop-arrow {
|
||||
top: calc(var(--arrow-size) / -2);
|
||||
|
||||
&::before {
|
||||
border-top: var(--drop-arrow-border);
|
||||
border-left: var(--drop-arrow-border);
|
||||
border-top-left-radius: 25%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
import { Drop } from '$lib/components';
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
export let autofocus = false;
|
||||
export let autocomplete = false;
|
||||
export let maxlength: number = null;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
export let fullWidth = false;
|
||||
|
||||
// https://www.geeksforgeeks.org/how-to-validate-a-domain-name-using-regular-expression/
|
||||
@@ -52,8 +53,8 @@
|
||||
|
||||
<FormItem {fullWidth}>
|
||||
<Label {required} hide={!showLabel} for={id}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -68,8 +69,10 @@
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:--p-card-padding=".75rem"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
import NullCheckbox from './nullCheckbox.svelte';
|
||||
import { Drop } from '$lib/components';
|
||||
@@ -17,7 +17,8 @@
|
||||
export let autofocus = false;
|
||||
export let autocomplete = false;
|
||||
export let tooltip: string = null;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
export let fullWidth = false;
|
||||
|
||||
let element: HTMLInputElement;
|
||||
@@ -61,8 +62,8 @@
|
||||
|
||||
<FormItem {fullWidth}>
|
||||
<Label {required} {optionalText} {tooltip} hide={!showLabel} for={id}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -77,8 +78,10 @@
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:--p-card-padding=".75rem"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Drop, Trim } from '$lib/components';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { Helper, Label } from '.';
|
||||
|
||||
export let label: string = null;
|
||||
@@ -13,7 +13,8 @@
|
||||
export let optionalText: string = null;
|
||||
export let tooltip: string = null;
|
||||
export let error: string = null;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
|
||||
let input: HTMLInputElement;
|
||||
let hovering = false;
|
||||
@@ -96,8 +97,8 @@
|
||||
<div>
|
||||
{#if label}
|
||||
<Label {required} {optionalText} {tooltip} hide={!label}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -112,8 +113,10 @@
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:--p-card-padding=".75rem"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
import { Drop } from '$lib/components';
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
export let showPasswordButton = false;
|
||||
export let minlength = 8;
|
||||
export let maxlength: number = null;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
export let fullWidth = false;
|
||||
|
||||
let element: HTMLInputElement;
|
||||
@@ -52,8 +53,8 @@
|
||||
|
||||
<FormItem {fullWidth}>
|
||||
<Label {required} hide={!showLabel} for={id}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show={showPopover} display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show={showPopover} display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -68,8 +69,10 @@
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:--p-card-padding=".75rem"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
import { Drop } from '$lib/components';
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
export let autofocus = false;
|
||||
export let autocomplete = false;
|
||||
export let maxlength: number = null;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
export let fullWidth = false;
|
||||
|
||||
const pattern = String.raw`^\+?[1-9]\d{1,14}$`;
|
||||
@@ -51,8 +52,8 @@
|
||||
|
||||
<FormItem {fullWidth}>
|
||||
<Label {required} hide={!showLabel} for={id}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -67,8 +68,10 @@
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:--p-card-padding=".75rem"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { SvelteComponent, onMount } from 'svelte';
|
||||
import { FormItem, FormItemPart, Helper, Label } from '.';
|
||||
import NullCheckbox from './nullCheckbox.svelte';
|
||||
import TextCounter from './textCounter.svelte';
|
||||
@@ -23,7 +23,8 @@
|
||||
export let maxlength: number = null;
|
||||
export let tooltip: string = null;
|
||||
export let isMultiple = false;
|
||||
export let isPopoverDefined = true;
|
||||
export let popover: typeof SvelteComponent<unknown> = null;
|
||||
export let popoverProps: Record<string, unknown> = {};
|
||||
|
||||
let element: HTMLInputElement;
|
||||
let error: string;
|
||||
@@ -77,8 +78,8 @@
|
||||
<svelte:component this={wrapper} {fullWidth}>
|
||||
{#if label}
|
||||
<Label {required} {hideRequired} {tooltip} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}{#if $$slots.popover && isPopoverDefined}
|
||||
<Drop bind:show display="inline-block">
|
||||
{label}{#if popover}
|
||||
<Drop isPopover bind:show display="inline-block">
|
||||
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -88,13 +89,15 @@
|
||||
<span
|
||||
class="icon-info"
|
||||
aria-hidden="true"
|
||||
style="font-size: var(--icon-size-small)" />
|
||||
style:font-size="var(--icon-size-small)" />
|
||||
</button>
|
||||
<svelte:fragment slot="list">
|
||||
<div
|
||||
class="dropped card u-max-width-250"
|
||||
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
|
||||
<slot name="popover" />
|
||||
style:--p-card-padding=".75rem"
|
||||
style:--card-border-radius="var(--border-radius-small)"
|
||||
style:box-shadow="var(--shadow-large)">
|
||||
<svelte:component this={popover} {...popoverProps} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ImagePreview } from '$lib/components';
|
||||
|
||||
export let lines = [];
|
||||
export let popoverImage: { src: { dark: string; light: string }; alt: string } | null = null;
|
||||
export let image: { src: { dark: string; light: string }; alt: string } | null = null;
|
||||
</script>
|
||||
|
||||
<div class="u-flex-vertical u-gap-16">
|
||||
@@ -10,11 +10,8 @@
|
||||
<p>{@html line}</p>
|
||||
{/each}
|
||||
|
||||
{#if popoverImage}
|
||||
<ImagePreview
|
||||
darkSrc={popoverImage.src.dark}
|
||||
lightSrc={popoverImage.src.light}
|
||||
alt={popoverImage.alt} />
|
||||
{#if image}
|
||||
<ImagePreview darkSrc={image.src.dark} lightSrc={image.src.light} alt={image.alt} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -41,7 +41,18 @@
|
||||
>;
|
||||
export let fullWidth = false;
|
||||
|
||||
let popoverImage = input.popoverImage;
|
||||
const popover = input.popover ? PopoverContent : null;
|
||||
const popoverProps = getPopoverProps(input);
|
||||
|
||||
function getPopoverProps(input: ProviderInput) {
|
||||
if (!input.popover) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
lines: input.popover,
|
||||
image: input.popoverImage
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if input.type === 'text'}
|
||||
@@ -51,13 +62,10 @@
|
||||
placeholder={input.placeholder}
|
||||
required={!input.optional}
|
||||
tooltip={input.tooltip}
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
{popover}
|
||||
{popoverProps}
|
||||
{fullWidth}
|
||||
bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputText>
|
||||
bind:value={params[input.name]} />
|
||||
{:else if input.type === 'password'}
|
||||
<InputPassword
|
||||
id={input.name}
|
||||
@@ -65,13 +73,10 @@
|
||||
placeholder={input.placeholder}
|
||||
required={!input.optional}
|
||||
showPasswordButton
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
{popover}
|
||||
{popoverProps}
|
||||
{fullWidth}
|
||||
bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputPassword>
|
||||
bind:value={params[input.name]} />
|
||||
{:else if input.type === 'email'}
|
||||
<InputEmail
|
||||
id={input.name}
|
||||
@@ -79,52 +84,39 @@
|
||||
placeholder={input.placeholder}
|
||||
required={!input.optional}
|
||||
tooltip={input.tooltip}
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
{popover}
|
||||
{popoverProps}
|
||||
{fullWidth}
|
||||
bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputEmail>
|
||||
bind:value={params[input.name]} />
|
||||
{:else if input.type === 'domain'}
|
||||
<InputDomain
|
||||
id={input.name}
|
||||
label={input.label}
|
||||
placeholder={input.placeholder}
|
||||
required={!input.optional}
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
{popover}
|
||||
{popoverProps}
|
||||
{fullWidth}
|
||||
bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputDomain>
|
||||
bind:value={params[input.name]} />
|
||||
{:else if input.type === 'phone'}
|
||||
<InputPhone
|
||||
id={input.name}
|
||||
label={input.label}
|
||||
placeholder={input.placeholder}
|
||||
required={!input.optional}
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
{popover}
|
||||
{popoverProps}
|
||||
{fullWidth}
|
||||
bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputPhone>
|
||||
bind:value={params[input.name]} />
|
||||
{:else if input.type === 'file'}
|
||||
<InputFile
|
||||
label={input.label}
|
||||
allowedFileExtensions={input.allowedFileExtensions}
|
||||
required={!input.optional}
|
||||
tooltip={input.tooltip}
|
||||
isPopoverDefined={input.popover !== undefined}
|
||||
bind:files={files[input.name]}>
|
||||
{fullWidth}
|
||||
<svelte:fragment slot="popover">
|
||||
<PopoverContent lines={input.popover} {popoverImage} />
|
||||
</svelte:fragment>
|
||||
</InputFile>
|
||||
{popover}
|
||||
{popoverProps}
|
||||
bind:files={files[input.name]} />
|
||||
{:else if input.type === 'switch'}
|
||||
<InputSwitch label={input.label} id={input.name} bind:value={params[input.name]}>
|
||||
<svelte:fragment slot="description">
|
||||
|
||||
Reference in New Issue
Block a user