import type { Color, ColorScheme, Palette } from '@blocksuite/affine-model';
import { DefaultTheme, resolveColor } from '@blocksuite/affine-model';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { ColorEvent } from '@blocksuite/affine-shared/utils';
import { css, html, LitElement, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { repeat } from 'lit/directives/repeat.js';
import isEqual from 'lodash-es/isEqual';
import { AdditionIcon } from './icons';
export class EdgelessColorButton extends LitElement {
static override styles = css`
:host {
position: relative;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.color-unit {
position: relative;
width: 16px;
height: 16px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
box-sizing: border-box;
}
.color-unit svg {
width: 100%;
height: 100%;
border-radius: 50%;
overflow: hidden;
}
:host .color-unit::after {
position: absolute;
display: block;
content: '';
width: 100%;
height: 100%;
border-radius: 50%;
box-sizing: border-box;
overflow: hidden;
border-width: 0.5px;
border-style: solid;
border-color: ${unsafeCSSVarV2('layer/insideBorder/blackBorder')};
}
:host(.black) .color-unit:after {
border-color: ${unsafeCSSVarV2('layer/insideBorder/border')};
}
:host(.large) {
width: 24px;
height: 24px;
}
:host(.large) .color-unit {
width: 20px;
height: 20px;
}
:host::after {
position: absolute;
display: block;
content: '';
width: 27px;
height: 27px;
border-radius: 50%;
box-sizing: border-box;
overflow: hidden;
pointer-events: none;
}
:host([active])::after {
border: 1.5px solid var(--affine-primary-color);
}
`;
get preprocessColor() {
const value = resolveColor(this.color, this.theme);
return value.startsWith('--') ? `var(${value})` : value;
}
override render() {
const { label, preprocessColor, hollowCircle } = this;
const additionIcon = AdditionIcon(preprocessColor, !!hollowCircle);
return html`
${additionIcon}
`;
}
@property({ attribute: true, type: Boolean })
accessor active: boolean = false;
@property({ attribute: false })
accessor color!: Color;
@property({ attribute: false })
accessor hollowCircle: boolean = false;
@property({ attribute: false })
accessor label: string | undefined = undefined;
@property({ attribute: false })
accessor theme!: ColorScheme;
}
export class EdgelessColorPanel extends LitElement {
static override styles = css`
:host {
display: grid;
grid-gap: 4px;
grid-template-columns: repeat(var(--columns, 9), 1fr);
}
/* note */
:host(.small) {
grid-template-columns: repeat(var(--columns, 6), 1fr);
grid-gap: 8px;
}
/* edgeless toolbar */
:host(.one-way) {
display: flex;
flex-wrap: nowrap;
padding: 0 2px;
gap: 14px;
box-sizing: border-box;
background: var(--affine-background-overlay-panel-color);
}
:host(.one-way.small) {
display: flex;
gap: 4px;
background: unset;
}
`;
select(palette: Palette) {
this.dispatchEvent(
new ColorEvent('select', {
detail: palette,
bubbles: true,
composed: true,
cancelable: true,
})
);
}
get resolvedValue() {
return this.value && resolveColor(this.value, this.theme);
}
override willUpdate(changedProperties: PropertyValues) {
if (changedProperties.has('columns')) {
if (this.columns) {
this.style.setProperty('--columns', this.columns.toString());
} else {
this.style.removeProperty('--columns');
}
}
}
override render() {
return html`
${repeat(
this.palettes,
palette => palette.key,
palette => {
const resolvedColor = resolveColor(palette.value, this.theme);
const activated = isEqual(resolvedColor, this.resolvedValue);
return html` {
this.select(palette);
this.value = resolvedColor;
}}
>
`;
}
)}
`;
}
@property({ attribute: false })
accessor hasTransparent: boolean = true;
@property({ attribute: false })
accessor hollowCircle = false;
@property({ type: Array })
accessor palettes: readonly Palette[] = DefaultTheme.Palettes;
@property({ attribute: false })
accessor theme!: ColorScheme;
@property({ attribute: false })
accessor value: Color | null = null;
@property({ attribute: false })
accessor columns: number | undefined = undefined;
}
export class EdgelessTextColorIcon extends LitElement {
static override styles = css`
:host {
display: flex;
justify-content: center;
align-items: center;
width: 20px;
height: 20px;
}
`;
get preprocessColor() {
const color = this.color;
return color.startsWith('--') ? `var(${color})` : color;
}
override render() {
return html`
`;
}
@property({ attribute: false })
accessor color!: string;
}