flush to develop (#380)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
Co-authored-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
Co-authored-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Platov
2021-11-26 12:28:15 +01:00
committed by GitHub
co-authored by Denis Bykhov Andrey Sobolev
parent cd0e7da28e
commit 68ae2f2e31
23 changed files with 312 additions and 347 deletions
@@ -20,14 +20,14 @@
import type { Channel, ChannelProvider } from '@anticrm/contact'
import { getClient } from '..'
import { AnyComponent, Icon } from '@anticrm/ui'
import IconCopy from './icons/Copy.svelte'
import { Tooltip, CircleButton } from '@anticrm/ui'
import ChannelsPopup from './ChannelsPopup.svelte'
import contact from '@anticrm/contact'
import { createEventDispatcher } from 'svelte'
export let value: Channel[] | null
export let size: 'small' | 'medium' = 'medium'
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'large'
export let reverse: boolean = false
interface Item {
@@ -69,143 +69,20 @@
$: if (value) update(value)
let displayItems: Item[] = []
let divHTML: HTMLElement
</script>
<div class="container" class:reverse>
<div
bind:this={divHTML}
class="flex-row-center"
class:safari-gap-1={size === 'small'}
class:safari-gap-2={size !== 'small'}
class:reverse
on:click|stopPropagation={() => {}}
>
{#each displayItems as item}
<div on:click|stopPropagation={() => {dispatch('click', item)}}>
<div class="circle list list-{size}">
<div class="icon" class:small={size === 'small'}>
<Icon icon={item.icon} size={'small'}/>
</div>
</div>
<div class="window {reverse ? 'right' : 'left'}">
<div class="circle circle-icon">
<div class="icon"><Icon icon={item.icon} size={'small'}/></div>
</div>
<div class="flex-grow flex-col caption-color">
<div class="overflow-label label">{item.label}</div>
<div class="overflow-label">{item.value}</div>
</div>
<div class="button" on:click|preventDefault={() => { alert('Copied: ' + item.value) }}>
<IconCopy size={'small'}/>
</div>
</div>
</div>
<Tooltip component={ChannelsPopup} props={{ value: item }} label={undefined} anchor={divHTML}>
<CircleButton icon={item.icon} {size} />
</Tooltip>
{/each}
</div>
<style lang="scss">
.container {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
.circle {
position: relative;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--theme-bg-focused-color);
border-radius: 50%;
cursor: pointer;
.small {
transform-origin: center center;
transform: scale(.55);
opacity: 1;
}
&-icon {
margin-right: .75rem;
width: 2.25rem;
height: 2.25rem;
.icon {
transform: none;
opacity: 1;
}
}
}
.list {
&:hover {
border-color: var(--theme-bg-focused-border);
z-index: 5;
.icon { opacity: 1; }
& + .window {
z-index: 4;
visibility: visible;
}
&::after { content: ''; }
}
&::after {
position: absolute;
top: 0;
bottom: -1rem;
left: -100%;
right: -100%;
clip-path: polygon(0 100%, 25% 50%, 25% 0, 75% 0, 75% 50%, 100% 100%);
// background-color: rgba(255, 255, 0, .5);
}
&:first-child:after {
left: 0;
right: -100%;
clip-path: polygon(0 0, 0 100%, 100% 100%, 65% 50%, 65% 0);
}
}
.list-small {
margin-right: .25rem;
width: 1.5rem;
height: 1.5rem;
}
.list-medium {
margin-right: .5rem;
width: 2rem;
height: 2rem;
}
&.reverse {
flex-direction: row-reverse;
.list:first-child:after {
left: -100%;
right: 0;
clip-path: polygon(0 100%, 35% 50%, 35% 0, 100% 0, 100% 100%);
}
}
.window {
position: absolute;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
top: calc(100% + .5rem);
min-width: 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);
visibility: hidden;
&:hover {
z-index: 4;
visibility: visible;
}
&.right { right: 0; }
&.left { left: 0; }
}
}
.label {
font-weight: 500;
font-size: .75rem;
}
.button {
margin-left: 1.5rem;
opacity: .4;
cursor: pointer;
&:hover { opacity: 1; }
}
</style>
@@ -0,0 +1,65 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// 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 type { IntlString, Asset } from '@anticrm/platform'
import { CircleButton, closeTooltip } from '@anticrm/ui'
import IconCopy from './icons/Copy.svelte'
interface Item {
label: IntlString,
icon: Asset,
value: string
}
export let value: Item
const copyLink = (): void => {
navigator.clipboard
.writeText(value.value)
// .then(() => {
// console.log('Copied!', value.value)
// })
// .catch((err) => {
// console.log('Something went wrong', err)
// })
closeTooltip()
}
</script>
<div class="flex-row-center">
<CircleButton icon={value.icon} size={'x-large'} />
<div class="flex-col caption-color ml-3">
<div class="label">{value.label}</div>
<div class="overflow-label">{value.value}</div>
</div>
<div class="button" on:click|preventDefault={copyLink}>
<IconCopy size={'small'}/>
</div>
</div>
<style lang="scss">
.label {
font-weight: 500;
font-size: .75rem;
}
.button {
margin-left: 1.5rem;
color: var(--theme-content-dark-color);
cursor: pointer;
&:hover { color: var(--theme-caption-color); }
}
</style>
@@ -1,6 +1,6 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'var(--theme-caption-color)'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
@@ -37,6 +37,14 @@
<code><svelte:self nodes={node.childNodes}/></code>
{:else if node.nodeName === 'BR'}
<br/>
{:else if node.nodeName === 'H1'}
<h1><svelte:self nodes={node.childNodes}/></h1>
{:else if node.nodeName === 'H2'}
<h2><svelte:self nodes={node.childNodes}/></h2>
{:else if node.nodeName === 'UL'}
<ul><svelte:self nodes={node.childNodes}/></ul>
{:else if node.nodeName === 'LI'}
<li><svelte:self nodes={node.childNodes}/></li>
{:else if node.nodeName === 'SPAN'}
<Person objectId={node.getAttribute('data-id')} title={node.getAttribute('data-label')} />
{:else}
+2
View File
@@ -25,6 +25,8 @@
--primary-button-outline: rgba(87, 132, 255, .3);
--primary-button-border: rgba(255, 255, 255, .09);
--duotone-color: rgba(126, 134, 158, .25);
--trans-primary-button-color: #fff;
--trans-primary-button-bg: #4474F6;
--trans-primary-button-border: transparent;
+25
View File
@@ -131,6 +131,9 @@ table {
flex-direction: row-reverse;
align-items: center;
}
.flex-reverse {
flex-direction: row-reverse;
}
.flex-col {
display: flex;
flex-direction: column;
@@ -146,6 +149,25 @@ table {
align-items: stretch;
}
.safari-gap-1 {
& > * { margin-right: .25rem; }
& > *:last-child { margin-right: 0; }
&.reverse {
flex-direction: row-reverse;
& > :last-child { margin-right: .25rem; }
& > :first-child { margin-right: 0; }
}
}
.safari-gap-2 {
& > * { margin-right: .5rem; }
& > *:last-child { margin-right: 0; }
&.reverse {
flex-direction: row-reverse;
& > :last-child { margin-right: .5rem; }
& > :first-child { margin-right: 0; }
}
}
/* --------- */
.sm-tool-icon {
display: flex;
@@ -170,10 +192,13 @@ table {
.step-lr75 + .step-lr75 { margin-left: .75rem; }
.step-tb75 + .step-tb75 { margin-top: .75rem; }
.ml-1 { margin-left: .25rem; }
.ml-2 { margin-left: .5rem; }
.ml-3 { margin-left: .75rem; }
.mr-1 { margin-right: .25rem; }
.mr-4 { margin-right: 1rem; }
.mr-8 { margin-right: 2rem; }
.mt-2 { margin-top: .5rem; }
.mt-5 { margin-top: 1.25rem; }
.mb-1 { margin-bottom: .25rem; }
+25 -6
View File
@@ -19,15 +19,16 @@
import Icon from './Icon.svelte'
export let icon: Asset | AnySvelteComponent
export let size: 'small' | 'medium' | 'large' = 'large'
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'large'
export let transparent: boolean = false
export let selected: boolean = false
export let primary: boolean = false
</script>
<div class="icon-button icon-{size}" class:selected class:transparent on:click>
<div class="icon-button icon-{size}" class:selected class:transparent class:primary on:click on:mousemove>
<div class="content">
{#if typeof (icon) === 'string'}
<Icon {icon} size={'small'}/>
<Icon {icon} size={'small'} />
{:else}
<svelte:component this={icon} size={'small'} />
{/if}
@@ -49,15 +50,27 @@
transform: scale(.75);
pointer-events: none;
}
&:hover {
color: var(--theme-caption-color);
border-color: var(--theme-bg-focused-border);
}
&:active {
color: var(--theme-content-accent-color);
background-color: var(--theme-bg-accent-color);
}
&.selected { background-color: var(--theme-button-bg-hovered); }
&.transparent { background-color: rgba(31, 31, 37, .3); }
&:hover { border-color: var(--theme-bg-focused-border); }
&:active { background-color: var(--theme-bg-accent-color); }
&.primary {
background-color: var(--primary-button-enabled);
border-color: var(--primary-button-border);
&:hover { background-color: var(--primary-button-hovered); }
&:active { background-color: var(--primary-button-pressed); }
}
}
.icon-small {
width: 1.5rem;
height: 1.5rem;
.content { transform: scale(.55); }
.content { transform: scale(.6); }
}
.icon-medium {
width: 1.75rem;
@@ -66,5 +79,11 @@
.icon-large {
width: 2rem;
height: 2rem;
.content { transform: scale(.9); }
}
.icon-x-large {
width: 2.25rem;
height: 2.25rem;
.content { transform: none; }
}
</style>
+3 -2
View File
@@ -19,9 +19,10 @@
import { tooltipstore as tooltip, showTooltip } from '..'
export let label: IntlString | undefined
export let direction: TooltipAligment | undefined
export let direction: TooltipAligment | undefined = undefined
export let component: AnySvelteComponent | AnyComponent | undefined = undefined
export let props: any | undefined = undefined
export let anchor: HTMLElement | undefined = undefined
let triggerHTML: HTMLElement
let shown: boolean = false
@@ -32,7 +33,7 @@
class="tooltip-trigger"
bind:this={triggerHTML}
on:mousemove={() => {
if (!shown) showTooltip(label, triggerHTML, direction, component, props)
if (!shown) showTooltip(label, triggerHTML, direction, component, props, anchor)
}}
>
<slot />
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { tooltipstore as tooltip, closeTooltip } from '..'
import type { TooltipAligment } from '..'
@@ -20,67 +21,70 @@
let tooltipHTML: HTMLElement
let dir: TooltipAligment
let rect: DOMRect
let rectAnchor: DOMRect
let tooltipSW: boolean // tooltipSW = true - Label; false - Component
$: tooltipSW = $tooltip.component ? false : true
$: {
if ($tooltip.label && tooltipHTML) {
if (($tooltip.label || $tooltip.component) && tooltipHTML) {
if ($tooltip.element) {
rect = $tooltip.element.getBoundingClientRect()
const doc = document.body.getBoundingClientRect()
rect = $tooltip.element.getBoundingClientRect()
rectAnchor = ($tooltip.anchor) ? $tooltip.anchor.getBoundingClientRect()
: $tooltip.element.getBoundingClientRect()
if ($tooltip.component) {
if (rect.bottom + tooltipHTML.clientHeight + 28 < doc.height) {
tooltipHTML.style.top = `calc(${rect.bottom}px + .75rem)`
if (rectAnchor.bottom + tooltipHTML.clientHeight + 28 < doc.height) {
tooltipHTML.style.top = `calc(${rectAnchor.bottom}px + .75rem)`
dir = 'bottom'
} else if (rect.top > doc.height - rect.bottom) {
tooltipHTML.style.bottom = `calc(${doc.height - rect.y}px + .75rem)`
if (tooltipHTML.clientHeight > rect.top - 28) {
} else if (rectAnchor.top > doc.height - rectAnchor.bottom) {
tooltipHTML.style.bottom = `calc(${doc.height - rectAnchor.y}px + .75rem)`
if (tooltipHTML.clientHeight > rectAnchor.top - 28) {
tooltipHTML.style.top = '1rem'
tooltipHTML.style.height = rect.top - 28 + 'px'
tooltipHTML.style.height = rectAnchor.top - 28 + 'px'
}
dir = 'top'
} else {
tooltipHTML.style.top = `calc(${rect.bottom}px + .75rem)`
if (tooltipHTML.clientHeight > doc.height - rect.bottom - 28) {
tooltipHTML.style.top = `calc(${rectAnchor.bottom}px + .75rem)`
if (tooltipHTML.clientHeight > doc.height - rectAnchor.bottom - 28) {
tooltipHTML.style.bottom = '1rem'
tooltipHTML.style.height = doc.height - rect.bottom - 28 + 'px'
tooltipHTML.style.height = doc.height - rectAnchor.bottom - 28 + 'px'
}
dir = 'bottom'
}
if (rect.left + tooltipHTML.clientWidth + 16 > doc.width) {
if (rectAnchor.left + tooltipHTML.clientWidth + 16 > doc.width) {
tooltipHTML.style.left = ''
tooltipHTML.style.right = doc.width - rect.right + 'px'
tooltipHTML.style.right = doc.width - rectAnchor.right + 'px'
} else {
tooltipHTML.style.left = rect.left + 'px'
tooltipHTML.style.left = rectAnchor.left + 'px'
tooltipHTML.style.right = ''
}
} else {
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'
if (rectAnchor.right < doc.width / 5) dir = 'right'
else if (rectAnchor.left > doc.width - doc.width / 5) dir = 'left'
else if (rectAnchor.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.top = rectAnchor.y + rectAnchor.height / 2 + 'px'
tooltipHTML.style.left = `calc(${rectAnchor.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.top = rectAnchor.y + rectAnchor.height / 2 + 'px'
tooltipHTML.style.right = `calc(${doc.width - rectAnchor.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.top = `calc(${rectAnchor.bottom}px + .5rem)`
tooltipHTML.style.left = rectAnchor.x + rectAnchor.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.bottom = `calc(${doc.height - rectAnchor.y}px + .75rem)`
tooltipHTML.style.left = rectAnchor.x + rectAnchor.width / 2 + 'px'
tooltipHTML.style.transform = 'translateX(-50%)'
}
tooltipHTML.classList.remove('no-arrow')
@@ -106,17 +110,16 @@
const whileShow = (ev: MouseEvent): void => {
if ($tooltip.element && tooltipHTML) {
const rectP = tooltipHTML.getBoundingClientRect()
const rectT = {
top: (dir === 'top') ? rect.top - 16 : rect.top,
bottom: (dir === 'bottom') ? rect.bottom + 16 : rect.bottom,
left: (dir === 'left') ? rect.left - 16 : rect.left,
right: (dir === 'right') ? rect.right + 16 : rect.right
const dT: number = dir === 'bottom' ? 12 : 0
const dB: number = dir === 'top' ? 12 : 0
const inTrigger: boolean = ev.x >= rect.left && ev.x <= rect.right && ev.y >= rect.top && ev.y <= rect.bottom
const inPopup: boolean =
ev.x >= rectP.left && ev.x <= rectP.right && ev.y >= rectP.top - dT && ev.y <= rectP.bottom + dB
if (tooltipSW) {
if (!inTrigger) hideTooltip()
} else {
if (!(inTrigger || inPopup)) hideTooltip()
}
const inTrigger: boolean = (ev.x >= rect.left && ev.x <= rect.right && ev.y >= rect.top && ev.y <= rect.bottom)
const inTriggerWS: boolean = (ev.x >= rectT.left && ev.x <= rectT.right && ev.y >= rectT.top && ev.y <= rectT.bottom)
const inPopup: boolean = (ev.x >= rectP.left && ev.x <= rectP.right && ev.y >= rectP.top && ev.y <= rectP.bottom)
if (tooltipSW) { if (!inTrigger) hideTooltip() }
else { if (!(inTriggerWS || inPopup)) hideTooltip() }
}
}
</script>
+5 -4
View File
@@ -127,15 +127,16 @@ export const tooltipstore = writable<LabelAndProps>({
element: undefined,
direction: undefined,
component: undefined,
props: undefined
props: undefined,
anchor: undefined
})
export function showTooltip (label: IntlString | undefined, element: HTMLElement, direction?: TooltipAligment, component?: AnySvelteComponent | AnyComponent, props?: any): void {
tooltipstore.set({ label: label, element: element, direction: direction, component: component, props: props })
export function showTooltip (label: IntlString | undefined, element: HTMLElement, direction?: TooltipAligment, component?: AnySvelteComponent | AnyComponent, props?: any, anchor?: HTMLElement): void {
tooltipstore.set({ label: label, element: element, direction: direction, component: component, props: props, anchor: anchor })
}
export function closeTooltip (): void {
tooltipstore.set({ label: undefined, element: undefined, direction: undefined, component: undefined, props: undefined })
tooltipstore.set({ label: undefined, element: undefined, direction: undefined, component: undefined, props: undefined, anchor: undefined })
}
export const ticker = readable(Date.now(), set => {
+1
View File
@@ -64,6 +64,7 @@ export interface LabelAndProps {
direction?: TooltipAligment
component?: AnySvelteComponent | AnyComponent
props?: any
anchor: HTMLElement | undefined
}
export interface ListItem {
@@ -14,7 +14,7 @@
-->
<script lang="ts">
import { CircleButton, IconAdd, showPopup, Spinner } from '@anticrm/ui'
import { CircleButton, IconAdd, showPopup, Spinner, Link } from '@anticrm/ui'
import type { Doc, Ref, Space, Class, Bag } from '@anticrm/core'
import { setPlatformStatus, unknownError } from '@anticrm/platform'
@@ -24,6 +24,7 @@
import { Table } from '@anticrm/view-resources'
import { uploadFile } from '../utils'
import Upload from './icons/Upload.svelte'
import chunter from '@anticrm/chunter'
@@ -37,12 +38,12 @@
$: query.query(chunter.class.Attachment, { attachedTo: objectId }, result => { attachments = result })
let inputFile: HTMLInputElement
let loading = false
let loading = 0
const client = getClient()
async function createAttachment(file: File) {
loading = true
loading++
try {
const uuid = await uploadFile(space, file, objectId)
console.log('uploaded file uuid', uuid)
@@ -56,16 +57,30 @@
} catch (err: any) {
setPlatformStatus(unknownError(err))
} finally {
loading = false
loading--
}
}
function fileSelected() {
function fileSelected () {
console.log(inputFile.files)
const file = inputFile.files?.[0]
if (file !== undefined) { createAttachment(file) }
const list = inputFile.files
if (list === null || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
}
}
function fileDrop (e: DragEvent) {
const list = e.dataTransfer?.files
if (list === undefined || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
}
}
let dragover = false
</script>
<div class="attachments-container">
@@ -76,14 +91,30 @@
{:else}
<CircleButton icon={IconAdd} size={'small'} on:click={ () => { inputFile.click() } } />
{/if}
<input bind:this={inputFile} type="file" name="file" id="file" style="display: none" on:change={fileSelected}/>
<input bind:this={inputFile} multiple type="file" name="file" id="file" style="display: none" on:change={fileSelected}/>
</div>
<Table
_class={chunter.class.Attachment}
config={['', 'lastModified']}
options={ {} }
query={ { attachedTo: objectId } }
/>
{#if attachments.length === 0 && !loading}
<div class="flex-col-center mt-5 resume" class:solid={dragover}
on:dragover|preventDefault={ () => { dragover = true } }
on:dragleave={ () => { dragover = false } }
on:drop|preventDefault|stopPropagation={fileDrop}
on:click={ () => { inputFile.click() } }
>
<Upload size={'large'} />
<div class="small-text content-dark-color mt-2">There are no attachments for this candidate.</div>
<div class="small-text">
Upload or drop files here
</div>
</div>
{:else}
<Table
_class={chunter.class.Attachment}
config={['', 'lastModified']}
options={ {} }
query={ { attachedTo: objectId } }
/>
{/if}
</div>
<style lang="scss">
@@ -99,44 +130,12 @@
}
}
.table-body {
margin-top: .75rem;
th, td {
padding: .75rem 0;
text-align: left;
}
th {
font-weight: 500;
font-size: .75rem;
color: var(--theme-content-dark-color);
}
td {
color: var(--theme-caption-color);
}
.tr-body { border-top: 1px solid var(--theme-button-border-hovered); }
}
.item {
display: flex;
align-items: center;
padding: .75rem 1rem;
}
.file-icon {
margin-right: 1.25rem;
width: 2rem;
height: 2rem;
font-weight: 500;
font-size: 0.625rem;
line-height: 150%;
text-transform: uppercase;
color: #fff;
background-color: var(--primary-button-enabled);
border: 1px solid rgba(0, 0, 0, .1);
border-radius: .5rem;
}
.file-desc {
font-size: 0.75rem;
color: var(--theme-content-dark-color);
.resume {
cursor: pointer;
padding: 1rem;
color: var(--theme-caption-color);
background: rgba(255, 255, 255, .03);
border: 1px dashed rgba(255, 255, 255, .16);
border-radius: .75rem;
}
</style>
@@ -151,7 +151,9 @@
<span><Label label={'Add social links'} /></span>
{:else}
<Channels value={object.channels} size={'small'} />
<CircleButton icon={Edit} size={'small'} transparent on:click={(ev) => showPopup(SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => { object.channels = result })} />
<div class="ml-1">
<CircleButton icon={Edit} size={'small'} transparent on:click={(ev) => showPopup(SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => { object.channels = result })} />
</div>
{/if}
</div>
@@ -73,18 +73,6 @@
</div>
</svelte:fragment> -->
<!-- <div class="flex-row-center">
<div class="avatar">
<div class="border"/>
<Avatar />
</div>
<div class="flex-col">
<div class="name">{formatName(candidate.name)}</div>
<div class="title">For {getVacancyName()}</div>
<div class="city">at Cisco</div>
</div>
</div> -->
<div class="grid-cards">
<CandidateCard {candidate}/>
<VacancyCard {vacancy}/>
@@ -98,57 +86,6 @@
{/if}
<style lang="scss">
@import '../../../../packages/theme/styles/mixins.scss';
.avatar {
flex-shrink: 0;
overflow: hidden;
position: relative;
display: flex;
justify-content: center;
align-items: center;
margin-right: 1.5rem;
width: 6rem;
height: 6rem;
border-radius: 50%;
filter: drop-shadow(0px 14px 44px rgba(28, 23, 22, .8));
cursor: pointer;
&::after {
content: '';
@include bg-layer(var(--theme-avatar-hover), .5);
z-index: -1;
}
&::before {
content: '';
@include bg-layer(var(--theme-avatar-bg), .1);
backdrop-filter: blur(25px);
z-index: -2;
}
.border {
@include bg-fullsize;
border: 2px solid var(--theme-avatar-border);
border-radius: 50%;
}
}
.name {
font-weight: 500;
font-size: 1.25rem;
color: var(--theme-caption-color);
}
.title, .city {
font-weight: 500;
font-size: .75rem;
color: var(--theme-content-color);
}
.title { margin-top: .75rem; }
.resume a {
font-size: .75rem;
color: var(--theme-content-dark-color);
&:hover { color: var(--theme-content-color); }
}
.attachments {
margin-top: 3.5rem;
}
@@ -158,21 +95,4 @@
grid-template-columns: 1fr 1fr;
column-gap: 1.5rem;
}
// .container {
// display: flex;
// flex-direction: column;
// height: 100%;
// background-color: var(--theme-bg-color);
// border-radius: 1.25rem;
// box-shadow: 0px 3.125rem 7.5rem rgba(0, 0, 0, .4);
// .tabs-container {
// flex-grow: 1;
// display: flex;
// flex-direction: column;
// height: fit-content;
// padding: 0 2.5rem 2.5rem;
// }
// }
</style>
@@ -23,7 +23,6 @@
import { Panel } from '@anticrm/panel'
import type { Candidate } from '@anticrm/recruit'
import Contact from './icons/Contact.svelte'
import IconAvatar from './icons/Avatar.svelte'
import Attachments from './Attachments.svelte'
import Edit from './icons/Edit.svelte'
import SocialEditor from './SocialEditor.svelte'
@@ -91,7 +90,9 @@
rightSection = ev.detail.presenter
}
}} />
<CircleButton icon={Edit} size={'small'} selected on:click={(ev) => showPopup(SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => { saveChannels(result) })} />
<div class="ml-1">
<CircleButton icon={Edit} size={'small'} selected on:click={(ev) => showPopup(SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => { saveChannels(result) })} />
</div>
{/if}
</div>
</div>
@@ -106,6 +106,6 @@
align-items: center;
margin-top: 1rem;
.btn { flex-grow: 1; }
.btn + .btn { margin-left: .75rem; }
// .btn + .btn { margin-left: .75rem; }
}
</style>
@@ -0,0 +1,28 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="var(--duotone-color)" d="M18,6.4c-0.1,0-0.2,0-0.3,0c-0.1,0-0.1,0-0.1,0c-0.1,0-0.1,0-0.1,0c0,0,0,0-0.1-0.1c0,0,0,0-0.1-0.1 c0-0.1-0.1-0.2-0.2-0.4c-0.9-1.9-2.8-3.3-5.1-3.3c-2.3,0-4.2,1.4-5.1,3.3C6.8,5.9,6.7,6,6.7,6.1c0,0.1-0.1,0.1-0.1,0.1 C6.6,6.3,6.6,6.3,6.5,6.3c0,0,0,0-0.1,0c0,0,0,0-0.1,0c-0.1,0-0.2,0-0.3,0C4,6.4,2.4,8,2.4,10S4,13.6,6,13.6h6h6 c2,0,3.6-1.6,3.6-3.6S20,6.4,18,6.4z"/>
<g {fill}>
<path d="M18,6.4c-0.1,0-0.2,0-0.3,0c-0.1,0-0.1,0-0.1,0c-0.1,0-0.1,0-0.1,0c0,0,0,0-0.1-0.1c0,0,0,0,0,0c0,0,0,0,0,0 c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0-0.1-0.1c0-0.1-0.1-0.2-0.2-0.4c-0.9-1.9-2.8-3.3-5.1-3.3c-2.3,0-4.2,1.4-5.1,3.3 C6.8,5.9,6.7,6,6.7,6.1c0,0.1-0.1,0.1-0.1,0.1c0,0,0,0,0,0C6.6,6.3,6.6,6.3,6.5,6.3c0,0,0,0-0.1,0c0,0,0,0-0.1,0 c-0.1,0-0.2,0-0.3,0C4,6.4,2.4,8,2.4,10S4,13.6,6,13.6h0.6l1.2-1.2H6c-1.3,0-2.4-1.1-2.4-2.4c0-1.3,1.1-2.4,2.4-2.4h0.1 c0.2,0,0.4,0,0.6,0c0.2,0,0.4-0.1,0.6-0.2c0.2-0.1,0.3-0.3,0.4-0.4c0.1-0.1,0.1-0.2,0.2-0.3C7.8,6.5,7.9,6.4,8,6.2l0,0 c0.7-1.5,2.2-2.6,4-2.6s3.3,1.1,4,2.6l0,0c0.1,0.2,0.1,0.3,0.2,0.4c0,0.1,0.1,0.2,0.2,0.3c0.1,0.2,0.2,0.3,0.4,0.4 c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.4,0,0.6,0H18c1.3,0,2.4,1.1,2.4,2.4c0,1.3-1.1,2.4-2.4,2.4h-1.8l1.2,1.2H18c2,0,3.6-1.6,3.6-3.6 S20,6.4,18,6.4z"/>
<path d="M12,11.2l-4.4,4.4l0.8,0.8l3-3V21c0,0.3,0.3,0.6,0.6,0.6s0.6-0.3,0.6-0.6v-7.6l3,3l0.8-0.8L12,11.2z"/>
</g>
</svg>
@@ -15,15 +15,11 @@
-->
<script lang="ts">
import type { IntlString } from '@anticrm/platform'
// import type { IntlString } from '@anticrm/platform'
import { Label } from '@anticrm/ui'
export let label: IntlString
export let placeholder: IntlString
export let value: any
export let focus: boolean
export let maxWidth: string
export let maxWidth: string | undefined = undefined
export let onChange: (value: any) => void
function getLabel(value: boolean | undefined) {
@@ -31,15 +27,21 @@
if (value === false) return 'No'
return 'N/A'
}
</script>
<div class="flex-row-center yesno-container" class:yes={value === true} class:no={value === false} class:unknown={value === undefined} on:click={() => {
if (value === true) value = false
else if (value === false) value = undefined
else value = true
onChange(value)
<div
class="flex-row-center yesno-container"
class:yes={value === true}
class:no={value === false}
class:unknown={value === undefined}
style={(maxWidth) ? `max-width: ${maxWidth};` : ''}
on:click={() => {
if (value === true) value = false
else if (value === false) value = undefined
else value = true
onChange(value)
}}
>
<svg class="svg-small" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<circle class:yes={value === true} class:no={value === false} cx="8" cy="8" r="6"/>
{#if value === true}
@@ -19,7 +19,7 @@
export let label: IntlString
export let color: string
export let counter: number
// export let counter: number
export let addAction: () => void | undefined
</script>
@@ -71,10 +71,10 @@
height: 100%;
font-weight: 500;
color: var(--theme-caption-color);
span {
font-weight: 400;
color: var(--theme-content-dark-color);
}
// span {
// font-weight: 400;
// color: var(--theme-content-dark-color);
// }
}
.tool {
opacity: .4;
@@ -19,7 +19,7 @@
import type { IntlString } from '@anticrm/platform'
import { EditBox } from '@anticrm/ui'
export let label: IntlString
// export let label: IntlString
export let placeholder: IntlString
export let value: any
export let focus: boolean
@@ -158,6 +158,7 @@
color: var(--theme-caption-color);
border-bottom: 1px solid var(--theme-button-border-hovered);
&:hover .firstCell .menuRow { visibility: visible; }
&:last-child { border-bottom: none; }
}
.fixed .menuRow { visibility: visible; }
</style>
@@ -200,6 +200,7 @@
.checkCell { visibility: visible; }
}
&:hover .firstCell .menuRow { visibility: visible; }
&:last-child { border-bottom: none; }
}
.fixed {
+13 -4
View File
@@ -151,6 +151,11 @@ class MongoAdapter extends MongoAdapterBase {
protected override async txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<TxResult> {
const domain = this.hierarchy.getDomain(tx.objectClass)
const operations = {
...tx.operations,
modifiedBy: tx.modifiedBy,
modifiedOn: tx.modifiedOn
}
if (isOperator(tx.operations)) {
const operator = Object.keys(tx.operations)[0]
if (operator === '$move') {
@@ -172,6 +177,10 @@ class MongoAdapter extends MongoAdapterBase {
updateOne: {
filter: { _id: tx.objectId },
update: {
$set: {
modifiedBy: tx.modifiedBy,
modifiedOn: tx.modifiedOn
},
$push: {
[arr]: {
$each: [desc.$value],
@@ -186,18 +195,18 @@ class MongoAdapter extends MongoAdapterBase {
return await this.db.collection(domain).bulkWrite(ops as any)
} else {
if (tx.retrieve === true) {
const result = await this.db.collection(domain).findOneAndUpdate({ _id: tx.objectId }, tx.operations, { returnDocument: 'after' })
const result = await this.db.collection(domain).findOneAndUpdate({ _id: tx.objectId }, operations, { returnDocument: 'after' })
return { object: result.value }
} else {
return await this.db.collection(domain).updateOne({ _id: tx.objectId }, tx.operations)
return await this.db.collection(domain).updateOne({ _id: tx.objectId }, operations)
}
}
} else {
if (tx.retrieve === true) {
const result = await this.db.collection(domain).findOneAndUpdate({ _id: tx.objectId }, { $set: tx.operations }, { returnDocument: 'after' })
const result = await this.db.collection(domain).findOneAndUpdate({ _id: tx.objectId }, { $set: operations }, { returnDocument: 'after' })
return { object: result.value }
} else {
return await this.db.collection(domain).updateOne({ _id: tx.objectId }, { $set: tx.operations })
return await this.db.collection(domain).updateOne({ _id: tx.objectId }, { $set: operations })
}
}
}