initial attributes bar

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov 2021-10-04 21:18:23 +02:00
parent 1bdc5c98d6
commit d4a03393ff
No known key found for this signature in database
GPG Key ID: C8787EFEB4B64AF0
11 changed files with 1117 additions and 773 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -81,6 +81,10 @@ export function createModel (builder: Builder): void {
presenter: view.component.StringPresenter presenter: view.component.StringPresenter
}) })
builder.mixin(core.class.TypeBoolean, core.class.Class, view.mixin.AttributeEditor, {
editor: view.component.BooleanEditor
})
builder.mixin(core.class.State, core.class.Class, view.mixin.AttributePresenter, { builder.mixin(core.class.State, core.class.Class, view.mixin.AttributePresenter, {
presenter: view.component.StatePresenter presenter: view.component.StatePresenter
}) })

View File

@ -29,6 +29,7 @@ export default mergeIds(viewId, view, {
component: { component: {
StringEditor: '' as AnyComponent, StringEditor: '' as AnyComponent,
StringPresenter: '' as AnyComponent, StringPresenter: '' as AnyComponent,
BooleanEditor: '' as AnyComponent,
StatePresenter: '' as AnyComponent, StatePresenter: '' as AnyComponent,
TableView: '' as AnyComponent, TableView: '' as AnyComponent,

View File

@ -0,0 +1,76 @@
<!--
// 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 { Ref, Class, Doc } from '@anticrm/core'
import { getResource } from '@anticrm/platform'
import type { AnySvelteComponent } from '@anticrm/ui'
import { CircleButton, Label } from '@anticrm/ui'
import { getClient } from '../utils'
import view from '@anticrm/view'
// export let _class: Ref<Class<Doc>>
export let key: string
export let object: Doc
export let maxWidth: string
export let focus: boolean = false
export let minimize: boolean = false
const _class = object._class
const client = getClient()
const hierarchy = client.getHierarchy()
const attribute = hierarchy.getAttribute(_class, key)
const typeClassId = attribute?.type._class
let editor: Promise<AnySvelteComponent> | undefined
if (typeClassId !== undefined) {
const typeClass = hierarchy.getClass(typeClassId)
const editorMixin = hierarchy.as(typeClass, view.mixin.AttributeEditor)
editor = getResource(editorMixin.editor)
}
function onChange(value: any) {
client.updateDoc(_class, object.space, object._id, { [key]: value })
}
</script>
{#if editor}
{#await editor}
...
{:then instance}
{#if attribute.icon}
<div class="flex-row-center">
<CircleButton icon={attribute.icon} size={'large'} />
{#if !minimize}
<div class="flex-col with-icon">
<Label label={attribute.label} />
<div class="value"><svelte:component this={instance} label={attribute?.label} placeholder={attribute?.label} {maxWidth} bind:value={object[key]} {onChange} {focus}/></div>
</div>
{/if}
</div>
{:else}
<div class="flex-col">
<Label label={attribute.label} />
<div class="value"><svelte:component this={instance} label={attribute?.label} placeholder={attribute?.label} {maxWidth} bind:value={object[key]} {onChange} {focus}/></div>
</div>
{/if}
{/await}
{/if}

View File

@ -21,6 +21,7 @@ export { default as UserInfo } from './components/UserInfo.svelte'
export { default as Avatar } from './components/Avatar.svelte' export { default as Avatar } from './components/Avatar.svelte'
export { default as MessageViewer } from './components/MessageViewer.svelte' export { default as MessageViewer } from './components/MessageViewer.svelte'
export { default as AttributeEditor } from './components/AttributeEditor.svelte' export { default as AttributeEditor } from './components/AttributeEditor.svelte'
export { default as AttributeBarEditor } from './components/AttributeBarEditor.svelte'
export { default as Card } from './components/Card.svelte' export { default as Card } from './components/Card.svelte'
export { default as Channels } from './components/Channels.svelte' export { default as Channels } from './components/Channels.svelte'
export { default as Backlink } from './components/Backlink.svelte' export { default as Backlink } from './components/Backlink.svelte'

View File

@ -15,23 +15,19 @@
<script lang="ts"> <script lang="ts">
import { CircleButton, Label } from '@anticrm/ui' import { CircleButton, Label } from '@anticrm/ui'
import Location from './icons/Location.svelte' import type { Ref, Class, Obj, Doc } from '@anticrm/core'
import YesNoPresenter from './YesNoPresenter.svelte' import { AttributeBarEditor } from '@anticrm/presentation'
import AttributeEditor from './AttributeEditor.svelte'
export let minimize: boolean = false export let object: Doc
export let keys: string[]
</script> </script>
<div class="flex-row-center small-text"> <div class="flex-row-center small-text">
<div class="column"> {#each keys as key}
<AttributeEditor icon={Location} label={'Location'} component={Label} props={{ label: 'Moscow' }} /> <div class="column">
</div> <AttributeBarEditor {key} {object} />
<div class="column"> </div>
<AttributeEditor label={'Onsite'} component={YesNoPresenter} props={{ state: 'yes' }} /> {/each}
</div>
<div class="column">
<AttributeEditor label={'Remote'} component={YesNoPresenter} props={{ state: 'no' }} />
</div>
</div> </div>
<style lang="scss"> <style lang="scss">

View File

@ -64,7 +64,7 @@
{#if object !== undefined} {#if object !== undefined}
<Panel icon={Contact} title={formatName(object.name)} {object} on:close={() => { dispatch('close') }}> <Panel icon={Contact} title={formatName(object.name)} {object} on:close={() => { dispatch('close') }}>
<AttributesBar slot="subtitle" /> <AttributesBar {object} keys={['city', 'onsite', 'remote']} slot="subtitle" />
<div class="flex-row-center"> <div class="flex-row-center">
<div class="avatar"> <div class="avatar">

View File

@ -0,0 +1,72 @@
<!--
// 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 } 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 onChange: (value: any) => void
function getLabel(value: boolean | undefined) {
if (value === true) return 'Yes'
if (value === false) return 'No'
return 'Unknown'
}
</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)
}}>
<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} class:unknown={value === undefined} cx="8" cy="8" r="6"/>
{#if value === true}
<polygon fill="#fff" points="7.4,10.9 4.9,8.4 5.7,7.6 7.3,9.1 10.2,5.6 11.1,6.4 "/>
{:else if value === false}
<polygon fill="#fff" points="10.7,6 10,5.3 8,7.3 6,5.3 5.3,6 7.3,8 5.3,10 6,10.7 8,8.7 10,10.7 10.7,10 8.7,8 "/>
{:else}
<path fill="#fff" d="M7.3,9.3h1.3V9c0.1-0.5,0.6-0.9,1.1-1.4c0.4-0.4,0.8-0.9,0.8-1.6c0-1.1-0.8-1.8-2.2-1.8c-1.4,0-2.4,0.8-2.5,2.2 h1.4c0.1-0.6,0.4-1,1-1C8.8,5.4,9,5.7,9,6.2c0,0.4-0.3,0.7-0.7,1.1c-0.5,0.5-1,0.9-1,1.7V9.3z M8,11.6c0.5,0,0.9-0.4,0.9-0.9 c0-0.5-0.4-0.9-0.9-0.9c-0.5,0-0.9,0.4-0.9,0.9C7.1,11.2,7.5,11.6,8,11.6z"/>
{/if}
</svg>
<span><Label label={getLabel(value)} /></span>
</div>
<style lang="scss">
.yesno-container {
max-width: fit-content;
user-select: none;
cursor: pointer;
&.yes { fill: #77C07B; }
&.no { fill: #F96E50; }
&.unknown { fill: #77818E; }
span {
margin-left: .25rem;
text-transform: capitalize;
font-weight: 500;
color: var(--theme-caption-color);
}
}
</style>

View File

@ -17,6 +17,7 @@ import type { Doc } from '@anticrm/core'
import StringEditor from './components/StringEditor.svelte' import StringEditor from './components/StringEditor.svelte'
import StringPresenter from './components/StringPresenter.svelte' import StringPresenter from './components/StringPresenter.svelte'
import BooleanEditor from './components/BooleanEditor.svelte'
import StatePresenter from './components/StatePresenter.svelte' import StatePresenter from './components/StatePresenter.svelte'
import TableView from './components/TableView.svelte' import TableView from './components/TableView.svelte'
import KanbanView from './components/KanbanView.svelte' import KanbanView from './components/KanbanView.svelte'
@ -35,6 +36,7 @@ export default async () => ({
component: { component: {
StringEditor, StringEditor,
StringPresenter, StringPresenter,
BooleanEditor,
StatePresenter, StatePresenter,
TableView, TableView,
KanbanView KanbanView

File diff suppressed because it is too large Load Diff