TSK-1323: Fix colors for list (#3069)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-04-25 23:11:50 +07:00 committed by GitHub
parent 123eb6e3ad
commit ef987eef56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 275 additions and 112 deletions

View File

@ -82,6 +82,27 @@ export function hexColorToNumber (hexColor: string): number {
return parseInt(hexColor.replace('#', ''), 16) return parseInt(hexColor.replace('#', ''), 16)
} }
/**
* @public
*/
export function hexToRgb (color: string): { r: number, g: number, b: number } {
if (!color.startsWith('#')) {
return { r: 128, g: 128, b: 128 }
}
color = color.replace('#', '')
if (color.length === 3) {
color = color
.split('')
.map((c) => c + c)
.join('')
}
return {
r: parseInt(color.slice(0, 2), 16),
g: parseInt(color.slice(2, 4), 16),
b: parseInt(color.slice(4, 6), 16)
}
}
/** /**
* @public * @public
*/ */
@ -110,54 +131,106 @@ export function numberToRGB (color: number, alpha?: number): string {
/** /**
* @public * @public
*/ */
export function hsvToRGB (h: number, s: number, v: number): { r: number, g: number, b: number, rgb: string } { export function hslToRgb (h: number, s: number, l: number): { r: number, g: number, b: number } {
s /= 100
l /= 100
const k = (n: number): number => (n + h / 30) % 12
const a = s * Math.min(l, 1 - l)
const f = (n: number): number => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))
return { r: 255 * f(0), g: 255 * f(8), b: 255 * f(4) }
}
/**
* @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
}
return (
'#' +
addZero((Math.round(color.r) % 255).toString(16)) +
addZero((Math.round(color.g) % 255).toString(16)) +
addZero((Math.round(color.b) % 255).toString(16))
)
}
export async function svgToColor (img: SVGSVGElement): Promise<{ r: number, g: number, b: number } | undefined> {
const outerHTML = img.outerHTML
const blob = new Blob([outerHTML], { type: 'image/svg+xml;charset=utf-8' })
const blobURL = URL.createObjectURL(blob)
const image = new Image()
return await new Promise((resolve) => {
image.setAttribute('crossOrigin', '')
image.src = blobURL
image.onload = () => {
resolve(imageToColor(image))
}
})
}
/**
* @public
*/
export function imageToColor (image: HTMLImageElement): { r: number, g: number, b: number } | undefined {
const canvas = document.createElement('canvas')
const height = (canvas.height = image.naturalHeight ?? image.offsetHeight ?? image.height)
const width = (canvas.width = image.naturalWidth ?? image.offsetWidth ?? image.width)
canvas.width = width
canvas.height = height
const blockSize = 5
let r: number = 0 let r: number = 0
let g: number = 0 let g: number = 0
let b: number = 0 let b: number = 0
const i = Math.floor(h * 6) let count = 0
const f = h * 6 - i
const p = v * (1 - s) const context = canvas.getContext('2d')
const q = v * (1 - f * s)
const t = v * (1 - (1 - f) * s) if (context != null) {
switch (i % 6) { context.drawImage(image, 0, 0, width, height)
case 0: context.beginPath()
r = v context.arc(0, 0, 60, 0, Math.PI * 2, true)
g = t context.clip()
b = p context.fillRect(0, 0, width, height)
break
case 1: const data = context?.getImageData(0, 0, width, height).data
r = q
g = v const length = data.length
b = p
break let i = 0
case 2: while (i < length) {
r = p if (data[i] > 5 && data[i + 1] > 5 && data[i + 2] > 5 && data[i + 3] > 50) {
g = v ++count
b = t r += data[i]
break g += data[i + 1]
case 3: b += data[i + 2]
r = p }
g = q i += blockSize * 4
b = v }
break
case 4: r = Math.round(r / count)
r = t g = Math.round(g / count)
g = p b = Math.round(b / count)
b = v return { r, g, b }
break }
case 5: }
r = v
g = p export function rgbToHsl (r: number, g: number, b: number): { h: number, s: number, l: number } {
b = q r /= 255
break g /= 255
} b /= 255
r = Math.round(r * 255) const l = Math.max(r, g, b)
g = Math.round(g * 255) const s = l - Math.min(r, g, b)
b = Math.round(b * 255) const h = s > 0 ? (l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s) : 0
return { return {
r, h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
g, s: 100 * (s > 0 ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0),
b, l: (100 * (2 * l - s)) / 2
rgb: '#' + r.toString(16) + g.toString(16) + b.toString(16)
} }
} }

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
export let size: 'small' | 'medium' | 'large' export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor' export let fill: string = 'currentColor'
</script> </script>
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">

