feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type SchemaDecoration } from '@flowgram-adapter/common';
|
||||
|
||||
import { type ColorService } from './color-service';
|
||||
|
||||
interface PreferenceSchema {
|
||||
properties: Record<string, SchemaDecoration>;
|
||||
}
|
||||
|
||||
interface ColorContribution {
|
||||
registerColors: (colors: ColorService) => void;
|
||||
}
|
||||
|
||||
const ColorContribution = Symbol('ColorContribution');
|
||||
|
||||
export { ColorContribution, type PreferenceSchema };
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { inject, injectable, named } from 'inversify';
|
||||
import {
|
||||
Disposable,
|
||||
type SchemaDecoration,
|
||||
ContributionProvider,
|
||||
} from '@flowgram-adapter/common';
|
||||
|
||||
import { type ColorDefinition, type ThemeType } from '../types';
|
||||
import { ColorContribution } from './color-contribution';
|
||||
|
||||
type ColorSchemaType = SchemaDecoration & {
|
||||
properties: {
|
||||
[key: string]: SchemaDecoration;
|
||||
};
|
||||
};
|
||||
|
||||
@injectable()
|
||||
class ColorService {
|
||||
@inject(ContributionProvider)
|
||||
@named(ColorContribution)
|
||||
colorContributions: ContributionProvider<ColorContribution>;
|
||||
|
||||
/** 颜色表 */
|
||||
private colors: Record<string, ColorDefinition> = {};
|
||||
|
||||
/** 颜色的 schema */
|
||||
private schema: ColorSchemaType = { type: 'object', properties: {} };
|
||||
|
||||
/** 颜色偏好设置的 schema */
|
||||
// private referenceSchema = { type: 'string', enum: [], enumDescriptions: [] };
|
||||
|
||||
init() {
|
||||
this.colorContributions.getContributions().forEach(contribution => {
|
||||
contribution.registerColors(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量注册 color
|
||||
*/
|
||||
register(...colors: ColorDefinition[]): Disposable[] {
|
||||
return colors.map(definition => {
|
||||
const { id } = definition;
|
||||
this.colors[id] = definition;
|
||||
this.schema.properties[id] = {
|
||||
type: 'string',
|
||||
description: definition.description,
|
||||
};
|
||||
return Disposable.create(() => this.deregisterColor(id));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销 color
|
||||
*/
|
||||
deregisterColor(id: string): void {
|
||||
delete this.colors[id];
|
||||
delete this.schema.properties[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的 color definition
|
||||
*/
|
||||
getColors(): ColorDefinition[] {
|
||||
return Object.keys(this.colors).map(id => this.colors[id]);
|
||||
}
|
||||
|
||||
getColor(id: string) {
|
||||
return this.colors[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定 theme 的 color value
|
||||
*/
|
||||
getThemeColor(id: string, themeType: ThemeType) {
|
||||
const color = this.getColor(id);
|
||||
let value = color.defaults?.[themeType];
|
||||
// 色值可以从其他色值继承
|
||||
if (
|
||||
value &&
|
||||
typeof value === 'string' &&
|
||||
!value.startsWith('#') &&
|
||||
!value?.startsWith('rgb')
|
||||
) {
|
||||
const parentColor = this.colors[value];
|
||||
value = parentColor?.defaults?.[themeType];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
toCssColor(id: string, themeType: ThemeType) {
|
||||
// 转换为变量名
|
||||
const variableName = `--${id.replace(/\./g, '-')}`;
|
||||
const value = this.getThemeColor(id, themeType);
|
||||
return `${variableName}: ${value};`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有色值转化为 css 变量
|
||||
*/
|
||||
toCss(themeType: ThemeType) {
|
||||
return `body {\n${this.getColors()
|
||||
.map(color => this.toCssColor(color.id, themeType))
|
||||
.join('\n')}\n}`;
|
||||
}
|
||||
}
|
||||
|
||||
export { ColorService };
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ColorDefinition } from '../../types';
|
||||
|
||||
// white
|
||||
const baseWhite: ColorDefinition = {
|
||||
id: 'flowide.color.base.white',
|
||||
defaults: {
|
||||
dark: 'rgba(255, 255, 255)',
|
||||
light: 'rgba(255, 255, 255)',
|
||||
},
|
||||
};
|
||||
|
||||
// background
|
||||
const baseBg0: ColorDefinition = {
|
||||
id: 'flowide.color.base.bg.0',
|
||||
defaults: {
|
||||
dark: 'rgba(22, 22, 26, 1)',
|
||||
light: 'rgba(255, 255, 255)',
|
||||
},
|
||||
};
|
||||
const baseBg1: ColorDefinition = {
|
||||
id: 'flowide.color.base.bg.1',
|
||||
defaults: {
|
||||
dark: 'rgba(35, 36, 41, 1)',
|
||||
light: 'rgba(255, 255, 255)',
|
||||
},
|
||||
};
|
||||
const baseBg2: ColorDefinition = {
|
||||
id: 'flowide.color.base.bg.2',
|
||||
defaults: {
|
||||
dark: 'rgba(53, 54, 60, 1)',
|
||||
light: 'rgba(255, 255, 255)',
|
||||
},
|
||||
};
|
||||
|
||||
// text
|
||||
const baseText0: ColorDefinition = {
|
||||
id: 'flowide.color.base.text.0',
|
||||
defaults: {
|
||||
dark: 'rgba(249,249,249)',
|
||||
light: 'rgba(28,31,35)',
|
||||
},
|
||||
};
|
||||
const baseText1: ColorDefinition = {
|
||||
id: 'flowide.color.base.text.1',
|
||||
defaults: {
|
||||
dark: 'rgba(249,249,249, 0.8)',
|
||||
light: 'rgba(28,31,35, 0.8)',
|
||||
},
|
||||
};
|
||||
const baseText2: ColorDefinition = {
|
||||
id: 'flowide.color.base.text.2',
|
||||
defaults: {
|
||||
dark: 'rgba(249,249,249, 0.6)',
|
||||
light: 'rgba(28,31,35, 0.62)',
|
||||
},
|
||||
};
|
||||
|
||||
// border color
|
||||
const baseBorder: ColorDefinition = {
|
||||
id: 'flowide.color.base.border',
|
||||
defaults: {
|
||||
dark: 'rgba(255, 255, 255, 0.08)',
|
||||
light: 'rgba(28,31,35, 0.08)',
|
||||
},
|
||||
};
|
||||
|
||||
// menu color
|
||||
const menuBorder: ColorDefinition = {
|
||||
id: 'flowide.color.menu.border',
|
||||
defaults: {
|
||||
dark: '#454545',
|
||||
light: 'unset',
|
||||
},
|
||||
};
|
||||
|
||||
// menu box shadow color
|
||||
const menuBoxShadow: ColorDefinition = {
|
||||
id: 'flowide.color.menu.box.shadow',
|
||||
defaults: {
|
||||
dark: 'rgba(0, 0, 0, 0.36)',
|
||||
light: 'rgba(0, 0, 0, 0.16)',
|
||||
},
|
||||
};
|
||||
|
||||
// fill color
|
||||
const baseFill0: ColorDefinition = {
|
||||
id: 'flowide.color.base.fill.0',
|
||||
defaults: {
|
||||
dark: 'rgba(255,255,255, 0.12)',
|
||||
light: 'rgba(46,50,56, 0.05)',
|
||||
},
|
||||
};
|
||||
const baseFill1: ColorDefinition = {
|
||||
id: 'flowide.color.base.fill.1',
|
||||
defaults: {
|
||||
dark: 'rgba(255,255,255, 0.16)',
|
||||
light: 'rgba(46,50,56, 0.09)',
|
||||
},
|
||||
};
|
||||
const baseFill2: ColorDefinition = {
|
||||
id: 'flowide.color.base.fill.2',
|
||||
defaults: {
|
||||
dark: 'rgba(255,255,255, 0.2)',
|
||||
light: 'rgba(46,50,56, 0.05)',
|
||||
},
|
||||
};
|
||||
|
||||
// primary
|
||||
const basePrimary: ColorDefinition = {
|
||||
id: 'flowide.color.base.primary',
|
||||
defaults: {
|
||||
dark: 'rgb(84,169,255)',
|
||||
light: 'rgb(0,100,250)',
|
||||
},
|
||||
};
|
||||
const basePrimaryHover: ColorDefinition = {
|
||||
id: 'flowide.color.base.primary.hover',
|
||||
defaults: {
|
||||
dark: 'rgb(127,193,255)',
|
||||
light: 'rgb(0,98,214)',
|
||||
},
|
||||
};
|
||||
|
||||
export {
|
||||
baseWhite,
|
||||
baseBg0,
|
||||
baseBg1,
|
||||
baseBg2,
|
||||
baseText0,
|
||||
baseText1,
|
||||
baseText2,
|
||||
baseBorder,
|
||||
menuBorder,
|
||||
menuBoxShadow,
|
||||
baseFill0,
|
||||
baseFill1,
|
||||
baseFill2,
|
||||
basePrimary,
|
||||
basePrimaryHover,
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { viewColors } from './view-colors';
|
||||
import * as baseColors from './base-colors';
|
||||
|
||||
const colors = [...Object.values(baseColors), ...viewColors];
|
||||
|
||||
export { colors };
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { baseBg0 } from './base-colors';
|
||||
|
||||
const viewColors = [
|
||||
{
|
||||
id: 'flowide.color.view.topBar.bg',
|
||||
defaults: {
|
||||
light: baseBg0.id,
|
||||
dark: baseBg0.id,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export { viewColors };
|
||||
19
frontend/packages/project-ide/core/src/styles/color/index.ts
Normal file
19
frontend/packages/project-ide/core/src/styles/color/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ColorService } from './color-service';
|
||||
export { ColorContribution } from './color-contribution';
|
||||
export { colors } from './colors';
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { bindContributions, bindContributionProvider } from '@flowgram-adapter/common';
|
||||
|
||||
import { definePluginCreator, LifecycleContribution } from '../common';
|
||||
import { ThemeService } from './theme';
|
||||
import { StylingService, StylingContribution } from './styling';
|
||||
import { StylesContribution } from './styles-contribution';
|
||||
import { ColorService, ColorContribution } from './color';
|
||||
|
||||
const createStylesPlugin = definePluginCreator({
|
||||
onBind({ bind }) {
|
||||
// service
|
||||
bind(ThemeService).toSelf().inSingletonScope();
|
||||
bind(StylingService).toSelf().inSingletonScope();
|
||||
bind(ColorService).toSelf().inSingletonScope();
|
||||
// provider
|
||||
bindContributionProvider(bind, StylingContribution);
|
||||
bindContributionProvider(bind, ColorContribution);
|
||||
// contribution
|
||||
bindContributions(bind, StylesContribution, [
|
||||
LifecycleContribution,
|
||||
StylingContribution,
|
||||
ColorContribution,
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
export { createStylesPlugin };
|
||||
25
frontend/packages/project-ide/core/src/styles/index.ts
Normal file
25
frontend/packages/project-ide/core/src/styles/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { createStylesPlugin } from './create-styles-plugin';
|
||||
export {
|
||||
StylingContribution,
|
||||
type Collector,
|
||||
type ColorTheme,
|
||||
StylingService,
|
||||
} from './styling';
|
||||
export { ThemeService } from './theme';
|
||||
export { ColorService } from './color';
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { Deferred, logger } from '@flowgram-adapter/common';
|
||||
|
||||
import { type LifecycleContribution } from '../common';
|
||||
import { ThemeService } from './theme';
|
||||
import {
|
||||
type StylingContribution,
|
||||
StylingService,
|
||||
type Collector,
|
||||
type ColorTheme,
|
||||
} from './styling';
|
||||
import { type ColorContribution, ColorService, colors } from './color';
|
||||
|
||||
@injectable()
|
||||
class StylesContribution
|
||||
implements LifecycleContribution, ColorContribution, StylingContribution
|
||||
{
|
||||
private ready = new Deferred<void>();
|
||||
|
||||
registerColors(colorService: ColorService) {
|
||||
colorService.register(...colors);
|
||||
}
|
||||
|
||||
registerStyle({ add }: Collector, { type }: ColorTheme) {
|
||||
add(this.colorService.toCss(type));
|
||||
}
|
||||
|
||||
@inject(ColorService)
|
||||
protected readonly colorService: ColorService;
|
||||
|
||||
@inject(ThemeService)
|
||||
protected readonly themeService: ThemeService;
|
||||
|
||||
@inject(StylingService)
|
||||
protected readonly stylingService: StylingService;
|
||||
|
||||
async onLoading() {
|
||||
this.colorService.init();
|
||||
this.themeService.onDidThemeChange(e => {
|
||||
this.stylingService.apply(e.next);
|
||||
this.ready.resolve();
|
||||
});
|
||||
this.themeService.init();
|
||||
await this.ready.promise;
|
||||
logger.log('theme loaded');
|
||||
}
|
||||
|
||||
onDispose(): void {
|
||||
this.themeService.dispose();
|
||||
this.stylingService.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export { StylesContribution };
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { StylingService } from './styling-service';
|
||||
export {
|
||||
StylingContribution,
|
||||
type Collector,
|
||||
type ColorTheme,
|
||||
} from './styling-contribution';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type Theme } from '../types';
|
||||
|
||||
interface Collector {
|
||||
prefix: string;
|
||||
add: (rule: string) => void;
|
||||
}
|
||||
type ColorTheme = Pick<Theme, 'type' | 'label'> & {
|
||||
getColor: (id: string) => string;
|
||||
};
|
||||
|
||||
interface StylingContribution {
|
||||
registerStyle: (collector: Collector, theme: ColorTheme) => void;
|
||||
}
|
||||
const StylingContribution = Symbol('StylingContribution');
|
||||
|
||||
export { type Collector, type ColorTheme, StylingContribution };
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { injectable, inject, named } from 'inversify';
|
||||
import {
|
||||
ContributionProvider,
|
||||
DecorationStyle,
|
||||
Disposable,
|
||||
} from '@flowgram-adapter/common';
|
||||
|
||||
import { type Theme } from '../types';
|
||||
import { ThemeService } from '../theme/theme-service';
|
||||
import { ColorService } from '../color';
|
||||
import {
|
||||
StylingContribution,
|
||||
type ColorTheme,
|
||||
type Collector,
|
||||
} from './styling-contribution';
|
||||
|
||||
@injectable()
|
||||
class StylingService {
|
||||
@inject(ThemeService)
|
||||
protected readonly themeService: ThemeService;
|
||||
|
||||
@inject(ColorService)
|
||||
protected readonly colorService: ColorService;
|
||||
|
||||
@inject(ContributionProvider)
|
||||
@named(StylingContribution)
|
||||
protected readonly stylingContributions: ContributionProvider<StylingContribution>;
|
||||
|
||||
static readonly PREFIX = 'flowide';
|
||||
|
||||
/**
|
||||
* 后面移到 map 里面,现在暂时没想好
|
||||
*/
|
||||
private cssElement: HTMLStyleElement | undefined;
|
||||
|
||||
private css = new Map<string, HTMLStyleElement>();
|
||||
|
||||
/**
|
||||
* 收集所有 css 挂载到 <head> 上
|
||||
*/
|
||||
apply(theme: Theme) {
|
||||
const rules: string[] = [];
|
||||
const colorTheme: ColorTheme = {
|
||||
type: theme.type,
|
||||
label: theme.label,
|
||||
getColor: id => this.colorService.getThemeColor(id, theme.type),
|
||||
};
|
||||
const collector: Collector = {
|
||||
prefix: StylingService.PREFIX,
|
||||
add: rule => rules.push(rule),
|
||||
};
|
||||
const cssElement = DecorationStyle.createStyleElement('flowide-styles');
|
||||
|
||||
this.stylingContributions
|
||||
.getContributions()
|
||||
.forEach(stylingContribution => {
|
||||
stylingContribution.registerStyle(collector, colorTheme);
|
||||
});
|
||||
const css = rules.join('\n');
|
||||
cssElement.innerHTML = css;
|
||||
|
||||
this.clear();
|
||||
this.cssElement = cssElement;
|
||||
|
||||
return Disposable.create(() => {
|
||||
this.clear();
|
||||
});
|
||||
}
|
||||
|
||||
register(id: string, css: string) {
|
||||
const el = this.css.get(id) || DecorationStyle.createStyleElement(id);
|
||||
el.innerHTML = css;
|
||||
this.css.set(id, el);
|
||||
return Disposable.create(() => {
|
||||
document.head.removeChild(el);
|
||||
this.css.delete(id);
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.cssElement) {
|
||||
document.head.removeChild(this.cssElement);
|
||||
this.cssElement = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export { StylingService };
|
||||
17
frontend/packages/project-ide/core/src/styles/theme/index.ts
Normal file
17
frontend/packages/project-ide/core/src/styles/theme/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ThemeService } from './theme-service';
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { Emitter, type Event, Disposable } from '@flowgram-adapter/common';
|
||||
|
||||
import { type Theme } from '../types';
|
||||
import { PreferencesManager } from '../../preference';
|
||||
|
||||
interface ThemeDidChangeEvent {
|
||||
readonly next: Theme;
|
||||
readonly prev: Theme;
|
||||
}
|
||||
|
||||
const DEFAULT_THEME: Theme = {
|
||||
id: 'flowide',
|
||||
type: 'dark',
|
||||
label: 'flow ide default theme',
|
||||
};
|
||||
const DEFAULT_LIGHT_THEME: Theme = {
|
||||
id: 'flowide',
|
||||
type: 'light',
|
||||
label: 'flow ide default theme',
|
||||
};
|
||||
|
||||
@injectable()
|
||||
class ThemeService {
|
||||
@inject(PreferencesManager)
|
||||
protected readonly preferencesManager: PreferencesManager;
|
||||
|
||||
/** 所有注册的 theme */
|
||||
private themes: Map<string, Theme> = new Map([
|
||||
[DEFAULT_THEME.type, DEFAULT_THEME],
|
||||
[DEFAULT_LIGHT_THEME.type, DEFAULT_LIGHT_THEME],
|
||||
]);
|
||||
|
||||
/** 当前 theme */
|
||||
private current: Theme = DEFAULT_THEME;
|
||||
|
||||
private readonly themeChange = new Emitter<ThemeDidChangeEvent>();
|
||||
|
||||
readonly onDidThemeChange: Event<ThemeDidChangeEvent> =
|
||||
this.themeChange.event;
|
||||
|
||||
init() {
|
||||
this.changeWithPreferences();
|
||||
// 先手动触发一次 change 模拟从 preference 读取配置
|
||||
this.preferencesManager.onDidPreferencesChange(() => {
|
||||
this.changeWithPreferences();
|
||||
});
|
||||
}
|
||||
|
||||
changeWithPreferences() {
|
||||
const type =
|
||||
this.preferencesManager.getPreferenceData('theme') || DEFAULT_THEME.type;
|
||||
this.themeChange.fire({
|
||||
next: {
|
||||
...DEFAULT_THEME,
|
||||
type,
|
||||
},
|
||||
prev: this.current,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 theme
|
||||
*/
|
||||
register(...themes: Theme[]) {
|
||||
themes.forEach(theme => this.themes.set(theme.id, theme));
|
||||
return Disposable.create(() => {
|
||||
themes.forEach(theme => {
|
||||
if (theme && theme === this.current) {
|
||||
this.setCurrent(DEFAULT_THEME.id);
|
||||
}
|
||||
this.themes.delete(theme.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setCurrent(themeId: string): void {
|
||||
const next = this.themes.get(themeId);
|
||||
const prev = this.current;
|
||||
if (next && next !== prev) {
|
||||
this.current = next;
|
||||
this.themeChange.fire({ next, prev });
|
||||
}
|
||||
}
|
||||
|
||||
getCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.themeChange.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export { ThemeService };
|
||||
42
frontend/packages/project-ide/core/src/styles/types.ts
Normal file
42
frontend/packages/project-ide/core/src/styles/types.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* theme
|
||||
*/
|
||||
type ThemeType = 'light' | 'dark';
|
||||
|
||||
interface Theme {
|
||||
readonly id: string;
|
||||
readonly type: ThemeType;
|
||||
readonly label: string;
|
||||
readonly description?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* color
|
||||
*/
|
||||
type Color = string;
|
||||
|
||||
type ColorDefaults = Required<Record<ThemeType, Color>>;
|
||||
|
||||
interface ColorDefinition {
|
||||
id: string;
|
||||
defaults: ColorDefaults;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type { ThemeType, Theme, Color, ColorDefaults, ColorDefinition };
|
||||
Reference in New Issue
Block a user