Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-11-29 22:22:33 +07:00 committed by GitHub
parent 63b0e63866
commit 5dde89f503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 375 additions and 99 deletions

View File

@ -17,7 +17,14 @@ import { ArrOf, Builder, Index, Model, Prop, TypeNumber, TypeRef, TypeString, UX
import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core'
import view from '@hcengineering/model-view'
import { Asset, IntlString } from '@hcengineering/platform'
import type { TagCategory, TagElement, TagReference } from '@hcengineering/tags'
import type {
ExpertKnowledge,
InitialKnowledge,
MeaningfullKnowledge,
TagCategory,
TagElement,
TagReference
} from '@hcengineering/tags'
import tags from './plugin'
export { TagCategory, TagElement, TagReference } from '@hcengineering/tags'
@ -63,6 +70,9 @@ export class TTagReference extends TAttachedDoc implements TagReference {
@Prop(TypeString(), tags.string.ColorLabel)
color!: number
@Prop(TypeNumber(), tags.string.Weight)
weight!: InitialKnowledge | MeaningfullKnowledge | ExpertKnowledge
}
@Model(tags.class.TagCategory, core.class.Doc, DOMAIN_TAGS)

View File

@ -34,8 +34,7 @@
const config: (BuildModelKey | string)[] = [
'',
'$lookup.space.name',
'comments',
'attachments',
'$lookup.space.$lookup.company',
'$lookup.state',
'$lookup.doneState'
]

View File

@ -197,7 +197,8 @@
await client.addCollection(skill._class, skill.space, candidateId, recruit.mixin.Candidate, 'skills', {
title: skill.title,
color: skill.color,
tag: skill.tag
tag: skill.tag,
weight: skill.weight
})
}
@ -404,7 +405,7 @@
<Card
label={recruit.string.CreateTalent}
okAction={createCandidate}
canSave={!loading && firstName.length > 0 && lastName.length > 0}
canSave={!loading && (firstName.length > 0 || lastName.length > 0 || channels.length > 0)}
on:close={() => {
dispatch('close')
}}
@ -470,47 +471,80 @@
</div>
</div>
<svelte:fragment slot="pool">
<ChannelsDropdown
editable={!loading}
focusIndex={10}
bind:value={channels}
highlighted={matchedChannels.map((it) => it.provider)}
/>
<YesNo
disabled={loading}
focusIndex={100}
label={recruit.string.Onsite}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.onsite}
/>
<YesNo
disabled={loading}
focusIndex={101}
label={recruit.string.Remote}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.remote}
/>
<Component
is={tags.component.TagsDropdownEditor}
props={{
disabled: loading,
focusIndex: 102,
items: skills,
key,
targetClass: recruit.mixin.Candidate,
showTitle: false,
elements,
newElements,
countLabel: recruit.string.NumberSkills
}}
on:open={(evt) => {
addTagRef(evt.detail)
}}
on:delete={(evt) => {
skills = skills.filter((it) => it._id !== evt.detail)
}}
/>
<div class="flex-col flex-grow">
<div class="flex flex-wrap">
<ChannelsDropdown
editable={!loading}
focusIndex={10}
bind:value={channels}
highlighted={matchedChannels.map((it) => it.provider)}
/>
<YesNo
disabled={loading}
focusIndex={100}
label={recruit.string.Onsite}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.onsite}
/>
<YesNo
disabled={loading}
focusIndex={101}
label={recruit.string.Remote}
tooltip={recruit.string.WorkLocationPreferences}
bind:value={object.remote}
/>
<Component
is={tags.component.TagsDropdownEditor}
props={{
disabled: loading,
focusIndex: 102,
items: skills,
key,
targetClass: recruit.mixin.Candidate,
showTitle: false,
elements,
newElements,
countLabel: recruit.string.NumberSkills
}}
on:open={(evt) => {
addTagRef(evt.detail)
}}
on:delete={(evt) => {
skills = skills.filter((it) => it._id !== evt.detail)
}}
/>
</div>
{#if skills.length > 0}
<div class="skills-box p-1 mt-2">
<Component
is={tags.component.TagsEditor}
props={{
disabled: loading,
focusIndex: 102,
items: skills,
key,
targetClass: recruit.mixin.Candidate,
showTitle: false,
elements,
newElements,
countLabel: recruit.string.NumberSkills
}}
on:open={(evt) => {
addTagRef(evt.detail)
}}
on:delete={(evt) => {
skills = skills.filter((it) => it._id !== evt.detail)
}}
on:change={(evt) => {
evt.detail.tag.weight = evt.detail.weight
skills = skills
}}
/>
</div>
{/if}
</div>
</svelte:fragment>
<svelte:fragment slot="footer">
<div
class="flex-center resume"
@ -581,4 +615,10 @@
border-style: solid;
}
}
.skills-box {
padding: 0.5rem 0.75rem;
background: var(--accent-bg-color);
border: 1px dashed var(--divider-color);
border-radius: 0.5rem;
}
</style>

