diff --git a/packages/affine/model/src/consts/line.ts b/packages/affine/model/src/consts/line.ts index 83ff57c90232f..26e5312342973 100644 --- a/packages/affine/model/src/consts/line.ts +++ b/packages/affine/model/src/consts/line.ts @@ -1,18 +1,29 @@ +/* eslint perfectionist/sort-enums: "off" */ + import { z } from 'zod'; import { createEnumMap } from '../utils/enum.js'; export enum LineWidth { - Eight = 8, + Two = 2, // Thin Four = 4, Six = 6, + Eight = 8, // Thick Ten = 10, Twelve = 12, - Two = 2, } +export const LINE_WIDTHS = [ + LineWidth.Two, + LineWidth.Four, + LineWidth.Six, + LineWidth.Eight, + LineWidth.Ten, + LineWidth.Twelve, +]; + export enum LineColor { Black = '--affine-palette-line-black', Blue = '--affine-palette-line-blue', diff --git a/packages/affine/shared/src/theme/color.ts b/packages/affine/shared/src/theme/color.ts new file mode 100644 index 0000000000000..4e0bb67a3b8b6 --- /dev/null +++ b/packages/affine/shared/src/theme/color.ts @@ -0,0 +1,40 @@ +/* eslint perfectionist/sort-enums: "off" */ + +import { themeToVar } from '@toeverything/theme/v2'; +import { z } from 'zod'; + +// 3 x 9 +export const PALETTES = [ + // Light + themeToVar('edgeless/palette/light/redLight'), + themeToVar('edgeless/palette/light/orangeLight'), + themeToVar('edgeless/palette/light/yellowLight'), + themeToVar('edgeless/palette/light/greenLight'), + themeToVar('edgeless/palette/light/blueLight'), + themeToVar('edgeless/palette/light/purpleLight'), + themeToVar('edgeless/palette/light/magentaLight'), + themeToVar('edgeless/palette/light/greyLight'), + 'transparent', + // Medium + themeToVar('edgeless/palette/medium/redMedium'), + themeToVar('edgeless/palette/medium/orangeMedium'), + themeToVar('edgeless/palette/medium/yellowMedium'), + themeToVar('edgeless/palette/medium/greenMedium'), + themeToVar('edgeless/palette/medium/blueMedium'), + themeToVar('edgeless/palette/medium/purpleMedium'), + themeToVar('edgeless/palette/medium/magentaMedium'), + themeToVar('edgeless/palette/medium/greyMedium'), + themeToVar('edgeless/palette/white'), + // Heavy + themeToVar('edgeless/palette/heavy/red'), + themeToVar('edgeless/palette/heavy/orange'), + themeToVar('edgeless/palette/heavy/yellow'), + themeToVar('edgeless/palette/heavy/green'), + themeToVar('edgeless/palette/heavy/blue'), + themeToVar('edgeless/palette/heavy/purple'), + themeToVar('edgeless/palette/heavy/magenta'), + themeToVar('edgeless/palette/black'), +] as const; + +export const PaletteEnum = z.enum(PALETTES); +export type PaletteEnum = z.infer; diff --git a/packages/affine/shared/src/theme/index.ts b/packages/affine/shared/src/theme/index.ts index 48ddb6d474e9f..01ea238bb39fb 100644 --- a/packages/affine/shared/src/theme/index.ts +++ b/packages/affine/shared/src/theme/index.ts @@ -1 +1,2 @@ +export * from './color.js'; export * from './css-variables.js'; diff --git a/packages/affine/shared/src/utils/zod-schema.ts b/packages/affine/shared/src/utils/zod-schema.ts index 95be5b7d0ec55..ac04c58605036 100644 --- a/packages/affine/shared/src/utils/zod-schema.ts +++ b/packages/affine/shared/src/utils/zod-schema.ts @@ -36,6 +36,8 @@ import { } from '@blocksuite/affine-model'; import { z, ZodDefault, ZodObject, type ZodTypeAny, ZodUnion } from 'zod'; +import { PaletteEnum } from '../theme/color.js'; + const ConnectorEndpointSchema = z.nativeEnum(PointStyle); const StrokeStyleSchema = z.nativeEnum(StrokeStyle); const LineWidthSchema = z.nativeEnum(LineWidth); @@ -60,8 +62,16 @@ export const ColorSchema = z.union([ }), ]); const LineColorSchema = z.union([LineColorsSchema, ColorSchema]); -const ShapeFillColorSchema = z.union([FillColorsSchema, ColorSchema]); -const ShapeStrokeColorSchema = z.union([StrokeColorsSchema, ColorSchema]); +const ShapeFillColorSchema = z.union([ + FillColorsSchema, + PaletteEnum, + ColorSchema, +]); +const ShapeStrokeColorSchema = z.union([ + StrokeColorsSchema, + PaletteEnum, + ColorSchema, +]); const TextColorSchema = z.union([LineColorsSchema, ColorSchema]); const NoteBackgroundColorSchema = z.union([ NoteBackgroundColorsSchema, diff --git a/packages/blocks/src/root-block/edgeless/components/color-picker/button.ts b/packages/blocks/src/root-block/edgeless/components/color-picker/button.ts index e185f77769034..c7c83eb025ff5 100644 --- a/packages/blocks/src/root-block/edgeless/components/color-picker/button.ts +++ b/packages/blocks/src/root-block/edgeless/components/color-picker/button.ts @@ -82,13 +82,15 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { ${this.isText ? html` ` : html` `} @@ -104,7 +106,7 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { diff --git a/packages/blocks/src/root-block/edgeless/components/color-picker/custom-button.ts b/packages/blocks/src/root-block/edgeless/components/color-picker/custom-button.ts index 9c76ed365f62b..c8c9fa8c2f3e3 100644 --- a/packages/blocks/src/root-block/edgeless/components/color-picker/custom-button.ts +++ b/packages/blocks/src/root-block/edgeless/components/color-picker/custom-button.ts @@ -1,18 +1,34 @@ import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; -import { colorContainerStyles } from '../panel/color-panel.js'; - export class EdgelessColorCustomButton extends LitElement { static override styles = css` - ${colorContainerStyles} + :host { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + } + + :host([active]):after { + position: absolute; + display: block; + content: ''; + width: 27px; + height: 27px; + border: 1.5px solid var(--affine-primary-color); + border-radius: 50%; + box-sizing: border-box; + overflow: hidden; + } .color-custom { display: flex; align-items: center; justify-content: center; - width: 16px; - height: 16px; + width: 21px; + height: 21px; border-radius: 50%; box-sizing: border-box; overflow: hidden; @@ -43,15 +59,11 @@ export class EdgelessColorCustomButton extends LitElement { `; override render() { - return html` -
-
-
- `; + return html`
`; } - @property({ attribute: false }) - accessor active!: boolean; + @property({ attribute: true, type: Boolean }) + accessor active: boolean = false; } declare global { diff --git a/packages/blocks/src/root-block/edgeless/components/panel/color-panel.ts b/packages/blocks/src/root-block/edgeless/components/panel/color-panel.ts index 04f48055fda7a..75aa50885acbc 100644 --- a/packages/blocks/src/root-block/edgeless/components/panel/color-panel.ts +++ b/packages/blocks/src/root-block/edgeless/components/panel/color-panel.ts @@ -1,11 +1,7 @@ import { TransparentIcon } from '@blocksuite/affine-components/icons'; -import { - ColorScheme, - LINE_COLORS, - LineColor, - NoteBackgroundColor, - ShapeFillColor, -} from '@blocksuite/affine-model'; +import { ColorScheme, LineColor } from '@blocksuite/affine-model'; +import { PALETTES, unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; import { css, html, LitElement, nothing } from 'lit'; import { property } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; @@ -35,17 +31,17 @@ export function isTransparent(color: string) { return color.toLowerCase().endsWith('transparent'); } -function isSameColorWithBackground(color: string) { - const colors: string[] = [ - LineColor.Black, - LineColor.White, - NoteBackgroundColor.Black, - NoteBackgroundColor.White, - ShapeFillColor.Black, - ShapeFillColor.White, - ]; - return colors.includes(color.toLowerCase()); -} +// function isSameColorWithBackground(color: string) { +// const colors: string[] = [ +// LineColor.Black, +// LineColor.White, +// NoteBackgroundColor.Black, +// NoteBackgroundColor.White, +// ShapeFillColor.Black, +// ShapeFillColor.White, +// ]; +// return colors.includes(color.toLowerCase()); +// } function TransparentColor(hollowCircle = false) { const containerStyle = { @@ -73,25 +69,39 @@ function TransparentColor(hollowCircle = false) { `; } -function BorderedHollowCircle(color: string) { - const valid = color.startsWith('--'); - const strokeWidth = valid && isSameColorWithBackground(color) ? 1 : 0; - const style = { - fill: valid ? `var(${color})` : color, - stroke: 'var(--affine-border-color)', - }; +function Circle(color: string) { return html` + + + `; +} + +function BorderedHollowCircle(color: string) { + return html` + + `; @@ -101,71 +111,63 @@ function AdditionIcon(color: string, hollowCircle: boolean) { if (isTransparent(color)) { return TransparentColor(hollowCircle); } + if (hollowCircle) { return BorderedHollowCircle(color); } - return nothing; -} -export function ColorUnit( - color: string, - { - hollowCircle, - letter, - }: { - hollowCircle?: boolean; - letter?: boolean; - } = {} -) { - const additionIcon = AdditionIcon(color, !!hollowCircle); - - const colorStyle = - !hollowCircle && !isTransparent(color) - ? { background: `var(${color})` } - : {}; - - const borderStyle = - isSameColorWithBackground(color) && !hollowCircle - ? { - border: '0.5px solid var(--affine-border-color)', - } - : {}; - - const style = { - width: '16px', - height: '16px', - borderRadius: '50%', - boxSizing: 'border-box', - overflow: 'hidden', - ...borderStyle, - ...colorStyle, - }; - - return html` -
- ${additionIcon} -
- `; + return Circle(color); } export class EdgelessColorButton extends LitElement { static override styles = css` :host { + position: relative; display: flex; justify-content: center; align-items: center; + } + + .color-unit { + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + box-sizing: border-box; + } + + :host(.large) { + width: 24px; + height: 24px; + } + :host(.large) .color-unit { + width: 21px; + height: 21px; + } + :host(.large:not([hollow-circle])) .color-unit { + border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/blackBorder')}; + } + + :host(.small) { width: 20px; height: 20px; } + :host(.small) .color-unit { + width: 16.25px; + height: 16.25px; + } + :host(.small) .color-unit svg { + width: 100%; + height: 100%; + } - .color-unit { - width: 16px; - height: 16px; + :host([active]):after { + position: absolute; + display: block; + content: ''; + width: 27px; + height: 27px; + border: 1.5px solid var(--affine-primary-color); border-radius: 50%; box-sizing: border-box; overflow: hidden; @@ -178,30 +180,25 @@ export class EdgelessColorButton extends LitElement { } override render() { - const { color, hollowCircle, letter } = this; - const additionIcon = AdditionIcon(color, !!hollowCircle); - const style: Record = {}; - if (!hollowCircle) { - style.background = this.preprocessColor; - if (isSameColorWithBackground(color)) { - style.border = '0.5px solid var(--affine-border-color)'; - } - } + const { color, preprocessColor, hollowCircle, letter } = this; + const additionIcon = AdditionIcon(preprocessColor, !!hollowCircle); return html`
${additionIcon}
`; } + @property({ attribute: true, type: Boolean }) + accessor active: boolean = false; + @property({ attribute: false }) accessor color!: string; - @property({ attribute: false }) - accessor hollowCircle: boolean | undefined = undefined; + @property({ attribute: 'hollow-circle', type: Boolean }) + accessor hollowCircle: boolean = false; @property({ attribute: false }) accessor letter: boolean | undefined = undefined; @@ -213,8 +210,8 @@ export const colorContainerStyles = css` display: flex; align-items: center; justify-content: center; - width: 24px; - height: 24px; + width: 27px; + height: 27px; border-radius: 50%; box-sizing: border-box; overflow: hidden; @@ -230,9 +227,9 @@ export const colorContainerStyles = css` .color-container[active]:after { position: absolute; - width: 20px; - height: 20px; - border: 0.5px solid var(--affine-primary-color); + width: 27px; + height: 27px; + border: 1.5px solid var(--affine-primary-color); border-radius: 50%; box-sizing: border-box; content: attr(data-letter); @@ -245,19 +242,11 @@ export class EdgelessColorPanel extends LitElement { display: flex; flex-direction: row; flex-wrap: wrap; - width: 184px; - gap: 8px; + width: 248px; + gap: 4px; } - - ${colorContainerStyles} `; - get palettes() { - return this.hasTransparent - ? ['--affine-palette-transparent', ...this.options] - : this.options; - } - onSelect(value: string) { this.dispatchEvent( new ColorEvent('select', { @@ -274,24 +263,17 @@ export class EdgelessColorPanel extends LitElement { ${repeat( this.palettes, color => color, - color => { - const unit = ColorUnit(color, { - hollowCircle: this.hollowCircle, - letter: this.showLetterMark, - }); - - return html` -
this.onSelect(color)} - > - ${unit} -
- `; - } + color => + html` this.onSelect(color)} + > + ` )} - `; } @@ -306,7 +288,7 @@ export class EdgelessColorPanel extends LitElement { accessor openColorPicker!: (e: MouseEvent) => void; @property({ type: Array }) - accessor options: readonly string[] = LINE_COLORS; + accessor palettes: readonly string[] = PALETTES; @property({ attribute: false }) accessor showLetterMark = false; diff --git a/packages/blocks/src/root-block/edgeless/components/panel/line-styles-panel.ts b/packages/blocks/src/root-block/edgeless/components/panel/line-styles-panel.ts index 7a43bd5064405..c267209c3997a 100644 --- a/packages/blocks/src/root-block/edgeless/components/panel/line-styles-panel.ts +++ b/packages/blocks/src/root-block/edgeless/components/panel/line-styles-panel.ts @@ -3,7 +3,7 @@ import { DashLineIcon, StraightLineIcon, } from '@blocksuite/affine-components/icons'; -import { type LineWidth, StrokeStyle } from '@blocksuite/affine-model'; +import { LineWidth, StrokeStyle } from '@blocksuite/affine-model'; import { html } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; @@ -47,14 +47,14 @@ const LINE_STYLE_LIST = [ export function LineStylesPanel({ onClick, - selectedLineSize, selectedLineStyle, + selectedLineSize = LineWidth.Two, lineStyles = [StrokeStyle.Solid, StrokeStyle.Dash, StrokeStyle.None], }: LineStylesPanelProps = {}) { const lineSizePanel = html` { onClick?.({ type: 'size', @@ -69,7 +69,7 @@ export function LineStylesPanel({ item => item.value, ({ name, icon, value }) => { const active = selectedLineStyle === value; - const classes: Record = { + const classes = { 'line-style-button': true, [`mode-${value}`]: true, }; diff --git a/packages/blocks/src/root-block/edgeless/components/panel/line-width-panel.ts b/packages/blocks/src/root-block/edgeless/components/panel/line-width-panel.ts index b6b4a47737cc5..a4ff82a269741 100644 --- a/packages/blocks/src/root-block/edgeless/components/panel/line-width-panel.ts +++ b/packages/blocks/src/root-block/edgeless/components/panel/line-width-panel.ts @@ -1,15 +1,17 @@ -import { LineWidth } from '@blocksuite/affine-model'; -import { requestConnectedFrame } from '@blocksuite/affine-shared/utils'; +import { LINE_WIDTHS, LineWidth } from '@blocksuite/affine-model'; +import { clamp, on, once } from '@blocksuite/affine-shared/utils'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, LitElement, nothing, type PropertyValues } from 'lit'; -import { property, query, queryAll } from 'lit/decorators.js'; - -type DragConfig = { - stepWidth: number; - boundLeft: number; - containerWidth: number; - bottomLineWidth: number; -}; +import { property, query } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; + +interface Config { + width: number; + itemSize: number; + itemIconSize: number; + dragHandleSize: number; + count: number; +} export class LineWidthEvent extends Event { detail: LineWidth; @@ -34,10 +36,28 @@ export class EdgelessLineWidthPanel extends WithDisposable(LitElement) { align-items: center; justify-content: center; align-self: stretch; + + --width: 140px; + --item-size: 16px; + --item-icon-size: 8px; + --drag-handle-size: 14px; + --cursor: 0; + --count: 6; + /* (16 - 14) / 2 + (cursor / (count - 1)) * (140 - 16) */ + --drag-handle-center-x: calc( + (var(--item-size) - var(--drag-handle-size)) / 2 + + (var(--cursor) / (var(--count) - 1)) * + (var(--width) - var(--item-size)) + ); + } + + :host([disabled]) { + opacity: 0.5; + pointer-events: none; } .line-width-panel { - width: 108px; + width: var(--width); height: 24px; display: flex; flex-direction: row; @@ -51,162 +71,70 @@ export class EdgelessLineWidthPanel extends WithDisposable(LitElement) { display: flex; align-items: center; justify-content: center; - width: 16px; - height: 16px; + width: var(--item-size); + height: var(--item-size); z-index: 2; } .line-width-icon { - width: 4px; - height: 4px; - border-radius: 50%; + width: var(--item-icon-size); + height: var(--item-icon-size); background-color: var(--affine-border-color); + border-radius: 50%; } - .line-width-button:nth-child(1) { - margin-right: 0; - } - - .line-width-button:nth-child(6) { - margin-left: 0; + .line-width-button[data-selected] .line-width-icon { + background-color: var(--affine-icon-color); } .drag-handle { position: absolute; - left: 0; - top: 50%; - width: 8px; - height: 8px; - transform: translateY(-50%) translateX(4px); + width: var(--drag-handle-size); + height: var(--drag-handle-size); border-radius: 50%; background-color: var(--affine-icon-color); z-index: 3; + transform: translateX(var(--drag-handle-center-x)); } .bottom-line, .line-width-overlay { - left: 8px; - top: 50%; - transform: translateY(-50%); - height: 1px; - background-color: var(--affine-border-color); position: absolute; + height: 1px; + left: calc(var(--item-size) / 2); } .bottom-line { - width: calc(100% - 16px); + width: calc(100% - var(--item-size)); background-color: var(--affine-border-color); } .line-width-overlay { - width: 0; background-color: var(--affine-icon-color); z-index: 1; + width: var(--drag-handle-center-x); } `; - private _dragConfig: DragConfig | null = null; - - private _getDragHandlePosition = (e: PointerEvent, config: DragConfig) => { - const x = e.clientX; - const { boundLeft, bottomLineWidth, stepWidth, containerWidth } = config; - - let steps: number; - if (x <= boundLeft) { - steps = 0; - } else if (x - boundLeft >= containerWidth) { - steps = 100; - } else { - steps = Math.floor((x - boundLeft) / stepWidth); - } - - // The drag handle should not be dragged to the left of the first icon or right of the last icon. - // Calculate the drag handle position based on the steps. - const bottomLineOffsetX = 4; - const bottomLineStepWidth = (bottomLineWidth - bottomLineOffsetX) / 100; - const dragHandlerPosition = steps * bottomLineStepWidth; - return dragHandlerPosition; + private _getDragHandlePosition = (e: PointerEvent) => { + return clamp(e.offsetX, 0, this.config.width); }; private _onPointerDown = (e: PointerEvent) => { e.preventDefault(); - if (this.disable) return; - const { left, width } = this._lineWidthPanel.getBoundingClientRect(); - const bottomLineWidth = this._bottomLine.getBoundingClientRect().width; - this._dragConfig = { - stepWidth: width / 100, - boundLeft: left, - containerWidth: width, - bottomLineWidth, - }; this._onPointerMove(e); - }; - private _onPointerMove = (e: PointerEvent) => { - e.preventDefault(); - if (!this._dragConfig) return; - const dragHandlerPosition = this._getDragHandlePosition( - e, - this._dragConfig - ); - this._dragHandle.style.left = `${dragHandlerPosition}%`; - this._lineWidthOverlay.style.width = `${dragHandlerPosition}%`; - this._updateIconsColor(); + const dispose = on(this, 'pointermove', this._onPointerMove); + this._disposables.add(once(this, 'pointerup', dispose)); + this._disposables.add(once(this, 'pointerout', dispose)); }; - private _onPointerOut = (e: PointerEvent) => { - // If the pointer is out of the line width panel - // Stop dragging and update the selected size by nearest size. - e.preventDefault(); - if (!this._dragConfig) return; - const dragHandlerPosition = this._getDragHandlePosition( - e, - this._dragConfig - ); - this._updateLineWidthPanelByDragHandlePosition(dragHandlerPosition); - this._dragConfig = null; - }; - - private _onPointerUp = (e: PointerEvent) => { + private _onPointerMove = (e: PointerEvent) => { e.preventDefault(); - if (!this._dragConfig) return; - const dragHandlerPosition = this._getDragHandlePosition( - e, - this._dragConfig - ); - this._updateLineWidthPanelByDragHandlePosition(dragHandlerPosition); - this._dragConfig = null; - }; - private _updateIconsColor = () => { - if (!this._dragHandle.offsetParent) { - requestConnectedFrame(() => this._updateIconsColor(), this); - return; - } + const x = this._getDragHandlePosition(e); - const dragHandleRect = this._dragHandle.getBoundingClientRect(); - const dragHandleCenterX = dragHandleRect.left + dragHandleRect.width / 2; - // All the icons located at the left of the drag handle should be filled with the icon color. - const leftIcons = []; - // All the icons located at the right of the drag handle should be filled with the border color. - const rightIcons = []; - - for (const icon of this._lineWidthIcons) { - const { left, width } = icon.getBoundingClientRect(); - const centerX = left + width / 2; - if (centerX < dragHandleCenterX) { - leftIcons.push(icon); - } else { - rightIcons.push(icon); - } - } - - leftIcons.forEach( - icon => (icon.style.backgroundColor = 'var(--affine-icon-color)') - ); - rightIcons.forEach( - icon => (icon.style.backgroundColor = 'var(--affine-border-color)') - ); + this._updateLineWidthPanelByDragHandlePosition(x); }; private _onSelect(lineWidth: LineWidth) { @@ -224,110 +152,73 @@ export class EdgelessLineWidthPanel extends WithDisposable(LitElement) { private _updateLineWidthPanel(selectedSize: LineWidth) { if (!this._lineWidthOverlay) return; - let width = 0; - let dragHandleOffsetX = 0; - switch (selectedSize) { - case LineWidth.Two: - width = 0; - break; - case LineWidth.Four: - width = 16; - dragHandleOffsetX = 1; - break; - case LineWidth.Six: - width = 32; - dragHandleOffsetX = 2; - break; - case LineWidth.Eight: - width = 48; - dragHandleOffsetX = 3; - break; - case LineWidth.Ten: - width = 64; - dragHandleOffsetX = 4; - break; - default: - width = 80; - dragHandleOffsetX = 4; - } + const index = this.lineWidths.findIndex(w => w === selectedSize); + if (index === -1) return; - dragHandleOffsetX += 4; - this._lineWidthOverlay.style.width = `${width}%`; - this._dragHandle.style.left = `${width}%`; - this._dragHandle.style.transform = `translateY(-50%) translateX(${dragHandleOffsetX}px)`; - this._updateIconsColor(); + this.style.setProperty('--cursor', `${index}`); } - private _updateLineWidthPanelByDragHandlePosition( - dragHandlerPosition: number - ) { + private _updateLineWidthPanelByDragHandlePosition(x: number) { // Calculate the selected size based on the drag handle position. // Need to select the nearest size. - let selectedSize = this.selectedSize; - if (dragHandlerPosition <= 12) { - selectedSize = LineWidth.Two; - } else if (dragHandlerPosition > 12 && dragHandlerPosition <= 26) { - selectedSize = LineWidth.Four; - } else if (dragHandlerPosition > 26 && dragHandlerPosition <= 40) { - selectedSize = LineWidth.Six; - } else if (dragHandlerPosition > 40 && dragHandlerPosition <= 54) { - selectedSize = LineWidth.Eight; - } else if (dragHandlerPosition > 54 && dragHandlerPosition <= 68) { - selectedSize = LineWidth.Ten; - } else { - selectedSize = LineWidth.Twelve; - } + + const { + config: { width, itemSize, count }, + lineWidths, + } = this; + const targetWidth = width - itemSize; + const halfItemSize = itemSize / 2; + const offsetX = halfItemSize + (width - itemSize * count) / (count - 1) / 2; + const selectedSize = lineWidths.findLast((_, n) => { + const cx = halfItemSize + (n / (count - 1)) * targetWidth; + return x >= cx - offsetX && x < cx + offsetX; + }); + if (!selectedSize) return; + this._updateLineWidthPanel(selectedSize); this._onSelect(selectedSize); } - override disconnectedCallback(): void { - this._disposables.dispose(); + override connectedCallback() { + super.connectedCallback(); + const { + style, + config: { width, itemSize, itemIconSize, dragHandleSize, count }, + } = this; + style.setProperty('--width', `${width}px`); + style.setProperty('--item-size', `${itemSize}px`); + style.setProperty('--item-icon-size', `${itemIconSize}px`); + style.setProperty('--drag-handle-size', `${dragHandleSize}px`); + style.setProperty('--count', `${count}`); } - override firstUpdated(): void { + override firstUpdated() { this._updateLineWidthPanel(this.selectedSize); this._disposables.addFromEvent(this, 'pointerdown', this._onPointerDown); - this._disposables.addFromEvent(this, 'pointermove', this._onPointerMove); - this._disposables.addFromEvent(this, 'pointerup', this._onPointerUp); - this._disposables.addFromEvent(this, 'pointerout', this._onPointerOut); } override render() { - return html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${this.hasTooltip - ? html`Thickness` - : nothing} -
`; + return html`
+ ${repeat( + this.lineWidths, + w => w, + (w, n) => + html`
+
+
` + )} +
+
+
+ ${this.hasTooltip + ? html`Thickness` + : nothing} +
`; } override willUpdate(changedProperties: PropertyValues) { @@ -336,27 +227,26 @@ export class EdgelessLineWidthPanel extends WithDisposable(LitElement) { } } - @query('.bottom-line') - private accessor _bottomLine!: HTMLElement; - - @query('.drag-handle') - private accessor _dragHandle!: HTMLElement; - - @queryAll('.line-width-icon') - private accessor _lineWidthIcons!: NodeListOf; - @query('.line-width-overlay') private accessor _lineWidthOverlay!: HTMLElement; - @query('.line-width-panel') - private accessor _lineWidthPanel!: HTMLElement; + accessor config: Config = { + width: 140, + itemSize: 16, + itemIconSize: 8, + dragHandleSize: 14, + count: LINE_WIDTHS.length, + }; - @property({ attribute: false }) - accessor disable = false; + @property({ attribute: false, type: Boolean }) + accessor disabled = true; @property({ attribute: false }) accessor hasTooltip = true; + @property({ attribute: false }) + accessor lineWidths: LineWidth[] = LINE_WIDTHS; + @property({ attribute: false }) accessor selectedSize: LineWidth = LineWidth.Two; } diff --git a/packages/blocks/src/root-block/edgeless/components/panel/stroke-style-panel.ts b/packages/blocks/src/root-block/edgeless/components/panel/stroke-style-panel.ts index 3dc0d7ef1a176..1b74e950ca224 100644 --- a/packages/blocks/src/root-block/edgeless/components/panel/stroke-style-panel.ts +++ b/packages/blocks/src/root-block/edgeless/components/panel/stroke-style-panel.ts @@ -1,4 +1,7 @@ -import { SHAPE_STROKE_COLORS, StrokeStyle } from '@blocksuite/affine-model'; +import { + SHAPE_STROKE_COLORS, + type StrokeStyle, +} from '@blocksuite/affine-model'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; @@ -31,7 +34,6 @@ export class StrokeStylePanel extends WithDisposable(LitElement) { selectedLineSize: this.strokeWidth, selectedLineStyle: this.strokeStyle, onClick: e => this.setStrokeStyle(e), - lineStyles: [StrokeStyle.Solid, StrokeStyle.Dash], })} `; @@ -389,7 +389,7 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { .color=${selectedStrokeColor} .colors=${colors} .colorType=${type} - .palettes=${SHAPE_STROKE_COLORS} + .palettes=${PALETTES} .hollowCircle=${true} >
this._setShapeStyles(e), - lineStyles: [StrokeStyle.Solid, StrokeStyle.Dash], })}
`} diff --git a/packages/blocks/src/root-block/widgets/pie-menu/components/pie-node-content.ts b/packages/blocks/src/root-block/widgets/pie-menu/components/pie-node-content.ts index f4ea22e02009e..092119b10cec6 100644 --- a/packages/blocks/src/root-block/widgets/pie-menu/components/pie-node-content.ts +++ b/packages/blocks/src/root-block/widgets/pie-menu/components/pie-node-content.ts @@ -4,7 +4,6 @@ import { property, query } from 'lit/decorators.js'; import type { PieNode } from '../node.js'; -import { ColorUnit } from '../../../edgeless/components/panel/color-panel.js'; import { isSubmenuNode } from '../utils.js'; const styles = css` @@ -46,7 +45,11 @@ export class PieNodeContent extends LitElement { 'IPieSubMenuNode.role with color-picker should have children of type color' ); const { color, hollowCircle } = hoveredNode.model; - return ColorUnit(color, { hollowCircle }); + return html``; } const { label } = model; diff --git a/packages/blocks/src/root-block/widgets/pie-menu/pie-builder.ts b/packages/blocks/src/root-block/widgets/pie-menu/pie-builder.ts index ec211ab750591..6b5ee411d2d20 100644 --- a/packages/blocks/src/root-block/widgets/pie-menu/pie-builder.ts +++ b/packages/blocks/src/root-block/widgets/pie-menu/pie-builder.ts @@ -1,4 +1,5 @@ import { assertExists } from '@blocksuite/global/utils'; +import { html } from 'lit'; import type { ActionFunction, @@ -10,7 +11,6 @@ import type { PieSubmenuNodeModel, } from './base.js'; -import { ColorUnit } from '../../edgeless/components/panel/color-panel.js'; import { PieManager } from './pie-manager.js'; import { calcNodeAngles, calcNodeWedges, isNodeWithChildren } from './utils.js'; @@ -118,7 +118,11 @@ export class PieMenuBuilder { const icon = (ctx: PieMenuContext) => { const color = props.active(ctx); - return ColorUnit(color, { hollowCircle: hollow }); + return html``; }; const colorPickerNode: PieSubmenuNodeModel = { @@ -128,7 +132,12 @@ export class PieMenuBuilder { role: 'color-picker', openOnHover: props.openOnHover ?? true, children: props.colors.map(({ color }) => ({ - icon: () => ColorUnit(color, { hollowCircle: hollow }), + icon: () => + html``, type: 'color', hollowCircle: hollow, label: color,