feat: 新增主题编辑器示例 (#4047)

This commit is contained in:
吴多益 2022-04-14 19:13:35 +08:00 committed by GitHub
parent 8bd421b3b1
commit 534dc7552a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1283 additions and 10 deletions

View File

@ -513,7 +513,7 @@ order: 9
**动作属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ---------- | -------- | --------- | -------------- |
| ---------- | -------- | --------------- | -------------- |
| actionType | `string` | `confirmDialog` | 打开确认对话框 |
| title | `string` | - | 对话框标题 |
| msg | `string` | - | 对话框提示内容 |
@ -1819,6 +1819,12 @@ order: 9
}
```
如果是在 js 中也能直接写函数,这个函数可以接收到 3 个参数,分别是:
- context上下文信息
- doAction 方法,用于调用其它动作
- event事件传递的数据以及可以禁止
**动作属性**
| 属性名 | 类型 | 默认值 | 说明 |

View File

@ -2,6 +2,8 @@
title: CSS 变量
---
目前示例中包含了一个[主题编辑器](../../examples/theme),可以在线实时预览效果。
要想使用 CSS 变量就必须知道某个组件都用到了哪些变量,目前最完善的方式是用 Chrome 开发者工具。
不过如果你不知道如何使用,本文将会介绍一些常用的 CSS 变量,掌握他们也能完成大部分定制工作。
@ -78,5 +80,5 @@ title: CSS 变量
## 图片
| 变量 | 类型 | 说明 |
| -------------------- | ---- | ------------------------------------------------ |
| ------------ | ---------- | ---------------------------------- |
| --Spinner-bg | background | 加载时的图片 url('data:image/...') |

View File

@ -2,6 +2,8 @@
title: 快速开始
---
示例有个[主题编辑器](../../examples/theme),可以在线实时预览效果。
> 这是 1.1.0 版本中新增的功能
在 amis 中自定义样式有四种方式:

View File

@ -98,13 +98,14 @@ import ServicesDataSchema from './Services/Data';
import ServicesSchemaSchema from './Services/Schema';
import ServicesFormSchema from './Services/Form';
import IFrameSchema from './IFrame';
import ThemeSchema from './Theme';
import NormalTabSchema from './Tabs/Normal';
import FormTabSchema from './Tabs/Form';
import DynamicTabSchema from './Tabs/Dynamic';
import Tab1Schema from './Tabs/Tab1';
import Tab2Schema from './Tabs/Tab2';
import Tab3Schema from './Tabs/Tab3';
import TestComponent from './Test';
import {normalizeLink} from '../../src/utils/normalizeLink';
@ -655,6 +656,13 @@ export const examples = [
]
},
{
label: '主题编辑器',
icon: 'fa fa-glasses',
path: '/examples/theme',
component: makeSchemaRenderer(ThemeSchema)
},
{
label: '向导',
icon: 'fa fa-desktop',

View File

@ -0,0 +1,232 @@
import From from './theme/form';
import {
colorControls,
fontControls,
sizeControls,
borderControls,
linkControls
} from './theme/vars';
import CRUD from './theme/crud';
function updateTheme(theme: any) {
let varStyleTag = document.getElementById('customVars');
if (!varStyleTag) {
varStyleTag = document.createElement('style');
varStyleTag.id = 'customVars';
document.body.appendChild(varStyleTag);
}
const vars = [];
const names = new Set();
for (const type in theme) {
if (type.startsWith('_')) {
for (const name in theme[type]) {
const value = theme[type][name];
if (typeof value !== undefined && value !== '') {
names.add(name);
vars.push(`${name}: ${value.replace(/[;<>]*/g, '')};`);
}
}
}
}
// bca-disable-line
varStyleTag.innerHTML = `:root {
${[...vars].join('')}
}`;
// 如果是改自定义样式
let styleTag = document.getElementById('customStyle');
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.id = 'customVars';
document.body.appendChild(styleTag);
}
if (theme?.style) {
// bca-disable-line
styleTag.innerHTML = theme.style;
}
}
export default {
type: 'form',
title:
'这是一个基于 amis 搭建较为复杂界面的例子,部分功能使用代码开发,请参考源码',
submitText: '',
persistData: 'amis-theme-editor',
actions: [],
onEvent: {
inited: {
actions: [
{
actionType: 'custom',
script: (context: any, doAction: any, event: any) => {
const theme = event.data.formData.config?.theme;
theme && updateTheme(theme);
}
}
]
}
},
// 用于主题修改的时候实时看效果
onChange: (values: any, diff: any) => {
const theme = diff.config?.theme;
theme && updateTheme(theme);
},
body: [
{
type: 'grid',
label: false,
columns: [
{
md: 4,
body: [
{
type: 'tabs',
tabs: [
{
title: '基础设置',
body: [
{
type: 'tpl',
tpl: '变量设置',
label: false
},
{
type: 'tabs',
mode: 'vertical',
subFormMode: 'normal',
tabs: [
{
title: '颜色',
body: colorControls
},
{
title: '字体',
body: fontControls
},
{
title: '间距',
body: sizeControls
},
{
title: '边框',
body: borderControls
},
{
title: '链接',
body: linkControls
},
{
title: '动画',
body: [
{
type: 'input-text',
label: '动画时长',
placeholder: '2s',
name: 'config.theme._vars["--animation-duration"]'
}
]
},
{
title: '其它变量',
body: [
{
type: 'combo',
multiple: true,
name: 'config.theme._otherVars',
body: [
{
type: 'input-text',
placeholder: '变量名',
required: true,
name: 'key'
},
{
type: 'input-text',
placeholder: '变量值',
required: true,
name: 'value'
}
]
}
]
}
]
}
]
},
{
title: '自定义 CSS',
body: [
{
label: false,
type: 'editor',
name: 'config.theme.style',
size: 'lg',
options: {
lineNumbers: 'off'
},
language: 'css'
}
]
},
{
title: '查看设置的变量',
body: [
{
type: 'static-tpl',
pipeIn: (value: any, data: any) => {
const vars = [];
const names = new Set();
const theme = data.data?.config?.theme || {};
for (const type in theme) {
if (type.startsWith('_')) {
for (const name in theme[type]) {
const value = theme[type][name];
if (typeof value !== undefined && value !== '') {
names.add(name);
vars.push(
`${name}: ${value.replace(/[;<>]*/g, '')};`
);
}
}
}
}
if (vars.length) {
return `<pre>${vars.join('\n')}</pre>`;
} else {
return '未设置变量';
}
}
}
]
}
]
}
]
},
{
md: 8,
type: 'container',
columnClassName: 'b-l',
body: [
{
type: 'tabs',
tabs: [
{
title: '表单预览',
tab: From
},
{
title: '表格预览',
tab: CRUD
}
]
}
]
}
]
}
]
};

View File

@ -0,0 +1,68 @@
/**
* CRUD
*/
export default {
type: 'crud',
syncLocation: false,
data: {
items: [
{
engine: 'Trident',
browser: 'Internet Explorer 4.0',
platform: 'Win 95+',
version: '4',
id: 1
},
{
engine: 'Trident',
browser: 'Internet Explorer 5.0',
platform: 'Win 95+',
id: 2
},
{
engine: 'Trident',
browser: 'Internet Explorer 5.5',
platform: 'Win 95+',
id: 3
},
{
engine: 'Trident',
browser: 'Internet Explorer 6',
platform: 'Win 98+',
id: 4
},
{
engine: 'Trident',
browser: 'Internet Explorer 7',
platform: 'Win XP SP2+',
id: 5
},
{
engine: 'Trident',
browser: 'AOL browser (AOL desktop)',
platform: 'Win XP',
id: 6
}
]
},
source: '${items}',
columns: [
{
name: 'id',
label: 'ID'
},
{
name: 'engine',
label: 'Rendering engine'
},
{
name: 'browser',
label: 'Browser'
},
{
name: 'platform',
label: 'Platform(s)'
}
]
};

View File

@ -0,0 +1,626 @@
/**
* @file
*/
export default {
type: 'form',
title: '表单项',
mode: 'horizontal',
wrapWithPanel: false,
autoFocus: true,
body: [
{
type: 'group',
body: [
{
type: 'input-text',
name: 'var1',
label: '输入框'
},
{
type: 'input-number',
name: 'number',
label: '数字',
placeholder: '',
inline: true,
value: 5,
min: 1,
max: 10
}
]
},
{
type: 'group',
body: [
{
type: 'input-tag',
name: 'tag',
label: '标签',
placeholder: '',
clearable: true,
// dropdown: false, 保留原来的展现方式。
// size: 'md',
// inline: true,
options: [
{
label: '诸葛亮',
value: 'zhugeliang'
},
{
label: '曹操',
value: 'caocao'
},
{
label: '钟无艳',
value: 'zhongwuyan'
},
{
label: '野核',
children: [
{
label: '李白',
value: 'libai'
},
{
label: '韩信',
value: 'hanxin'
},
{
label: '云中君',
value: 'yunzhongjun'
}
]
}
]
},
{
type: 'input-text',
disabled: true,
name: 'disabled',
label: '禁用状态',
placeholder: '这里禁止输入内容'
}
]
},
{
type: 'group',
body: [
{
type: 'input-text',
name: 'text-sug',
label: '文本提示',
options: ['lixiaolong', 'zhouxingxing', 'yipingpei', 'liyuanfang'],
addOn: {
type: 'input-text',
label: '$'
}
},
{
type: 'input-text',
name: 'text-sug-multiple',
label: '文本提示多选',
multiple: true,
options: ['lixiaolong', 'zhouxingxing', 'yipingpei', 'liyuanfang']
}
]
},
{
type: 'button-toolbar',
label: '按钮',
buttons: [
{
type: 'action',
label: '默认'
},
{
type: 'action',
label: '信息',
level: 'info'
},
{
type: 'action',
label: '主要',
level: 'primary'
},
{
type: 'action',
label: '次要',
level: 'secondary'
},
{
type: 'action',
label: '成功',
level: 'success'
},
{
type: 'action',
label: '警告',
level: 'warning'
},
{
type: 'action',
label: '危险',
level: 'danger'
},
{
type: 'action',
label: '浅色',
level: 'light'
},
{
type: 'action',
label: '深色',
level: 'dark'
},
{
type: 'action',
label: '链接',
level: 'link'
}
]
},
{
type: 'group',
body: [
{
type: 'radios',
name: 'radios',
label: '单选',
value: 3,
options: [
{
label: '选项1',
value: 1
},
{
label: '选项2',
value: 2
},
{
label: '选项3',
disabled: true,
value: 3
}
]
},
{
type: 'checkboxes',
name: 'checkboxes',
label: '多选框',
value: 3,
options: [
{
label: '选项1',
value: 1
},
{
label: '选项2',
value: 2
},
{
label: '选项3',
disabled: true,
value: 3
}
]
}
]
},
{
type: 'group',
body: [
{
type: 'switch',
name: 'switch',
onText: '开',
offText: '关',
label: '开关'
},
{
type: 'switch',
name: 'switch2',
value: true,
label: '开关开启'
},
{
type: 'switch',
name: 'switch3',
value: true,
disabled: true,
label: '开关禁用'
}
]
},
{
type: 'group',
body: [
{
type: 'button-group-select',
name: 'btn-group',
label: '按钮组',
options: [
{
label: '选项 A',
value: 1
},
{
label: '选项 B',
value: 2
},
{
label: '选项 C',
value: 3
}
]
},
{
type: 'list-select',
name: 'List',
label: 'List',
options: [
{
label: '选项 A',
value: 1
},
{
label: '选项 B',
value: 2
},
{
label: '选项 C',
value: 3
}
]
}
]
},
{
type: 'group',
body: [
{
type: 'select',
name: 'type',
label: '单选',
inline: true,
options: [
{
label: '选项1',
value: 1
},
{
label: '选项2',
value: 2
}
]
},
{
type: 'select',
name: 'type2',
label: '多选',
multiple: true,
inline: true,
options: [
{
label: '选项1',
value: 1
},
{
label: '选项2',
value: 2
}
]
}
]
},
{
type: 'group',
body: [
{
type: 'input-date',
name: 'date',
inline: true,
label: '日期'
},
{
type: 'input-time',
name: 'time',
inline: true,
label: '时间'
}
]
},
{
type: 'input-date-range',
name: 'daterangee',
inline: true,
label: '时间范围'
},
{
type: 'input-group',
size: 'sm',
inline: true,
label: 'Icon 组合',
body: [
{
type: 'icon',
addOnclassName: 'no-bg',
className: 'text-sm',
icon: 'search'
// "vendor": "iconfont"
},
{
type: 'input-text',
placeholder: '搜索作业ID/名称',
inputClassName: 'b-l-none p-l-none',
name: 'jobName'
}
]
},
{
type: 'input-tree',
name: 'tree',
label: '树',
options: [
{
label: 'Folder A',
value: 1,
children: [
{
label: 'file A',
value: 2
},
{
label: 'file B',
value: 3
}
]
},
{
label: 'file C',
value: 4
},
{
label: 'file D',
value: 5
}
]
},
{
type: 'group',
body: [
{
type: 'input-tree',
name: 'trees',
label: '树多选',
multiple: true,
options: [
{
label: 'Folder A',
value: 1,
children: [
{
label: 'file A',
value: 2
},
{
label: 'file B',
value: 3
}
]
},
{
label: 'file C',
value: 4
},
{
label: 'file D',
value: 5
}
]
},
{
type: 'nested-select',
name: 'nestedSelect',
label: '级联选择器',
options: [
{
label: '概念',
value: 'concepts',
children: [
{
label: '配置与组件',
value: 'schema'
},
{
label: '数据域与数据链',
value: 'scope'
},
{
label: '模板',
value: 'template'
},
{
label: '数据映射',
value: 'data-mapping'
},
{
label: '表达式',
value: 'expression'
},
{
label: '联动',
value: 'linkage'
},
{
label: '行为',
value: 'action'
},
{
label: '样式',
value: 'style'
}
]
},
{
label: '类型',
value: 'types',
children: [
{
label: 'SchemaNode',
value: 'schemanode'
},
{
label: 'API',
value: 'api'
},
{
label: 'Definitions',
value: 'definitions'
}
]
},
{
label: '组件',
value: 'zujian',
children: [
{
label: '布局',
value: 'buju',
children: [
{
label: 'Page 页面',
value: 'page'
},
{
label: 'Container 容器',
value: 'container'
},
{
label: 'Collapse 折叠器',
value: 'Collapse'
}
]
},
{
label: '功能',
value: 'gongneng',
children: [
{
label: 'Action 行为按钮',
value: 'action-type'
},
{
label: 'App 多页应用',
value: 'app'
},
{
label: 'Button 按钮',
value: 'button'
}
]
},
{
label: '数据输入',
value: 'shujushuru',
children: [
{
label: 'Form 表单',
value: 'form'
},
{
label: 'FormItem 表单项',
value: 'formitem'
},
{
label: 'Options 选择器表单项',
value: 'options'
}
]
},
{
label: '数据展示',
value: 'shujuzhanshi',
children: [
{
label: 'CRUD 增删改查',
value: 'crud'
},
{
label: 'Table 表格',
value: 'table'
},
{
label: 'Card 卡片',
value: 'card'
}
]
},
{
label: '反馈',
value: 'fankui'
}
]
}
]
}
]
},
{
type: 'matrix-checkboxes',
name: 'matrix',
label: '矩阵开关',
rowLabel: '行标题说明',
columns: [
{
label: '列1'
},
{
label: '列2'
}
],
rows: [
{
label: '行1'
},
{
label: '行2'
}
]
},
{
type: 'combo',
name: 'combo2',
label: '组合多条',
multiple: true,
value: [{}],
items: [
{
name: 'a',
type: 'input-text',
placeholder: 'A'
},
{
name: 'b',
type: 'select',
options: ['a', 'b', 'c']
}
]
},
{
type: 'input-file',
name: 'file',
label: '文件上传',
joinValues: false
},
{
type: 'input-range',
name: 'range',
label: '范围'
},
{
type: 'divider'
}
],
actions: []
};

View File

@ -0,0 +1,326 @@
/**
* combo
*/
const colors = [
{
label: '文字颜色',
name: '--text-color',
cxdValue: '#666',
antdValue: 'rgba(0, 0, 0, 0.85)'
},
{
label: '文字置灰时的颜色',
name: '--text--muted-color',
cxdValue: '#a6a6a6',
antdValue: 'rgba(64, 64, 64, 0.85)'
},
{
label: '标题文字颜色',
name: '--text--loud-color',
cxdValue: '#4d4d4d',
antdValue: 'rgba(0, 0, 0, 0.85)'
},
{
label: '按钮文字颜色',
name: '--button-color',
cxdValue: '#fff',
antdValue: '#fff'
},
{label: '最浅色', name: '--light', cxdValue: '#eaf6fe', antdValue: '#d9d9d9'},
{label: '最深色', name: '--dark', cxdValue: '#343a40', antdValue: '#343a40'},
{
label: '全局背景色',
name: '--body-bg',
cxdValue: '#eaf6fe',
antdValue: '#d9d9d9'
},
{
label: '常用背景色',
name: '--background',
cxdValue: '#fff',
antdValue: '#fff'
},
{
label: '主颜色',
name: '--primary',
cxdValue: '#108cee',
antdValue: '#1890ff'
},
{
label: '主颜色鼠标放上去的颜色',
name: '--primary-onHover',
cxdValue: '#0e77ca',
antdValue: '#007df1'
},
{
label: '主颜色激活时的颜色',
name: '--primary-onActive',
cxdValue: '#0d70be',
antdValue: '#0076e4'
},
{
label: '次颜色',
name: '--secondary',
cxdValue: '#6c757d',
antdValue: '#6c757d'
},
{
label: '次颜色鼠标放上去的颜色',
name: '--secondary-onHover',
cxdValue: '#5a6268',
antdValue: '#5a6268'
},
{
label: '次颜色激活时的颜色',
name: '--secondary-onActive',
cxdValue: '#545b62',
antdValue: '#545b62'
},
{
label: '成功时的颜色',
name: '--success',
cxdValue: '#5fb333',
antdValue: '#52c41a'
},
{
label: '成功时在鼠标移上去后的颜色',
name: '--success-onHover',
cxdValue: '#4f952b',
antdValue: '#44a216'
},
{
label: '成功时激活的颜色',
name: '--success-onActive',
cxdValue: '#4a8b28',
antdValue: '#3f9714'
},
{
label: '信息的颜色',
name: '--info',
cxdValue: '#108cee',
antdValue: '#1890ff'
},
{
label: '信息在鼠标移上去后的颜色',
name: '--info-onHover',
cxdValue: '#0e77ca',
antdValue: '#007df1'
},
{
label: '信息在激活时的颜色',
name: '--info-onActive',
cxdValue: '#0d70be',
antdValue: '#0076e4'
},
{
label: '警告的颜色',
name: '--warning',
cxdValue: '#f39000',
antdValue: '#faad14'
},
{
label: '警告在鼠标移上去后的颜色',
name: '--warning-onHover',
cxdValue: '#cd7900',
antdValue: '#e39905'
},
{
label: '警告在鼠标移上去后的颜色',
name: '--warning-onActive',
cxdValue: '#c07200',
antdValue: '#d69005'
},
{
label: '错误的颜色',
name: '--danger',
cxdValue: '#ea2e2e',
antdValue: '#ff4d4f'
},
{
label: '错误在鼠标移上去后的颜色',
name: '--danger-onHover',
cxdValue: '#dc1616',
antdValue: '#ff2729'
},
{
label: '错误在激活时的颜色',
name: '--danger-onActive',
cxdValue: '#d01515',
antdValue: '#ff1a1d'
}
];
export const colorControls: any = [];
for (const color of colors) {
colorControls.push({
type: 'group',
controls: [
{
type: 'input-color',
label: color.label,
name: `config.theme._vars["${color.name}"]`
},
{
label: '云舍默认值',
type: 'static-color',
value: color.cxdValue,
visibleOn: 'data.config.theme.baseTheme === "cxd"',
inputClassName: 'text-xs'
},
{
label: 'AntD 默认值',
type: 'static-color',
value: color.antdValue,
visibleOn: 'data.config.theme.baseTheme === "antd"',
inputClassName: 'text-xs'
}
]
});
}
const fonts = [
{
label: '基础字体',
name: '--fontFamilyBase',
defaultValue:
"-apple-system, BlinkMacSystemFont, 'SF Pro SC', 'SF Pro Text', 'Helvetica Neue', Helvetica, 'PingFang SC', 'Segoe UI', Roboto, 'Hiragino Sans GB', 'Arial', 'microsoft yahei ui', 'Microsoft YaHei',SimSun, sans-serif"
},
{
label: '等宽字体',
name: '--fontFamilyMonospace',
defaultValue:
"SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace"
},
{
label: '基础字体大小',
name: '--fontSizeBase',
defaultValue: '14px'
},
{
label: '最小字体大小',
name: '--fontSizeXs',
defaultValue: '11px'
},
{
label: '小字体大小',
name: '--fontSizeSm',
defaultValue: '12px'
},
{
label: '中型字体大小',
name: '--fontSizeMd',
defaultValue: '14px'
},
{
label: '大字体大小',
name: '--fontSizeLg',
defaultValue: '16px'
},
{
label: '超大字体大小',
name: '--fontSizeXl',
defaultValue: '20px'
},
{
label: '行高',
name: '--lineHeightBase',
defaultValue: '1.5'
}
];
export const fontControls: any = [];
for (const font of fonts) {
fontControls.push({
type: 'input-text',
label: font.label,
name: `config.theme._vars["${font.name}"]`,
placeholder: font.defaultValue
});
}
const sizes = [
{
label: '基础间距',
name: '--gap-base',
defaultValue: '12px'
},
{
label: '最小间距',
name: '--gap-xs',
defaultValue: '4px'
},
{
label: '小间距',
name: '--gap-sm',
defaultValue: '8px'
},
{
label: '中间距',
name: '--gap-md',
defaultValue: '16px'
},
{
label: '小间距',
name: '--gap-lg',
defaultValue: '20px'
},
{
label: '小间距',
name: '--gap-xl',
defaultValue: '24px'
}
];
export const sizeControls: any = [];
for (const size of sizes) {
sizeControls.push({
type: 'input-text',
label: size.label,
name: `config.theme._vars["${size.name}"]`,
placeholder: size.defaultValue
});
}
export const borderControls: any = [
{
type: 'input-color',
label: '边框颜色',
name: 'config.theme._vars["--buttonColor"]'
},
{
type: 'input-text',
label: '边框圆角大小',
placeholder: '2px',
name: 'config.theme._vars["--borderRadius"]'
}
];
export const linkControls: any = [
{
type: 'input-color',
label: '链接颜色',
name: 'config.theme._vars["--link-color"]'
},
{
type: 'input-color',
label: '链接在鼠标移上去的颜色',
name: 'config.theme._vars["--link-onHover-color"]'
},
{
type: 'input-text',
label: '链接下划线',
placeholder: 'none',
name: 'config.theme._vars["--link-decoration"]'
},
{
type: 'input-text',
label: '链接在鼠标移上去后端下划线',
placeholder: 'none',
name: 'config.theme._vars["--link-onHover-decoration"]'
}
];

View File

@ -657,7 +657,10 @@ export default class Form extends React.Component<FormProps, object> {
};
}
persistData && store.getLocalPersistData();
if (persistData) {
store.getLocalPersistData();
data = cloneObject(store.data);
}
// 派发init事件参数为初始化数据
const dispatcher = dispatchEvent(