View File

@ -2,4 +2,19 @@
<symbol id="tags" viewBox="0 0 16 16">
<path d="M2.5,9.8l3.7,3.7c0,0,0,0,0,0c0.6,0.6,1.6,0.6,2.2,0l5.5-5.5C13.9,8,14,7.8,14,7.7V2.5C14,2.2,13.8,2,13.5,2H8.3 C8.1,2,8,2.1,7.9,2.1L2.5,7.6C2.2,7.9,2,8.3,2,8.7C2,9.1,2.2,9.5,2.5,9.8z M3.2,8.3L8.5,3H13v4.5l-5.3,5.3c-0.2,0.2-0.6,0.2-0.8,0 L3.2,9.1C3.1,9,3,8.9,3,8.7S3.1,8.4,3.2,8.3z"/>
</symbol>
<symbol id="level-3" viewBox="0 0 16 16">
<rect x="1" y="8" width="3" height="6" rx="1" />
<rect x="6" y="5" width="3" height="9" rx="1" />
<rect x="11" y="2" width="3" height="12" rx="1" />
</symbol>
<symbol id="level-2" viewBox="0 0 16 16">
<rect x="1" y="8" width="3" height="6" rx="1" />
<rect x="6" y="5" width="3" height="9" rx="1" />
<rect x="11" y="2" width="3" height="12" rx="1" fill-opacity=".4" />
</symbol>
<symbol id="level-1" viewBox="0 0 16 16">
<rect x="1" y="8" width="3" height="6" rx="1" />
<rect x="6" y="5" width="3" height="9" rx="1" fill-opacity=".4" />
<rect x="11" y="2" width="3" height="12" rx="1" fill-opacity=".4" />
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 419 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -33,6 +33,10 @@
"DefaultLabel": "Default category",
"SelectAll": "Select all",
"SelectNone": "Select none",
"ApplyTags": "Apply"
"ApplyTags": "Apply",
"Weight": "Weight",
"Expert": "Expert",
"Meaningfull": "Meaningfull",
"Initial": "Initial"
}
}

View File

@ -33,6 +33,10 @@
"DefaultLabel": "Категория по умолчанию",
"SelectAll": "Выбрать все",
"SelectNone": "Выбрать ничего",
"ApplyTags": "Применить"
"ApplyTags": "Применить",
"Weight": "Вес",
"Expert": "Эксперт",
"Meaningfull": "Значимый",
"Initial": "Начальный"
}
}

View File

@ -19,7 +19,10 @@ import tags, { tagsId } from '@hcengineering/tags'
const icons = require('../assets/icons.svg') as string // eslint-disable-line
loadMetadata(tags.icon, {
Tags: `${icons}#tags`
Tags: `${icons}#tags`,
Level1: `${icons}#level-1`,
Level2: `${icons}#level-2`,
Level3: `${icons}#level-3`
})
addStringsLoader(tagsId, async (lang: string) => await import(`../lang/${lang}.json`))

View File

