UBER-206: Redefined color palettes (#3243)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-05-24 23:53:06 +07:00 committed by GitHub
parent df5fc73eeb
commit 3776137a52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 897 additions and 578 deletions

View File

@ -50,6 +50,7 @@ import workbench from '@hcengineering/model-workbench'
import notification from '@hcengineering/notification'
import { Asset, IntlString } from '@hcengineering/platform'
import hr from './plugin'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
export { hrId } from '@hcengineering/hr'
export { hrOperation } from './migration'
@ -243,7 +244,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.Sick,
icon: hr.icon.Sick,
color: 11,
color: PaletteColorIndexes.Turquoise,
value: -1
},
hr.ids.Sick
@ -255,7 +256,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.PTO,
icon: hr.icon.PTO,
color: 9,
color: PaletteColorIndexes.Firework,
value: -1
},
hr.ids.PTO
@ -267,7 +268,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.PTO2,
icon: hr.icon.PTO,
color: 9,
color: PaletteColorIndexes.Watermelon,
value: -0.5
},
hr.ids.PTO2
@ -279,7 +280,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.Overtime,
icon: hr.icon.Overtime,
color: 5,
color: PaletteColorIndexes.Waterway,
value: 1
},
hr.ids.Overtime
@ -291,7 +292,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.Overtime2,
icon: hr.icon.Overtime,
color: 5,
color: PaletteColorIndexes.Cerulean,
value: 0.5
},
hr.ids.Overtime2
@ -303,7 +304,7 @@ export function createModel (builder: Builder): void {
{
label: hr.string.Remote,
icon: hr.icon.Remote,
color: 4,
color: PaletteColorIndexes.Coin,
value: 0
},
hr.ids.Remote

View File

@ -19,6 +19,7 @@ import core from '@hcengineering/model-core'
import { createKanbanTemplate, createSequence } from '@hcengineering/model-task'
import task, { createKanban, KanbanTemplate } from '@hcengineering/task'
import lead from './plugin'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
async function createSpace (tx: TxOperations): Promise<void> {
const current = await tx.findOne(core.class.Space, {
@ -62,12 +63,12 @@ async function createSpace (tx: TxOperations): Promise<void> {
async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<KanbanTemplate>> {
const defaultKanban = {
states: [
{ color: 9, name: 'Incoming' },
{ color: 10, name: 'Negotation' },
{ color: 1, name: 'Offer preparing' },
{ color: 0, name: 'Make a decision' },
{ color: 11, name: 'Contract conclusion' },
{ color: 9, name: 'Done' }
{ color: PaletteColorIndexes.Coin, name: 'Incoming' },
{ color: PaletteColorIndexes.Arctic, name: 'Negotation' },
{ color: PaletteColorIndexes.Watermelon, name: 'Offer preparing' },
{ color: PaletteColorIndexes.Orange, name: 'Make a decision' },
{ color: PaletteColorIndexes.Ocean, name: 'Contract conclusion' },
{ color: PaletteColorIndexes.Grass, name: 'Done' }
],
doneStates: [
{ isWon: true, name: 'Won' },

View File

@ -1009,6 +1009,32 @@ export function createModel (builder: Builder): void {
group: 'edit'
}
})
createAction(builder, {
action: view.actionImpl.ValueSelector,
actionPopup: view.component.ValueSelector,
actionProps: {
attribute: 'doneState',
_class: task.class.DoneState,
query: {},
searchField: 'name',
// should match space
fillQuery: { space: 'space' },
// Only apply for same vacancy
docMatches: ['space'],
placeholder: task.string.DoneState
},
label: task.string.DoneState,
icon: task.icon.TaskState,
keyBinding: [],
input: 'none',
category: recruit.category.Recruit,
target: recruit.class.Applicant,
context: {
mode: ['context'],
application: recruit.app.Recruit,
group: 'edit'
}
})
createAction(
builder,
{

View File

@ -34,6 +34,7 @@ import { createKanbanTemplate, createSequence, DOMAIN_KANBAN } from '@hcengineer
import { Vacancy } from '@hcengineering/recruit'
import task, { KanbanTemplate, Sequence } from '@hcengineering/task'
import recruit from './plugin'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
async function fixImportedTitle (client: MigrationClient): Promise<void> {
await client.update(
@ -189,10 +190,10 @@ async function createDefaults (tx: TxOperations): Promise<void> {
async function createDefaultKanbanTemplate (tx: TxOperations): Promise<Ref<KanbanTemplate>> {
const defaultKanban = {
states: [
{ color: 9, name: 'HR Interview' },
{ color: 10, name: 'Technical Interview' },
{ color: 1, name: 'Test task' },
{ color: 0, name: 'Offer' }
{ color: PaletteColorIndexes.Coin, name: 'HR Interview' },
{ color: PaletteColorIndexes.Cerulean, name: 'Technical Interview' },
{ color: PaletteColorIndexes.Waterway, name: 'Test task' },
{ color: PaletteColorIndexes.Grass, name: 'Offer' }
],
doneStates: [
{ isWon: true, name: 'Won' },

View File

@ -65,21 +65,22 @@ import {
IssueStatus,
IssueTemplate,
IssueTemplateChild,
Milestone,
MilestoneStatus,
Project,
Scrum,
ScrumRecord,
Milestone,
MilestoneStatus,
TimeReportDayType,
TimeSpendReport,
trackerId
} from '@hcengineering/tracker'
import { KeyBinding, ViewOptionsModel } from '@hcengineering/view'
import { KeyBinding, ViewOptionModel, ViewOptionsModel } from '@hcengineering/view'
import tracker from './plugin'
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
import presentation from '@hcengineering/model-presentation'
import { defaultPriorities, issuePriorities } from '@hcengineering/tracker-resources/src/types'
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
export { trackerId } from '@hcengineering/tracker'
export { trackerOperation } from './migration'
@ -448,7 +449,15 @@ export function createModel (builder: Builder): void {
TTypeReportedTime
)
const issuesOptions: ViewOptionsModel = {
const showColors: ViewOptionModel = {
key: 'shouldShowColors',
type: 'toggle',
defaultValue: false,
actionTarget: 'display',
label: tracker.string.ShowColors
}
const issuesOptions = (kanban: boolean): ViewOptionsModel => ({
groupBy: ['status', 'assignee', 'priority', 'component', 'milestone'],
orderBy: [
['status', SortingOrder.Ascending],
@ -474,9 +483,10 @@ export function createModel (builder: Builder): void {
actionTarget: 'category',
action: view.function.ShowEmptyGroups,
label: view.string.ShowEmptyGroups
}
},
...(!kanban ? [showColors] : [])
]
}
})
builder.createDoc(
view.class.Viewlet,
@ -484,7 +494,7 @@ export function createModel (builder: Builder): void {
{
attachTo: tracker.class.Issue,
descriptor: view.viewlet.List,
viewOptions: issuesOptions,
viewOptions: issuesOptions(false),
config: [
{
key: '',
@ -586,7 +596,7 @@ export function createModel (builder: Builder): void {
['dueDate', SortingOrder.Ascending]
],
groupDepth: 1,
other: []
other: [showColors]
}
builder.createDoc(
@ -665,7 +675,7 @@ export function createModel (builder: Builder): void {
['dueDate', SortingOrder.Ascending],
['rank', SortingOrder.Ascending]
],
other: []
other: [showColors]
},
config: [
// { key: '', presenter: tracker.component.PriorityEditor, props: { kind: 'list', size: 'small' } },
@ -728,7 +738,7 @@ export function createModel (builder: Builder): void {
attachTo: tracker.class.Issue,
descriptor: tracker.viewlet.Kanban,
viewOptions: {
...issuesOptions,
...issuesOptions(true),
groupDepth: 1
},
config: []
@ -754,7 +764,7 @@ export function createModel (builder: Builder): void {
ofAttribute: tracker.attribute.IssueStatus,
label: tracker.string.CategoryBacklog,
icon: tracker.icon.CategoryBacklog,
color: 12,
color: PaletteColorIndexes.Cloud,
defaultStatusName: 'Backlog',
order: 0
},
@ -768,7 +778,7 @@ export function createModel (builder: Builder): void {
ofAttribute: tracker.attribute.IssueStatus,
label: tracker.string.CategoryUnstarted,
icon: tracker.icon.CategoryUnstarted,
color: 13,
color: PaletteColorIndexes.Porpoise,
defaultStatusName: 'Todo',
order: 1
},
@ -782,7 +792,7 @@ export function createModel (builder: Builder): void {
ofAttribute: tracker.attribute.IssueStatus,
label: tracker.string.CategoryStarted,
icon: tracker.icon.CategoryStarted,
color: 14,
color: PaletteColorIndexes.Cerulean,
defaultStatusName: 'In Progress',
order: 2
},
@ -796,7 +806,7 @@ export function createModel (builder: Builder): void {
ofAttribute: tracker.attribute.IssueStatus,
label: tracker.string.CategoryCompleted,
icon: tracker.icon.CategoryCompleted,
color: 15,
color: PaletteColorIndexes.Grass,
defaultStatusName: 'Done',
order: 3
},
@ -810,7 +820,7 @@ export function createModel (builder: Builder): void {
ofAttribute: tracker.attribute.IssueStatus,
label: tracker.string.CategoryCanceled,
icon: tracker.icon.CategoryCanceled,
color: 16,
color: PaletteColorIndexes.Coin,
defaultStatusName: 'Canceled',
order: 4
},
@ -1772,7 +1782,7 @@ export function createModel (builder: Builder): void {
['targetDate', SortingOrder.Descending],
['createOn', SortingOrder.Descending]
],
other: []
other: [showColors]
}
builder.createDoc(
@ -1844,7 +1854,7 @@ export function createModel (builder: Builder): void {
['modifiedOn', SortingOrder.Descending],
['createOn', SortingOrder.Descending]
],
other: []
other: [showColors]
}
builder.createDoc(

View File

@ -1,4 +1,5 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",

View File

@ -13,9 +13,9 @@
// limitations under the License.
-->
<script lang="ts">
import { Component, ScrollerBar, getPlatformColor } from '@hcengineering/ui'
import BreadcrumbsElement from './BreadcrumbsElement.svelte'
import { Component, ScrollerBar, getPlatformColor, themeStore } from '@hcengineering/ui'
import { NavLink } from '../..'
import BreadcrumbsElement from './BreadcrumbsElement.svelte'
import { BreadcrumbsModel } from './types'
import { hasComponent } from './utils'
@ -44,7 +44,7 @@
{@const { component, props } = model}
<BreadcrumbsElement
position={getPosition(i)}
color={color !== undefined ? getPlatformColor(color) : 'var(--accent-bg-color)'}
color={color !== undefined ? getPlatformColor(color, $themeStore.dark) : 'var(--accent-bg-color)'}
>
{#if typeof component === 'string'}
<Component is={component} {props} />
@ -59,7 +59,7 @@
label={title}
{title}
position={getPosition(i)}
color={color !== undefined ? getPlatformColor(color) : 'var(--accent-bg-color)'}
color={color !== undefined ? getPlatformColor(color, $themeStore.dark) : 'var(--accent-bg-color)'}
/>
</NavLink>
{/if}

View File

@ -94,10 +94,6 @@ export const Completion = Node.create<CompletionOptions>({
draggable: true,
onFocus () {
console.log('focus')
},
addAttributes () {
return {
id: {

View File

@ -33,7 +33,8 @@
IconObjects,
IconSize,
SelectPopup,
showPopup
showPopup,
themeStore
} from '@hcengineering/ui'
import { WebsocketProvider } from 'y-websocket'
import * as Y from 'yjs'
@ -246,7 +247,7 @@
provider: wsProvider,
user: {
name: currentUser.email,
color: getPlatformColorForText(currentUser.email)
color: getPlatformColorForText(currentUser.email, $themeStore.dark)
}
}),
DecorationExtension

View File

@ -13,39 +13,37 @@
// limitations under the License.
-->
<script lang="ts">
import { setContext, onMount } from 'svelte'
import platform, { loadPluginStrings, setMetadata } from '@hcengineering/platform'
import { themeStore as themeOptions } from './'
import { onMount, setContext } from 'svelte'
import { ThemeOptions, getCurrentFontSize, getCurrentLanguage, getCurrentTheme, themeStore as themeOptions } from './'
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
const getCurrnetLanguage = (): string => localStorage.getItem('lang') ?? 'en'
const currentTheme = getCurrentTheme()
const currentFontSize = getCurrnetFontSize()
let currentLanguage = getCurrnetLanguage()
const currentFontSize = getCurrentFontSize()
let currentLanguage = getCurrentLanguage()
const setRootColors = (theme: string) => {
document.documentElement.setAttribute('class', `${theme} ${getCurrnetFontSize()}`)
document.documentElement.setAttribute('class', `${theme} ${getCurrentFontSize()}`)
themeOptions.set(
new ThemeOptions(getCurrentFontSize() === 'normal-font' ? 16 : 14, getCurrentTheme() === 'theme-dark')
)
}
const setRootFontSize = (fontsize: string) => {
document.documentElement.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
themeOptions.update((opt) => {
return { ...opt, fontSize: fontsize === 'normal-font' ? 16 : 14 }
})
themeOptions.set(new ThemeOptions(fontsize === 'normal-font' ? 16 : 14, getCurrentTheme() === 'theme-dark'))
}
setContext('theme', {
currentTheme,
setTheme: (name: string) => {
setRootColors(name)
localStorage.setItem('theme', name)
setRootColors(name)
}
})
setContext('fontsize', {
currentFontSize,
setFontSize: (fontsize: string) => {
setRootFontSize(fontsize)
localStorage.setItem('fontsize', fontsize)
setRootFontSize(fontsize)
}
})
setContext('lang', {

View File

@ -18,7 +18,22 @@ import { writable } from 'svelte/store'
export { default as Theme } from './Theme.svelte'
export interface ThemeOptions {
fontSize: number
/**
* @public
*/
export const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
/**
* @public
*/
export const getCurrentFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
/**
* @public
*/
export const getCurrentLanguage = (): string => localStorage.getItem('lang') ?? 'en'
export class ThemeOptions {
constructor (readonly fontSize: number, readonly dark: boolean) {}
}
export const themeStore = writable<ThemeOptions>()
export const themeStore = writable<ThemeOptions>(
new ThemeOptions(getCurrentFontSize() === 'normal-font' ? 16 : 14, getCurrentTheme() === 'theme-dark')
)

View File

@ -1,4 +1,5 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",

View File

@ -1,3 +1,208 @@
/**
* @public
*/
export interface RGBColor {
r: number
g: number
b: number
}
/**
* @public
*/
export interface ColorDefinition {
name: string
color: string
icon?: string
title?: string
number?: string
background?: string
}
const define = (
name: string,
color: string,
icon: string,
title: string,
number: string,
background: string,
percents: number[]
): ColorDefinition => {
return {
name,
color: defineAlpha(color),
icon: defineAlpha(icon),
title: defineAlpha(title),
number: defineAlpha(number, percents[0]),
background:
percents.length > 2
? `linear-gradient(90deg, ${defineAlpha(color, percents[1])}, ${defineAlpha(color, percents[2])})`
: defineAlpha(color, percents[1])
}
}
const defineAvatarColor = (name: string, h: number, s: number, l: number, gradient: number[]): ColorDefinition => {
const background = rgbToHex(hslToRgb(h / 360, s / 100, l / 100))
return {
name,
color: background,
icon: undefined,
title: undefined,
number: undefined,
background:
gradient.length === 1
? defineAlpha(background)
: `linear-gradient(90deg, ${gradient.map((it) => defineAlpha(background, it)).join(',')})`
}
}
/**
* @public
*/
export enum PaletteColorIndexes {
Firework,
Watermelon,
Pink,
Fuschia,
Lavander,
Mauve,
Heather,
Orchid,
Blueberry,
Arctic,
Sky,
Cerulean,
Waterway,
Ocean,
Turquoise,
Houseplant,
Crocodile,
Grass,
Sunshine,
Orange,
Pumpkin,
Cloud,
Coin,
Porpoise
}
/**
* @public
*/
export const whitePalette = Object.freeze<ColorDefinition[]>([
define('Firework', 'D15045', 'D15045', 'C03B2F', 'C03B2F', 'C03B2F', [60, 20]),
define('Watermelon', 'DB877D', 'DB877D', 'D2685B', 'D2685B', 'D2685B', [60, 20]),
define('Pink', 'EF86AA', 'EF86AA', 'E9588A', 'E9588A', 'E9588A', [60, 20]),
define('Fuschia', 'EB5181', 'EB5181', 'E62360', 'E62360', 'E62360', [60, 20]),
define('Lavander', 'DC85F5', 'DC85F5', 'CE55F1', 'CE55F1', 'CE55F1', [60, 20]),
define('Mauve', '925CB1', '925CB1', '784794', '784794', '784794', [60, 20]),
define('Heather', '7B86C6', '7B86C6', '5866B7', '5866B7', '5866B7', [60, 20]),
define('Orchid', '8458E3 ', '8458E3', '6A3ACF', '6A3ACF', '6A3ACF', [60, 20]),
define('Blueberry', '6260C2', '6260C2', '4542AD', '4542AD', '4542AD', [60, 20]),
define('Arctic', '8BB0F9', '8BB0F9', '5A8FF6', '5A8FF6', '5A8FF6', [60, 20]),
define('Sky', '4CA6EE', '4CA6EE', '1F90EA', '1F90EA', '1F90EA', [60, 20]),
define('Cerulean', '5195D7', '5195D7', '2E7CC7', '2E7CC7', '2E7CC7', [60, 20]),
define('Waterway', '1467B3', '1467B3', '0F4C85', '0F4C85', '0F4C85', [60, 20]),
define('Ocean', '167B82', '167B82', '0F5357', '0F5357', '0F5357', [60, 20]),
define('Turquoise', '58B99D', '58B99D', '429E84', '429E84', '429E84', [60, 20]),
define('Houseplant', '46A44F', '46A44F', '37813E', '37813E', '37813E', [60, 20]),
define('Crocodile', '709A3F', '709A3F', '577731', '577731', '577731', [60, 20]),
define('Grass', '83AF12', '83AF12', '719C40', '60810E', '60810E', [60, 20]),
define('Sunshine', 'D29840', 'D29840', 'C1811F', 'C1811F', 'C1811F', [60, 20]),
define('Orange', 'D27540', 'D27540', 'B65D2B', 'B65D2B', 'B65D2B', [60, 20]),
define('Pumpkin', 'BF5C24', 'BF5C24', '96481C', '96481C', '96481C', [60, 20]),
define('Cloud', 'A1A1A1', 'A1A1A1', '878787', '878787', '878787', [60, 20]),
define('Coin', '939395', '939395', '79797C', '79797C', '79797C', [60, 20]),
define('Porpoise', '758595', '758595', '5D6B79', '5D6B79', '5D6B79', [60, 20])
])
/**
* @public
*/
export const blackPalette = Object.freeze<ColorDefinition[]>([
define('Firework', 'D15045', 'D15045', 'FFFFFF', 'FFFFFF', 'C03B2F', [60, 15, 0]),
define('Watermelon', 'DB877D', 'DB877D', 'FFFFFF', 'FFFFFF', 'D2685B', [60, 15, 0]),
define('Pink', 'EF86AA', 'EF86AA', 'FFFFFF', 'FFFFFF', 'E9588A', [60, 15, 0]),
define('Fuschia', 'EB5181', 'EB5181', 'FFFFFF', 'FFFFFF', 'E62360', [60, 15, 0]),
define('Lavander', 'DC85F5', 'DC85F5', 'FFFFFF', 'FFFFFF', 'CE55F1', [60, 15, 0]),
define('Mauve', '925CB1', '925CB1', 'FFFFFF', 'FFFFFF', '784794', [60, 15, 0]),
define('Heather', '7B86C6', '7B86C6', 'FFFFFF', 'FFFFFF', '5866B7', [60, 15, 0]),
define('Orchid', '8862D9', '8862D9', 'FFFFFF', 'FFFFFF', '6A3ACF', [60, 15, 0]),
define('Blueberry', '6260C2', '6260C2', 'FFFFFF', 'FFFFFF', '4542AD', [60, 15, 0]),
define('Arctic', '8BB0F9', '8BB0F9', 'FFFFFF', 'FFFFFF', '5A8FF6', [60, 15, 0]),
define('Sky', '4CA6EE', '4CA6EE', 'FFFFFF', 'FFFFFF', '1F90EA', [60, 15, 0]),
define('Cerulean', '5195D7', '5195D7', 'FFFFFF', 'FFFFFF', '2E7CC7', [60, 15, 0]),
define('Waterway', '1467B3', '1467B3', 'FFFFFF', 'FFFFFF', '0F4C85', [60, 15, 0]),
define('Ocean', '167B82', '167B82', 'FFFFFF', 'FFFFFF', '0F5357', [60, 15, 0]),
define('Turquoise', '58B99D', '58B99D', 'FFFFFF', 'FFFFFF', '429E84', [60, 15, 0]),
define('Houseplant', '46A44F', '46A44F', 'FFFFFF', 'FFFFFF', '37813E', [60, 15, 0]),
define('Crocodile', '709A3F', '709A3F', 'FFFFFF', 'FFFFFF', '577731', [60, 15, 0]),
define('Grass', '83AF12', '83AF12', 'FFFFFF', 'FFFFFF', '83AF12', [60, 15, 0]),
define('Sunshine', 'D29840', 'D29840', 'FFFFFF', 'FFFFFF', 'B67E2B', [60, 15, 0]),
define('Orange', 'D27540', 'D27540', 'FFFFFF', 'FFFFFF', 'B65D2B', [60, 15, 0]),
define('Pumpkin', 'BF5C24', 'BF5C24', 'FFFFFF', 'FFFFFF', '96481C', [60, 15, 0]),
define('Cloud', 'A1A1A1', 'A1A1A1', 'FFFFFF', 'FFFFFF', '878787', [60, 15, 0]),
define('Coin', '939395', '939395', 'FFFFFF', 'FFFFFF', '79797C', [60, 15, 0]),
define('Porpoise', '758595', '758595', 'FFFFFF', 'FFFFFF', '5D6B79', [60, 15, 0])
])
export const avatarWhiteColors = Object.freeze<ColorDefinition[]>([
defineAvatarColor('Unassigned', 0, 0, 91, [20]),
defineAvatarColor('Magic', 235, 14, 89, [20]),
defineAvatarColor('Waterlily', 222, 16, 87, [20]),
defineAvatarColor('Light', 216, 16, 87, [20]),
defineAvatarColor('Aqua', 200, 8, 85, [20]),
defineAvatarColor('Turtle', 192, 14, 85, [20]),
defineAvatarColor('Ocean', 186, 13, 85, [20]),
defineAvatarColor('Heather', 153, 11, 86, [20]),
defineAvatarColor('Juice', 108, 10, 90, [20]),
defineAvatarColor('Lime', 70, 9, 87, [20]),
defineAvatarColor('Warmth', 45, 13, 88, [20]),
defineAvatarColor('Desert', 30, 14, 89, [20]),
defineAvatarColor('Sand', 25, 14, 89, [20]),
defineAvatarColor('Rust', 23, 12, 87, [20]),
defineAvatarColor('Magnolia', 334, 11, 88, [20]),
defineAvatarColor('Blossom', 300, 14, 89, [20]),
defineAvatarColor('Unicorn', 274, 11, 88, [20]),
defineAvatarColor('Violet', 252, 16, 87, [20]),
defineAvatarColor('Happy', 232, 16, 87, [20]),
defineAvatarColor('Blueish', 222, 13, 85, [20]),
defineAvatarColor('Baby blue', 210, 12, 87, [20]),
defineAvatarColor('Grey 3', 213, 9, 81, [20]),
defineAvatarColor('Grey 2', 210, 10, 84, [20]),
defineAvatarColor('Grey 1', 210, 11, 89, [20])
])
export const avatarBlackColors = Object.freeze<ColorDefinition[]>([
defineAvatarColor('Unassigned', 0, 0, 91, [20, 0, 0]),
defineAvatarColor('Magic', 235, 14 + 50, 89 - 20, [20, 2, 0]),
defineAvatarColor('Waterlily', 222, 16 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Light', 216, 16 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Aqua', 200, 8 + 50, 85 - 20, [20, 2, 0]),
defineAvatarColor('Turtle', 192, 14 + 50, 85 - 20, [20, 2, 0]),
defineAvatarColor('Ocean', 186, 13 + 50, 85 - 20, [20, 2, 0]),
defineAvatarColor('Heather', 153, 11 + 50, 86 - 20, [20, 2, 0]),
defineAvatarColor('Juice', 108, 10 + 50, 90 - 20, [20, 2, 0]),
defineAvatarColor('Lime', 70, 9 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Warmth', 45, 13 + 50, 88 - 20, [20, 2, 0]),
defineAvatarColor('Desert', 30, 14 + 50, 89 - 20, [20, 2, 0]),
defineAvatarColor('Sand', 25, 14 + 50, 89 - 20, [20, 2, 0]),
defineAvatarColor('Rust', 23, 12 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Magnolia', 334, 11 + 50, 88 - 20, [20, 2, 0]),
defineAvatarColor('Blossom', 300, 14 + 50, 89 - 20, [20, 2, 0]),
defineAvatarColor('Unicorn', 274, 11 + 50, 88 - 20, [20, 2, 0]),
defineAvatarColor('Violet', 252, 16 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Happy', 232, 16 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Blueish', 222, 13 + 50, 85 - 20, [20, 2, 0]),
defineAvatarColor('Baby blue', 210, 12 + 50, 87 - 20, [20, 2, 0]),
defineAvatarColor('Grey 3', 213, 9, 81, [20, 2, 0]),
defineAvatarColor('Grey 2', 210, 10, 84, [20, 2, 0]),
defineAvatarColor('Grey 1', 210, 11, 89, [20, 2, 0])
])
export function defaultBackground (dark: boolean): string {
return dark ? 'linear-gradient(90deg, #262634, #26263400)' : '#FFFFFF'
}
export const FeijoaColor = '#A5D179'
export const DeYorkColor = '#77C07B'
export const FernColor = '#60B96E' // green
@ -20,45 +225,55 @@ export const CrayolaColor = '#F2C94C'
export const SlateBlueColor = '#5E6AD2'
export const CadetGreyColor = '#95A2B3'
const blackColors = Object.freeze([
FeijoaColor,
DeYorkColor,
FernColor,
PuertoRicoColor,
MediumTurquoiseColor,
SummerSkyColor,
MalibuColor,
SeagullColor,
EastSideColor,
MoodyBlueColor,
ChetwodeBlueColor,
SalmonColor,
SilverSandColor,
PlatinumColor,
CrayolaColor,
SlateBlueColor,
CadetGreyColor
])
/**
* @public
*/
export function getPlatformColor (hash: number): string {
return blackColors[Math.abs(hash) % blackColors.length]
export function getPlatformColor (hash: number, blackTheme: boolean): string {
const palette = blackTheme ? blackPalette : whitePalette
return (palette[Math.abs(hash) % palette.length] ?? palette[0]).color
}
/**
* @public
*/
export function getPlatformColorForText (text: string): string {
return getPlatformColor(hashCode(text))
export function getPlatformColorDef (hash: number, blackTheme: boolean): ColorDefinition {
const palette = blackTheme ? blackPalette : whitePalette
return palette[Math.abs(hash) % palette.length] ?? palette[0]
}
/**
* @public
*/
export function getPlatformColors (): readonly string[] {
return blackColors
export function getPlatformAvatarColorDef (hash: number, blackTheme: boolean): ColorDefinition {
const palette = blackTheme ? avatarBlackColors : avatarWhiteColors
return palette[Math.abs(hash) % palette.length] ?? palette[0]
}
/**
* @public
*/
export function getPlatformAvatarColorForTextDef (text: string, blackTheme: boolean): ColorDefinition {
return getPlatformAvatarColorDef(hashCode(text), blackTheme)
}
/**
* @public
*/
export function getPlatformColorForText (text: string, blackTheme: boolean): string {
return getPlatformColor(hashCode(text), blackTheme)
}
/**
* @public
*/
export function getPlatformColorForTextDef (text: string, blackTheme: boolean): ColorDefinition {
return getPlatformColorDef(hashCode(text), blackTheme)
}
/**
* @public
*/
export function getPlatformColors (blackTheme: boolean): readonly ColorDefinition[] {
return blackTheme ? blackPalette : whitePalette
}
function hashCode (str: string): number {
@ -85,7 +300,7 @@ export function hexColorToNumber (hexColor: string): number {
/**
* @public
*/
export function hexToRgb (color: string): { r: number, g: number, b: number } {
export function hexToRgb (color: string): RGBColor {
if (!color.startsWith('#')) {
return { r: 128, g: 128, b: 128 }
}
@ -96,6 +311,7 @@ export function hexToRgb (color: string): { r: number, g: number, b: number } {
.map((c) => c + c)
.join('')
}
color = color.toLowerCase()
return {
r: parseInt(color.slice(0, 2), 16),
g: parseInt(color.slice(2, 4), 16),
@ -103,6 +319,37 @@ export function hexToRgb (color: string): { r: number, g: number, b: number } {
}
}
/**
* @public
*/
export function hexHSLToRgb (color: string, percent = 100): RGBColor {
const h = parseInt(color.slice(0, 2), 16)
const s = parseInt(color.slice(2, 4), 16)
const l = parseInt(color.slice(4, 6), 16)
return hslToRgb(h, s, (l / 100) * percent)
}
function addZero (d: string): string {
if (d.length < 2) {
return '0' + d
}
return d
}
/**
* @public
*/
export function defineAlpha (color: string, percent = 100): string {
let rgb = color
if (!rgb.startsWith('#')) {
rgb = '#' + rgb
}
if (percent === 100) {
return rgb
}
return rgb + addZero(Math.round((percent / 100) * 255).toString(16))
}
/**
* @public
*/
@ -131,7 +378,7 @@ export function numberToRGB (color: number, alpha?: number): string {
/**
* @public
*/
export function hslToRgb (h: number, s: number, l: number): { r: number, g: number, b: number } {
export function hslToRgb (h: number, s: number, l: number): RGBColor {
let r, g, b
if (s === 0) {
@ -159,13 +406,7 @@ export function hslToRgb (h: number, s: number, l: number): { r: number, g: numb
/**
* @public
*/
export function rgbToHex (color: { r: number, g: number, b: number }): string {
function addZero (d: string): string {
if (d.length < 2) {
return '0' + d
}
return d
}
export function rgbToHex (color: RGBColor): string {
return (
'#' +
addZero((Math.round(color.r) % 255).toString(16)) +
@ -174,7 +415,7 @@ export function rgbToHex (color: { r: number, g: number, b: number }): string {
)
}
export async function svgToColor (img: SVGSVGElement): Promise<{ r: number, g: number, b: number } | undefined> {
export async function svgToColor (img: SVGSVGElement): Promise<RGBColor | undefined> {
const outerHTML = img.outerHTML
const blob = new Blob([outerHTML], { type: 'image/svg+xml;charset=utf-8' })
const blobURL = URL.createObjectURL(blob)
@ -191,7 +432,7 @@ export async function svgToColor (img: SVGSVGElement): Promise<{ r: number, g: n
/**
* @public
*/
export function imageToColor (image: HTMLImageElement): { r: number, g: number, b: number } | undefined {
export function imageToColor (image: HTMLImageElement): RGBColor | undefined {
const canvas = document.createElement('canvas')
const height = (canvas.height = image.naturalHeight ?? image.offsetHeight ?? image.height)

View File

@ -15,11 +15,11 @@
<script lang="ts">
import type { IntlString } from '@hcengineering/platform'
import { createEventDispatcher } from 'svelte'
import { deviceOptionsStore, resizeObserver } from '..'
import { getPlatformColor } from '../colors'
import ListView from './ListView.svelte'
import Icon from './Icon.svelte'
import { deviceOptionsStore, resizeObserver, themeStore } from '..'
import { getPlatformColorDef } from '../colors'
import EditWithIcon from './EditWithIcon.svelte'
import Icon from './Icon.svelte'
import ListView from './ListView.svelte'
import IconCheck from './icons/Check.svelte'
import IconSearch from './icons/Search.svelte'
@ -93,14 +93,15 @@
>
<svelte:fragment slot="item" let:item>
{@const itemValue = objects[item]}
{@const color = getPlatformColorDef(itemValue.color, $themeStore.dark)}
<button
class="menu-item withList w-full"
on:click={() => {
dispatch('close', itemValue)
}}
>
<div class="color" style="background-color: {getPlatformColor(itemValue.color)}" />
<span class="label">{itemValue.label}</span>
<div class="color" style:background-color={color.background}>{color.name}</div>
<span class="label" style:color={color.title}>{itemValue.label}</span>
<div class="check">
{#if itemValue.id === selected}
<Icon icon={IconCheck} size={'small'} />

View File

@ -13,6 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { themeStore } from '@hcengineering/theme'
import { getPlatformColor } from '../colors'
export let values: Progress[]
export let min: number = 0
@ -56,10 +57,10 @@
class="bar fs-title"
class:first={i === 0}
class:last={i === filtred.length - 1}
style="background-color: {getPlatformColor(item.color)}; left: {getLeft(width, i)}%; width: calc(100% * {proc !==
0
? getWidth(filtred, i)
: 0} / 100);"
style="background-color: {getPlatformColor(item.color, $themeStore.dark)}; left: {getLeft(
width,
i
)}%; width: calc(100% * {proc !== 0 ? getWidth(filtred, i) : 0} / 100);"
>
{item.value}
</div>

View File

@ -13,6 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { themeStore } from '@hcengineering/theme'
import { getPlatformColor } from '../colors'
export let value: number
export let min: number = 0
@ -33,10 +34,11 @@
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="container" on:click={click} class:cursor-pointer={editable}>
<div
class="bar"
style="background-color: {getPlatformColor(color)}; width: calc(100% * {proc !== 0
style="background-color: {getPlatformColor(color, $themeStore.dark)}; width: calc(100% * {proc !== 0
? Math.round((value - min) / proc)
: 0} / 100);"
/>

View File

@ -13,6 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { themeStore } from '@hcengineering/theme'
import { getPlatformColor } from '../colors'
import { IconSize } from '../types'
@ -48,7 +49,7 @@
cy={8}
r={7}
class="progress-circle"
style:stroke={primary ? 'var(--primary-bg-color)' : getPlatformColor(color)}
style:stroke={primary ? 'var(--primary-bg-color)' : getPlatformColor(color, $themeStore.dark)}
style:opacity={dashOffset === 0 ? 0 : 1}
style:transform={'rotate(-82deg)'}
style:stroke-dasharray={lenghtC}

View File

@ -15,7 +15,7 @@
-->
<script lang="ts">
import { getPlatformColor } from '../../colors'
import { Component, WizardModel, WizardItemPosition } from '../..'
import { Component, WizardModel, WizardItemPosition, themeStore } from '../..'
import ScrollerBar from '../ScrollerBar.svelte'
import WizardStep from './WizardStep.svelte'
@ -43,8 +43,8 @@
label={item.label}
position={getPosition(i)}
positionState={selected === i ? 'current' : i < selected ? 'prev' : 'next'}
prevColor={getPlatformColor(COLOR)}
currentColor={getPlatformColor(COLOR)}
prevColor={getPlatformColor(COLOR, $themeStore.dark)}
currentColor={getPlatformColor(COLOR, $themeStore.dark)}
nextColor="var(--trans-content-10)"
/>
{/each}

View File

@ -37,6 +37,8 @@ export type {
TabItem,
DeviceOptions
} from './types'
export { themeStore } from '@hcengineering/theme'
// export { applicationShortcutKey } from './utils'
export { getCurrentLocation, locationToUrl, navigate, location } from './location'

View File

@ -326,8 +326,3 @@ export interface DialogStep {
readonly component: AnyComponent | AnySvelteComponent
props?: Record<string, any>
}
export interface AccentColor {
textColor: string
backgroundColor: string
}

View File

@ -1,4 +1,5 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",

View File

@ -3,10 +3,11 @@
import {
Button,
getEventPositionElement,
getPlatformColor,
getPlatformColorForText,
getPlatformColorDef,
getPlatformColorForTextDef,
IconMoreV,
showPopup
showPopup,
themeStore
} from '@hcengineering/ui'
import { ContextMenu } from '@hcengineering/view-resources'
export let state: State
@ -21,7 +22,9 @@
<div class="flex-col h-16">
<div
class="h-2 border-radius-1"
style="background-color: {state.color ? getPlatformColor(state.color) : getPlatformColorForText(state.name)}"
style="background-color: {state.color
? getPlatformColorDef(state.color, $themeStore.dark).background
: getPlatformColorForTextDef(state.name, $themeStore.dark).background}"
/>
<div class="flex-between h-full font-medium pr-2 pl-4">
<span class="lines-limit-2">{state.name}</span>

View File

@ -15,7 +15,7 @@
<script lang="ts">
import { Event } from '@hcengineering/calendar'
import { Class, Doc, DocumentQuery, FindOptions, Ref } from '@hcengineering/core'
import { addZero, Label, tooltip, getPlatformColorForText } from '@hcengineering/ui'
import { Label, addZero, getPlatformColorForTextDef, themeStore, tooltip } from '@hcengineering/ui'
import { BuildModelKey } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import calendar from '../plugin'
@ -51,6 +51,7 @@
{#if size === 'huge'}
<div class="flex-grow h-full w-full p-1 flex-col" use:tooltip={tip}>
<div class="flex flex-reverse fs-title">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="date flex-center"
class:today
@ -63,6 +64,7 @@
{date.getDate()}
</div>
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="flex-col flex-grow mt-1"
on:click={() => {
@ -72,7 +74,7 @@
{#each events.slice(0, eventCount) as e}
<div
class="overflow-label mt-1 py-1 flex flex-between event"
style="background-color: {getPlatformColorForText(e._class)};"
style="background-color: {getPlatformColorForTextDef(e._class, $themeStore.dark).background};"
>
{e.title}
<div>

View File

@ -15,7 +15,7 @@
<script lang="ts">
import { Event } from '@hcengineering/calendar'
import { Ref } from '@hcengineering/core'
import { areDatesEqual, getPlatformColorForText, showPanel, tooltip } from '@hcengineering/ui'
import { areDatesEqual, getPlatformColorForTextDef, showPanel, themeStore, tooltip } from '@hcengineering/ui'
import view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import EventPresenter from './EventPresenter.svelte'
@ -77,7 +77,7 @@
function getStyle (events: Event[], i: number, date: Date): string {
const e = events[i]
let res = `background-color: ${getPlatformColorForText(e._class)};`
let res = `background-color: ${getPlatformColorForTextDef(e._class, $themeStore.dark).background};`
res += `left: ${getShift(events, i)}rem;`
if (startCell(e.date, date)) {
res += ` top: ${getTop(e)};`
@ -89,6 +89,7 @@
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="cursor-pointer w-full h-full"
on:click={() => {

View File

@ -31,8 +31,7 @@
import { Client, Ref } from '@hcengineering/core'
import { Asset, getResource } from '@hcengineering/platform'
import { getBlobURL, getClient } from '@hcengineering/presentation'
import { AnySvelteComponent, Icon, IconSize, hexToRgb, imageToColor } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { AnySvelteComponent, Icon, IconSize } from '@hcengineering/ui'
import { getAvatarProviderId } from '../utils'
import AvatarIcon from './icons/Avatar.svelte'
@ -44,8 +43,6 @@
let url: string | undefined
let avatarProvider: AvatarProvider | undefined
const dispatch = createEventDispatcher()
async function update (size: IconSize, avatar?: string | null, direct?: Blob) {
if (direct !== undefined) {
getBlobURL(direct).then((blobURL) => {
@ -71,64 +68,15 @@
}
$: update(size, avatar, direct)
let style = ''
async function updateStyle (avatar?: string | null, avatarProvider?: AvatarProvider) {
if (!avatar || avatarProvider?.type !== AvatarType.COLOR) {
style = ''
} else {
const uri = avatar.split('://')[1]
const color: string | undefined = (await getResource(avatarProvider.getUrl))(uri, size)
if (color != null) {
style = `background-color: ${color}`
accentColor = hexToRgb(color)
dispatch('accent-color', accentColor)
}
}
}
$: updateStyle(avatar, avatarProvider)
let imageElement: HTMLImageElement | undefined = undefined
let accentColor: any | undefined
</script>
<div class="ava-{size} flex-center avatar-container" class:no-img={!url} {style}>
<div class="ava-{size} flex-center avatar-container" class:no-img={!url}>
{#if url}
{#if size === 'large' || size === 'x-large'}
<img
class="ava-{size} ava-blur"
src={url}
alt={''}
bind:this={imageElement}
on:load={() => {
if (imageElement !== undefined) {
try {
accentColor = imageToColor(imageElement)
dispatch('accent-color', accentColor)
} catch (err) {
// Ignore
}
}
}}
/>
<img class="ava-{size} ava-blur" src={url} alt={''} bind:this={imageElement} />
{/if}
<img
class="ava-{size} ava-mask"
src={url}
alt={''}
bind:this={imageElement}
on:load={() => {
if (imageElement !== undefined) {
try {
accentColor = imageToColor(imageElement)
dispatch('accent-color', accentColor)
} catch (err) {
// ignore
}
}
}}
/>
<img class="ava-{size} ava-mask" src={url} alt={''} bind:this={imageElement} />
{:else}
<Icon icon={icon ?? AvatarIcon} size={size === 'card' ? 'x-small' : size} />
{/if}

View File

@ -15,9 +15,17 @@
<script lang="ts">
import { Employee, getName, Person } from '@hcengineering/contact'
import { IntlString } from '@hcengineering/platform'
import { Label, LabelAndProps, tooltip } from '@hcengineering/ui'
import type { IconSize } from '@hcengineering/ui'
import {
getPlatformAvatarColorDef,
getPlatformAvatarColorForTextDef,
IconSize,
Label,
LabelAndProps,
themeStore,
tooltip
} from '@hcengineering/ui'
import { DocNavLink } from '@hcengineering/view-resources'
import { createEventDispatcher, onMount } from 'svelte'
import Avatar from './Avatar.svelte'
export let value: Person | Employee | undefined | null
@ -25,6 +33,7 @@
export let disabled = false
export let shouldShowAvatar: boolean = true
export let shouldShowName = true
export let element: HTMLElement | undefined = undefined
export let shouldShowPlaceholder = false
export let defaultName: IntlString | undefined = undefined
export let statusLabel: IntlString | undefined = undefined
@ -32,7 +41,6 @@
export let onEdit: ((event: MouseEvent) => void) | undefined = undefined
export let showTooltip: LabelAndProps | undefined = undefined
export let enlargedText = false
export let element: HTMLElement | undefined = undefined
export let colorInherit: boolean = false
export let accent: boolean = false
@ -41,6 +49,18 @@
onEdit?.(evt)
}
}
const dispatch = createEventDispatcher()
$: accentColor =
value?.name !== undefined
? getPlatformAvatarColorForTextDef(value?.name ?? '', $themeStore.dark)
: getPlatformAvatarColorDef(0, $themeStore.dark)
$: dispatch('accent-color', accentColor)
onMount(() => {
dispatch('accent-color', accentColor)
})
</script>
{#if value}
@ -57,7 +77,7 @@
class:mr-2={shouldShowName && !enlargedText}
class:mr-3={shouldShowName && enlargedText}
>
<Avatar size={avatarSize} avatar={value.avatar} on:accent-color />
<Avatar size={avatarSize} avatar={value.avatar} />
</span>
{/if}
{#if shouldShowName}

View File

@ -15,7 +15,7 @@
<script lang="ts">
import hr, { Department, Request, RequestType, Staff } from '@hcengineering/hr'
import { getClient } from '@hcengineering/presentation'
import { closeTooltip, getPlatformColor, Icon, isWeekend, showPopup } from '@hcengineering/ui'
import { closeTooltip, getPlatformColor, Icon, isWeekend, showPopup, themeStore } from '@hcengineering/ui'
import { ContextMenu } from '@hcengineering/view-resources'
import { getHolidayDatesForEmployee, isHoliday } from '../utils'
import { Ref } from '@hcengineering/core'
@ -40,8 +40,8 @@
let res = `background-color: ${
(isWeekend(date) || isHoliday(getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays), date)) &&
noWeekendHolidayType.includes(type._id)
? getPlatformColor(16)
: getPlatformColor(type.color)
? getPlatformColor(16, $themeStore.dark)
: getPlatformColor(type.color, $themeStore.dark)
};`
if (Math.abs(type.value % 1) === 0.5) {
res += ' height: 50%;'

View File

@ -15,6 +15,9 @@
<script lang="ts">
import activity, { TxViewlet } from '@hcengineering/activity'
import { activityKey, ActivityKey } from '@hcengineering/activity-resources'
import chunter from '@hcengineering/chunter'
import { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
import { Avatar, employeeAccountByIdStore, employeeByIdStore } from '@hcengineering/contact-resources'
import core, { Account, Doc, getCurrentAccount, Ref } from '@hcengineering/core'
import notification, { DocUpdates } from '@hcengineering/notification'
import { ActionContext, createQuery, getClient } from '@hcengineering/presentation'
@ -22,9 +25,6 @@
import { ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import NotificationView from './NotificationView.svelte'
import { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
import { Avatar, employeeAccountByIdStore, employeeByIdStore } from '@hcengineering/contact-resources'
import chunter from '@hcengineering/chunter'
export let accountId: Ref<Account>
const dispatch = createEventDispatcher()

View File

@ -13,19 +13,19 @@
// limitations under the License.
-->
<script lang="ts">
import { AnyComponent, Component, Tabs } from '@hcengineering/ui'
import Activity from './Activity.svelte'
import People from './People.svelte'
import notification from '../plugin'
import { Class, Doc, Ref } from '@hcengineering/core'
import { NotificationClientImpl } from '../utils'
import { getClient } from '@hcengineering/presentation'
import { DocUpdates } from '@hcengineering/notification'
import view from '@hcengineering/view'
import Filter from './Filter.svelte'
import { EmployeeAccount } from '@hcengineering/contact'
import EmployeeInbox from './EmployeeInbox.svelte'
import chunter from '@hcengineering/chunter'
import { EmployeeAccount } from '@hcengineering/contact'
import { Class, Doc, Ref } from '@hcengineering/core'
import { DocUpdates } from '@hcengineering/notification'
import { getClient } from '@hcengineering/presentation'
import { AnyComponent, Component, Tabs } from '@hcengineering/ui'
import view from '@hcengineering/view'
import notification from '../plugin'
import { NotificationClientImpl } from '../utils'
import Activity from './Activity.svelte'
import EmployeeInbox from './EmployeeInbox.svelte'
import Filter from './Filter.svelte'
import People from './People.svelte'
export let visibileNav: boolean
let filter: 'all' | 'read' | 'unread' = 'all'

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import { Doc } from '@hcengineering/core'
import { getPlatformColor } from '@hcengineering/ui'
import { getPlatformColor, themeStore } from '@hcengineering/ui'
import { NotificationClientImpl } from '../utils'
export let value: Doc
@ -28,7 +28,7 @@
</script>
{#if hasNotification}
<div class="notify-{kind}-kind" style="color: {getPlatformColor(11)}" />
<div class="notify-{kind}-kind" style="color: {getPlatformColor(11, $themeStore.dark)}" />
{/if}
<style lang="scss">

View File

@ -23,35 +23,36 @@
Class,
Client,
Doc,
fillDefaults,
FindOptions,
generateId,
Markup,
Ref,
SortingOrder,
Space
Space,
fillDefaults,
generateId
} from '@hcengineering/core'
import { getResource, OK, Resource, Severity, Status } from '@hcengineering/platform'
import { OK, Resource, Severity, Status, getResource } from '@hcengineering/platform'
import presentation, {
Card,
createQuery,
getClient,
InlineAttributeBar,
SpaceSelect
SpaceSelect,
createQuery,
getClient
} from '@hcengineering/presentation'
import type { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
import task, { calcRank, State } from '@hcengineering/task'
import task, { State, calcRank } from '@hcengineering/task'
import ui, {
Button,
ColorPopup,
FocusHandler,
Label,
Status as StatusControl,
createFocusManager,
deviceOptionsStore as deviceInfo,
FocusHandler,
getColorNumberByText,
getPlatformColor,
Label,
getPlatformColorDef,
showPopup,
Status as StatusControl
themeStore
} from '@hcengineering/ui'
import view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
@ -390,9 +391,10 @@
{#if selectedState}
<div
class="color"
style="background-color: {getPlatformColor(
selectedState.color ?? getColorNumberByText(selectedState.name)
)}"
style="background-color: {getPlatformColorDef(
selectedState.color ?? getColorNumberByText(selectedState.name),
$themeStore.dark
).background}"
/>
<span class="label overflow-label">{selectedState.name}</span>
{:else}

View File

@ -22,7 +22,6 @@
import VacancyCard from './VacancyCard.svelte'
import ExpandRightDouble from './icons/ExpandRightDouble.svelte'
import { getName } from '@hcengineering/contact'
import { Ref } from '@hcengineering/core'
import recruit from '../plugin'
import Reviews from './review/Reviews.svelte'
@ -36,7 +35,7 @@
dispatch('open', {
ignoreKeys: ['comments', 'number'],
allowedCollections: ['labels'],
title: `APP-${object.number} ${candidate !== undefined ? '- ' + getName(candidate) : ''}`
title: `APP-${object.number}`
})
}

View File

@ -17,21 +17,22 @@
import ExpandRightDouble from '@hcengineering/contact-resources/src/components/icons/ExpandRightDouble.svelte'
import { FindOptions, SortingOrder } from '@hcengineering/core'
import { OK, Severity, Status } from '@hcengineering/platform'
import presentation, { Card, createQuery, getClient, SpaceSelect } from '@hcengineering/presentation'
import presentation, { Card, SpaceSelect, createQuery, getClient } from '@hcengineering/presentation'
import type { Applicant, Vacancy } from '@hcengineering/recruit'
import task, { State } from '@hcengineering/task'
import ui, {
Button,
ColorPopup,
createFocusManager,
deviceOptionsStore as deviceInfo,
FocusHandler,
getColorNumberByText,
getPlatformColor,
Label,
ListView,
Status as StatusControl,
createFocusManager,
deviceOptionsStore as deviceInfo,
getColorNumberByText,
getPlatformColorDef,
showPopup,
Status as StatusControl
themeStore
} from '@hcengineering/ui'
import { moveToSpace } from '@hcengineering/view-resources/src/utils'
import { createEventDispatcher } from 'svelte'
@ -197,9 +198,10 @@
{#if selectedState}
<div
class="color"
style="background-color: {getPlatformColor(
selectedState.color ?? getColorNumberByText(selectedState.name)
)}"
style="background-color: {getPlatformColorDef(
selectedState.color ?? getColorNumberByText(selectedState.name),
$themeStore.dark
).background}"
/>
<span class="label overflow-label">{selectedState.name}</span>
{:else}

View File

@ -16,7 +16,7 @@
import { Class, Doc, Ref, SortingOrder } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import { TagCategory, TagElement } from '@hcengineering/tags'
import { Button, getPlatformColorForText, showPopup } from '@hcengineering/ui'
import { Button, getPlatformColorForTextDef, showPopup, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { getTagStyle } from '../utils'
@ -169,12 +169,13 @@
<div class="flex-row-center caption-color states">
<div class="antiStatesBar mask-none {stepStyle}">
{#each visibleCategories as item, i}
{@const color = getPlatformColorForTextDef(item.label, $themeStore.dark)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
bind:this={visibleCategoriesRef[i]}
class="categoryElement flex-center"
id={item.label}
style={getTagStyle(getPlatformColorForText(item.label), item._id === category)}
style={getTagStyle(color, item._id === category)}
on:click={(evt) => {
if (mode === 'category') {
selectItem(item)

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import { TagElement } from '@hcengineering/tags'
import { getPlatformColor } from '@hcengineering/ui'
import { getPlatformColorDef, themeStore } from '@hcengineering/ui'
export let values: TagElement[]
export let limit: number = 4
@ -22,11 +22,12 @@
<div class="container">
{#each values as value, i}
{@const valueColor = getPlatformColorDef(value.color ?? 0, $themeStore.dark)}
{#if i < limit}
<div class="item" class:last={i === limit - 1} class:first={i === 0}>
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<div class="color" style:background-color={valueColor.background} />
{#if i === limit - 1 && values.length <= limit}
<span class="label overflow-label ml-1-5 max-w-40">
<span class="label overflow-label ml-1-5 max-w-40" style:color={valueColor.title}>
{value.title}
</span>
{/if}

View File

@ -23,9 +23,10 @@
EditBox,
eventToHTMLElement,
getColorNumberByText,
getPlatformColor,
getPlatformColorDef,
IconFolder,
showPopup
showPopup,
themeStore
} from '@hcengineering/ui'
import { ColorsPopup } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
@ -90,12 +91,17 @@
dispatch('close')
}
const showColorPopup = (evt: MouseEvent) => {
showPopup(ColorsPopup, { selected: getPlatformColor(color) }, eventToHTMLElement(evt), (col) => {
if (col != null) {
color = col
colorSet = true
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(color, $themeStore.dark).name },
eventToHTMLElement(evt),
(col) => {
if (col != null) {
color = col
colorSet = true
}
}
})
)
}
</script>
@ -113,7 +119,7 @@
<div class="mr-3">
<Button size={'medium'} kind={'link-bordered'} on:click={showColorPopup}>
<svelte:fragment slot="content">
<div class="color pointer-events-none" style={getTagStyle(getPlatformColor(color))} />
<div class="color pointer-events-none" style={getTagStyle(getPlatformColorDef(color, $themeStore.dark))} />
</svelte:fragment>
</Button>
</div>

View File

@ -16,7 +16,14 @@
import core, { Data, DocumentUpdate } from '@hcengineering/core'
import { Card, createQuery, getClient } from '@hcengineering/presentation'
import { TagElement, TagReference } from '@hcengineering/tags'
import { DropdownLabels, EditBox, eventToHTMLElement, getPlatformColor, showPopup } from '@hcengineering/ui'
import {
DropdownLabels,
EditBox,
eventToHTMLElement,
getPlatformColorDef,
showPopup,
themeStore
} from '@hcengineering/ui'
import { DropdownTextItem } from '@hcengineering/ui/src/types'
import { ColorsPopup } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
@ -106,13 +113,18 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="color"
style={getTagStyle(getPlatformColor(data.color))}
style={getTagStyle(getPlatformColorDef(data.color, $themeStore.dark))}
on:click={(evt) => {
showPopup(ColorsPopup, { selected: getPlatformColor(data.color) }, eventToHTMLElement(evt), (col) => {
if (col != null) {
data.color = col
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(data.color, $themeStore.dark).name },
eventToHTMLElement(evt),
(col) => {
if (col != null) {
data.color = col
}
}
})
)
}}
/>
<EditBox placeholder={tags.string.TagName} placeholderParam={{ word: keyTitle }} bind:value={data.title} />

View File

@ -14,13 +14,13 @@
-->
<script lang="ts">
import { TagElement } from '@hcengineering/tags'
import { getPlatformColor } from '@hcengineering/ui'
import { getPlatformColorDef, themeStore } from '@hcengineering/ui'
export let value: TagElement
</script>
<div class="container">
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<div class="color" style:background-color={getPlatformColorDef(value.color ?? 0, $themeStore.dark).background} />
<span class="label overflow-label ml-1-5 max-w-40">
{value.title}
</span>

View File

@ -15,7 +15,15 @@
<script lang="ts">
import { Asset } from '@hcengineering/platform'
import { TagElement, TagReference } from '@hcengineering/tags'
import { ActionIcon, AnySvelteComponent, getPlatformColor, Icon, tooltip } from '@hcengineering/ui'
import {
ActionIcon,
AnySvelteComponent,
Icon,
getPlatformColor,
getPlatformColorDef,
themeStore,
tooltip
} from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { getTagStyle, tagLevel } from '../utils'
@ -37,7 +45,7 @@
{#if inline}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
style={`--tag-color:${getPlatformColor(tag?.color ?? element?.color ?? 0)}`}
style={`--tag-color:${getPlatformColor(tag?.color ?? element?.color ?? 0, $themeStore.dark)}`}
class="tag-item-inline overflow-label max-w-40"
on:click
use:tooltip={{
@ -51,7 +59,7 @@
{:else}
<div
class="tag-item"
style={`${getTagStyle(getPlatformColor(tag?.color ?? element?.color ?? 0), selected)}`}
style={`${getTagStyle(getPlatformColorDef(tag?.color ?? element?.color ?? 0, $themeStore.dark), selected)}`}
on:click
on:keydown
use:tooltip={{

View File

@ -15,7 +15,7 @@
<script lang="ts">
import { AnyAttribute } from '@hcengineering/core'
import type { TagReference } from '@hcengineering/tags'
import { getPlatformColor, Icon, IconClose, resizeObserver } from '@hcengineering/ui'
import { getPlatformColorDef, Icon, IconClose, resizeObserver, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import TagItem from './TagItem.svelte'
@ -27,6 +27,8 @@
export let inline: boolean = false
const dispatch = createEventDispatcher()
$: color = getPlatformColorDef(value.color ?? 0, $themeStore.dark)
</script>
{#if value}
@ -41,8 +43,10 @@
realWidth = element.clientWidth
}}
>
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<span class="label overflow-label ml-1 text-sm caption-color max-w-40">{value.title}</span>
<div class="color" style:background-color={color.background} />
<span class="label overflow-label ml-1 text-sm caption-color max-w-40" style:color={color.title}
>{value.title}</span
>
</button>
{:else if kind === 'list'}
<div
@ -52,8 +56,8 @@
realWidth = element.clientWidth
}}
>
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<span class="label overflow-label ml-1-5 max-w-40">
<div class="color" style:background-color={color.background} />
<span class="label overflow-label ml-1-5 max-w-40" style:color={color.title}>
{value.title}
</span>
{#if isEditable}

View File

@ -18,7 +18,16 @@
import { translate } from '@hcengineering/platform'
import presentation, { createQuery } from '@hcengineering/presentation'
import { TagCategory, TagElement } from '@hcengineering/tags'
import { Button, CheckBox, getPlatformColor, Icon, IconClose, Label, resizeObserver } from '@hcengineering/ui'
import {
Button,
CheckBox,
Icon,
IconClose,
Label,
getPlatformColorDef,
resizeObserver,
themeStore
} from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
import tags from '../plugin'
@ -110,6 +119,7 @@
/>
</div>
<div class="buttons-group small-gap">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="clear-btn"
class:show={search !== ''}
@ -129,6 +139,7 @@
<div class="sticky-wrapper">
<div class="menu-group" style:overflow="visible">
{#each elements.filter((it) => tagElements?.has(it._id)) as element}
{@const color = getPlatformColorDef(element.color, $themeStore.dark)}
<button
class="menu-item"
on:click={() => {
@ -138,11 +149,13 @@
<div class="check pointer-events-none">
<CheckBox checked={isSelected(element, selected)} primary />
</div>
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
{element.title}
{#if (tagElements?.get(element._id)?.count ?? 0) > 0}
({tagElements?.get(element._id)?.count})
{/if}
<div class="tag" style="background-color: {color.background};" />
<span style:color={color.title}>
{element.title}
{#if (tagElements?.get(element._id)?.count ?? 0) > 0}
({tagElements?.get(element._id)?.count})
{/if}
</span>
</button>
{/each}
</div>

View File

@ -18,17 +18,18 @@
import { TagCategory, TagElement } from '@hcengineering/tags'
import {
Button,
EditWithIcon,
Icon,
IconCheck,
IconSearch,
EditWithIcon,
Label,
Loading,
deviceOptionsStore,
getEventPopupPositionElement,
getPlatformColor,
getPlatformColorDef,
resizeObserver,
showPopup
showPopup,
themeStore
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
@ -190,14 +191,15 @@
</button>
<div class="menu-group">
{#each sortFilterValues(values, isSelected) as element}
{@const color = getPlatformColorDef(element.color, $themeStore.dark)}
<button
class="menu-item no-focus flex-row-center"
on:click={() => {
handleFilterToggle(element)
}}
>
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
<span class="overflow-label label flex-grow">{element.title}</span>
<div class="tag" style:background-color={color.background} />
<span class="overflow-label label flex-grow" style:color={color.title}>{element.title}</span>
<div class="check pointer-events-none">
{#if isSelected(element)}
<Icon icon={IconCheck} size={'small'} />

View File

@ -19,16 +19,17 @@
import { TagCategory, TagElement } from '@hcengineering/tags'
import {
Button,
IconCheck,
getPlatformColor,
EditWithIcon,
Icon,
IconAdd,
IconCheck,
IconSearch,
EditWithIcon,
Label,
showPopup,
deviceOptionsStore,
getPlatformColorDef,
resizeObserver,
deviceOptionsStore
showPopup,
themeStore
} from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
@ -159,6 +160,7 @@
</button>
<div class="menu-group">
{#each catObjects.slice(0, 50) as element}
{@const color = getPlatformColorDef(element.color, $themeStore.dark)}
<button
class="menu-item no-focus flex-row-center"
class:selected={isSelected(selected, element)}
@ -166,8 +168,8 @@
checkSelected(selected, element)
}}
>
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
<span class="lines-limit-2 flex-grow">{element.title}</span>
<div class="tag" style:background-color={color.background} />
<span class="lines-limit-2 flex-grow" style:color={color.title}>{element.title}</span>
<span class="ml-2 text-xs">
({element.refCount ?? 0})
</span>

View File

@ -3,14 +3,16 @@
import { Doc, DocumentQuery, FindResult, Ref } from '@hcengineering/core'
import { Asset } from '@hcengineering/platform'
import { InitialKnowledge, TagReference } from '@hcengineering/tags'
import { ColorDefinition } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FilterQuery } from '@hcengineering/view-resources'
import tags from './plugin'
export function getTagStyle (color: string, selected = false): string {
export function getTagStyle (color: ColorDefinition, selected = false): string {
return `
background: ${color + (selected ? 'ff' : '33')};
border: 1px solid ${color + (selected ? 'ff' : '66')};
background: ${color.color + (selected ? 'ff' : '33')};
border: 1px solid ${color.color + (selected ? 'ff' : '66')};
color: ${color.title ?? 'var(--theme-caption-color)'};
`
}

View File

@ -48,8 +48,8 @@
"NoTodoItems": "No to do's defined",
"TodoName": "Name",
"TodoState": "State",
"DoneState": "done",
"UndoneState": "todo",
"DoneState": "Done State",
"UndoneState": "Todo",
"TodoDueDate": "Due to",
"TodoDescription": "To do description *",
"TodoEdit": "Edit To Do",

View File

@ -48,8 +48,8 @@
"NoTodoItems": "Нет to do",
"TodoName": "Название",
"TodoState": "Статус",
"DoneState": "Завершен",
"UndoneState": "todo",
"DoneState": "Статус Завершен",
"UndoneState": "В работу",
"TodoDueDate": "Срок сдачи",
"TodoDescription": "Описание to do *",
"TodoEdit": "Редактировать To Do",

View File

@ -29,13 +29,12 @@
import { createQuery, getClient, statusStore, ActionContext } from '@hcengineering/presentation'
import { Kanban, SpaceWithStates, Task, TaskGrouping, TaskOrdering } from '@hcengineering/task'
import {
ColorDefinition,
defaultBackground,
getEventPositionElement,
Label,
showPopup,
deviceOptionsStore as deviceInfo,
hslToRgb,
rgbToHsl,
AccentColor
themeStore
} from '@hcengineering/ui'
import {
AttributeModel,
@ -81,8 +80,11 @@
$: dontUpdateRank = orderBy[0] !== TaskOrdering.Manual
$: lth = $deviceInfo.theme === 'theme-light'
const accentColors: AccentColor[] = []
let accentColors: Map<string, ColorDefinition> = new Map()
const setAccentColor = (n: number, ev: CustomEvent<ColorDefinition>) => {
accentColors.set(`${n}${$themeStore.dark}${groupByKey}`, ev.detail)
accentColors = accentColors
}
const spaceQuery = createQuery()
@ -170,14 +172,6 @@
viewOptionsModel: ViewOptionModel[] | undefined
) {
categories = await getCategories(client, _class, docs, groupByKey, $statusStore, viewlet.descriptor)
categories.forEach((_, i) => {
if (accentColors[i] === undefined) {
accentColors[i] = {
textColor: 'var(--theme-caption-color)',
backgroundColor: lth ? '230, 230, 230' : '100, 100, 108'
}
}
})
for (const viewOption of viewOptionsModel ?? []) {
if (viewOption.actionTarget !== 'category') continue
const categoryFunc = viewOption as CategoryOption
@ -244,16 +238,6 @@
})
const getDoneUpdate = (e: any) => ({ doneState: e.detail._id } as DocumentUpdate<Doc>)
const setAccentColor = (n: number, ev: CustomEvent) => {
const accColor = rgbToHsl(ev.detail.r, ev.detail.g, ev.detail.b)
const textColor = !lth ? { r: 255, g: 255, b: 255 } : hslToRgb(accColor.h, accColor.s, 0.3)
const bgColor = !lth ? hslToRgb(accColor.h, accColor.s, 0.55) : hslToRgb(accColor.h, accColor.s, 0.9)
accentColors[n] = {
textColor: !lth ? 'var(--theme-caption-color)' : `rgb(${textColor.r}, ${textColor.g}, ${textColor.b})`,
backgroundColor: `${bgColor.r}, ${bgColor.g}, ${bgColor.b}`
}
}
</script>
{#await cardPresenter then presenter}
@ -283,37 +267,33 @@
on:contextmenu={(evt) => showMenu(evt.detail.evt, evt.detail.objects)}
>
<svelte:fragment slot="header" let:state let:count let:index>
<!-- {@const status = $statusStore.get(state._id)} -->
{#key lth}
<div
style:--kanban-header-rgb-color={accentColors[index]?.backgroundColor}
class="header flex-row-center"
class:gradient={!lth}
{@const color = accentColors.get(`${index}${$themeStore.dark}${groupByKey}`)}
{@const headerBGColor = color?.background ?? defaultBackground($themeStore.dark)}
<div style:background={headerBGColor} class="header flex-row-center">
<span
class="clear-mins fs-bold overflow-label pointer-events-none"
style:color={color?.title ?? 'var(--theme-caption-color)'}
>
<span
class="clear-mins fs-bold overflow-label pointer-events-none"
style:color={accentColors[index]?.textColor}
>
{#if groupByKey === noCategory}
<Label label={view.string.NoGrouping} />
{:else if headerComponent}
<svelte:component
this={headerComponent.presenter}
value={state}
{space}
size={'small'}
kind={'list-header'}
colorInherit={lth}
accent
on:accent-color={(ev) => setAccentColor(index, ev)}
/>
{/if}
</span>
<span class="counter ml-1">
{count}
</span>
</div>
{/key}
{#if groupByKey === noCategory}
<Label label={view.string.NoGrouping} />
{:else if headerComponent}
<svelte:component
this={headerComponent.presenter}
value={state}
{space}
size={'small'}
kind={'list-header'}
colorInherit={!$themeStore.dark}
accent
on:accent-color={(ev) => setAccentColor(index, ev)}
/>
{/if}
</span>
<span class="counter ml-1">
{count}
</span>
</div>
</svelte:fragment>
<svelte:fragment slot="card" let:object let:dragged>
<svelte:component this={presenter} {object} {dragged} {groupByKey} />
@ -340,17 +320,6 @@
border: 1px solid var(--theme-divider-color);
border-radius: 0.25rem;
&:not(.gradient) {
background: rgba(var(--kanban-header-rgb-color), 1);
}
&.gradient {
background: linear-gradient(
90deg,
rgba(var(--kanban-header-rgb-color), 0.15),
rgba(var(--kanban-header-rgb-color), 0.05)
);
}
.counter {
color: var(--theme-dark-color);
}

View File

@ -16,19 +16,22 @@
<script lang="ts">
import type { DoneState } from '@hcengineering/task'
import task from '@hcengineering/task'
import { getPlatformColor } from '@hcengineering/ui'
import Won from '../icons/Won.svelte'
import { PaletteColorIndexes, getPlatformColorDef, themeStore } from '@hcengineering/ui'
import Lost from '../icons/Lost.svelte'
import Won from '../icons/Won.svelte'
export let value: DoneState | null | undefined
export let showTitle: boolean = true
$: color = value?._class === task.class.WonState ? getPlatformColor(0) : getPlatformColor(11)
$: color =
value?._class === task.class.WonState
? getPlatformColorDef(PaletteColorIndexes.Crocodile, $themeStore.dark)
: getPlatformColorDef(PaletteColorIndexes.Firework, $themeStore.dark)
</script>
{#if value}
<div class="flex-center">
<div class:mr-2={showTitle} style="color: {color};">
<div class:mr-2={showTitle} style="color: {color.color};">
<svelte:component this={value._class === task.class.WonState ? Won : Lost} size={'small'} />
</div>
{#if showTitle}

View File

@ -18,12 +18,18 @@
import { statusStore } from '@hcengineering/presentation'
import type { DoneState } from '@hcengineering/task'
import DoneStatePresenter from './DoneStatePresenter.svelte'
import DoneStateEditor from './DoneStateEditor.svelte'
export let value: Ref<DoneState> | StatusValue
export let showTitle: boolean = true
export let onChange: ((value: Ref<DoneState>) => void) | undefined = undefined
</script>
{#if value}
{@const state = $statusStore.get(typeof value === 'string' ? value : value.values[0]._id)}
<DoneStatePresenter value={state} {showTitle} />
{#if onChange !== undefined && state !== undefined}
<DoneStateEditor value={state._id} space={state.space} {onChange} kind="link" size="medium" />
{:else}
<DoneStatePresenter value={state} {showTitle} />
{/if}
{/if}

View File

@ -17,12 +17,12 @@
import { Class, Doc, Ref, SortingOrder } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import { DoneState, SpaceWithStates } from '@hcengineering/task'
import { getPlatformColor, Label, resizeObserver } from '@hcengineering/ui'
import { Label, PaletteColorIndexes, getPlatformColor, resizeObserver, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import task from '../../plugin'
import Won from '../icons/Won.svelte'
import Lost from '../icons/Lost.svelte'
import Unknown from '../icons/Unknown.svelte'
import Won from '../icons/Won.svelte'
export let space: Ref<SpaceWithStates>
let states: DoneState[] = []
@ -42,7 +42,9 @@
}
)
function getColor (_class: Ref<Class<Doc>>): string {
return _class === task.class.WonState ? getPlatformColor(0) : getPlatformColor(11)
return _class === task.class.WonState
? getPlatformColor(PaletteColorIndexes.Crocodile, $themeStore.dark)
: getPlatformColor(PaletteColorIndexes.Firework, $themeStore.dark)
}
</script>

View File

@ -14,9 +14,15 @@
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'
import type { State } from '@hcengineering/task'
import { getColorNumberByText, getPlatformColor, hexToRgb, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
import {
ColorDefinition,
defaultBackground,
getColorNumberByText,
getPlatformColorDef,
themeStore
} from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
export let value: State | undefined
export let shouldShowAvatar = true
@ -28,25 +34,24 @@
const dispatch = createEventDispatcher()
const defaultFill = 'currentColor'
$: fill = value ? getPlatformColor(value.color ?? getColorNumberByText(value.name)) : defaultFill
$: lth = $deviceInfo.theme === 'theme-light'
const dispatchAccentColor = (fill: string) =>
dispatch(
'accent-color',
fill !== defaultFill ? hexToRgb(fill) : lth ? { r: 220, g: 220, b: 220 } : { r: 100, g: 100, b: 108 }
)
$: dispatchAccentColor(fill)
$: color = value ? getPlatformColorDef(value.color ?? getColorNumberByText(value.name), $themeStore.dark) : undefined
const dispatchAccentColor = (color?: ColorDefinition) => dispatch('accent-color', color)
$: dispatchAccentColor(color)
onMount(() => {
dispatchAccentColor(fill)
dispatchAccentColor(color)
})
</script>
{#if value}
<div class="flex-presenter" class:inline-presenter={inline}>
{#if shouldShowAvatar}
<div class="state-container" class:inline style="background-color: {fill}" />
<div
class="state-container"
class:inline
style="background-color: {color?.color ?? defaultBackground($themeStore.dark)}"
/>
{/if}
<span class="overflow-label label" class:nowrap={oneLine} class:no-underline={disabled}>{value.name}</span>
</div>

View File

@ -17,7 +17,7 @@
import { Ref } from '@hcengineering/core'
import { BreadcrumbsElement, statusStore } from '@hcengineering/presentation'
import task, { SpaceWithStates, State } from '@hcengineering/task'
import { getColorNumberByText, getPlatformColor, ScrollerBar } from '@hcengineering/ui'
import { ScrollerBar, getColorNumberByText, getPlatformColor, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import type { StatesBarPosition } from '../..'
@ -60,7 +60,7 @@
label={item.name}
position={getPosition(i)}
selected={item._id === state}
color={getPlatformColor(item.color ?? getColorNumberByText(item.name))}
color={getPlatformColor(item.color ?? getColorNumberByText(item.name), $themeStore.dark)}
on:click={(ev) => {
ev.stopPropagation()
if (item._id !== state) selectItem(ev, item)

View File

@ -19,22 +19,25 @@
import type { DoneState, KanbanTemplate, KanbanTemplateSpace, State } from '@hcengineering/task'
import {
CircleButton,
Component,
IconAdd,
IconCircles,
IconMoreH,
Label,
showPopup,
getPlatformColor,
PaletteColorIndexes,
defaultBackground,
eventToHTMLElement,
Component,
IconCircles,
getColorNumberByText
getColorNumberByText,
getPlatformColorDef,
showPopup,
themeStore
} from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { ColorsPopup } from '@hcengineering/view-resources'
import StatusesPopup from './StatusesPopup.svelte'
import { createEventDispatcher } from 'svelte'
import task from '../../plugin'
import Won from '../icons/Won.svelte'
import Lost from '../icons/Lost.svelte'
import Won from '../icons/Won.svelte'
import StatusesPopup from './StatusesPopup.svelte'
export let template: KanbanTemplate | undefined = undefined
export let space: KanbanTemplateSpace | undefined = undefined
@ -77,7 +80,7 @@
const onColorChange =
(state: State) =>
async (color: number | undefined): Promise<void> => {
if (color === undefined) {
if (color == null) {
return
}
@ -104,10 +107,12 @@
</div>
<div class="mt-3">
{#each states as state, i}
{@const color = getPlatformColorDef(state.color ?? getColorNumberByText(state.name), $themeStore.dark)}
{#if state}
<div
bind:this={elements[i]}
class="flex-between states"
style:background={color.background ?? defaultBackground($themeStore.dark)}
draggable={true}
on:dragover|preventDefault={(ev) => {
dragover(ev, i)
@ -127,14 +132,9 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="color"
style="background-color: {getPlatformColor(state.color ?? getColorNumberByText(state.name))}"
style:background-color={color.color}
on:click={() => {
showPopup(
ColorsPopup,
{ selected: getPlatformColor(state.color ?? getColorNumberByText(state.name)) },
elements[i],
onColorChange(state)
)
showPopup(ColorsPopup, { selected: color.name }, elements[i], onColorChange(state))
}}
/>
<div class="flex-grow caption-color">
@ -173,8 +173,13 @@
</div>
<div class="mt-4">
{#each wonStates as state}
{@const color = getPlatformColorDef(PaletteColorIndexes.Crocodile, $themeStore.dark)}
{#if state}
<div class="states flex-row-center">
<div
class="states flex-row-center"
style:color={color.title}
style:background={color.background ?? defaultBackground($themeStore.dark)}
>
<div class="bar" />
<div class="mr-2">
<Won size={'medium'} />
@ -216,8 +221,13 @@
</div>
<div class="mt-4 mb-10">
{#each lostStates as state}
{@const color = getPlatformColorDef(PaletteColorIndexes.Firework, $themeStore.dark)}
{#if state}
<div class="states flex-row-center">
<div
class="states flex-row-center"
style:color={color.title}
style:background={color.background ?? defaultBackground($themeStore.dark)}
>
<div class="bar" />
<div class="mr-2">
<Lost size={'medium'} />

View File

@ -17,7 +17,7 @@
import { Ref, SortingOrder } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import task, { SpaceWithStates, State } from '@hcengineering/task'
import { getColorNumberByText, getPlatformColor, resizeObserver } from '@hcengineering/ui'
import { getColorNumberByText, getPlatformColorDef, resizeObserver, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
export let space: Ref<SpaceWithStates>
@ -42,16 +42,14 @@
<div class="scroll">
<div class="box">
{#each states as state}
{@const color = getPlatformColorDef(state.color ?? getColorNumberByText(state.name), $themeStore.dark)}
<button
class="menu-item"
on:click={() => {
dispatch('close', state)
}}
>
<div
class="color"
style="background-color: {getPlatformColor(state.color ?? getColorNumberByText(state.name))}"
/>
<div class="color" style:background-color={color.color} />
<span class="label">{state.name}</span>
</button>
{/each}

View File

@ -29,6 +29,7 @@
</script>
{#if value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-presenter" class:inline-presenter={inline} on:click={(ev) => show(ev.target)}>
<div class="icon">
<Icon icon={task.icon.Task} size={'small'} />

View File

@ -14,11 +14,11 @@
// limitations under the License.
-->
<script lang="ts">
import { getPlatformColor, Label } from '@hcengineering/ui'
import { getPlatformColor, Label, themeStore } from '@hcengineering/ui'
import task from '../../plugin'
export let value: boolean
$: color = value ? getPlatformColor(2) : getPlatformColor(10)
$: color = value ? getPlatformColor(2, $themeStore.dark) : getPlatformColor(16, $themeStore.dark)
$: text = value ? task.string.DoneState : task.string.UndoneState
</script>

View File

@ -20,7 +20,7 @@
import { WithLookup } from '@hcengineering/core'
import { MessageViewer } from '@hcengineering/presentation'
import type { SharedTelegramMessage } from '@hcengineering/telegram'
import { CheckBox, getPlatformColorForText } from '@hcengineering/ui'
import { CheckBox, getPlatformColorForText, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
export let message: WithLookup<SharedTelegramMessage>
@ -48,7 +48,9 @@
<div class="message-container" class:out={!message.incoming}>
<div class="message" class:outcoming={!message.incoming} class:selected>
{#if showName}
<div class="name" style="color: {getPlatformColorForText(message.sender)}">{formatName(message.sender)}</div>
<div class="name" style="color: {getPlatformColorForText(message.sender, $themeStore.dark)}">
{formatName(message.sender)}
</div>
{/if}
{#if attachments}
<AttachmentList {attachments} />

View File

@ -1,4 +1,5 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/ui/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",

View File

@ -281,7 +281,8 @@
"NoStatusFound": "No matching status found",
"CreateMissingStatus": "Create missing status",
"UnsetParent": "Parent issue will be unset"
"UnsetParent": "Parent issue will be unset",
"ShowColors": "Use colors"
},
"status": {}
}

View File

@ -280,7 +280,8 @@
"ProjectEmojiiCategory": "Эмодзи",
"NoStatusFound": "Статус не найдет",
"CreateMissingStatus": "Создать отсутствущий статус",
"UnsetParent": "Родительская задача будет убрана"
"UnsetParent": "Родительская задача будет убрана",
"ShowColors": "Использовать цвета"
},
"status": {}
}

View File

@ -1,12 +1,12 @@
<script lang="ts">
import { StatusCategory } from '@hcengineering/core'
import { IconSize, hexToRgb } from '@hcengineering/ui'
import { ColorDefinition, IconSize, getPlatformColorDef, themeStore } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
import tracker from '../../plugin'
export let size: IconSize
const defaultFill = 'currentColor'
export let fill: string = defaultFill
export let fill: number = -1
export let category: StatusCategory
export let statusIcon: {
index: number | undefined
@ -17,20 +17,20 @@
const dispatch = createEventDispatcher()
const dispatchAccentColor = (fill: string) =>
dispatch('accent-color', fill !== defaultFill ? hexToRgb(fill) : { r: 127, g: 127, b: 127 })
const dispatchAccentColor = (color?: ColorDefinition) => dispatch('accent-color', color)
$: dispatchAccentColor(fill)
$: color = getPlatformColorDef(fill, $themeStore.dark)
$: dispatchAccentColor(color)
onMount(() => {
dispatchAccentColor(fill)
dispatchAccentColor(color)
})
</script>
<svg
bind:this={element}
class="svg-{size}"
{fill}
fill={color?.icon ?? 'currentColor'}
id={category._id}
style:transform={category._id === tracker.issueStatusCategory.Started ? 'rotate(-90deg)' : ''}
style:flex-shrink={0}

View File

@ -16,13 +16,12 @@
import core, { StatusCategory, WithLookup } from '@hcengineering/core'
import { getClient, statusStore } from '@hcengineering/presentation'
import { IssueStatus } from '@hcengineering/tracker'
import { IconSize, getPlatformColor } from '@hcengineering/ui'
import { IconSize } from '@hcengineering/ui'
import tracker from '../../plugin'
import StatusIcon from '../icons/StatusIcon.svelte'
export let value: WithLookup<IssueStatus>
export let size: IconSize
export let fill: string | undefined = undefined
const dynamicFillCategories = [tracker.issueStatusCategory.Started]
@ -69,11 +68,7 @@
$: updateCategory(value, statuses)
$: icon = category?.icon
$: color =
fill ??
(value.color !== undefined ? getPlatformColor(value.color) : undefined) ??
(category !== undefined ? getPlatformColor(category.color) : undefined) ??
'currentColor'
$: color = value.color !== undefined ? value.color : category !== undefined ? category.color : -1
</script>
{#if icon !== undefined && color !== undefined && category !== undefined}

View File

@ -13,6 +13,8 @@
// limitations under the License.
-->
<script lang="ts">
import { AttachmentsPresenter } from '@hcengineering/attachment-resources'
import { CommentsPresenter } from '@hcengineering/chunter-resources'
import contact from '@hcengineering/contact'
import { employeeByIdStore } from '@hcengineering/contact-resources'
import {
@ -34,18 +36,17 @@
import { Issue, IssuesGrouping, IssuesOrdering, Project } from '@hcengineering/tracker'
import {
Button,
ColorDefinition,
Component,
defaultBackground,
getEventPositionElement,
IconAdd,
Label,
Loading,
showPanel,
showPopup,
tooltip,
deviceOptionsStore as deviceInfo,
hslToRgb,
rgbToHsl,
AccentColor
themeStore,
tooltip
} from '@hcengineering/ui'
import {
AttributeModel,
@ -70,20 +71,18 @@
setGroupByValues
} from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin'
import { AttachmentsPresenter } from '@hcengineering/attachment-resources'
import { CommentsPresenter } from '@hcengineering/chunter-resources'
import { onMount } from 'svelte'
import tracker from '../../plugin'
import ComponentEditor from '../components/ComponentEditor.svelte'
import CreateIssue from '../CreateIssue.svelte'
import AssigneePresenter from './AssigneePresenter.svelte'
import DueDatePresenter from './DueDatePresenter.svelte'
import SubIssuesSelector from './edit/SubIssuesSelector.svelte'
import IssuePresenter from './IssuePresenter.svelte'
import ParentNamesPresenter from './ParentNamesPresenter.svelte'
import PriorityEditor from './PriorityEditor.svelte'
import StatusEditor from './StatusEditor.svelte'
import EstimationEditor from './timereport/EstimationEditor.svelte'
import DueDatePresenter from './DueDatePresenter.svelte'
export let space: Ref<Project> | undefined = undefined
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
@ -97,10 +96,11 @@
$: orderBy = viewOptions.orderBy
$: sort = { [orderBy[0]]: orderBy[1] }
$: lth = $deviceInfo.theme === 'theme-light'
const accentColors: AccentColor[] = []
// issuesGroupBySorting[groupByKey]
let accentColors: Map<string, ColorDefinition> = new Map()
const setAccentColor = (n: number, ev: CustomEvent<ColorDefinition>) => {
accentColors.set(`${n}${$themeStore.dark}${groupByKey}`, ev.detail)
accentColors = accentColors
}
$: dontUpdateRank = orderBy[0] !== IssuesOrdering.Manual
@ -197,14 +197,6 @@
viewOptionsModel: ViewOptionModel[] | undefined
) {
categories = await getCategories(client, _class, docs, groupByKey, $statusStore, viewlet.descriptor)
categories.forEach((_, i) => {
if (accentColors[i] === undefined) {
accentColors[i] = {
textColor: 'var(--theme-caption-color)',
backgroundColor: lth ? '230, 230, 230' : '100, 100, 108'
}
}
})
for (const viewOption of viewOptionsModel ?? []) {
if (viewOption.actionTarget !== 'category') continue
const categoryFunc = viewOption as CategoryOption
@ -259,16 +251,6 @@
space: doc.space
}
}
const setAccentColor = (n: number, ev: CustomEvent) => {
const accColor = rgbToHsl(ev.detail.r, ev.detail.g, ev.detail.b)
const textColor = !lth ? { r: 255, g: 255, b: 255 } : hslToRgb(accColor.h, accColor.s, 0.3)
const bgColor = !lth ? hslToRgb(accColor.h, accColor.s, 0.55) : hslToRgb(accColor.h, accColor.s, 0.9)
accentColors[n] = {
textColor: !lth ? 'var(--theme-caption-color)' : `rgb(${textColor.r}, ${textColor.g}, ${textColor.b})`,
backgroundColor: `${bgColor.r}, ${bgColor.g}, ${bgColor.b}`
}
}
</script>
{#if categories.length === 0}
@ -301,49 +283,44 @@
on:contextmenu={(evt) => showMenu(evt.detail.evt, evt.detail.objects)}
>
<svelte:fragment slot="header" let:state let:count let:index>
<!-- {@const status = $statusStore.get(state._id)} -->
{#key lth}
<div
style:--kanban-header-rgb-color={accentColors[index]?.backgroundColor}
class="header flex-between"
class:gradient={!lth}
>
<div class="flex-row-center gap-1">
<span
class="clear-mins fs-bold overflow-label pointer-events-none"
style:color={accentColors[index]?.textColor}
>
{#if groupByKey === noCategory}
<Label label={view.string.NoGrouping} />
{:else if headerComponent}
<svelte:component
this={headerComponent.presenter}
value={state}
{space}
size={'small'}
kind={'list-header'}
colorInherit={lth}
accent
on:accent-color={(ev) => setAccentColor(index, ev)}
/>
{/if}
</span>
<span class="counter">
{count}
</span>
</div>
<div class="tools gap-1">
<Button
icon={IconAdd}
kind={'transparent'}
showTooltip={{ label: tracker.string.AddIssueTooltip, direction: 'left' }}
on:click={() => {
showPopup(CreateIssue, { space: currentSpace, [groupByKey]: state._id }, 'top')
}}
/>
</div>
{@const color = accentColors.get(`${index}${$themeStore.dark}${groupByKey}`)}
{@const headerBGColor = color?.background ?? defaultBackground($themeStore.dark)}
<div style:background={headerBGColor} class="header flex-between">
<div class="flex-row-center gap-1">
<span
class="clear-mins fs-bold overflow-label pointer-events-none"
style:color={color?.title ?? 'var(--theme-caption-color)'}
>
{#if groupByKey === noCategory}
<Label label={view.string.NoGrouping} />
{:else if headerComponent}
<svelte:component
this={headerComponent.presenter}
value={state}
{space}
size={'small'}
kind={'list-header'}
colorInherit={!$themeStore.dark}
accent
on:accent-color={(ev) => setAccentColor(index, ev)}
/>
{/if}
</span>
<span class="counter">
{count}
</span>
</div>
{/key}
<div class="tools gap-1">
<Button
icon={IconAdd}
kind={'transparent'}
showTooltip={{ label: tracker.string.AddIssueTooltip, direction: 'left' }}
on:click={() => {
showPopup(CreateIssue, { space: currentSpace, [groupByKey]: state._id }, 'top')
}}
/>
</div>
</div>
</svelte:fragment>
<svelte:fragment slot="card" let:object>
{@const issue = toIssue(object)}
@ -451,17 +428,6 @@
border: 1px solid var(--theme-divider-color);
border-radius: 0.25rem;
&:not(.gradient) {
background: rgba(var(--kanban-header-rgb-color), 1);
}
&.gradient {
background: linear-gradient(
90deg,
rgba(var(--kanban-header-rgb-color), 0.15),
rgba(var(--kanban-header-rgb-color), 0.05)
);
}
.counter {
color: var(--theme-dark-color);
}

View File

@ -23,9 +23,10 @@
SelectPopup,
Spinner,
closeTooltip,
getPlatformColor,
getPlatformColorDef,
navigate,
showPopup,
themeStore,
tooltip
} from '@hcengineering/ui'
import { ListSelectionProvider } from '@hcengineering/view-resources'
@ -72,7 +73,7 @@
icon,
isSelected: iss._id === issue._id,
...(project !== undefined ? { text: `${getIssueId(project, iss)} ${iss.title}` } : undefined),
...(color !== undefined ? { iconColor: getPlatformColor(color) } : undefined)
...(color !== undefined ? { iconColor: getPlatformColorDef(color, $themeStore.dark).icon } : undefined)
}
}),
width: 'large'

View File

@ -29,9 +29,10 @@
ToggleWithLabel,
eventToHTMLElement,
getColorNumberByText,
getPlatformColor,
getPlatformColorForText,
showPopup
getPlatformColorDef,
getPlatformColorForTextDef,
showPopup,
themeStore
} from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin'
@ -233,7 +234,12 @@
icon={icon === tracker.component.IconWithEmojii ? IconWithEmojii : icon ?? tracker.icon.Home}
iconProps={icon === tracker.component.IconWithEmojii
? { icon: color }
: { fill: color !== undefined ? getPlatformColor(color) : getPlatformColorForText(name) }}
: {
fill:
color !== undefined
? getPlatformColorDef(color, $themeStore.dark).icon
: getPlatformColorForTextDef(name, $themeStore.dark).icon
}}
kind="no-border"
size="medium"
on:click={chooseIcon}

View File

@ -8,7 +8,9 @@
TabsControl,
eventToHTMLElement,
getPlatformColor,
showPopup
getPlatformColorDef,
showPopup,
themeStore
} from '@hcengineering/ui'
import { ColorsPopup } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
@ -27,10 +29,16 @@
dispatch('close', { icon: _icon, color: _color })
}
function pickColor (evt: MouseEvent) {
showPopup(ColorsPopup, { selected: _color }, eventToHTMLElement(evt), (newColor) => {
_color = newColor
console.log(newColor)
})
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(_color, $themeStore.dark).name },
eventToHTMLElement(evt),
(newColor) => {
if (newColor != null) {
_color = newColor
}
}
)
}
</script>
@ -54,14 +62,14 @@
<div class="flex-row-center">
<Label label={tracker.string.ProjectColor} />
<div class="flex-no-shrink ml-2 color" on:click={pickColor}>
<div class="dot" style="background-color: {getPlatformColor(_color ?? 0)}" />
<div class="dot" style="background-color: {getPlatformColor(_color ?? 0, $themeStore.dark)}" />
</div>
</div>
{#each icons as obj}
<div class="float-left p-2">
<Button
icon={obj}
iconProps={{ fill: getPlatformColor(_color ?? 0) }}
iconProps={{ fill: getPlatformColor(_color ?? 0, $themeStore.dark) }}
size="medium"
kind={obj === _icon ? 'primary' : 'transparent'}
on:click={() => {

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import { Project } from '@hcengineering/tracker'
import { Icon, IconWithEmojii, getPlatformColor, getPlatformColorForText } from '@hcengineering/ui'
import { Icon, IconWithEmojii, getPlatformColorDef, getPlatformColorForTextDef, themeStore } from '@hcengineering/ui'
import tracker from '../../plugin'
export let value: Project
@ -26,7 +26,12 @@
icon={value.icon === tracker.component.IconWithEmojii ? IconWithEmojii : value.icon ?? tracker.icon.Home}
iconProps={value.icon === tracker.component.IconWithEmojii
? { icon: value.color }
: { fill: value.color !== undefined ? getPlatformColor(value.color) : getPlatformColorForText(value.name) }}
: {
fill:
value.color !== undefined
? getPlatformColorDef(value.color, $themeStore.dark).icon
: getPlatformColorForTextDef(value.name, $themeStore.dark).icon
}}
size="small"
/>
</div>

View File

@ -15,7 +15,13 @@
<script lang="ts">
import { Ref, Space } from '@hcengineering/core'
import { Project } from '@hcengineering/tracker'
import { IconWithEmojii, getPlatformColor, getPlatformColorForText, getCurrentLocation } from '@hcengineering/ui'
import {
IconWithEmojii,
getCurrentLocation,
getPlatformColorDef,
getPlatformColorForTextDef,
themeStore
} from '@hcengineering/ui'
import { NavLink, TreeNode } from '@hcengineering/view-resources'
import { SpacesNavModel } from '@hcengineering/workbench'
import { SpecialElement } from '@hcengineering/workbench-resources'
@ -40,7 +46,12 @@
icon={space?.icon === tracker.component.IconWithEmojii ? IconWithEmojii : space?.icon ?? model.icon}
iconProps={space?.icon === tracker.component.IconWithEmojii
? { icon: space.color }
: { fill: space.color !== undefined ? getPlatformColor(space.color) : getPlatformColorForText(space.name) }}
: {
fill:
space.color !== undefined
? getPlatformColorDef(space.color, $themeStore.dark).icon
: getPlatformColorForTextDef(space.name, $themeStore.dark).icon
}}
title={space.name}
actions={() => getActions(space)}
on:click={() => localStorage.setItem(getSpaceCollapsedKey(), collapsed ? '' : COLLAPSED)}

View File

@ -13,12 +13,19 @@
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { Data } from '@hcengineering/core'
import { IssueStatus } from '@hcengineering/tracker'
import { Button, eventToHTMLElement, getPlatformColor, IconCircles, showPopup } from '@hcengineering/ui'
import presentation from '@hcengineering/presentation'
import { IssueStatus } from '@hcengineering/tracker'
import {
Button,
eventToHTMLElement,
getPlatformColorDef,
IconCircles,
showPopup,
themeStore
} from '@hcengineering/ui'
import { ColorsPopup } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin'
import StatusInput from './StatusInput.svelte'
@ -31,9 +38,13 @@
function pickColor (evt: MouseEvent) {
showPopup(
ColorsPopup,
{ selected: value.color ? getPlatformColor(value.color) : undefined },
{ selected: value.color ? getPlatformColorDef(value.color, $themeStore.dark).name : undefined },
eventToHTMLElement(evt),
(newColor) => (value.color = newColor)
(newColor) => {
if (value != null) {
value.color = newColor
}
}
)
}
@ -47,7 +58,7 @@
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-no-shrink ml-2 color" on:click={pickColor}>
<div class="dot" style="background-color: {getPlatformColor(value.color ?? 0)}" />
<div class="dot" style="background-color: {getPlatformColorDef(value.color ?? 0, $themeStore.dark).color}" />
</div>
<div class="ml-2 w-full name">
<StatusInput bind:value={value.name} placeholder={tracker.string.Name} focus fill />

View File

@ -300,7 +300,8 @@ export default mergeIds(trackerId, tracker, {
NoStatusFound: '' as IntlString,
CreateMissingStatus: '' as IntlString,
UnsetParent: '' as IntlString
UnsetParent: '' as IntlString,
ShowColors: '' as IntlString
},
component: {
NopeComponent: '' as AnyComponent,

View File

@ -14,15 +14,15 @@
// limitations under the License.
-->
<script lang="ts">
import { getPlatformColor } from '@hcengineering/ui'
import { getPlatformColor, themeStore } from '@hcengineering/ui'
export let value: boolean
export let trueColor = 0
export let falseColor = 11
export let falseColor = 16
export let useInvert = false
$: val = useInvert ? !value : value
$: color = val ? getPlatformColor(trueColor) : getPlatformColor(falseColor)
$: color = val ? getPlatformColor(trueColor, $themeStore.dark) : getPlatformColor(falseColor, $themeStore.dark)
</script>
{#if val}

View File

@ -14,13 +14,13 @@
// limitations under the License.
-->
<script lang="ts">
import { ColorDefinition, getPlatformColors, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { getPlatformColors } from '@hcengineering/ui'
import PopupDialog from './PopupDialog.svelte'
import view from '../plugin'
import PopupDialog from './PopupDialog.svelte'
export let colors: readonly string[] = getPlatformColors()
export let columns: number = 5
export let colors: readonly ColorDefinition[] = getPlatformColors($themeStore.dark)
export let columns: number = 8
export let selected: string | undefined = undefined
const dispatch = createEventDispatcher()
@ -32,8 +32,8 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="color"
class:selected={selected === color}
style="background-color: {color}"
class:selected={selected === color.name}
style="background-color: {color.color}"
on:click={() => {
dispatch('close', i)
}}

View File

@ -17,7 +17,7 @@
import { Class, ClassifierKind, Doc, Mixin, Ref } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import setting from '@hcengineering/setting'
import { Icon, Label, tooltip } from '@hcengineering/ui'
import { Icon, Label, themeStore, tooltip } from '@hcengineering/ui'
import { getMixinStyle } from '../utils'
export let value: Doc
@ -54,7 +54,11 @@
<div class="mixin-container">
{#each mixins as mixin}
{@const userMixin = hierarchy.hasMixin(mixin, setting.mixin.UserMixin)}
<div class="mixin-selector" class:user-selector={userMixin} style={getMixinStyle(mixin._id, true)}>
<div
class="mixin-selector"
class:user-selector={userMixin}
style={getMixinStyle(mixin._id, true, $themeStore.dark)}
>
{#if !userMixin}
<Label label={mixin.label} />
{:else}

View File

@ -30,6 +30,7 @@
Loading,
SelectPopup,
showPopup,
themeStore,
ToggleButton
} from '@hcengineering/ui'
import { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view'
@ -273,13 +274,13 @@
}
}
function getColor (attribute: AttributeConfig): string {
const color = getPlatformColorForText(attribute._class)
function getColor (attribute: AttributeConfig, black: boolean): string {
const color = getPlatformColorForText(attribute._class, black)
return `${color + (attribute.enabled ? 'cc' : '33')};`
}
function getStyle (attribute: AttributeConfig): string {
const color = getPlatformColorForText(attribute._class)
function getStyle (attribute: AttributeConfig, black: boolean): string {
const color = getPlatformColorForText(attribute._class, black)
return `border: 1px solid ${color + (attribute.enabled ? 'ff' : 'cc')};`
}
@ -319,7 +320,7 @@
{#each enabled as attribute, i}
<div
class="m-0-5 border-radius-1 overflow-label"
style={getStyle(attribute)}
style={getStyle(attribute, $themeStore.dark)}
bind:this={elements[i]}
draggable={true}
on:dragover|preventDefault={(ev) => {
@ -334,7 +335,7 @@
}}
>
<ToggleButton
backgroundColor={getColor(attribute)}
backgroundColor={getColor(attribute, $themeStore.dark)}
icon={attribute.icon}
label={attribute.label}
bind:value={attribute.enabled}

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import { MessageViewer } from '@hcengineering/presentation'
import { getPlatformColor, Label as LabelComponent } from '@hcengineering/ui'
import { getPlatformColor, Label as LabelComponent, themeStore } from '@hcengineering/ui'
import view from '../../plugin'
export let href: string
@ -63,7 +63,7 @@
</script>
<div class="flex mt-2">
<div class="line" style="background-color: {getPlatformColor(7)}" />
<div class="line" style="background-color: {getPlatformColor(7, $themeStore.dark)}" />
{#await getData(href) then data}
<div class="flex-col">
<a class="fs-title mb-1" {href}>#{data.number} {data.title}</a>

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import Play from '../icons/Play.svelte'
import { getPlatformColor } from '@hcengineering/ui'
import { getPlatformColor, themeStore } from '@hcengineering/ui'
export let href: string
const maxWidth = 400
@ -56,7 +56,7 @@
</script>
<div class="flex mt-2">
<div class="line" style="background-color: {getPlatformColor(2)}" />
<div class="line" style="background-color: {getPlatformColor(2, $themeStore.dark)}" />
{#await getData(href) then data}
<div class="flex-col">
<div class="mb-1"><a class="fs-title" {href}>{data.title}</a></div>

View File

@ -374,6 +374,7 @@
{collapsed}
{props}
{lastCat}
{viewOptions}
on:more={() => {
if (limit !== undefined) limit += 20
}}

View File

@ -19,6 +19,7 @@
ActionIcon,
AnyComponent,
Button,
ColorDefinition,
Component,
IconAdd,
IconBack,
@ -26,13 +27,12 @@
IconCollapseArrow,
IconMoreH,
Label,
deviceOptionsStore as deviceInfo,
defaultBackground,
eventToHTMLElement,
hslToRgb,
rgbToHsl,
showPopup
showPopup,
themeStore
} from '@hcengineering/ui'
import { AttributeModel } from '@hcengineering/view'
import { AttributeModel, ViewOptions } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import view from '../../plugin'
import { selectionStore, selectionStoreMap } from '../../selection'
@ -55,15 +55,18 @@
export let props: Record<string, any> = {}
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
export let viewOptions: ViewOptions
const dispatch = createEventDispatcher()
$: lth = $deviceInfo.theme === 'theme-light'
let accentColor: ColorDefinition | undefined = undefined
let accentColor = lth ? { h: 0, s: 0, l: 1 } : { h: 0, s: 0, l: 0.3 }
$: headerBGColor =
level === 0 && (viewOptions as any).shouldShowColors
? accentColor?.background ?? defaultBackground($themeStore.dark)
: defaultBackground($themeStore.dark)
$: headerBGColor = !lth ? hslToRgb(accentColor.h, accentColor.s, 0.35) : hslToRgb(accentColor.h, accentColor.s, 0.9)
$: headerTextColor = !lth ? { r: 255, g: 255, b: 255 } : hslToRgb(accentColor.h, accentColor.s, 0.3)
$: headerTextColor = accentColor?.title ?? 'var(--theme-caption-color)'
const handleCreateItem = (event: MouseEvent) => {
if (createItemDialog === undefined) return
@ -78,9 +81,8 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
style:z-index={10 - level}
style:--list-header-rgb-color={`${headerBGColor.r}, ${headerBGColor.g}, ${headerBGColor.b}`}
style:background={headerBGColor}
class="flex-between categoryHeader row"
class:gradient={!lth}
class:flat
class:collapsed
class:subLevel={level !== 0}
@ -108,22 +110,17 @@
<Label label={view.string.NoGrouping} />
</span>
{:else if headerComponent}
<span
class="clear-mins"
style:color={lth
? `rgb(${headerTextColor.r}, ${headerTextColor.g}, ${headerTextColor.b})`
: 'var(--theme-caption-color)'}
>
<span class="clear-mins" style:color={headerTextColor}>
<svelte:component
this={headerComponent.presenter}
value={category}
{space}
size={'small'}
kind={'list-header'}
colorInherit={lth && level === 0}
colorInherit={!$themeStore.dark && level === 0}
accent={level === 0}
on:accent-color={(evt) => {
accentColor = rgbToHsl(evt.detail.r, evt.detail.g, evt.detail.b)
accentColor = evt.detail
}}
/>
</span>
@ -215,16 +212,6 @@
transform: rotate(90deg);
transition: transform 0.15s ease-in-out;
}
&:not(.gradient)::before {
background: rgba(var(--list-header-rgb-color), 1);
}
&.gradient::before {
background: linear-gradient(
90deg,
rgba(var(--list-header-rgb-color), 0.15),
rgba(var(--list-header-rgb-color), 0.05)
);
}
&::before,
&::after {
position: absolute;

View File

@ -343,8 +343,8 @@ export async function deleteObjects (client: TxOperations, objects: Doc[]): Prom
await ops.commit()
}
export function getMixinStyle (id: Ref<Class<Doc>>, selected: boolean): string {
const color = getPlatformColorForText(id as string)
export function getMixinStyle (id: Ref<Class<Doc>>, selected: boolean, black: boolean): string {
const color = getPlatformColorForText(id as string, black)
return `
color: ${selected ? '#fff' : 'var(--caption-color)'};
background: ${color + (selected ? 'ff' : '33')};

View File

@ -539,7 +539,7 @@ export interface ViewOption {
defaultValue: any
label: IntlString
hidden?: (viewOptions: ViewOptions) => boolean
actionTarget?: 'query' | 'category'
actionTarget?: 'query' | 'category' | 'display'
action?: Resource<(value: any, ...params: any) => any>
}
/**

View File

@ -66,7 +66,7 @@ export function startHttpServer (
const token = req.query.token as string
const payload = decodeToken(token)
const admin = payload.extra?.admin === 'true'
res.writeHead(200)
res.writeHead(200, { 'Content-Type': 'application/json' })
const json = JSON.stringify({
...getStatistics(ctx, sessions, admin),
users: getUsers,