mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-22 09:35:00 +02:00
Init home page (#9735)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
+1
-1
Submodule communication updated: ff4411ca57...a8d58f18bb
@@ -21,7 +21,7 @@ import { mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type Location, type ResolvedLocation } from '@hcengineering/ui/src/types'
|
||||
import { type LocationData } from '@hcengineering/workbench'
|
||||
import { type ActionCategory, type Action, type ViewAction } from '@hcengineering/view'
|
||||
import { type TagCategory, type TagElement } from '@hcengineering/tags'
|
||||
import { type TagCategory } from '@hcengineering/tags'
|
||||
|
||||
export default mergeIds(cardId, card, {
|
||||
app: {
|
||||
@@ -57,9 +57,5 @@ export default mergeIds(cardId, card, {
|
||||
CardCustomLinkMatch: '' as Resource<(doc: Doc) => boolean>,
|
||||
CardCustomLinkEncode: '' as Resource<(doc: Doc) => Location>,
|
||||
CheckRelationsSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>
|
||||
},
|
||||
label: {
|
||||
Subscribed: '' as Ref<TagElement>,
|
||||
NewMessages: '' as Ref<TagElement>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
import LiteNode from './markup/lite/LiteNode.svelte'
|
||||
|
||||
export let message: Markup | MarkupNode
|
||||
export let colorInherit: boolean = false
|
||||
|
||||
$: node = typeof message === 'string' ? markupToJSON(message) : message
|
||||
</script>
|
||||
|
||||
<div class="text-markup-view">
|
||||
<LiteNode {node} />
|
||||
<div class="text-markup-view" class:colorInherit>
|
||||
<LiteNode {node} {colorInherit} />
|
||||
</div>
|
||||
|
||||
@@ -19,12 +19,13 @@
|
||||
import NodeMarks from '../NodeMarks.svelte'
|
||||
|
||||
export let node: MarkupNode
|
||||
export let colorInherit: boolean = false
|
||||
</script>
|
||||
|
||||
{#if node}
|
||||
{@const marks = node.marks ?? []}
|
||||
|
||||
<NodeMarks {marks}>
|
||||
<LiteNodeContent {node} />
|
||||
<LiteNodeContent {node} {colorInherit} />
|
||||
</NodeMarks>
|
||||
{/if}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import { getBlobRef } from '../../../preview'
|
||||
|
||||
export let node: MarkupNode
|
||||
export let colorInherit: boolean = false
|
||||
|
||||
function toRefBlob (blobId: AttrValue): Ref<Blob> {
|
||||
return blobId as Ref<Blob>
|
||||
@@ -48,15 +49,15 @@
|
||||
{@const nodes = node.content ?? []}
|
||||
|
||||
{#if node.type === MarkupNodeType.doc}
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
{:else if node.type === MarkupNodeType.text}
|
||||
{node.text}
|
||||
{:else if node.type === MarkupNodeType.paragraph}
|
||||
<p class="p-inline contrast" class:overflow-label={true} style:margin="0">
|
||||
<LiteNodes {nodes} />
|
||||
<p class="p-inline" class:overflow-label={true} style:margin="0" class:contrast={!colorInherit} class:colorInherit>
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
</p>
|
||||
{:else if node.type === MarkupNodeType.blockquote}
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
{:else if node.type === MarkupNodeType.horizontal_rule}
|
||||
<!-- nothing-->
|
||||
{:else if node.type === MarkupNodeType.code_block}
|
||||
@@ -69,7 +70,7 @@
|
||||
}
|
||||
]}
|
||||
>
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
</NodeMarks>
|
||||
</p>
|
||||
{:else if node.type === MarkupNodeType.reference}
|
||||
@@ -80,7 +81,7 @@
|
||||
{#if objectClass !== undefined && objectId !== undefined}
|
||||
<ObjectNode _id={toRef(objectId)} _class={toClassRef(objectClass)} title={objectLabel} />
|
||||
{:else}
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
{/if}
|
||||
{:else if node.type === MarkupNodeType.emoji}
|
||||
<span class="emoji">
|
||||
@@ -100,9 +101,15 @@
|
||||
<!-- TODO not implemented -->
|
||||
{:else if node.type === MarkupNodeType.subLink}
|
||||
<sub>
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
</sub>
|
||||
{:else}
|
||||
<LiteNodes {nodes} />
|
||||
<LiteNodes {nodes} {colorInherit} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.colorInherit {
|
||||
color: inherit;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
import LiteNode from './LiteNode.svelte'
|
||||
|
||||
export let nodes: MarkupNode[]
|
||||
export let colorInherit: boolean = false
|
||||
</script>
|
||||
|
||||
{#if nodes}
|
||||
{#each nodes as node}
|
||||
<LiteNode {node} />
|
||||
<LiteNode {node} {colorInherit} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
color: var(--theme-text-primary-color);
|
||||
margin: 0.25rem 0;
|
||||
|
||||
&.colorInherit {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
padding-left: 0.25rem;
|
||||
color: var(--theme-link-color);
|
||||
@@ -544,7 +548,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.embed-youtube {
|
||||
&.embed-youtube {
|
||||
iframe {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -585,4 +589,4 @@
|
||||
|
||||
.select-text .text-editor-image-container {
|
||||
user-select: all;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {týden} other {týdny}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {měsíc} other {měsíce}}",
|
||||
"Filter": "Filtr",
|
||||
"Clear": "Vymazat"
|
||||
"Clear": "Vymazat",
|
||||
"Yesterday": "Včera",
|
||||
"ThisWeek": "Tento týden",
|
||||
"ThisMonth": "Tento měsíc",
|
||||
"ThisYear": "Tento rok"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {Woche} other {Wochen}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {Monat} other {Monate}}",
|
||||
"Filter": "Filter",
|
||||
"Clear": "Löschen"
|
||||
"Clear": "Löschen",
|
||||
"Yesterday": "Gestern",
|
||||
"ThisWeek": "Diese Woche",
|
||||
"ThisMonth": "Diesen Monat",
|
||||
"ThisYear": "Dieses Jahr"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {week} other {weeks}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {month} other {months}}",
|
||||
"Filter": "Filter",
|
||||
"Clear": "Clear"
|
||||
"Clear": "Clear",
|
||||
"Yesterday": "Yesterday",
|
||||
"ThisWeek": "This week",
|
||||
"ThisMonth": "This month",
|
||||
"ThisYear": "This year"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {semana} other {semanas}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {mes} other {meses}}",
|
||||
"Filter": "Filtrar",
|
||||
"Clear": "Limpiar"
|
||||
"Clear": "Limpiar",
|
||||
"Yesterday": "Ayer",
|
||||
"ThisWeek": "Esta semana",
|
||||
"ThisMonth": "Este mes",
|
||||
"ThisYear": "Este año"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {semaine} other {semaines}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {mois} other {mois}}",
|
||||
"Filter": "Filtrer",
|
||||
"Clear": "Effacer"
|
||||
"Clear": "Effacer",
|
||||
"Yesterday": "Hier",
|
||||
"ThisWeek": "Cette semaine",
|
||||
"ThisMonth": "Ce mois-ci",
|
||||
"ThisYear": "Cette année"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {settimana} other {settimane}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {mese} other {mesi}}",
|
||||
"Filter": "Filtra",
|
||||
"Clear": "Cancella"
|
||||
"Clear": "Cancella",
|
||||
"Yesterday": "Ieri",
|
||||
"ThisWeek": "Questa settimana",
|
||||
"ThisMonth": "Questo mese",
|
||||
"ThisYear": "Quest'anno"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {週} other {週}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {か月} other {か月}}",
|
||||
"Filter": "フィルター",
|
||||
"Clear": "クリア"
|
||||
"Clear": "クリア",
|
||||
"Yesterday": "昨日",
|
||||
"ThisWeek": "今週",
|
||||
"ThisMonth": "今月",
|
||||
"ThisYear": "今年"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {semana} other {semanas}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {mês} other {meses}}",
|
||||
"Filter": "Filtrar",
|
||||
"Clear": "Limpar"
|
||||
"Clear": "Limpar",
|
||||
"Yesterday": "Ontem",
|
||||
"ThisWeek": "Esta semana",
|
||||
"ThisMonth": "Este mês",
|
||||
"ThisYear": "Este ano"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, one {неделя} few {недели} other {недель}}",
|
||||
"MonthsWOValue": "{months, plural, one {месяц} few {месяца} other {месяцев}}",
|
||||
"Filter": "Фильтр",
|
||||
"Clear": "Очистить"
|
||||
"Clear": "Очистить",
|
||||
"Yesterday": "Вчера",
|
||||
"ThisWeek": "Эта неделя",
|
||||
"ThisMonth": "Этот месяц",
|
||||
"ThisYear": "Этот год"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
"WeeksWOValue": "{weeks, plural, =1 {周} other {周}}",
|
||||
"MonthsWOValue": "{months, plural, =1 {月} other {月}}",
|
||||
"Filter": "过滤",
|
||||
"Clear": "清除"
|
||||
"Clear": "清除",
|
||||
"Yesterday": "昨天",
|
||||
"ThisWeek": "本周",
|
||||
"ThisMonth": "本月",
|
||||
"ThisYear": "今年"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
export let label: IntlString
|
||||
export let value: string | undefined = undefined
|
||||
export let kind: 'default' | 'ghost' = 'default'
|
||||
export let kind: 'default' | 'ghost' | 'secondary' = 'default'
|
||||
export let size: 'small' | 'medium' | 'large' = 'small'
|
||||
export let disabled: boolean = false
|
||||
export let error: boolean = false
|
||||
@@ -149,6 +149,25 @@
|
||||
height: var(--global-extra-large-Size);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: var(--input-BackgroundColor);
|
||||
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
|
||||
|
||||
&.small {
|
||||
padding: var(--spacing-1) var(--spacing-1_5);
|
||||
height: var(--global-small-Size);
|
||||
}
|
||||
&.medium {
|
||||
padding: var(--spacing-1_5) var(--spacing-2);
|
||||
height: var(--global-medium-Size);
|
||||
}
|
||||
&.large {
|
||||
position: relative;
|
||||
padding: 0 var(--spacing-2);
|
||||
height: var(--global-extra-large-Size);
|
||||
}
|
||||
}
|
||||
&.ghost {
|
||||
&.small,
|
||||
&.medium {
|
||||
@@ -187,9 +206,27 @@
|
||||
background-color: var(--input-hover-BackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
input::placeholder {
|
||||
color: var(--input-PlaceholderColor);
|
||||
}
|
||||
&:active,
|
||||
&:focus-within {
|
||||
background-color: var(--input-BackgroundColor);
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--input-hover-BackgroundColor);
|
||||
}
|
||||
}
|
||||
&.ghost input::placeholder {
|
||||
color: var(--input-PlaceholderColor);
|
||||
}
|
||||
&.secondary input::placeholder {
|
||||
color: var(--input-PlaceholderColor);
|
||||
}
|
||||
&:hover input:not(:focus)::placeholder {
|
||||
color: var(--input-hover-PlaceholderColor);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ export const uis = plugin(uiId, {
|
||||
None: '' as IntlString,
|
||||
NotSelected: '' as IntlString,
|
||||
Today: '' as IntlString,
|
||||
Yesterday: '' as IntlString,
|
||||
ThisWeek: '' as IntlString,
|
||||
ThisMonth: '' as IntlString,
|
||||
ThisYear: '' as IntlString,
|
||||
NoDate: '' as IntlString,
|
||||
StartDate: '' as IntlString,
|
||||
TargetDate: '' as IntlString,
|
||||
|
||||
@@ -46,4 +46,7 @@
|
||||
<symbol id="document" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 4C7.89543 4 7 4.89543 7 6V26C7 27.1046 7.89543 28 9 28H23C24.1046 28 25 27.1046 25 26V12H21C18.7909 12 17 10.2091 17 8V4H9ZM19 4.41421V8C19 9.10457 19.8954 10 21 10H24.5858L19 4.41421ZM5 6C5 3.79086 6.79086 2 9 2H18.5858C19.1162 2 19.6249 2.21071 20 2.58579L26.4142 9C26.7893 9.37507 27 9.88378 27 10.4142V26C27 28.2091 25.2091 30 23 30H9C6.79086 30 5 28.2091 5 26V6ZM10 17C10 16.4477 10.4477 16 11 16H21C21.5523 16 22 16.4477 22 17C22 17.5523 21.5523 18 21 18H11C10.4477 18 10 17.5523 10 17ZM10 23C10 22.4477 10.4477 22 11 22H21C21.5523 22 22 22.4477 22 23C22 23.5523 21.5523 24 21 24H11C10.4477 24 10 23.5523 10 23Z" />
|
||||
</symbol>
|
||||
<symbol id="home" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.2929 2.29302C15.6834 1.90249 16.3166 1.90249 16.7071 2.29302L29.7071 15.293C30.0976 15.6835 30.0976 16.3167 29.7071 16.7072C29.3166 17.0978 28.6834 17.0978 28.2929 16.7072L28 16.4143V26.0001C28 27.1047 27.1046 28.0001 26 28.0001H6C4.89543 28.0001 4 27.1047 4 26.0001V16.4143L3.70711 16.7072C3.31658 17.0978 2.68342 17.0978 2.29289 16.7072C1.90237 16.3167 1.90237 15.6835 2.29289 15.293L15.2929 2.29302ZM6 14.4143V26.0001H12V17.0001C12 16.4478 12.4477 16.0001 13 16.0001H19C19.5523 16.0001 20 16.4478 20 17.0001V26.0001H26V14.4143L16 4.41434L6 14.4143ZM18 26.0001V18.0001H14V26.0001H18Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -40,6 +40,12 @@
|
||||
"Properties": "Vlastnosti",
|
||||
"NoChildren": "Žádné děti",
|
||||
"ConfigDescription": "Rozšíření pro správu znalostí ve stylu databáze.",
|
||||
"AddCollaborators": "Přidat spolupracovníky"
|
||||
"AddCollaborators": "Přidat spolupracovníky",
|
||||
"Home": "Domů",
|
||||
"WhatDoYouWantToShare": "Co chcete sdílet?",
|
||||
"Share": "Sdílet",
|
||||
"Compact": "Kompaktní",
|
||||
"Comfortable": "Komfortní",
|
||||
"Comfortable2": "Komfortní 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Eigenschaften",
|
||||
"NoChildren": "Keine Kinder",
|
||||
"ConfigDescription": "Erweiterung für Datenbank-basiertes Wissensmanagement.",
|
||||
"AddCollaborators": "Mitarbeiter hinzufügen"
|
||||
"AddCollaborators": "Mitarbeiter hinzufügen",
|
||||
"Home": "Startseite",
|
||||
"WhatDoYouWantToShare": "Was möchten Sie teilen?",
|
||||
"Share": "Teilen",
|
||||
"Compact": "Kompakt",
|
||||
"Comfortable": "Komfortabel",
|
||||
"Comfortable2": "Komfortabel 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Properties",
|
||||
"NoChildren": "No children",
|
||||
"ConfigDescription": "Extension for database-style knowledge management.",
|
||||
"AddCollaborators": "Add collaborators"
|
||||
"AddCollaborators": "Add collaborators",
|
||||
"Home": "Home",
|
||||
"WhatDoYouWantToShare": "What do you want to share?",
|
||||
"Share": "Share",
|
||||
"Compact": "Compact",
|
||||
"Comfortable": "Comfortable",
|
||||
"Comfortable2": "Comfortable 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Propiedades",
|
||||
"NoChildren": "No hay hijos",
|
||||
"ConfigDescription": "Extensión para la gestión del conocimiento al estilo de una base de datos.",
|
||||
"AddCollaborators": "Agregar colaboradores"
|
||||
"AddCollaborators": "Agregar colaboradores",
|
||||
"Home": "Inicio",
|
||||
"WhatDoYouWantToShare": "¿Qué quieres compartir?",
|
||||
"Share": "Compartir",
|
||||
"Compact": "Compacto",
|
||||
"Comfortable": "Confortable",
|
||||
"Comfortable2": "Confortable 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Propriétés",
|
||||
"NoChildren": "Pas d'enfants",
|
||||
"ConfigDescription": "Extension pour la gestion des connaissances de style base de données.",
|
||||
"AddCollaborators": "Ajouter des collaborateurs"
|
||||
"AddCollaborators": "Ajouter des collaborateurs",
|
||||
"Home": "Accueil",
|
||||
"WhatDoYouWantToShare": "Que voulez-vous partager ?",
|
||||
"Share": "Partager",
|
||||
"Compact": "Compact",
|
||||
"Comfortable": "Confortable",
|
||||
"Comfortable2": "Confortable 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"NoChildren": "Nessun figlio",
|
||||
"NumberTypes": "{count, plural, one {# tipo} other {# tipi}}",
|
||||
"ConfigDescription": "Estensione per la gestione della conoscenza in stile database.",
|
||||
"AddCollaborators": "Aggiungi collaboratori"
|
||||
"AddCollaborators": "Aggiungi collaboratori",
|
||||
"Home": "Home",
|
||||
"WhatDoYouWantToShare": "Cosa vuoi condividere?",
|
||||
"Share": "Condividi",
|
||||
"Compact": "Compatto",
|
||||
"Comfortable": "Confortabile",
|
||||
"Comfortable2": "Confortabile 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "プロパティ",
|
||||
"NoChildren": "子がありません",
|
||||
"ConfigDescription": "データベーススタイルのナレッジマネジメント用の拡張機能。",
|
||||
"AddCollaborators": "コラボレーターを追加"
|
||||
"AddCollaborators": "コラボレーターを追加",
|
||||
"Home": "ホーム",
|
||||
"WhatDoYouWantToShare": "どうしますかを共有しますか?",
|
||||
"Share": "共有",
|
||||
"Compact": "コンパクト",
|
||||
"Comfortable": "コンファンティブ",
|
||||
"Comfortable2": "コンファンティブ 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Propriedades",
|
||||
"NoChildren": "Sem filhos",
|
||||
"ConfigDescription": "Extensão para gerenciamento de conhecimento no estilo de banco de dados.",
|
||||
"AddCollaborators": "Adicionar colaboradores"
|
||||
"AddCollaborators": "Adicionar colaboradores",
|
||||
"Home": "Início",
|
||||
"WhatDoYouWantToShare": "O que você deseja compartilhar?",
|
||||
"Share": "Compartilhar",
|
||||
"Compact": "Compacto",
|
||||
"Comfortable": "Confortável",
|
||||
"Comfortable2": "Confortável 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "Свойства",
|
||||
"NoChildren": "Нет потомков",
|
||||
"ConfigDescription": "Расширение для управления знаниями в стиле базы данных.",
|
||||
"AddCollaborators": "Добавить сотрудников"
|
||||
"AddCollaborators": "Добавить сотрудников",
|
||||
"Home": "Дом",
|
||||
"WhatDoYouWantToShare": "Что вы хотите поделиться?",
|
||||
"Share": "Поделиться",
|
||||
"Compact": "Компактный",
|
||||
"Comfortable": "Комфортный",
|
||||
"Comfortable2": "Комфортный 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
"Properties": "属性",
|
||||
"NoChildren": "没有子级",
|
||||
"ConfigDescription": "用于数据库风格知识管理的扩展。",
|
||||
"AddCollaborators": "添加协作者"
|
||||
"AddCollaborators": "添加协作者",
|
||||
"Home": "主页",
|
||||
"WhatDoYouWantToShare": "您想分享什么?",
|
||||
"Share": "分享",
|
||||
"Compact": "紧凑",
|
||||
"Comfortable": "舒适",
|
||||
"Comfortable2": "舒适 2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@ loadMetadata(card.icon, {
|
||||
Card: `${icons}#card`,
|
||||
File: `${icons}#file`,
|
||||
View: `${icons}#view`,
|
||||
Document: `${icons}#document`
|
||||
Document: `${icons}#document`,
|
||||
Home: `${icons}#home`
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
import card from '../plugin'
|
||||
import { getCardIconInfo } from '../utils'
|
||||
|
||||
export let value: Card | undefined = undefined
|
||||
export let value: Card | undefined | null = undefined
|
||||
export let _id: Ref<Card> | undefined = undefined
|
||||
export let size: IconSize = 'small'
|
||||
export let buttonSize: ButtonSize = 'medium'
|
||||
@@ -33,14 +33,14 @@
|
||||
const hierarchy = client.getHierarchy()
|
||||
const query = createQuery()
|
||||
|
||||
let doc: Card | undefined = value
|
||||
let doc: Card | undefined = value ?? undefined
|
||||
|
||||
$: if (_id !== undefined && doc === undefined) {
|
||||
$: if (_id !== undefined && value == null) {
|
||||
query.query(card.class.Card, { _id }, (res) => {
|
||||
doc = res[0]
|
||||
})
|
||||
} else {
|
||||
doc = value
|
||||
doc = value ?? undefined
|
||||
query.unsubscribe()
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
.divider {
|
||||
border: 1px solid var(--theme-content-color);
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
height: 0.125rem;
|
||||
margin: 0 0.125rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
|
||||
import { createCard } from '../utils'
|
||||
import CardCollaborators from './CardCollaborators.svelte'
|
||||
import { TypeSelector } from '../index'
|
||||
|
||||
export let type: Ref<MasterTag>
|
||||
export let title: string = ''
|
||||
export let type: Ref<MasterTag> = 'chat:masterTag:Thread' as Ref<MasterTag>
|
||||
export let space: CardSpace | undefined = undefined
|
||||
export let changeType: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
@@ -37,12 +40,14 @@
|
||||
const me = getCurrentEmployee()
|
||||
const _id = generateId<Card>()
|
||||
|
||||
const extension = client
|
||||
.getModel()
|
||||
.findAllSync(card.mixin.CreateCardExtension, {})
|
||||
.find((it) => hierarchy.isDerived(type, it._id))
|
||||
$: extension = type
|
||||
? client
|
||||
.getModel()
|
||||
.findAllSync(card.mixin.CreateCardExtension, {})
|
||||
.find((it) => hierarchy.isDerived(type, it._id))
|
||||
: undefined
|
||||
|
||||
let data: Partial<Data<Card>> = {}
|
||||
let data: Partial<Data<Card>> = { title }
|
||||
let _space: Ref<CardSpace> | undefined = space?._id
|
||||
let description: Markup = EmptyMarkup
|
||||
let collaborators: Ref<Employee>[] = [me]
|
||||
@@ -50,6 +55,7 @@
|
||||
let creating = false
|
||||
|
||||
async function addCollaborators (): Promise<void> {
|
||||
if (type == null) return
|
||||
const accounts = collaborators
|
||||
.filter((it) => it !== me)
|
||||
.map((it) => $employeeByIdStore.get(it)?.personUuid)
|
||||
@@ -61,7 +67,7 @@
|
||||
}
|
||||
|
||||
async function okAction (): Promise<void> {
|
||||
if (_space === undefined) return
|
||||
if (_space === undefined || type == null) return
|
||||
|
||||
try {
|
||||
creating = true
|
||||
@@ -171,6 +177,12 @@
|
||||
</div>
|
||||
|
||||
<div class="hulyModal-content__settingsSet">
|
||||
{#if changeType}
|
||||
<div class="hulyModal-content__settingsSet-line">
|
||||
<span class="label"><Label label={card.string.MasterTag} /></span>
|
||||
<TypeSelector bind:value={type} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if space == null && !(extension?.hideSpace ?? false)}
|
||||
<div class="hulyModal-content__settingsSet-line">
|
||||
<span class="label"><Label label={core.string.Space} /></span>
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<!-- Copyright © 2025 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 { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { SortingOrder } from '@hcengineering/core'
|
||||
import ui, {
|
||||
eventToHTMLElement,
|
||||
IconSettings,
|
||||
Label,
|
||||
ModernButton,
|
||||
ModernEditbox,
|
||||
Scroller,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import HomeCardPresenter from './HomeCardPresenter.svelte'
|
||||
import HomeSettings from './HomeSettings.svelte'
|
||||
import CreateCardPopup from './CreateCardPopup.svelte'
|
||||
import card from '../plugin'
|
||||
|
||||
const cardsQuery = createQuery()
|
||||
const limitStep = 50
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let divScroll: HTMLDivElement
|
||||
let limit = limitStep
|
||||
let cards: Card[] = []
|
||||
let total = -1
|
||||
|
||||
cardsQuery.query(
|
||||
card.class.Card,
|
||||
{},
|
||||
(res) => {
|
||||
cards = res
|
||||
total = res.total
|
||||
},
|
||||
{
|
||||
sort: { modifiedOn: SortingOrder.Descending },
|
||||
limit,
|
||||
total: true
|
||||
}
|
||||
)
|
||||
|
||||
$: hasNextPage = total > cards.length
|
||||
|
||||
function onScroll (): void {
|
||||
if (divScroll != null && hasNextPage) {
|
||||
const isAtBottom = divScroll.scrollTop + divScroll.clientHeight >= divScroll.scrollHeight - 400
|
||||
if (isAtBottom) {
|
||||
limit += limitStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getFormatDateId (timestamp: number): string {
|
||||
const now = new Date()
|
||||
const date = new Date(timestamp)
|
||||
|
||||
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime()
|
||||
const yesterdayStart = todayStart - 24 * 60 * 60 * 1000
|
||||
|
||||
const thisWeekStart = new Date(now)
|
||||
const day = thisWeekStart.getDay() === 0 ? 7 : thisWeekStart.getDay()
|
||||
|
||||
thisWeekStart.setDate(thisWeekStart.getDate() - (day - 1))
|
||||
thisWeekStart.setHours(0, 0, 0, 0)
|
||||
|
||||
const thisMonthStart = new Date(now.getFullYear(), now.getMonth(), 1).getTime()
|
||||
const thisYearStart = new Date(now.getFullYear(), 0, 1).getTime()
|
||||
|
||||
if (date.getTime() >= todayStart) {
|
||||
return 'today'
|
||||
} else if (date.getTime() >= yesterdayStart) {
|
||||
return 'yesterday'
|
||||
} else if (date.getTime() >= thisWeekStart.getTime()) {
|
||||
return 'thisWeek'
|
||||
} else if (date.getTime() >= thisMonthStart) {
|
||||
return 'thisMonth'
|
||||
} else if (date.getTime() >= thisYearStart) {
|
||||
return 'thisYear'
|
||||
} else {
|
||||
return date.getFullYear().toString()
|
||||
}
|
||||
}
|
||||
|
||||
function onSettings (e: MouseEvent): void {
|
||||
showPopup(HomeSettings, {}, eventToHTMLElement(e))
|
||||
}
|
||||
|
||||
function onShare (): void {
|
||||
showPopup(CreateCardPopup, { title, changeType: true }, 'center', async (result) => {
|
||||
if (result !== undefined) {
|
||||
const doc = await getClient().findOne(card.class.Card, { _id: result })
|
||||
if (doc === undefined) return
|
||||
dispatch('selectCard', doc)
|
||||
}
|
||||
})
|
||||
title = ''
|
||||
}
|
||||
|
||||
let title: string = ''
|
||||
</script>
|
||||
|
||||
<Scroller bind:divScroll {onScroll} padding="2rem 4rem">
|
||||
<div class="home">
|
||||
<div class="header flex-gap-2">
|
||||
<div class="header__title">
|
||||
<Label label={card.string.Home} />
|
||||
</div>
|
||||
<ModernButton icon={IconSettings} on:click={onSettings} size="small" iconSize="small" kind="tertiary" />
|
||||
</div>
|
||||
<div class="create-card">
|
||||
<ModernEditbox
|
||||
bind:value={title}
|
||||
label={card.string.WhatDoYouWantToShare}
|
||||
size="large"
|
||||
kind="secondary"
|
||||
width="100%"
|
||||
disabled={false}
|
||||
autoFocus={true}
|
||||
>
|
||||
<svelte:fragment slot="after">
|
||||
<ModernButton
|
||||
label={card.string.Share}
|
||||
size="small"
|
||||
kind="primary"
|
||||
disabled={title.trim() === ''}
|
||||
on:click={onShare}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</ModernEditbox>
|
||||
</div>
|
||||
|
||||
<div class="body flex-gap-2">
|
||||
{#each cards as card, index}
|
||||
{@const previousCard = cards[index - 1]}
|
||||
{@const currentDate = card.modifiedOn}
|
||||
{@const previousDate = previousCard?.modifiedOn}
|
||||
{@const currentDateId = getFormatDateId(currentDate)}
|
||||
{@const previousDateId = previousDate != null ? getFormatDateId(previousDate) : undefined}
|
||||
{#if currentDateId !== previousDateId}
|
||||
<div class="date">
|
||||
{#if currentDateId === 'today'}
|
||||
<Label label={ui.string.Today} />
|
||||
{:else if currentDateId === 'yesterday'}
|
||||
<Label label={ui.string.Yesterday} />
|
||||
{:else if currentDateId === 'thisWeek'}
|
||||
<Label label={ui.string.ThisWeek} />
|
||||
{:else if currentDateId === 'thisMonth'}
|
||||
<Label label={ui.string.ThisMonth} />
|
||||
{:else if currentDateId === 'thisYear'}
|
||||
<Label label={ui.string.ThisYear} />
|
||||
{:else}
|
||||
{currentDateId}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<HomeCardPresenter {card} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</Scroller>
|
||||
|
||||
<style lang="scss">
|
||||
.home {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.create-card {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 1rem 0;
|
||||
justify-content: space-between;
|
||||
|
||||
&__title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--global-primary-TextColor);
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.date {
|
||||
display: flex;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--global-secondary-TextColor);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,284 @@
|
||||
<!-- Copyright © 2025 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 cardPlugin, { Card } from '@hcengineering/card'
|
||||
import { createMessagesQuery } from '@hcengineering/presentation'
|
||||
import { PersonId, SortingOrder } from '@hcengineering/core'
|
||||
import { CardID, Message, Label as CardLabel } from '@hcengineering/communication-types'
|
||||
import { Avatar, getPersonByPersonIdStore, PersonPreviewProvider } from '@hcengineering/contact-resources'
|
||||
import { Person } from '@hcengineering/contact'
|
||||
import { MessagePresenter, labelsStore, MessagePreview } from '@hcengineering/communication-resources'
|
||||
import { Button, IconMoreH, tooltip } from '@hcengineering/ui'
|
||||
import { showMenu } from '@hcengineering/view-resources'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
|
||||
import { isHomeSettingEnabled, compactSettingId, homeSettingsStore, comfortableSettingId2 } from '../home'
|
||||
import { openCardInSidebar } from '../utils'
|
||||
import CardTagsColored from './CardTagsColored.svelte'
|
||||
import CardIcon from './CardIcon.svelte'
|
||||
|
||||
export let card: Card
|
||||
|
||||
const messagesQuery = createMessagesQuery()
|
||||
|
||||
let message: Message | undefined = undefined
|
||||
|
||||
let socialId: PersonId | undefined = undefined
|
||||
let person: Person | undefined = undefined
|
||||
|
||||
$: isCompact = isHomeSettingEnabled($homeSettingsStore, compactSettingId)
|
||||
$: isComfortable2 = isHomeSettingEnabled($homeSettingsStore, comfortableSettingId2)
|
||||
|
||||
$: messagesQuery.query(
|
||||
{ card: card._id, strict: true, attachments: true, reactions: true, limit: 1, order: SortingOrder.Descending },
|
||||
(res) => {
|
||||
const msgs = res.getResult().reverse()
|
||||
message = msgs[msgs.length - 1]
|
||||
}
|
||||
)
|
||||
|
||||
$: socialId = message?.creator ?? card.modifiedBy
|
||||
$: personStore = getPersonByPersonIdStore([socialId])
|
||||
$: person = $personStore.get(socialId)
|
||||
|
||||
function hasNewMessages (labels: CardLabel[], cardId: CardID): boolean {
|
||||
return labels.some((it) => (it.labelId as string) === cardPlugin.label.NewMessages && it.cardId === cardId)
|
||||
}
|
||||
let isActionsOpened = false
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="card" on:click|stopPropagation|preventDefault={() => openCardInSidebar(card._id, card)}>
|
||||
<div class="card__avatar">
|
||||
<PersonPreviewProvider value={person}>
|
||||
<Avatar name={person?.name} {person} size="medium" />
|
||||
</PersonPreviewProvider>
|
||||
</div>
|
||||
|
||||
<div class="card__body">
|
||||
<div class="card__header">
|
||||
{#if hasNewMessages($labelsStore, card._id)}
|
||||
<span class="notifyMarker" />
|
||||
{/if}
|
||||
<span class="card__title overflow-label" use:tooltip={{ label: getEmbeddedLabel(card.title), textAlign: 'left' }}>
|
||||
{card.title}
|
||||
</span>
|
||||
{#if !isComfortable2}
|
||||
<span class="card__tags">
|
||||
<CardTagsColored value={card} />
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="card__message">
|
||||
{#if message}
|
||||
{#if isCompact}
|
||||
<MessagePreview {card} {message} colorInherit />
|
||||
{:else}
|
||||
<MessagePresenter {card} {message} hideHeader hideAvatar readonly padding="0" thread={false} />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="card__parent" class:wrap={isComfortable2}>
|
||||
{#if isComfortable2}
|
||||
<span class="card__tags mr-2">
|
||||
<CardTagsColored value={card} />
|
||||
</span>
|
||||
{/if}
|
||||
{#if card.parent != null && !isCompact}
|
||||
{@const info = card.parentInfo?.find((it) => it._id === card.parent)}
|
||||
{#if info}
|
||||
<span
|
||||
class="parent"
|
||||
use:tooltip={{ label: getEmbeddedLabel(info.title), textAlign: 'left' }}
|
||||
on:click|stopPropagation|preventDefault={() => openCardInSidebar(info._id)}
|
||||
>
|
||||
<CardIcon size="x-small" _id={info._id} editable={false} />
|
||||
<span class="overflow-label max-w-100">
|
||||
{info.title}
|
||||
</span>
|
||||
</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if card.parent && isCompact}
|
||||
{@const info = card.parentInfo?.find((it) => it._id === card.parent)}
|
||||
{#if info}
|
||||
<div class="card__parent column">
|
||||
<span
|
||||
class="parent"
|
||||
use:tooltip={{ label: getEmbeddedLabel(info.title), textAlign: 'left' }}
|
||||
on:click|stopPropagation|preventDefault={() => openCardInSidebar(info._id)}
|
||||
>
|
||||
<CardIcon size="x-small" _id={info._id} editable={false} />
|
||||
<span class="overflow-label max-w-40">
|
||||
{info.title}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if !isCompact}
|
||||
<div class="card__actions" class:opened={isActionsOpened}>
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind="icon"
|
||||
dataId="btnMoreActions"
|
||||
on:click={(e) => {
|
||||
isActionsOpened = true
|
||||
showMenu(e, { object: card }, () => {
|
||||
isActionsOpened = false
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
padding-top: 0.375rem;
|
||||
|
||||
gap: 0.75rem;
|
||||
min-height: 4.75rem;
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--global-ui-hover-BackgroundColor);
|
||||
|
||||
.card__actions {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
color: var(--global-primary-TextColor);
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
margin-top: 0.625rem;
|
||||
}
|
||||
|
||||
&__message {
|
||||
display: flex;
|
||||
min-height: 1.375rem;
|
||||
color: var(--global-secondary-TextColor);
|
||||
}
|
||||
|
||||
&__parent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
&.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: auto;
|
||||
padding-left: 0.5rem;
|
||||
visibility: hidden;
|
||||
|
||||
&.opened {
|
||||
visibility: visible;
|
||||
}
|
||||
&:hover {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
.parent {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 0.5rem;
|
||||
min-width: 2rem;
|
||||
max-width: 25rem;
|
||||
min-height: 1.5rem;
|
||||
max-height: 1.5rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
border-radius: 1rem;
|
||||
white-space: nowrap;
|
||||
gap: 0.25rem;
|
||||
background: var(--global-ui-hover-BackgroundColor);
|
||||
border: var(--global-subtle-ui-BorderColor);
|
||||
color: var(--global-secondary-TextColor);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--global-ui-active-BackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
.notifyMarker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
background-color: var(--global-higlight-Color);
|
||||
|
||||
min-width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,154 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 { createEventDispatcher } from 'svelte'
|
||||
import { createFocusManager, FocusHandler, Label, ListView, ModernToggle, resizeObserver } from '@hcengineering/ui'
|
||||
|
||||
import card from '../plugin'
|
||||
|
||||
import {
|
||||
updateHomeSetting,
|
||||
isHomeSettingEnabled,
|
||||
comfortableSettingId,
|
||||
compactSettingId,
|
||||
comfortableSettingId2,
|
||||
homeSettingsStore,
|
||||
homeViewSettings
|
||||
} from '../home'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let popupElement: HTMLDivElement | undefined = undefined
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: compactSettingId,
|
||||
label: card.string.Compact
|
||||
},
|
||||
{
|
||||
id: comfortableSettingId,
|
||||
label: card.string.Comfortable
|
||||
},
|
||||
{
|
||||
id: comfortableSettingId2,
|
||||
label: card.string.Comfortable2
|
||||
}
|
||||
]
|
||||
|
||||
let selection = 0
|
||||
let list: ListView
|
||||
|
||||
export function onKeydown (key: KeyboardEvent): boolean {
|
||||
if (key.code === 'Tab') {
|
||||
dispatch('close')
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
return true
|
||||
}
|
||||
if (key.code === 'ArrowUp') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(selection - 1)
|
||||
return true
|
||||
}
|
||||
if (key.code === 'ArrowDown') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(selection + 1)
|
||||
return true
|
||||
}
|
||||
if (key.code === 'Enter') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
const item = items[selection]
|
||||
if (item != null) {
|
||||
onToggle(item.id)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const manager = createFocusManager()
|
||||
|
||||
$: if (popupElement) {
|
||||
popupElement.focus()
|
||||
}
|
||||
|
||||
function onToggle (id: string): void {
|
||||
const isEnabled = !isHomeSettingEnabled($homeSettingsStore, id)
|
||||
updateHomeSetting(id, isEnabled)
|
||||
|
||||
if (isEnabled) {
|
||||
for (const setting of homeViewSettings) {
|
||||
if (setting === id) continue
|
||||
updateHomeSetting(setting, false)
|
||||
}
|
||||
} else {
|
||||
const toEnable = homeViewSettings.find((it) => it !== id)
|
||||
if (toEnable != null) {
|
||||
updateHomeSetting(toEnable, true)
|
||||
}
|
||||
for (const setting of homeViewSettings) {
|
||||
if (setting === toEnable) continue
|
||||
updateHomeSetting(setting, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<FocusHandler {manager} />
|
||||
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="selectPopup"
|
||||
bind:this={popupElement}
|
||||
tabindex="0"
|
||||
use:resizeObserver={() => {
|
||||
dispatch('changeContent')
|
||||
}}
|
||||
on:keydown={onKeydown}
|
||||
>
|
||||
<div class="menu-space" />
|
||||
<div class="scroll">
|
||||
<div class="box">
|
||||
<ListView bind:this={list} count={items.length} bind:selection on:changeContent={() => dispatch('changeContent')}>
|
||||
<svelte:fragment slot="item" let:item={itemId}>
|
||||
{@const item = items[itemId]}
|
||||
<div class="menu-item withList w-full container">
|
||||
<Label label={item.label} />
|
||||
<ModernToggle
|
||||
checked={isHomeSettingEnabled($homeSettingsStore, item.id)}
|
||||
size="small"
|
||||
on:change={() => {
|
||||
onToggle(item.id)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ListView>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -15,16 +15,19 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Scroller } from '@hcengineering/ui'
|
||||
import cardPlugin, { MasterTag, Card, CardSpace } from '@hcengineering/card'
|
||||
import { MasterTag, Card, CardSpace } from '@hcengineering/card'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { SavedView } from '@hcengineering/workbench-resources'
|
||||
import { getCurrentAccount, SortingOrder, Ref } from '@hcengineering/core'
|
||||
import { TreeItem } from '@hcengineering/view-resources'
|
||||
|
||||
import { type NavigatorConfig } from '../../types'
|
||||
import NavigatorSpace from './NavigatorSpace.svelte'
|
||||
import NavigatorVariant from './NavigatorVariant.svelte'
|
||||
|
||||
import cardPlugin from '../../plugin'
|
||||
|
||||
export let config: NavigatorConfig
|
||||
export let applicationId: string
|
||||
export let selectedType: Ref<MasterTag> | undefined = undefined
|
||||
@@ -94,6 +97,13 @@
|
||||
selectedSpecial = 'favorites'
|
||||
dispatch('favorites')
|
||||
}
|
||||
|
||||
function onHomeClick (): void {
|
||||
selectedCard = undefined
|
||||
selectedType = undefined
|
||||
selectedSpecial = 'home'
|
||||
dispatch('home')
|
||||
}
|
||||
</script>
|
||||
|
||||
<Scroller shrink>
|
||||
@@ -101,6 +111,15 @@
|
||||
{#if config.savedViews}
|
||||
<SavedView alias={applicationId} />
|
||||
{/if}
|
||||
{#if config.home}
|
||||
<TreeItem
|
||||
_id={'home'}
|
||||
label={cardPlugin.string.Home}
|
||||
selected={selectedSpecial === 'home'}
|
||||
icon={cardPlugin.icon.Home}
|
||||
on:click={onHomeClick}
|
||||
/>
|
||||
{/if}
|
||||
{#if config.groupBySpace}
|
||||
{#each spaces as space (space._id)}
|
||||
<NavigatorSpace
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright © 2025 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.
|
||||
|
||||
import { get, writable } from 'svelte/store'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import { location } from '@hcengineering/ui'
|
||||
|
||||
export interface HomeSetting {
|
||||
id: string
|
||||
on: boolean
|
||||
}
|
||||
|
||||
export const compactSettingId = 'home-settings.compact'
|
||||
export const comfortableSettingId = 'home-settings.comfortable'
|
||||
export const comfortableSettingId2 = 'home-settings.comfortable2'
|
||||
|
||||
const defaultValues = {
|
||||
[compactSettingId]: false,
|
||||
[comfortableSettingId]: true,
|
||||
[comfortableSettingId2]: false
|
||||
} as const
|
||||
|
||||
export const homeViewSettings = [compactSettingId, comfortableSettingId, comfortableSettingId2]
|
||||
|
||||
export const homeSettingsStore = writable<HomeSetting[]>([])
|
||||
|
||||
export function isHomeSettingEnabled (settings: HomeSetting[], id: string): boolean {
|
||||
const index = settings.findIndex((it) => it.id === id)
|
||||
if (index === -1) return (defaultValues as any)[id] ?? false
|
||||
return settings[index].on
|
||||
}
|
||||
|
||||
export function updateHomeSetting (id: string, on: boolean): void {
|
||||
const settings = get(homeSettingsStore)
|
||||
const index = settings.findIndex((it) => it.id === id)
|
||||
if (index === -1) {
|
||||
homeSettingsStore.set([...settings, { id, on }])
|
||||
} else {
|
||||
homeSettingsStore.set(settings.map((it) => (it.id === id ? { ...it, on } : it)))
|
||||
}
|
||||
}
|
||||
|
||||
let prevWorkspace: string | undefined
|
||||
|
||||
location.subscribe((loc) => {
|
||||
const workspace = loc.path[1]
|
||||
if (prevWorkspace !== workspace) {
|
||||
initHomeSettings()
|
||||
prevWorkspace = workspace
|
||||
}
|
||||
})
|
||||
|
||||
homeSettingsStore.subscribe((settings) => {
|
||||
const key = geLocalStorageKey()
|
||||
if (key === undefined) return
|
||||
localStorage.setItem(key, JSON.stringify(settings))
|
||||
})
|
||||
|
||||
function geLocalStorageKey (): string | undefined {
|
||||
const me = getCurrentAccount()
|
||||
const loc = get(location)
|
||||
const workspace = loc.path[1] ?? ''
|
||||
if (me == null || workspace === '') return undefined
|
||||
return `${workspace}.${me.uuid}.home.settings.v1`
|
||||
}
|
||||
|
||||
function initHomeSettings (): void {
|
||||
const key = geLocalStorageKey()
|
||||
if (key === undefined) return
|
||||
|
||||
const stored = localStorage.getItem(key)
|
||||
|
||||
if (stored == null) {
|
||||
homeSettingsStore.set([])
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(stored)
|
||||
Array.isArray(data) ? homeSettingsStore.set(data as HomeSetting[]) : homeSettingsStore.set([])
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
homeSettingsStore.set([])
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ export { default as Favorites } from './components/Favorites.svelte'
|
||||
export { default as CardPresenter } from './components/CardPresenter.svelte'
|
||||
export { default as TypeSelector } from './components/TypeSelector.svelte'
|
||||
export { default as AssociationsSelect } from './components/settings/view/AssociationsSelect.svelte'
|
||||
export { default as Home } from './components/Home.svelte'
|
||||
|
||||
export * from './types'
|
||||
export { getCardIconInfo } from './utils'
|
||||
|
||||
@@ -100,6 +100,12 @@ export default mergeIds(cardId, card, {
|
||||
NumberTypes: '' as IntlString,
|
||||
Properties: '' as IntlString,
|
||||
NoChildren: '' as IntlString,
|
||||
AddCollaborators: '' as IntlString
|
||||
AddCollaborators: '' as IntlString,
|
||||
Home: '' as IntlString,
|
||||
WhatDoYouWantToShare: '' as IntlString,
|
||||
Share: '' as IntlString,
|
||||
Compact: '' as IntlString,
|
||||
Comfortable: '' as IntlString,
|
||||
Comfortable2: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,6 +18,7 @@ import { type Heading } from '@hcengineering/text-editor'
|
||||
|
||||
interface BaseNavigatorConfig {
|
||||
types: Array<Ref<MasterTag>>
|
||||
home?: boolean
|
||||
groupBySpace?: boolean
|
||||
savedViews?: boolean
|
||||
allowCreate?: boolean
|
||||
|
||||
@@ -149,7 +149,8 @@ const cardPlugin = plugin(cardId, {
|
||||
Card: '' as Asset,
|
||||
File: '' as Asset,
|
||||
View: '' as Asset,
|
||||
Document: '' as Asset
|
||||
Document: '' as Asset,
|
||||
Home: '' as Asset
|
||||
},
|
||||
extensions: {
|
||||
EditCardExtension: '' as ComponentExtensionId
|
||||
@@ -184,6 +185,10 @@ const cardPlugin = plugin(cardId, {
|
||||
},
|
||||
function: {
|
||||
OpenCardInSidebar: '' as Resource<(_id: Ref<Card>, card?: Card) => Promise<void>>
|
||||
},
|
||||
label: {
|
||||
Subscribed: '' as Ref<Doc>,
|
||||
NewMessages: '' as Ref<Doc>
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import { chatId } from '@hcengineering/chat'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import view from '@hcengineering/view'
|
||||
import { Favorites } from '@hcengineering/card-resources'
|
||||
import { Favorites, Home } from '@hcengineering/card-resources'
|
||||
|
||||
import ChatNavigation from './ChatNavigation.svelte'
|
||||
import {
|
||||
@@ -39,7 +39,9 @@
|
||||
navigateToType,
|
||||
getTypeIdFromLocation,
|
||||
isFavoritesLocation,
|
||||
navigateToFavorites
|
||||
navigateToFavorites,
|
||||
navigateToHome,
|
||||
isHomeLocation
|
||||
} from '../location'
|
||||
import ChatNavigationCategoryList from './ChatNavigationCategoryList.svelte'
|
||||
|
||||
@@ -55,6 +57,7 @@
|
||||
doc: MasterTag
|
||||
}
|
||||
| { type: 'favorites' }
|
||||
| { type: 'home' }
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
@@ -74,12 +77,18 @@
|
||||
const typeId = getTypeIdFromLocation(loc)
|
||||
const cardId = getCardIdFromLocation(loc)
|
||||
const isFavorites = isFavoritesLocation(loc)
|
||||
const isHome = isHomeLocation(loc)
|
||||
|
||||
if (isFavorites) {
|
||||
selection = { type: 'favorites' }
|
||||
return
|
||||
}
|
||||
|
||||
if (isHome) {
|
||||
selection = { type: 'home' }
|
||||
return
|
||||
}
|
||||
|
||||
const type = typeId != null ? await client.findOne(cardPlugin.class.MasterTag, { _id: typeId }) : undefined
|
||||
|
||||
if (type != null) {
|
||||
@@ -127,6 +136,13 @@
|
||||
navigateToFavorites()
|
||||
}
|
||||
|
||||
function selectHome (): void {
|
||||
if (selection?.type === 'home') return
|
||||
closePanel(false)
|
||||
selection = { type: 'home' }
|
||||
navigateToHome()
|
||||
}
|
||||
|
||||
function getSelectedCard (selection: Selection | undefined): Card | undefined {
|
||||
if (selection?.type !== 'card') return undefined
|
||||
return selection.doc
|
||||
@@ -164,10 +180,11 @@
|
||||
<ChatNavigation
|
||||
card={getSelectedCard(selection)}
|
||||
type={getSelectedType(selection)}
|
||||
isFavorites={selection?.type === 'favorites'}
|
||||
special={selection?.type}
|
||||
on:selectCard={selectCard}
|
||||
on:selectType={selectType}
|
||||
on:favorites={selectFavorites}
|
||||
on:home={selectHome}
|
||||
/>
|
||||
</div>
|
||||
{#if !($deviceInfo.isMobile && $deviceInfo.isPortrait && $deviceInfo.minWidth)}
|
||||
@@ -188,6 +205,10 @@
|
||||
{#key selection.type}
|
||||
<Favorites application={chatId} />
|
||||
{/key}
|
||||
{:else if selection?.type === 'home'}
|
||||
{#key selection.type}
|
||||
<Home on:selectCard={selectCard} />
|
||||
{/key}
|
||||
{:else if selectedCard}
|
||||
{@const panelComponent = hierarchy.classHierarchyMixin(selectedCard._class, view.mixin.ObjectPanel)}
|
||||
{@const comp = panelComponent?.component ?? view.component.EditDoc}
|
||||
|
||||
@@ -23,7 +23,17 @@
|
||||
|
||||
export let card: Card | undefined = undefined
|
||||
export let type: Ref<MasterTag> | undefined = undefined
|
||||
export let isFavorites: boolean = false
|
||||
export let special: 'home' | 'favorites' | string | undefined = undefined
|
||||
|
||||
function getSpecial (special: 'home' | 'favorites' | string | undefined): string | undefined {
|
||||
if (special === 'favorites') {
|
||||
return 'favorites'
|
||||
}
|
||||
if (special === 'home') {
|
||||
return 'home'
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<Navigator
|
||||
@@ -34,6 +44,7 @@
|
||||
groupBySpace: false,
|
||||
hideEmpty: true,
|
||||
limit: 5,
|
||||
home: true,
|
||||
labelFilter: [SubscriptionLabelID],
|
||||
preorder: [
|
||||
{ type: chat.masterTag.Thread, order: 1 },
|
||||
@@ -53,8 +64,9 @@
|
||||
applicationId={chatId}
|
||||
selectedType={type}
|
||||
selectedCard={card?._id}
|
||||
selectedSpecial={isFavorites ? 'favorites' : undefined}
|
||||
selectedSpecial={getSpecial(special)}
|
||||
on:selectType
|
||||
on:selectCard
|
||||
on:favorites
|
||||
on:home
|
||||
/>
|
||||
|
||||
@@ -26,6 +26,10 @@ export function isFavoritesLocation (loc: Location): boolean {
|
||||
return loc.path[2] === chatId && loc.path[3] === 'favorites'
|
||||
}
|
||||
|
||||
export function isHomeLocation (loc: Location): boolean {
|
||||
return loc.path[2] === chatId && loc.path[3] === 'home'
|
||||
}
|
||||
|
||||
export function getCardIdFromLocation (loc: Location): Ref<Card> | undefined {
|
||||
if (loc.path[2] !== chatId) {
|
||||
return undefined
|
||||
@@ -78,6 +82,16 @@ export function navigateToFavorites (): void {
|
||||
navigate(loc)
|
||||
}
|
||||
|
||||
export function navigateToHome (): void {
|
||||
const loc = getCurrentResolvedLocation()
|
||||
|
||||
loc.path[2] = chatId
|
||||
loc.path[3] = 'home'
|
||||
delete loc.query?.message
|
||||
|
||||
navigate(loc)
|
||||
}
|
||||
|
||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
if (loc.path[2] !== chatId) {
|
||||
return undefined
|
||||
|
||||
@@ -53,7 +53,9 @@
|
||||
|
||||
let avatarSize = size
|
||||
|
||||
$: if (size === 'small') {
|
||||
$: if (size === 'x-small') {
|
||||
avatarSize = 'tiny'
|
||||
} else if (size === 'small') {
|
||||
avatarSize = 'x-small'
|
||||
} else if (size === 'medium') {
|
||||
avatarSize = 'small'
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<!-- Copyright © 2025 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 { LiteMessageViewer } from '@hcengineering/presentation'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { type WithLookup } from '@hcengineering/core'
|
||||
import { Message, SocialID } from '@hcengineering/communication-types'
|
||||
import { Person } from '@hcengineering/contact'
|
||||
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
||||
import { employeeByPersonIdStore, getPersonByPersonId } from '@hcengineering/contact-resources'
|
||||
import { markdownToMarkup } from '@hcengineering/text-markdown'
|
||||
import { jsonToMarkup, markupToText } from '@hcengineering/text'
|
||||
import { tooltip } from '@hcengineering/ui'
|
||||
|
||||
import { isActivityMessage } from '../activity'
|
||||
import ActivityMessageViewer from './message/ActivityMessageViewer.svelte'
|
||||
import AttachmentsPreview from './AttachmentsPreview.svelte'
|
||||
|
||||
export let card: Card
|
||||
export let message: Message
|
||||
export let colorInherit: boolean = false
|
||||
|
||||
const tooltipLimit = 512
|
||||
|
||||
let person: WithLookup<Person> | undefined = undefined
|
||||
|
||||
$: void updatePerson(message.creator)
|
||||
|
||||
function getTooltipLabel (message: Message): IntlString {
|
||||
const text = markupToText(jsonToMarkup(markdownToMarkup(message.content)))
|
||||
if (text.length > tooltipLimit) {
|
||||
return getEmbeddedLabel(text.substring(0, tooltipLimit) + '...')
|
||||
}
|
||||
return getEmbeddedLabel(text)
|
||||
}
|
||||
|
||||
async function updatePerson (socialId: SocialID): Promise<void> {
|
||||
person = $employeeByPersonIdStore.get(socialId) ?? (await getPersonByPersonId(socialId)) ?? undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<span class="message-preview overflow-label" use:tooltip={{ label: getTooltipLabel(message) }}>
|
||||
{#if isActivityMessage(message)}
|
||||
<ActivityMessageViewer {message} {card} author={person} />
|
||||
{:else}
|
||||
<LiteMessageViewer message={markdownToMarkup(message.content)} {colorInherit} />
|
||||
{/if}
|
||||
<AttachmentsPreview {message} />
|
||||
</span>
|
||||
@@ -33,6 +33,8 @@
|
||||
export let isEditing = false
|
||||
export let compact: boolean = false
|
||||
export let hideAvatar: boolean = false
|
||||
export let hideHeader: boolean = false
|
||||
export let thread: boolean = true
|
||||
|
||||
function formatDate (date: Date): string {
|
||||
return date.toLocaleTimeString('default', {
|
||||
@@ -42,15 +44,17 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if compact}
|
||||
{#if compact || hideHeader}
|
||||
<div class="message__body">
|
||||
<div class="time-container">
|
||||
<div class="message__time message--time_hoverable">
|
||||
<div class="message__date">
|
||||
{formatDate(message.created)}
|
||||
{#if !hideHeader}
|
||||
<div class="time-container">
|
||||
<div class="message__time message--time_hoverable">
|
||||
<div class="message__date">
|
||||
{formatDate(message.created)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="message__content">
|
||||
{#if !isEditing && message.content !== ''}
|
||||
@@ -70,7 +74,7 @@
|
||||
/>
|
||||
{/if}
|
||||
{#if !isEditing}
|
||||
<MessageFooter {message} />
|
||||
<MessageFooter {message} {thread} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +136,7 @@
|
||||
/>
|
||||
{/if}
|
||||
{#if !isEditing}
|
||||
<MessageFooter {message} />
|
||||
<MessageFooter {message} {thread} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
import communication from '../../plugin'
|
||||
|
||||
export let message: Message
|
||||
export let thread: boolean = true
|
||||
|
||||
const me = getCurrentAccount()
|
||||
const communicationClient = getCommunicationClient()
|
||||
@@ -130,7 +131,7 @@
|
||||
<ReactionsList reactions={message.reactions} on:click={handleReaction} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if message.thread && message.thread.threadId}
|
||||
{#if thread && message.thread && message.thread.threadId}
|
||||
<div class="message__replies overflow-label">
|
||||
<MessageThread thread={message.thread} on:click={handleReply} />
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
export let padding: string | undefined = undefined
|
||||
export let compact: boolean = false
|
||||
export let hideAvatar: boolean = false
|
||||
export let hideHeader: boolean = false
|
||||
export let readonly: boolean = false
|
||||
export let thread: boolean = true
|
||||
|
||||
let isEditing = false
|
||||
let isDeleted = false
|
||||
@@ -151,9 +153,18 @@
|
||||
style:padding
|
||||
>
|
||||
{#if message.type === MessageType.Activity || (message.removed && message.thread?.threadId === undefined)}
|
||||
<OneRowMessageBody {message} {card} {author} {hideAvatar} />
|
||||
<OneRowMessageBody {message} {card} {author} {hideAvatar} {hideHeader} />
|
||||
{:else}
|
||||
<MessageBody {message} {card} {author} {isEditing} compact={compact && !isThread} {hideAvatar} />
|
||||
<MessageBody
|
||||
{message}
|
||||
{card}
|
||||
{author}
|
||||
{isEditing}
|
||||
compact={compact && !isThread}
|
||||
{hideAvatar}
|
||||
{hideHeader}
|
||||
{thread}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if showActions}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
export let author: Person | undefined
|
||||
export let message: Message
|
||||
export let hideAvatar: boolean = false
|
||||
export let hideHeader: boolean = false
|
||||
|
||||
function formatDate (date: Date): string {
|
||||
return date.toLocaleTimeString('default', {
|
||||
@@ -51,7 +52,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if !isDeleted}
|
||||
{#if !isDeleted && !hideHeader}
|
||||
<div class="message__header">
|
||||
<PersonPreviewProvider value={author}>
|
||||
<div class="message__username">
|
||||
|
||||
+7
-2
@@ -85,7 +85,12 @@
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--global-primary-TextColor);
|
||||
fill: var(--global-primary-TextColor);
|
||||
color: var(--global-secondary-TextColor);
|
||||
fill: var(--global-secondary-TextColor);
|
||||
|
||||
&:hover {
|
||||
color: var(--global-secondary-TextColor);
|
||||
fill: var(--global-secondary-TextColor);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -48,6 +48,8 @@ export * from './stores'
|
||||
export { default as MessagePresenter } from './components/message/MessagePresenter.svelte'
|
||||
export { default as MessageInput } from './components/message/MessageInput.svelte'
|
||||
export { default as ActivityMessageViewer } from './components/message/ActivityMessageViewer.svelte'
|
||||
export { default as AttachmentsPreview } from './components/AttachmentsPreview.svelte'
|
||||
export { default as MessagePreview } from './components/MessagePreview.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
|
||||
@@ -21,9 +21,8 @@
|
||||
import { employeeByPersonIdStore, getPersonByPersonId } from '@hcengineering/contact-resources'
|
||||
import { markdownToMarkup } from '@hcengineering/text-markdown'
|
||||
import { jsonToMarkup, markupToText } from '@hcengineering/text'
|
||||
import { ActivityMessageViewer, isActivityMessage } from '@hcengineering/communication-resources'
|
||||
import { ActivityMessageViewer, isActivityMessage, AttachmentsPreview } from '@hcengineering/communication-resources'
|
||||
|
||||
import AttachmentsPreview from './AttachmentsPreview.svelte'
|
||||
import PreviewTemplate from './PreviewTemplate.svelte'
|
||||
|
||||
export let card: Card
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Doc, Ref } from '@hcengineering/core'
|
||||
import type { Asset } from '@hcengineering/platform'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import type { Action, IconSize } from '@hcengineering/ui'
|
||||
import TreeElement from './TreeElement.svelte'
|
||||
import { AnySvelteComponent } from '@hcengineering/ui'
|
||||
|
||||
export let _id: Ref<Doc> | undefined = undefined
|
||||
export let _id: Ref<Doc> | string | undefined = undefined
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let folderIcon: boolean = false
|
||||
export let iconProps: Record<string, any> | undefined = undefined
|
||||
export let iconSize: IconSize = 'small'
|
||||
export let title: string
|
||||
export let title: string | undefined = undefined
|
||||
export let label: IntlString | undefined = undefined
|
||||
export let notifications = 0
|
||||
export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => []
|
||||
export let selected: boolean = false
|
||||
@@ -49,6 +50,7 @@
|
||||
{iconSize}
|
||||
{iconProps}
|
||||
{title}
|
||||
{label}
|
||||
{notifications}
|
||||
{selected}
|
||||
{actions}
|
||||
|
||||
Reference in New Issue
Block a user