@ -15,10 +15,10 @@
<script lang="ts">
import { Asset } from '@hcengineering/platform'
import { TagElement, TagReference } from '@hcengineering/tags'
import { ActionIcon, AnySvelteComponent, getPlatformColor, tooltip } from '@hcengineering/ui'
import { ActionIcon, AnySvelteComponent, getPlatformColor, Icon, tooltip } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { getTagStyle } from '../utils'
import { getTagStyle, tagLevel } from '../utils'
export let tag: TagReference | undefined = undefined
export let element: TagElement | undefined = undefined
@ -28,11 +28,15 @@
const dispatch = createEventDispatcher()
$: name = element?.title ?? tag?.title ?? 'New item'
$: tagIcon = tagLevel[(((tag?.weight ?? 0) % 3) + 1) as 1 | 2 | 3]
</script>
<div
class="text-sm flex flex-between tag-item"
style={`${getTagStyle(getPlatformColor(tag?.color ?? element?.color ?? 0), selected)}`}
on:click
on:keydown
use:tooltip={{
label: element?.description ? tags.string.TagTooltip : undefined,
props: { text: element?.description },
@ -40,11 +44,16 @@
}}
>
{name}
<span class="ml-1">
{#if tag}
<Icon icon={tagIcon} size={'small'} />
{/if}
</span>
{#if action}
<div class="ml-1">
<ActionIcon
icon={action}
size={'small'}
size={'medium'}
action={() => {
dispatch('action')
}}
@ -61,7 +70,7 @@
border-radius: 0.25rem;
font-weight: 500;
font-size: 0.625rem;
font-size: 0.75rem;
text-transform: uppercase;
color: var(--accent-color);

View File

@ -14,9 +14,10 @@
-->
<script lang="ts">
import type { TagReference } from '@hcengineering/tags'
import { getPlatformColor, IconClose, Icon, resizeObserver } from '@hcengineering/ui'
import TagItem from './TagItem.svelte'
import { getPlatformColor, Icon, IconClose, resizeObserver } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { tagLevel } from '../utils'
import TagItem from './TagItem.svelte'
export let value: TagReference
export let isEditable: boolean = false
@ -24,6 +25,7 @@
export let realWidth: number | undefined = undefined
const dispatch = createEventDispatcher()
$: tagIcon = tagLevel[(((value?.weight ?? 0) % 3) + 1) as 1 | 2 | 3]
</script>
{#if value}
@ -48,7 +50,10 @@
}}
>
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<span class="overflow-label ml-1-5 caption-color">{value.title}</span>
<span class="overflow-label ml-1-5 caption-color"
>{value.title}-
<Icon icon={tagIcon} size={'small'} />
</span>
{#if isEditable}
<button class="btn-close" on:click|stopPropagation={() => dispatch('remove', value.tag)}>
<Icon icon={IconClose} size={'x-small'} />

View File

@ -34,7 +34,7 @@
(result) => {
items = result
},
{ sort: { title: 1 } }
{ sort: { weight: -1, title: 1 } }
)
async function addRef (tag: TagElement): Promise<void> {
@ -49,6 +49,10 @@
await client.removeCollection(tags.class.TagReference, object.space, id, object._id, _class, key.key)
}
async function updateWeight (tag: TagReference, weight: TagReference['weight']): Promise<void> {
await client.update(tag, { weight })
}
let elements: Map<Ref<TagElement>, TagElement> = new Map()
const elementQuery = createQuery()
$: elementQuery.query(tags.class.TagElement, {}, (result) => {
@ -63,4 +67,5 @@
targetClass={_class}
on:open={(evt) => addRef(evt.detail)}
on:delete={(evt) => removeTag(evt.detail)}
on:change={(evt) => updateWeight(evt.detail.tag, evt.detail.weight)}
/>

View File

@ -17,11 +17,20 @@
import { translate } from '@hcengineering/platform'
import { KeyedAttribute } from '@hcengineering/presentation'
import { TagElement, TagReference } from '@hcengineering/tags'
import { Button, IconAdd, IconClose, Label, ShowMore, showPopup } from '@hcengineering/ui'
import {
Button,
getEventPopupPositionElement,
IconAdd,
IconClose,
Label,
ShowMore,
showPopup
} from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import TagItem from './TagItem.svelte'
import TagsPopup from './TagsPopup.svelte'
import WeightPopup from './WeightPopup.svelte'
export let items: TagReference[] = []
export let targetClass: Ref<Class<Doc>>
@ -39,6 +48,16 @@
keyLabel = v
})
$: expert = items.filter((it) => (it.weight ?? 0) >= 6 && (it.weight ?? 0) <= 8)
$: meaningfull = items.filter((it) => (it.weight ?? 0) >= 3 && (it.weight ?? 0) <= 5)
$: initial = items.filter((it) => (it.weight ?? 1) >= 0 && (it.weight ?? 0) <= 2)
$: categories = [
{ items: expert, label: tags.string.Expert },
{ items: meaningfull, label: tags.string.Meaningfull },
{ items: initial, label: tags.string.Initial }
]
async function addRef (tag: TagElement): Promise<void> {
dispatch('open', tag)
}
@ -87,7 +106,7 @@
{/if}
<ShowMore ignore={!showTitle}>
<div class:tags-container={showTitle} class:mt-3={showTitle} class:empty={items.length === 0}>
<div class="tag-items" class:tag-items-scroll={!showTitle}>
<div class="tag-items-container" class:tag-items-scroll={!showTitle}>
{#if items.length === 0}
{#if keyLabel}
<div class="text-sm dark-color w-full flex-center">
@ -95,15 +114,38 @@
</div>
{/if}
{/if}
{#each items as tag}
<TagItem
{tag}
element={elements.get(tag.tag)}
action={IconClose}
on:action={() => {
removeTag(tag._id)
}}
/>
{#each categories as cat, ci}
{#if cat.items.length > 0}
<div class="text-sm mb-1" class:mt-2={ci > 0 && categories[ci - 1].items.length > 0}>
<Label label={cat.label} />
</div>
{/if}
<div class="tag-items">
{#each cat.items as tag}
<TagItem
{tag}
element={elements.get(tag.tag)}
action={IconClose}
on:action={() => {
removeTag(tag._id)
}}
on:click={(evt) => {
showPopup(
WeightPopup,
{ value: tag.weight ?? 1, format: 'number' },
getEventPopupPositionElement(evt),
(res) => {
if (Number.isFinite(res) && res >= 0 && res <= 8) {
if (res != null) {
dispatch('change', { tag, weight: res })
}
}
}
)
}}
/>
{/each}
</div>
{/each}
</div>
</div>
@ -122,6 +164,11 @@
background-color: transparent;
}
}
.tag-items-container {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.tag-items {
flex-grow: 1;
display: flex;
@ -129,6 +176,6 @@
}
.tag-items-scroll {
overflow-y: scroll;
max-height: 10rem;
max-height: 20rem;
}
</style>

View File

@ -16,13 +16,24 @@
import { Class, Doc, FindResult, Ref } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import { Button, CheckBox, getPlatformColor, Loading, resizeObserver } from '@hcengineering/ui'
import { TagCategory, TagElement } from '@hcengineering/tags'
import {
Button,
CheckBox,
getEventPopupPositionElement,
getPlatformColor,
Label,
Loading,
resizeObserver,
showPopup
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FilterQuery } from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher, onMount } from 'svelte'
import tags from '../plugin'
import { TagCategory, TagElement } from '@hcengineering/tags'
import { FilterQuery } from '@hcengineering/view-resources'
import { tagLevel } from '../utils'
import WeightPopup from './WeightPopup.svelte'
export let _class: Ref<Class<Doc>>
export let filter: Filter
@ -32,6 +43,7 @@
}
const client = getClient()
let selected: Ref<TagElement>[] = filter.value
let level: number = filter.props?.level ?? 0
filter.modes = [tags.filter.FilterTagsIn, tags.filter.FilterTagsNin]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
@ -100,6 +112,9 @@
const dispatch = createEventDispatcher()
getValues(search)
$: tagLevelIcon = tagLevel[((level % 3) + 1) as 1 | 2 | 3]
$: tagLevelLabel = [tags.string.Initial, tags.string.Meaningfull, tags.string.Expert][Math.floor(level / 3)]
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
@ -113,6 +128,22 @@
}}
placeholder={phTraslate}
/>
<div class="flex-row-center flex-between flex-grow p-1">
<Label label={tags.string.Weight} />
<Button
label={tagLevelLabel}
icon={tagLevelIcon}
on:click={(evt) => {
showPopup(WeightPopup, { value: level }, getEventPopupPositionElement(evt), (res) => {
if (Number.isFinite(res) && res >= 0 && res <= 8) {
if (res != null) {
level = res
}
}
})
}}
/>
</div>
</div>
<div class="scroll">
<div class="box">
@ -169,7 +200,9 @@
shape={'round'}
label={view.string.Apply}
on:click={async () => {
filter.value = selected
filter.value = [...selected]
// Replace last one with value with level
filter.props = { level }
onChange(filter)
dispatch('close')
}}

View File

@ -123,6 +123,7 @@
/>
</div>
<div class="buttons-group small-gap">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="clear-btn"
class:show={search !== ''}

View File

@ -19,6 +19,7 @@
import tags from '../plugin'
import TagItem from './TagItem.svelte'
import { selectedTagElements } from '@hcengineering/tags'
import { Label } from '@hcengineering/ui'
export let object: Doc
export let _class: Ref<Class<Doc>>
@ -39,13 +40,32 @@
(res) => {
items = res
},
{ sort: { title: 1 } }
{ sort: { weight: -1, title: 1 } }
)
$: expert = items.filter((it) => (it.weight ?? 0) >= 6 && (it.weight ?? 0) <= 8)
$: meaningfull = items.filter((it) => (it.weight ?? 0) >= 3 && (it.weight ?? 0) <= 5)
$: initial = items.filter((it) => (it.weight ?? 1) >= 0 && (it.weight ?? 0) <= 2)
$: categories = [
{ items: expert, label: tags.string.Expert },
{ items: meaningfull, label: tags.string.Meaningfull },
{ items: initial, label: tags.string.Initial }
]
</script>
<div class="tags flex flex-wrap">
{#each items as tag}
<TagItem {tag} element={elements.get(tag.tag)} selected={$selectedTagElements.includes(tag.tag)} />
<div class="tags flex flex-col">
{#each categories as cat, ci}
{#if cat.items.length > 0}
<div class="text-xs mb-1" class:mt-2={ci > 0 && categories[ci - 1].items.length > 0}>
<Label label={cat.label} />
</div>
{/if}
<div class="flex-row-center flex-wrap tags">
{#each cat.items as tag}
<TagItem {tag} element={elements.get(tag.tag)} selected={$selectedTagElements.includes(tag.tag)} />
{/each}
</div>
{/each}
</div>

View File

@ -0,0 +1,47 @@
<!--
// Copyright © 2022 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 { Button, resizeObserver } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { tagLevel } from '../utils'
export let value: number | undefined
const dispatch = createEventDispatcher()
const labels = [tags.string.Initial, tags.string.Meaningfull, tags.string.Expert]
</script>
<div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header no-border p-3">
{#each labels as l, i}
<div class="flex gap-2 p-1">
{#each Object.entries(tagLevel) as k, j}
{@const valueK = i * 3 + j}
<Button
label={l}
icon={k[1]}
size={'small'}
justify={'left'}
selected={value === valueK}
on:click={() => dispatch('close', valueK)}
width={'8rem'}
/>
{/each}
</div>
{/each}
</div>
</div>

View File

@ -46,7 +46,12 @@ export default mergeIds(tagsId, tags, {
AllCategories: '' as IntlString,
SelectAll: '' as IntlString,
SelectNone: '' as IntlString,
ApplyTags: '' as IntlString
ApplyTags: '' as IntlString,
Weight: '' as IntlString,
Expert: '' as IntlString,
Meaningfull: '' as IntlString,
Initial: '' as IntlString
},
function: {
FilterTagsInResult: '' as Resource<(filter: Filter, onUpdate: () => void) => Promise<ObjQueryType<any>>>,

View File

@ -1,10 +1,11 @@
// Copyright © 2022 Hardcore Engineering Inc.
import { Doc, FindResult, Ref } from '@hcengineering/core'
import { TagReference } from '@hcengineering/tags'
import tags from './plugin'
import { FilterQuery } from '@hcengineering/view-resources'
import { Doc, DocumentQuery, FindResult, Ref } from '@hcengineering/core'
import { Asset } from '@hcengineering/platform'
import { InitialKnowledge, TagReference } from '@hcengineering/tags'
import { Filter } from '@hcengineering/view'
import { FilterQuery } from '@hcengineering/view-resources'
import tags from './plugin'
export function getTagStyle (color: string, selected = false): string {
return `
@ -16,21 +17,29 @@ export function getTagStyle (color: string, selected = false): string {
export async function getRefs (filter: Filter, onUpdate: () => void): Promise<Array<Ref<Doc>>> {
const lq = FilterQuery.getLiveQuery(filter.index)
const promise = new Promise<Array<Ref<Doc>>>((resolve, reject) => {
const refresh = lq.query(
tags.class.TagReference,
{
tag: { $in: filter.value }
},
(refs: FindResult<TagReference>) => {
const result = Array.from(new Set(refs.map((p) => p.attachedTo)))
FilterQuery.results.set(filter.index, result)
resolve(result)
onUpdate()
}
)
const level = filter.props?.level ?? 0
const q: DocumentQuery<TagReference> = {
tag: { $in: filter.value },
weight:
level === 0
? { $in: [null as unknown as InitialKnowledge, 0, 1, 2, 3, 4, 5, 6, 7, 8] }
: { $gte: level as TagReference['weight'] }
}
const refresh = lq.query(tags.class.TagReference, q, (refs: FindResult<TagReference>) => {
const result = Array.from(new Set(refs.map((p) => p.attachedTo)))
FilterQuery.results.set(filter.index, result)
resolve(result)
onUpdate()
})
if (!refresh) {
resolve(FilterQuery.results.get(filter.index) ?? [])
}
})
return await promise
}
export const tagLevel: Record<1 | 2 | 3, Asset> = {
3: tags.icon.Level3,
2: tags.icon.Level2,
1: tags.icon.Level1
}

View File

@ -32,6 +32,21 @@ export interface TagElement extends Doc {
refCount?: number
}
/**
* @public
*/
export type InitialKnowledge = 0 | 1 | 2
/**
* @public
*/
export type MeaningfullKnowledge = 3 | 4 | 5
/**
* @public
*/
export type ExpertKnowledge = 6 | 7 | 8
/**
* @public
*/
@ -39,6 +54,9 @@ export interface TagReference extends AttachedDoc {
tag: Ref<TagElement>
title: string // Copy of title for full text search, updated with trigger.
color: number // Copy of color from tagElement. Updated with trigger.
// If set in [8-10] it is speciality, [5-7] - meaningfull, [1-4] - initial
weight?: InitialKnowledge | MeaningfullKnowledge | ExpertKnowledge
}
/**
@ -76,7 +94,10 @@ const tagsPlugin = plugin(tagsId, {
Tags: '' as Ref<Space>
},
icon: {
Tags: '' as Asset
Tags: '' as Asset,
Level1: '' as Asset,
Level2: '' as Asset,
Level3: '' as Asset
},
component: {
TagsView: '' as AnyComponent,

View File

@ -21,7 +21,7 @@
import Lost from '../icons/Lost.svelte'
export let value: DoneState
export let showTitle: boolean = false
export let showTitle: boolean = true
$: color = value._class === task.class.WonState ? getPlatformColor(0) : getPlatformColor(11)
</script>

View File

@ -47,11 +47,9 @@
onMount(() => {
;(document.activeElement as HTMLElement)?.blur()
})
let docWidth: number
</script>
<svelte:window bind:innerWidth={docWidth} />
<svelte:window />
<ActionContext
context={{
@ -61,7 +59,7 @@
{#if showFilterBar}
<FilterBar {_class} {query} on:change={(e) => (resultQuery = e.detail)} />
{/if}
<Scroller fade={tableSP} horizontal={docWidth < 1024}>
<Scroller fade={tableSP} horizontal={true}>
<Table
bind:this={table}
{_class}

View File

@ -63,6 +63,7 @@ export interface Filter {
mode: Ref<FilterMode>
modes: Ref<FilterMode>[]
value: any[]
props?: Record<string, any>
index: number
onRemove?: () => void
}