diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-item/ai-item-list.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-item/ai-item-list.ts index af10ff413..ae4efe57a 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-item/ai-item-list.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-item/ai-item-list.ts @@ -1,5 +1,6 @@ import { createLitPortal } from '@blocksuite/affine/components/portal'; import { WithDisposable } from '@blocksuite/affine/global/lit'; +import { ColorScheme } from '@blocksuite/affine/model'; import { EditorHost, PropTypes, @@ -123,6 +124,7 @@ export class AIItemList extends WithDisposable(LitElement) { item => item.name, item => html` e.stopPropagation()} @click=${() => { @@ -59,6 +61,9 @@ export class AIItem extends WithDisposable(LitElement) { @property({ attribute: false }) accessor onClick: (() => void) | undefined; + + @property({ attribute: false }) + accessor theme: ColorScheme = ColorScheme.Light; } declare global { diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-item/styles.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-item/styles.ts index 75236710e..4ffb5a416 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-item/styles.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-item/styles.ts @@ -1,4 +1,10 @@ -import { css } from 'lit'; +import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme'; +import { darkCssVariables, lightCssVariables } from '@toeverything/theme'; +import { + darkCssVariablesV2, + lightCssVariablesV2, +} from '@toeverything/theme/v2'; +import { css, unsafeCSS } from 'lit'; export const menuItemStyles = css` .menu-item { @@ -13,36 +19,41 @@ export const menuItemStyles = css` border-radius: 4px; box-sizing: border-box; } + .menu-item:hover { - background: var(--affine-hover-color); + background: ${unsafeCSSVar('--affine-hover-color')}; cursor: pointer; } + .item-icon { display: flex; - color: var(--item-icon-color, var(--affine-brand-color)); + color: ${unsafeCSSVar('--affine-brand-color')}; svg { width: 20px; height: 20px; } } + .menu-item:hover .item-icon { - color: var(--item-icon-hover-color, var(--affine-brand-color)); + color: ${unsafeCSSVar('--affine-brand-color')}; } + .menu-item.discard:hover { - background: var(--affine-background-error-color); + background: ${unsafeCSSVar('--affine-background-error-color')}; .item-name, .item-icon, .enter-icon { - color: var(--affine-error-color); + color: ${unsafeCSSVar('--affine-error-color')}; } } + .item-name { display: flex; padding: 0px 4px; align-items: baseline; flex: 1 0 0; - color: var(--affine-text-primary-color); + color: ${unsafeCSSVarV2('text/primary')}; text-align: start; white-space: nowrap; font-feature-settings: @@ -55,7 +66,7 @@ export const menuItemStyles = css` } .item-beta { - color: var(--affine-text-secondary-color); + color: ${unsafeCSSVarV2('text/secondary')}; font-size: var(--affine-font-xs); font-weight: 500; margin-left: 0.5em; @@ -63,14 +74,66 @@ export const menuItemStyles = css` .enter-icon, .arrow-right-icon { - color: var(--affine-icon-color); + color: ${unsafeCSSVarV2('icon/primary')}; display: flex; } + .enter-icon { opacity: 0; } + .arrow-right-icon, .menu-item:hover .enter-icon { opacity: 1; } + + .menu-item[data-app-theme='light'] { + .item-name { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-text-primary'])}; + } + + .item-beta { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-text-secondary'])}; + } + + .enter-icon, + .arrow-right-icon { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-icon-primary'])}; + } + } + + .menu-item[data-app-theme='light']:hover { + background: ${unsafeCSS(lightCssVariables['--affine-hover-color'])}; + } + + .menu-item.discard[data-app-theme='light']:hover { + background: ${unsafeCSS( + lightCssVariables['--affine-background-error-color'] + )}; + } + + .menu-item[data-app-theme='dark'] { + .item-name { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-text-primary'])}; + } + + .item-beta { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-text-secondary'])}; + } + + .enter-icon, + .arrow-right-icon { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-icon-primary'])}; + } + } + + .menu-item[data-app-theme='dark']:hover { + background: ${unsafeCSS(darkCssVariables['--affine-hover-color'])}; + } + + .menu-item.discard[data-app-theme='dark']:hover { + background: ${unsafeCSS( + darkCssVariables['--affine-background-error-color'] + )}; + } `; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ask-ai-panel.ts b/packages/frontend/core/src/blocksuite/ai/components/ask-ai-panel.ts index 2d9e4777d..20fa7abd6 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ask-ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ask-ai-panel.ts @@ -1,5 +1,8 @@ import { WithDisposable } from '@blocksuite/affine/global/lit'; -import { DocModeProvider } from '@blocksuite/affine/shared/services'; +import { + DocModeProvider, + ThemeProvider, +} from '@blocksuite/affine/shared/services'; import { scrollbarStyle } from '@blocksuite/affine/shared/styles'; import { type EditorHost } from '@blocksuite/affine/std'; import { cssVar } from '@toeverything/theme'; @@ -70,12 +73,23 @@ export class AskAIPanel extends WithDisposable(LitElement) { return filteredConfig; } + override connectedCallback() { + super.connectedCallback(); + this.disposables.add( + this.host.std.get(ThemeProvider).app$.subscribe(() => { + this.requestUpdate(); + }) + ); + } + override render() { const style = styleMap({ minWidth: `${this.minWidth}px`, }); + const appTheme = this.host.std.get(ThemeProvider).app$.value; return html`
{ + this.appTheme = theme; + this.requestUpdate(); + }) + ); this.tabIndex = -1; // No need to synchronize the contents of the input into the editor. @@ -460,7 +486,7 @@ export class AffineAIPanelWidget extends WidgetComponent { if (!this.config) return nothing; const config = this.config; - const theme = this.std.get(ThemeProvider).theme; + const theme = this.std.get(ThemeProvider).app$.value; const mainTemplate = choose(this.state, [ [ 'input', @@ -470,6 +496,7 @@ export class AffineAIPanelWidget extends WidgetComponent { .onFinish=${this._inputFinish} .onInput=${this.onInput} .networkSearchConfig=${config.networkSearchConfig} + .theme=${theme} >`, ], [ @@ -564,6 +591,9 @@ export class AffineAIPanelWidget extends WidgetComponent { @property() accessor state: AffineAIPanelState = 'hidden'; + + @property({ attribute: 'data-app-theme', reflect: true }) + accessor appTheme: ColorScheme = ColorScheme.Light; } export const aiPanelWidget = WidgetViewExtension( diff --git a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/components/state/input.ts b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/components/state/input.ts index cebc13178..89d07e221 100644 --- a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/components/state/input.ts +++ b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/components/state/input.ts @@ -1,9 +1,14 @@ import { AIStarIcon } from '@blocksuite/affine/components/icons'; import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit'; +import { ColorScheme } from '@blocksuite/affine/model'; import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme'; import { stopPropagation } from '@blocksuite/affine/shared/utils'; import { PublishIcon, SendIcon } from '@blocksuite/icons/lit'; -import { css, html, LitElement, nothing } from 'lit'; +import { + darkCssVariablesV2, + lightCssVariablesV2, +} from '@toeverything/theme/v2'; +import { css, html, LitElement, nothing, unsafeCSS } from 'lit'; import { property, query, state } from 'lit/decorators.js'; import type { AINetworkSearchConfig } from '../../type'; @@ -20,7 +25,6 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { display: flex; align-items: flex-start; gap: 8px; - background: var(--affine-background-overlay-panel-color); } .star { @@ -47,7 +51,7 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { overflow: hidden; padding: 0px; - color: var(--affine-text-primary-color); + color: ${unsafeCSSVarV2('text/primary')}; /* light/sm */ font-family: var(--affine-font-family); @@ -58,11 +62,11 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { } textarea::placeholder { - color: var(--affine-placeholder-color); + color: ${unsafeCSSVarV2('text/placeholder')}; } textarea::-moz-placeholder { - color: var(--affine-placeholder-color); + color: ${unsafeCSSVarV2('text/placeholder')}; } } @@ -79,12 +83,15 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { color: ${unsafeCSSVarV2('button/pureWhiteText')}; } } + .arrow[data-active] { background: ${unsafeCSSVarV2('icon/activated')}; } + .arrow[data-active]:hover { cursor: pointer; } + .network { display: flex; align-items: center; @@ -97,9 +104,90 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { color: ${unsafeCSSVarV2('icon/primary')}; } } + .network[data-active='true'] svg { color: ${unsafeCSSVarV2('icon/activated')}; } + + :host([data-app-theme='light']) { + .network svg { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-icon-primary'])}; + } + + .network[data-active='true'] svg { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-icon-activated'])}; + } + + textarea { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-text-primary'])}; + } + + textarea::placeholder { + color: ${unsafeCSS( + lightCssVariablesV2['--affine-v2-text-placeholder'] + )}; + } + + textarea::-moz-placeholder { + color: ${unsafeCSS( + lightCssVariablesV2['--affine-v2-text-placeholder'] + )}; + } + + .arrow { + background: ${unsafeCSS( + lightCssVariablesV2['--affine-v2-icon-disable'] + )}; + } + + .arrow[data-active] { + background: ${unsafeCSS( + lightCssVariablesV2['--affine-v2-icon-activated'] + )}; + } + + .arrow svg { + color: ${unsafeCSS(lightCssVariablesV2['--affine-v2-pure-white-text'])}; + } + } + + :host([data-app-theme='dark']) { + .network svg { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-icon-primary'])}; + } + + .network[data-active='true'] svg { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-icon-activated'])}; + } + + textarea { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-text-primary'])}; + } + + textarea::placeholder { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-text-placeholder'])}; + } + + textarea::-moz-placeholder { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-text-placeholder'])}; + } + + .arrow { + background: ${unsafeCSS( + darkCssVariablesV2['--affine-v2-icon-disable'] + )}; + } + + .arrow[data-active] { + background: ${unsafeCSS( + darkCssVariablesV2['--affine-v2-icon-activated'] + )}; + } + + .arrow svg { + color: ${unsafeCSS(darkCssVariablesV2['--affine-v2-pure-white-text'])}; + } + } `; private readonly _onInput = () => { @@ -209,6 +297,9 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) { @property({ attribute: false }) accessor onInput: ((input: string) => void) | undefined = undefined; + @property({ attribute: 'data-app-theme', reflect: true }) + accessor theme: ColorScheme = ColorScheme.Light; + @query('textarea') accessor textarea!: HTMLTextAreaElement; } diff --git a/packages/frontend/core/src/blocksuite/ai/widgets/edgeless-copilot-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/widgets/edgeless-copilot-panel/index.ts index 90b448d72..8b1914c74 100644 --- a/packages/frontend/core/src/blocksuite/ai/widgets/edgeless-copilot-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/ai/widgets/edgeless-copilot-panel/index.ts @@ -1,8 +1,11 @@ import { WithDisposable } from '@blocksuite/affine/global/lit'; +import { ThemeProvider } from '@blocksuite/affine/shared/services'; import { scrollbarStyle } from '@blocksuite/affine/shared/styles'; +import { unsafeCSSVar } from '@blocksuite/affine/shared/theme'; import { on, stopPropagation } from '@blocksuite/affine/shared/utils'; import type { EditorHost } from '@blocksuite/affine/std'; -import { css, html, LitElement, nothing } from 'lit'; +import { darkCssVariables, lightCssVariables } from '@toeverything/theme'; +import { css, html, LitElement, nothing, unsafeCSS } from 'lit'; import { property } from 'lit/decorators.js'; import type { AIItemGroupConfig } from '../../components/ai-item/types'; @@ -20,16 +23,44 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) { min-width: 330px; max-height: 374px; overflow-y: auto; - background: var(--affine-background-overlay-panel-color); - box-shadow: var(--affine-shadow-2); + background: ${unsafeCSSVar('--affine-background-overlay-panel-color')}; + box-shadow: ${unsafeCSSVar('--affine-overlay-shadow')}; border-radius: 8px; z-index: var(--affine-z-index-popover); } + .edgeless-copilot-panel[data-app-theme='light'] { + background: ${unsafeCSS( + lightCssVariables['--affine-background-overlay-panel-color'] + )}; + + box-shadow: ${unsafeCSS(lightCssVariables['--affine-overlay-shadow'])}; + } + + .edgeless-copilot-panel[data-app-theme='dark'] { + background: ${unsafeCSS( + darkCssVariables['--affine-background-overlay-panel-color'] + )}; + + box-shadow: ${unsafeCSS(darkCssVariables['--affine-overlay-shadow'])}; + } + + .edgeless-copilot-panel[data-app-theme='dark'] ai-item { + background: blue; + } + ${scrollbarStyle('.edgeless-copilot-panel')} .edgeless-copilot-panel:hover::-webkit-scrollbar-thumb { background-color: var(--affine-black-30); } + + .edgeless-copilot-panel[data-app-theme='light']:hover::-webkit-scrollbar-thumb { + background-color: ${unsafeCSS(lightCssVariables['--affine-black30'])}; + } + + .edgeless-copilot-panel[data-app-theme='dark']:hover::-webkit-scrollbar-thumb { + background-color: ${unsafeCSS(darkCssVariables['--affine-black30'])}; + } `; private _getChain() { @@ -40,6 +71,11 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) { super.connectedCallback(); this._disposables.add(on(this, 'wheel', stopPropagation)); this._disposables.add(on(this, 'pointerdown', stopPropagation)); + this.disposables.add( + this.host.std.get(ThemeProvider).app$.subscribe(() => { + this.requestUpdate(); + }) + ); } hide() { @@ -47,6 +83,7 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) { } override render() { + const appTheme = this.host.std.get(ThemeProvider).app$.value; const chain = this._getChain(); const groups = this.groups.reduce((pre, group) => { const filtered = group.items.filter(item => @@ -61,8 +98,9 @@ export class EdgelessCopilotPanel extends WithDisposable(LitElement) { if (groups.every(group => group.items.length === 0)) return nothing; return html` -
+
{ this.onClick?.(); }}