View File

@ -15,7 +15,7 @@
import { Timestamp } from '@hcengineering/core' import { Timestamp } from '@hcengineering/core'
import type { Asset, IntlString } from '@hcengineering/platform' import type { Asset, IntlString } from '@hcengineering/platform'
import { /* Metadata, Plugin, plugin, */ Resource /*, Service */ } from '@hcengineering/platform' import { /* Metadata, Plugin, plugin, */ Resource /*, Service */ } from '@hcengineering/platform'
import { /* getContext, */ SvelteComponent } from 'svelte' import { /* getContext, */ ComponentType } from 'svelte'
/** /**
* Describe a browser URI location parsed to path, query and fragment. * Describe a browser URI location parsed to path, query and fragment.
@ -55,7 +55,7 @@ export function areLocationsEqual (loc1: Location, loc2: Location): boolean {
return keys1.findIndex((k) => loc1.query?.[k] !== loc2.query?.[k]) < 0 return keys1.findIndex((k) => loc1.query?.[k] !== loc2.query?.[k]) < 0
} }
export type AnySvelteComponent = typeof SvelteComponent export type AnySvelteComponent = ComponentType
export type Component<C extends AnySvelteComponent> = Resource<C> export type Component<C extends AnySvelteComponent> = Resource<C>
export type AnyComponent = Resource<AnySvelteComponent> export type AnyComponent = Resource<AnySvelteComponent>

View File

@ -145,7 +145,7 @@
> >
{#if selected} {#if selected}
{#if hideIcon || selected} {#if hideIcon || selected}
<UserInfo value={selected} size={kind === 'link' ? 'x-small' : 'tiny'} {icon} /> <UserInfo value={selected} size={kind === 'link' ? 'x-small' : 'tiny'} {icon} on:accent-color />
{:else} {:else}
{getName(selected)} {getName(selected)}
{/if} {/if}

View File

@ -31,7 +31,8 @@
import { Client, Ref } from '@hcengineering/core' import { Client, Ref } from '@hcengineering/core'
import { Asset, getResource } from '@hcengineering/platform' import { Asset, getResource } from '@hcengineering/platform'
import { getBlobURL, getClient } from '@hcengineering/presentation' import { getBlobURL, getClient } from '@hcengineering/presentation'
import { AnySvelteComponent, Icon, IconSize } from '@hcengineering/ui' import { AnySvelteComponent, Icon, IconSize, hexToRgb, imageToColor } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { getAvatarProviderId } from '../utils' import { getAvatarProviderId } from '../utils'
import AvatarIcon from './icons/Avatar.svelte' import AvatarIcon from './icons/Avatar.svelte'
@ -43,6 +44,8 @@
let url: string | undefined let url: string | undefined
let avatarProvider: AvatarProvider | undefined let avatarProvider: AvatarProvider | undefined
const dispatch = createEventDispatcher()
async function update (size: IconSize, avatar?: string | null, direct?: Blob) { async function update (size: IconSize, avatar?: string | null, direct?: Blob) {
if (direct !== undefined) { if (direct !== undefined) {
getBlobURL(direct).then((blobURL) => { getBlobURL(direct).then((blobURL) => {
@ -78,17 +81,44 @@
const color = (await getResource(avatarProvider.getUrl))(uri, size) const color = (await getResource(avatarProvider.getUrl))(uri, size)
style = `background-color: ${color}` style = `background-color: ${color}`
accentColor = hexToRgb(color)
dispatch('accent-color', accentColor)
} }
} }
$: updateStyle(avatar, avatarProvider) $: updateStyle(avatar, avatarProvider)
let imageElement: HTMLImageElement | undefined = undefined
let accentColor: any | undefined
</script> </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} {style}>
{#if url} {#if url}
{#if size === 'large' || size === 'x-large'} {#if size === 'large' || size === 'x-large'}
<img class="ava-{size} ava-blur" src={url} alt={''} /> <img
class="ava-{size} ava-blur"
src={url}
alt={''}
bind:this={imageElement}
on:load={(data) => {
if (imageElement !== undefined) {
accentColor = imageToColor(imageElement)
dispatch('accent-color', accentColor)
}
}}
/>
{/if} {/if}
<img class="ava-{size} ava-mask" src={url} alt={''} /> <img
class="ava-{size} ava-mask"
src={url}
alt={''}
bind:this={imageElement}
on:load={(data) => {
if (imageElement !== undefined) {
accentColor = imageToColor(imageElement)
dispatch('accent-color', accentColor)
}
}}
/>
{:else} {:else}
<Icon icon={icon ?? AvatarIcon} {size} /> <Icon icon={icon ?? AvatarIcon} {size} />
{/if} {/if}

View File

@ -38,6 +38,7 @@
showNavigate={false} showNavigate={false}
justify={'left'} justify={'left'}
on:change={({ detail }) => onChange?.(detail)} on:change={({ detail }) => onChange?.(detail)}
on:accent-color
/> />
{:else} {:else}
<EmployeePresenter <EmployeePresenter
@ -53,5 +54,6 @@
disableClick disableClick
{colorInherit} {colorInherit}
{accent} {accent}
on:accent-color
/> />
{/if} {/if}

View File

@ -38,4 +38,5 @@
{accent} {accent}
{defaultName} {defaultName}
statusLabel={value?.active === false && shouldShowName ? contact.string.Inactive : undefined} statusLabel={value?.active === false && shouldShowName ? contact.string.Inactive : undefined}
on:accent-color
/> />

View File

@ -17,11 +17,29 @@
{#if Array.isArray(value)} {#if Array.isArray(value)}
<div class="inline-content"> <div class="inline-content">
{#each value as employee} {#each value as employee}
<EmployeeAttributePresenter value={employee} {kind} {tooltipLabels} {onChange} {inline} {colorInherit} {accent} /> <EmployeeAttributePresenter
value={employee}
{kind}
{tooltipLabels}
{onChange}
{inline}
{colorInherit}
{accent}
on:accent-color
/>
{/each} {/each}
</div> </div>
{:else} {:else}
<EmployeeAttributePresenter {value} {kind} {tooltipLabels} {onChange} {inline} {colorInherit} {accent} /> <EmployeeAttributePresenter
{value}
{kind}
{tooltipLabels}
{onChange}
{inline}
{colorInherit}
{accent}
on:accent-color
/>
{/if} {/if}
<style lang="scss"> <style lang="scss">

View File

@ -57,7 +57,7 @@
class:mr-2={shouldShowName && !enlargedText} class:mr-2={shouldShowName && !enlargedText}
class:mr-3={shouldShowName && enlargedText} class:mr-3={shouldShowName && enlargedText}
> >
<Avatar size={avatarSize} avatar={value.avatar} /> <Avatar size={avatarSize} avatar={value.avatar} on:accent-color />
</span> </span>
{/if} {/if}
{#if shouldShowName} {#if shouldShowName}
@ -79,7 +79,7 @@
class:mr-2={shouldShowName && !enlargedText} class:mr-2={shouldShowName && !enlargedText}
class:mr-3={shouldShowName && enlargedText} class:mr-3={shouldShowName && enlargedText}
> >
<Avatar size={avatarSize} /> <Avatar size={avatarSize} on:accent-color />
</span> </span>
{/if} {/if}
{#if shouldShowName && defaultName} {#if shouldShowName && defaultName}

View File

@ -78,5 +78,6 @@
{colorInherit} {colorInherit}
{accent} {accent}
bind:element bind:element
on:accent-color
/> />
{/if} {/if}

View File

@ -27,7 +27,7 @@
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-row-center" on:click> <div class="flex-row-center" on:click>
<Avatar avatar={value.avatar} {size} {icon} /> <Avatar avatar={value.avatar} {size} {icon} on:accent-color />
<div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}"> <div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}">
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if} {#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
<div class="content-accent-color overflow-label text-left">{getName(value)}</div> <div class="content-accent-color overflow-label text-left">{getName(value)}</div>

View File

@ -26,6 +26,6 @@
<div class="icon"> <div class="icon">
{#if status} {#if status}
<IssueStatusIcon value={status} size="small" /> <IssueStatusIcon value={status} size="small" on:accent-color />
{/if} {/if}
</div> </div>

View File

@ -1,18 +1,34 @@
<script lang="ts"> <script lang="ts">
import { StatusCategory } from '@hcengineering/core' import { StatusCategory } from '@hcengineering/core'
import { IconSize } from '@hcengineering/ui' import { IconSize, hexToRgb } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
import tracker from '../../plugin' import tracker from '../../plugin'
export let size: IconSize export let size: IconSize
export let fill: string = 'currentColor' const defaultFill = 'currentColor'
export let fill: string = defaultFill
export let category: StatusCategory export let category: StatusCategory
export let statusIcon: { export let statusIcon: {
index: number | undefined index: number | undefined
count: number | undefined count: number | undefined
} = { index: 0, count: 0 } } = { index: 0, count: 0 }
let element: SVGSVGElement
const dispatch = createEventDispatcher()
const dispatchAccentColor = (fill: string) =>
dispatch('accent-color', fill !== defaultFill ? hexToRgb(fill) : 'var(--theme-halfcontent-color)')
$: dispatchAccentColor(fill)
onMount(() => {
dispatchAccentColor(fill)
})
</script> </script>
<svg <svg
bind:this={element}
class="svg-{size}" class="svg-{size}"
{fill} {fill}
id={category._id} id={category._id}

View File

@ -14,11 +14,10 @@
--> -->
<script lang="ts"> <script lang="ts">
import core, { StatusCategory, WithLookup } from '@hcengineering/core' import core, { StatusCategory, WithLookup } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient, statusStore } from '@hcengineering/presentation'
import { IssueStatus } from '@hcengineering/tracker' import { IssueStatus } from '@hcengineering/tracker'
import { getPlatformColor, IconSize } from '@hcengineering/ui' import { IconSize, getPlatformColor } from '@hcengineering/ui'
import tracker from '../../plugin' import tracker from '../../plugin'
import { statusStore } from '@hcengineering/presentation'
import StatusIcon from '../icons/StatusIcon.svelte' import StatusIcon from '../icons/StatusIcon.svelte'
export let value: WithLookup<IssueStatus> export let value: WithLookup<IssueStatus>
@ -78,5 +77,5 @@
</script> </script>
{#if icon !== undefined && color !== undefined && category !== undefined} {#if icon !== undefined && color !== undefined && category !== undefined}
<StatusIcon {category} {size} fill={color} {statusIcon} /> <StatusIcon on:accent-color {category} {size} fill={color} {statusIcon} />
{/if} {/if}

View File

@ -27,7 +27,7 @@
{#if value} {#if value}
<div class="flex-presenter cursor-default" style:color={'inherit'}> <div class="flex-presenter cursor-default" style:color={'inherit'}>
{#if !inline} {#if !inline}
<IssueStatusIcon {value} {size} /> <IssueStatusIcon {value} {size} on:accent-color />
{/if} {/if}
<span <span
class="overflow-label" class="overflow-label"

View File

@ -31,5 +31,6 @@
{kind} {kind}
{colorInherit} {colorInherit}
{accent} {accent}
on:accent-color
/> />
{/if} {/if}

View File

@ -13,55 +13,65 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { Doc, Ref, Space } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform' import { IntlString } from '@hcengineering/platform'
import ui, { import ui, {
ActionIcon, ActionIcon,
AnyComponent, AnyComponent,
Button,
IconAdd,
IconCollapseArrow,
IconMoreH, IconMoreH,
Label, Label,
hsvToRGB, deviceOptionsStore as deviceInfo,
IconCollapseArrow, eventToHTMLElement,
deviceOptionsStore as deviceInfo hslToRgb,
rgbToHsl,
showPopup
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { noCategory } from '../../viewOptions'
import view from '../../plugin'
import { Doc, Ref, Space } from '@hcengineering/core'
import { AttributeModel } from '@hcengineering/view' import { AttributeModel } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import view from '../../plugin'
import { noCategory } from '../../viewOptions'
export let groupByKey: string export let groupByKey: string
export let category: any export let category: any
export let headerComponent: AttributeModel | undefined export let headerComponent: AttributeModel | undefined
export let space: Ref<Space> | undefined export let space: Ref<Space> | undefined
export let createItemDialog: AnyComponent | undefined
export let createItemLabel: IntlString | undefined
export let limited: number export let limited: number
export let items: Doc[] export let items: Doc[]
export let extraHeaders: AnyComponent[] | undefined
export let flat = false export let flat = false
export let collapsed = false export let collapsed = false
export let lastCat = false export let lastCat = false
export let props: Record<string, any> = {}
export let level: number export let level: number
export let createItemDialog: AnyComponent | undefined
export let createItemLabel: IntlString | undefined
export let extraHeaders: AnyComponent[] | undefined
export let props: Record<string, any> = {}
export let newObjectProps: (doc: Doc) => Record<string, any> | undefined export let newObjectProps: (doc: Doc) => Record<string, any> | undefined
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
// const handleCreateItem = (event: MouseEvent) => {
// if (createItemDialog === undefined) return
// showPopup(createItemDialog, newObjectProps(items[0]), eventToHTMLElement(event))
// }
const hue = Math.random()
$: lth = $deviceInfo.theme === 'theme-light' $: lth = $deviceInfo.theme === 'theme-light'
$: headerBGColor = lth ? hsvToRGB(hue, 0.15, 0.9) : hsvToRGB(hue, 0.15, 0.3)
$: headerTextColor = lth ? hsvToRGB(hue, 0.5, 0.5) : hsvToRGB(hue, 0.6, 0.95) let accentColor = { h: 0, s: 0, l: 65 }
$: headerBGColor = !lth
? hslToRgb(accentColor.h, accentColor.s, accentColor.l / 1.5 + (mouseOver ? -20 : 0))
: hslToRgb(accentColor.h, accentColor.s, accentColor.l * 1.5 + (mouseOver ? -20 : 0))
const handleCreateItem = (event: MouseEvent) => {
if (createItemDialog === undefined) return
showPopup(createItemDialog, newObjectProps(items[0]), eventToHTMLElement(event))
}
let mouseOver = false
</script> </script>
{#if headerComponent || groupByKey === noCategory} {#if headerComponent || groupByKey === noCategory}
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div <div
style:z-index={10 - level} style:z-index={10 - level}
style:--list-header-color={headerBGColor.rgb}
style:--list-header-rgb-color={`${headerBGColor.r}, ${headerBGColor.g}, ${headerBGColor.b}`} style:--list-header-rgb-color={`${headerBGColor.r}, ${headerBGColor.g}, ${headerBGColor.b}`}
class="flex-between categoryHeader row" class="flex-between categoryHeader row"
class:gradient={!lth} class:gradient={!lth}
@ -69,19 +79,30 @@
class:collapsed class:collapsed
class:subLevel={level !== 0} class:subLevel={level !== 0}
class:lastCat class:lastCat
on:focus={() => {
mouseOver = true
}}
on:mouseenter={() => {
mouseOver = true
}}
on:mouseover={() => {
mouseOver = true
}}
on:mouseleave={() => {
mouseOver = false
}}
on:click={() => dispatch('collapse')} on:click={() => dispatch('collapse')}
> >
<div class="flex-row-center clear-mins"> <div class="flex-row-center clear-mins">
{#if level === 0} {#if level === 0}
<div class="chevron"><IconCollapseArrow size={'small'} /></div> <div class="chevron"><IconCollapseArrow size={'small'} /></div>
{/if} {/if}
<!-- <FixedColumn key={`list_groupBy_${groupByKey}`} justify={'left'}> -->
{#if groupByKey === noCategory} {#if groupByKey === noCategory}
<span style:color={headerTextColor.rgb} class="text-base fs-bold overflow-label pointer-events-none"> <span class="text-base fs-bold overflow-label pointer-events-none">
<Label label={view.string.NoGrouping} /> <Label label={view.string.NoGrouping} />
</span> </span>
{:else if headerComponent} {:else if headerComponent}
<span class="clear-mins" style:color={headerTextColor.rgb}> <span class="clear-mins">
<svelte:component <svelte:component
this={headerComponent.presenter} this={headerComponent.presenter}
value={category} value={category}
@ -90,17 +111,12 @@
kind={'list-header'} kind={'list-header'}
colorInherit={lth && level === 0} colorInherit={lth && level === 0}
accent={level === 0} accent={level === 0}
on:accent-color={(evt) => {
accentColor = rgbToHsl(evt.detail.r, evt.detail.g, evt.detail.b)
}}
/> />
</span> </span>
{/if} {/if}
<!-- </FixedColumn> -->
<!-- {#if extraHeaders}
{#each extraHeaders as extra}
<FixedColumn key={`list_groupBy_${groupByKey}_extra_${extra}`} justify={'left'}>
<Component is={extra} props={{ ...props, value: category, docs: items }} />
</FixedColumn>
{/each}
{/if} -->
{#if limited < items.length} {#if limited < items.length}
<div class="antiSection-header__counter flex-row-center mx-2"> <div class="antiSection-header__counter flex-row-center mx-2">
<span class="caption-color">{limited}</span> <span class="caption-color">{limited}</span>
@ -119,14 +135,16 @@
<span class="antiSection-header__counter ml-2">{items.length}</span> <span class="antiSection-header__counter ml-2">{items.length}</span>
{/if} {/if}
</div> </div>
<!-- {#if createItemDialog !== undefined && createItemLabel !== undefined} {#if createItemDialog !== undefined && createItemLabel !== undefined}
<Button <div class:on-hover={!mouseOver}>
icon={IconAdd} <Button
kind={'transparent'} icon={IconAdd}
showTooltip={{ label: createItemLabel }} kind={'transparent'}
on:click={handleCreateItem} showTooltip={{ label: createItemLabel }}
/> on:click={handleCreateItem}
{/if} --> />
</div>
{/if}
</div> </div>
{/if} {/if}
@ -135,12 +153,16 @@
position: relative; position: relative;
position: sticky; position: sticky;
top: 0; top: 0;
padding: 0 2.5rem 0 0.75rem; padding: 0 0.75rem 0 0.75rem;
height: 2.75rem; height: 2.75rem;
min-height: 2.75rem; min-height: 2.75rem;
min-width: 0; min-width: 0;
background: var(--theme-bg-color); background: var(--theme-bg-color);
.on-hover {
visibility: hidden;
}
.chevron { .chevron {
flex-shrink: 0; flex-shrink: 0;
min-width: 0; min-width: 0;
@ -151,10 +173,14 @@
transition: transform 0.15s ease-in-out; transition: transform 0.15s ease-in-out;
} }
&:not(.gradient)::before { &:not(.gradient)::before {
background: var(--list-header-color); background: rgba(var(--list-header-rgb-color), 0.15);
} }
&.gradient::before { &.gradient::before {
background: linear-gradient(90deg, var(--list-header-color), rgba(var(--list-header-rgb-color), 0.3)); background: linear-gradient(
90deg,
rgba(var(--list-header-rgb-color), 0.15),
rgba(var(--list-header-rgb-color), 0.05)
);
} }
&::before { &::before {
box-sizing: border-box; box-sizing: border-box;
@ -187,7 +213,7 @@
border-left: 1px solid var(--theme-list-border-color); border-left: 1px solid var(--theme-list-border-color);
border-right: 1px solid var(--theme-list-border-color); border-right: 1px solid var(--theme-list-border-color);
border-bottom: 1px solid var(--theme-list-subheader-divider); border-bottom: 1px solid var(--theme-list-subheader-divider);
// here shoul be top 3rem for sticky, but with ExpandCollapse it gives strange behavior // here should be top 3rem for sticky, but with ExpandCollapse it gives strange behavior
&::before { &::before {
content: none; content: none;
@ -206,8 +232,4 @@
padding: 0 0.25rem 0 0.25rem; padding: 0 0.25rem 0 0.25rem;
} }
} }
// .row:not(:last-child) {
// border-bottom: 1px solid var(--accent-bg-color);
// }
</style> </style>