mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
Update and combine popup layout for select. Add svelte-check in presentation. (#845)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
6f9853ca4c
commit
496113cdb5
@ -3,9 +3,9 @@
|
||||
"Create": "Create",
|
||||
"Cancel": "Cancel",
|
||||
"Ok": "Ok",
|
||||
"Save": "Save",
|
||||
"Download": "Download",
|
||||
"Delete": "Delete",
|
||||
"Suggested": "Suggested",
|
||||
"NotSelected": "Not selected",
|
||||
"Deselect": "Deselect",
|
||||
"AddSocialLinks": "Add social links"
|
||||
|
@ -9,7 +9,8 @@
|
||||
"build:docs": "api-extractor run --local",
|
||||
"lint": "svelte-check && eslint",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src"
|
||||
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src",
|
||||
"svelte-check": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader": "^3.1.2",
|
||||
|
@ -15,8 +15,8 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { AttachedDoc, Class, Doc, Ref } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
// import core from '@anticrm/core'
|
||||
import type { Class, Doc, Ref } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { Button } from '@anticrm/ui'
|
||||
import imageCropper from '@anticrm/image-cropper'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let file: File
|
||||
|
||||
@ -38,7 +39,7 @@
|
||||
<Cropper bind:this={cropper} image={file} />
|
||||
</div>
|
||||
<div class="footer ml-6 mr-6 mt-4 mb-4">
|
||||
<Button label={"Save"} primary on:click={onCrop} />
|
||||
<Button label={plugin.string.Save} primary on:click={onCrop} />
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
|
@ -15,12 +15,11 @@
|
||||
<script lang="ts">
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
|
||||
import { Label, EditWithIcon, IconSearch } from '@anticrm/ui'
|
||||
import ui, { Label, EditWithIcon, IconSearch } from '@anticrm/ui'
|
||||
import SpaceInfo from './SpaceInfo.svelte'
|
||||
|
||||
import type { Ref, Class, Space } from '@anticrm/core'
|
||||
import { createQuery } from '../utils'
|
||||
import presentation from '..'
|
||||
|
||||
export let _class: Ref<Class<Space>>
|
||||
|
||||
@ -33,62 +32,21 @@
|
||||
afterUpdate(() => { dispatch('update', Date.now()) })
|
||||
</script>
|
||||
|
||||
<div class="popup">
|
||||
<div class="flex-col">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={'Search...'} />
|
||||
<div class="label"><Label label={presentation.string.Suggested} /></div>
|
||||
<div class="antiPopup antiPopup-withHeader">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={ui.string.SearchDots} focus />
|
||||
<div class="ap-caption"><Label label={ui.string.Suggested} /></div>
|
||||
</div>
|
||||
<div class="flex-grow scroll">
|
||||
<div class="flex-col h-full box">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll">
|
||||
<div class="ap-box">
|
||||
{#each objects as space}
|
||||
<button class="menu-item" on:click={() => { dispatch('close', space) }}>
|
||||
<button class="ap-menuItem" on:click={() => { dispatch('close', space) }}>
|
||||
<SpaceInfo size={'large'} value={space} />
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: .5rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin: 1rem 0 .625rem .375rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
|
||||
.scroll {
|
||||
overflow-y: scroll;
|
||||
.box { padding-right: 1px; }
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
justify-content: start;
|
||||
padding: .5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
}
|
||||
&:focus {
|
||||
color: var(--theme-content-accent-color);
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -16,7 +16,7 @@
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
|
||||
import { Label, EditWithIcon, IconSearch } from '@anticrm/ui'
|
||||
import ui, { Label, EditWithIcon, IconSearch } from '@anticrm/ui'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
|
||||
import type { Ref, Class } from '@anticrm/core'
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
export let _class: Ref<Class<Person>>
|
||||
export let title: IntlString
|
||||
export let caption: IntlString
|
||||
export let caption: IntlString = ui.string.Suggested
|
||||
export let selected: Ref<Person> | undefined
|
||||
|
||||
export let allowDeselect: boolean = false
|
||||
@ -42,16 +42,17 @@
|
||||
afterUpdate(() => { dispatch('update', Date.now()) })
|
||||
</script>
|
||||
|
||||
<div class="popup">
|
||||
<div class="title"><Label label={title} /></div>
|
||||
<div class="flex-col header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={'Search...'} focus />
|
||||
<div class="caption"><Label label={caption} /></div>
|
||||
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle">
|
||||
<div class="ap-title"><Label label={title} /></div>
|
||||
<div class="ap-header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={ui.string.SearchDots} focus />
|
||||
<div class="ap-caption"><Label label={caption} /></div>
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="flex-col box">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll">
|
||||
<div class="ap-box">
|
||||
{#each objects as person}
|
||||
<button class="menu-item" on:click={() => { dispatch('close', person) }}>
|
||||
<button class="ap-menuItem" on:click={() => { dispatch('close', person) }}>
|
||||
<div class='flex-grow'>
|
||||
<UserInfo size={'medium'} value={person} />
|
||||
</div>
|
||||
@ -62,61 +63,5 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 1rem 1rem .25rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.header {
|
||||
margin: .25rem 1rem 0;
|
||||
text-align: left;
|
||||
.caption {
|
||||
margin-top: .5rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
}
|
||||
|
||||
.scroll {
|
||||
flex-grow: 1;
|
||||
padding: .5rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.box {
|
||||
margin-right: 1px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
justify-content: start;
|
||||
padding: .375rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
}
|
||||
&:focus {
|
||||
color: var(--theme-content-accent-color);
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -27,9 +27,9 @@ export default plugin(presentationId, {
|
||||
Create: '' as IntlString,
|
||||
Cancel: '' as IntlString,
|
||||
Ok: '' as IntlString,
|
||||
Save: '' as IntlString,
|
||||
Download: '' as IntlString,
|
||||
Delete: '' as IntlString,
|
||||
Suggested: '' as IntlString,
|
||||
NotSelected: '' as IntlString,
|
||||
Deselect: '' as IntlString,
|
||||
AddSocialLinks: '' as IntlString
|
||||
|
@ -222,6 +222,9 @@ p:last-child { margin-block-end: 0; }
|
||||
.mb-3 { margin-bottom: .75rem; }
|
||||
.mb-4 { margin-bottom: 1rem; }
|
||||
|
||||
.pr-1 { padding-right: .25rem; }
|
||||
.pr-4 { padding-right: 1rem; }
|
||||
|
||||
/* --------- */
|
||||
.relative { position: relative; }
|
||||
.abs-lt-content {
|
||||
@ -259,6 +262,8 @@ p:last-child { margin-block-end: 0; }
|
||||
}
|
||||
|
||||
.h-full { height: 100%; }
|
||||
.h-2 { height: .5rem; }
|
||||
.h-9 { height: 2.25rem; }
|
||||
.w-full { width: 100%; }
|
||||
.min-w-0 { min-width: 0; }
|
||||
.min-h-0 { min-height: 0; }
|
||||
@ -393,8 +398,107 @@ a.no-line {
|
||||
.overflow-y-auto { overflow-y: auto; }
|
||||
.whitespace-nowrap { white-space: nowrap; }
|
||||
|
||||
/* Scrollbars */
|
||||
.scroll-m-0::-webkit-scrollbar-track { margin: 0; }
|
||||
.scroll-m-10::-webkit-scrollbar-track { margin: 2.5rem; }
|
||||
|
||||
.scroll-bg-accent-color::-webkit-scrollbar-thumb {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
&:hover { background-color: var(--theme-menu-divider); }
|
||||
}
|
||||
|
||||
/* Popups */
|
||||
.antiPopup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
user-select: none;
|
||||
|
||||
.ap-space {
|
||||
flex-shrink: 0;
|
||||
height: .5rem;
|
||||
}
|
||||
.ap-scroll {
|
||||
flex-grow: 1;
|
||||
margin: 0 .25rem;
|
||||
min-height: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar-track { margin: 0; }
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
&:hover { background-color: var(--theme-menu-divider); }
|
||||
}
|
||||
}
|
||||
.ap-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 .25rem;
|
||||
height: 100%;
|
||||
}
|
||||
.ap-menuItem {
|
||||
justify-content: start;
|
||||
padding: .5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
text-align: left;
|
||||
|
||||
&.ap-woScroll { margin: 0 .5rem; }
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
cursor: pointer;
|
||||
}
|
||||
&:focus {
|
||||
color: var(--theme-content-accent-color);
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.ap-check {
|
||||
margin-left: 1rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
&-withHeader {
|
||||
.ap-header {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 .5rem;
|
||||
text-align: left;
|
||||
|
||||
.ap-caption {
|
||||
margin: .5rem 0 0 .75rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-withTitle {
|
||||
.ap-title {
|
||||
flex-shrink: 0;
|
||||
margin: 1rem 1rem .25rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.ap-header {
|
||||
margin: .25rem 1rem 0;
|
||||
.ap-caption {
|
||||
margin: .5rem 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Backgrounds & Colors */
|
||||
.background-theme-bg-color { background-color: var(--theme-bg-color); }
|
||||
.background-highlight-red { background-color: var(--highlight-red); }
|
||||
|
@ -7,6 +7,8 @@
|
||||
"Days": "{days, plural, =0 {today} =1 {yesterday} other {# days ago}}",
|
||||
"ShowMore": "Show more",
|
||||
"ShowLess": "Show less",
|
||||
"Search": "Search"
|
||||
"Search": "Search",
|
||||
"SearchDots": "Search...",
|
||||
"Suggested": "Suggested"
|
||||
}
|
||||
}
|
||||
|
@ -106,14 +106,13 @@
|
||||
.popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
user-select: none;
|
||||
filter: drop-shadow(0 1.5rem 4rem rgba(0, 0, 0, .35));
|
||||
}
|
||||
|
||||
.arrow {
|
||||
|
@ -22,98 +22,46 @@
|
||||
import IconSearch from './icons/Search.svelte'
|
||||
import IconBlueCheck from './icons/BlueCheck.svelte'
|
||||
import type { DropdownTextItem } from '../types'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let title: IntlString
|
||||
export let caption: IntlString | undefined = undefined
|
||||
export let title: IntlString | undefined = undefined
|
||||
export let caption: IntlString = plugin.string.Suggested
|
||||
export let items: DropdownTextItem[]
|
||||
export let selected: DropdownTextItem['id'] | undefined = undefined
|
||||
export let header: boolean = false
|
||||
|
||||
let search: string = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="popup">
|
||||
<div
|
||||
class="antiPopup"
|
||||
class:antiPopup-withHeader={header}
|
||||
class:antiPopup-withTitle={title}
|
||||
>
|
||||
{#if header}
|
||||
{#if title}<div class="title"><Label label={title} /></div>{/if}
|
||||
<div class="flex-col header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={'Search...'} />
|
||||
{#if caption}<div class="caption"><Label label={caption} /></div>{/if}
|
||||
{#if title}
|
||||
<div class="ap-title"><Label label={title} /></div>
|
||||
{:else}
|
||||
<div class="ap-space" />
|
||||
{/if}
|
||||
<div class="ap-header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={plugin.string.SearchDots} focus />
|
||||
<div class="ap-caption"><Label label={caption} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="scroll">
|
||||
<div class="flex-col box">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll">
|
||||
<div class="ap-box">
|
||||
{#each items.filter((x) => x.label.toLowerCase().includes(search.toLowerCase())) as item}
|
||||
<button class="flex-between menu-item" on:click={() => { dispatch('close', item.id) }}>
|
||||
<button class="ap-menuItem flex-row-center h-9" on:click={() => { dispatch('close', item.id) }}>
|
||||
<div class="flex-grow caption-color">{item.label}</div>
|
||||
{#if item.id === selected}
|
||||
<div class="check"><IconBlueCheck size={'small'} /></div>
|
||||
<div class="ap-check"><IconBlueCheck size={'small'} /></div>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 15rem;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 1rem 1rem .25rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.header {
|
||||
margin: .25rem 1rem 0;
|
||||
text-align: left;
|
||||
.caption {
|
||||
margin-top: .5rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
}
|
||||
|
||||
.scroll {
|
||||
flex-grow: 1;
|
||||
padding: .5rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.box {
|
||||
margin-right: 1px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
text-align: left;
|
||||
padding: .5rem;
|
||||
border-radius: .5rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
}
|
||||
&:focus {
|
||||
color: var(--theme-content-accent-color);
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-left: 1rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -20,29 +20,38 @@
|
||||
import EditWithIcon from './EditWithIcon.svelte'
|
||||
import IconSearch from './icons/Search.svelte'
|
||||
import type { ListItem } from '../types'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let title: IntlString
|
||||
export let caption: IntlString
|
||||
export let title: IntlString | undefined = undefined
|
||||
export let caption: IntlString = plugin.string.Suggested
|
||||
export let items: ListItem[]
|
||||
export let header: boolean = true
|
||||
|
||||
let search: string = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="popup">
|
||||
<div class="title"><Label label={title} /></div>
|
||||
<div
|
||||
class="antiPopup"
|
||||
class:antiPopup-withHeader={header}
|
||||
class:antiPopup-withTitle={title}
|
||||
>
|
||||
{#if header}
|
||||
<div class="flex-col header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={'Search...'} />
|
||||
<div class="caption"><Label label={caption} /></div>
|
||||
{#if title}
|
||||
<div class="ap-title"><Label label={title} /></div>
|
||||
{:else}
|
||||
<div class="ap-space" />
|
||||
{/if}
|
||||
<div class="ap-header">
|
||||
<EditWithIcon icon={IconSearch} bind:value={search} placeholder={plugin.string.SearchDots} focus />
|
||||
<div class="ap-caption"><Label label={caption} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="scroll">
|
||||
<div class="flex-col box">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll">
|
||||
<div class="ap-box">
|
||||
{#each items.filter((x) => x.label.toLowerCase().includes(search.toLowerCase())) as item}
|
||||
<button class="flex-row-center menu-item" on:click={() => { dispatch('close', item) }}>
|
||||
<button class="ap-menuItem" on:click={() => { dispatch('close', item) }}>
|
||||
<div class="flex-center img">
|
||||
<img src={item.item} alt={item.label} />
|
||||
</div>
|
||||
@ -51,68 +60,18 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 1rem 1rem .25rem;
|
||||
font-weight: 500;
|
||||
.img {
|
||||
margin-right: .75rem;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.header {
|
||||
margin: .25rem 1rem 0;
|
||||
text-align: left;
|
||||
.caption {
|
||||
margin-top: .5rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
}
|
||||
|
||||
.scroll {
|
||||
flex-grow: 1;
|
||||
padding: .5rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.box {
|
||||
margin-right: 1px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
text-align: left;
|
||||
padding: .5rem;
|
||||
border-radius: .5rem;
|
||||
overflow: hidden;
|
||||
|
||||
.img {
|
||||
margin-right: .75rem;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
border-radius: .5rem;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
max-width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover { background-color: var(--theme-button-bg-hovered); }
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
z-index: 1;
|
||||
}
|
||||
img { max-width: fit-content; }
|
||||
}
|
||||
</style>
|
||||
|
@ -14,32 +14,36 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
import { translate } from '@anticrm/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import IconClose from './icons/Close.svelte'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let width: string | undefined = undefined
|
||||
export let value: string | undefined = undefined
|
||||
export let placeholder: string = 'placeholder'
|
||||
export let placeholder: IntlString = plugin.string.EditBoxPlaceholder
|
||||
export let focus: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let textHTML: HTMLInputElement
|
||||
let phTraslate: string = ''
|
||||
|
||||
$: translate(placeholder, {}).then(res => { phTraslate = res })
|
||||
$: if (textHTML !== undefined) {
|
||||
if (focus) {
|
||||
textHTML.focus()
|
||||
focus = false
|
||||
}
|
||||
}
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="flex-between editbox" style={width ? 'width: ' + width : ''} on:click={() => textHTML.focus()}>
|
||||
<div class="mr-2"><Icon {icon} size={'small'} /></div>
|
||||
<input bind:this={textHTML} type="text" bind:value {placeholder} on:change on:input on:keydown/>
|
||||
<input bind:this={textHTML} type="text" bind:value placeholder={phTraslate} on:change on:input on:keydown/>
|
||||
{#if value}
|
||||
<div class="ml-2 btn" on:click={() => { value = ''; dispatch('change', '') }}>
|
||||
<Icon icon={IconClose} size={'x-small'} />
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import { Action } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import Label from './Label.svelte'
|
||||
@ -23,43 +23,23 @@
|
||||
export let ctx: any = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
afterUpdate(() => { dispatch('update', Date.now()) })
|
||||
</script>
|
||||
|
||||
<div class="flex-col popup">
|
||||
{#each actions as action}
|
||||
<div class="flex-row-center menu-item" on:click={() => {
|
||||
dispatch('close')
|
||||
action.action(ctx)
|
||||
}}>
|
||||
{#if action.icon}
|
||||
<Icon icon={action.icon} size={'small'} />
|
||||
{/if}
|
||||
<div class="ml-3"><Label label={action.label} /></div>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="antiPopup">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll"><div class="ap-box">
|
||||
{#each actions as action}
|
||||
<div class="ap-menuItem flex-row-center" on:click={() => {
|
||||
dispatch('close')
|
||||
action.action(ctx)
|
||||
}}>
|
||||
{#if action.icon}
|
||||
<Icon icon={action.icon} size={'small'} />
|
||||
{/if}
|
||||
<div class="ml-3 pr-1"><Label label={action.label} /></div>
|
||||
</div>
|
||||
{/each}
|
||||
</div></div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
padding: .5rem;
|
||||
height: 100%;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0 .75rem 1.25rem rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .375rem 1rem .375rem .5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -47,6 +47,7 @@
|
||||
if (element) {
|
||||
show = false
|
||||
modalHTML.style.left = modalHTML.style.right = modalHTML.style.top = modalHTML.style.bottom = ''
|
||||
modalHTML.style.maxHeight = modalHTML.style.height = ''
|
||||
if (typeof element !== 'string') {
|
||||
let el: HTMLElement = element as HTMLElement
|
||||
const rect = el.getBoundingClientRect()
|
||||
@ -56,7 +57,10 @@
|
||||
modalHTML.style.top = `calc(${rect.bottom}px + .75rem)`
|
||||
else if (rectPopup.height + 28 < rect.top)
|
||||
modalHTML.style.bottom = `calc(${document.body.clientHeight - rect.y}px + .75rem)`
|
||||
else modalHTML.style.top = modalHTML.style.bottom = '1rem'
|
||||
else
|
||||
modalHTML.style.top = modalHTML.style.bottom = '1rem'
|
||||
// modalHTML.style.maxHeight = 'calc(100vh - 2rem)'
|
||||
// }
|
||||
// Horizontal
|
||||
if (rect.left + rectPopup.width + 16 > document.body.clientWidth)
|
||||
modalHTML.style.right = document.body.clientWidth - rect.right + 'px'
|
||||
@ -105,6 +109,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
max-height: calc(100vh - 2rem);
|
||||
background-color: transparent;
|
||||
}
|
||||
.modal-overlay {
|
||||
|
@ -1,8 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { translate } from '@anticrm/platform'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ui from '../plugin'
|
||||
import EditWithIcon from './EditWithIcon.svelte'
|
||||
import IconSearch from './icons/Search.svelte'
|
||||
|
||||
@ -10,16 +7,10 @@
|
||||
|
||||
$: _search = value
|
||||
const dispatch = createEventDispatcher()
|
||||
let placeholder = ''
|
||||
|
||||
translate(ui.string.Search, {}).then((v) => {
|
||||
placeholder = v
|
||||
})
|
||||
</script>
|
||||
|
||||
<EditWithIcon
|
||||
icon={IconSearch}
|
||||
placeholder={placeholder}
|
||||
bind:value={_search}
|
||||
on:change={() => {
|
||||
if (_search === '') {
|
||||
|
@ -22,9 +22,10 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="flex-col popup">
|
||||
<div class="antiPopup">
|
||||
<div class="ap-space" />
|
||||
{#each langs as lang}
|
||||
<div class="flex-row-center menu-item" on:click={() => {
|
||||
<div class="ap-menuItem ap-woScroll flex-row-center" on:click={() => {
|
||||
dispatch('close', lang.id)
|
||||
}}>
|
||||
<svg class="svg-small">
|
||||
@ -33,29 +34,5 @@
|
||||
<div class="ml-3"><Label label={lang.label} /></div>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
padding: .5rem;
|
||||
height: 100%;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0 .75rem 1.25rem rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .375rem 1rem .375rem .5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { showPopup } from '../..'
|
||||
import LangPopup from './LangPopup.svelte'
|
||||
|
||||
@ -22,8 +23,8 @@
|
||||
|
||||
const { currentLanguage, setLanguage } = getContext('lang')
|
||||
const langs
|
||||
= [{ id: 'en', label: 'English' },
|
||||
{ id: 'ru', label: 'Russian' }]
|
||||
= [{ id: 'en', label: 'English' as IntlString },
|
||||
{ id: 'ru', label: 'Russian' as IntlString }]
|
||||
|
||||
$: selected = langs.find(item => item.id === currentLanguage)
|
||||
let trigger: HTMLElement
|
||||
|
@ -31,6 +31,8 @@ export default plugin(uiId, {
|
||||
Days: '' as IntlString,
|
||||
ShowMore: '' as IntlString,
|
||||
ShowLess: '' as IntlString,
|
||||
Search: '' as IntlString
|
||||
Search: '' as IntlString,
|
||||
SearchDots: '' as IntlString,
|
||||
Suggested: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -20,7 +20,6 @@
|
||||
import { getPlatformColor } from '@anticrm/ui'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import StatesBarElement from './StatesBarElement.svelte'
|
||||
import { getPlatformColor } from '@anticrm/ui'
|
||||
|
||||
export let space: Ref<SpaceWithStates>
|
||||
export let state: Ref<State> | undefined = undefined
|
||||
|
Loading…
Reference in New Issue
Block a user