diff --git a/components/collapse/Collapse.tsx b/components/collapse/Collapse.tsx index f91142dd5..99b498e69 100644 --- a/components/collapse/Collapse.tsx +++ b/components/collapse/Collapse.tsx @@ -81,7 +81,7 @@ export default defineComponent({ return (
['header', 'icon'].includes(props.collapsible) && onClickItem(panelProps.panelKey) } diff --git a/components/tag/index.tsx b/components/tag/index.tsx index 208386c4e..be61ee7fa 100644 --- a/components/tag/index.tsx +++ b/components/tag/index.tsx @@ -25,6 +25,9 @@ export const tagProps = () => ({ onClose: { type: Function as PropType<(e: MouseEvent) => void>, }, + onClick: { + type: Function as PropType<(e: MouseEvent) => void>, + }, 'onUpdate:visible': Function as PropType<(vis: boolean) => void>, icon: PropTypes.any, }); @@ -86,7 +89,7 @@ const Tag = defineComponent({ ); const tagClassName = computed(() => - classNames(prefixCls.value, hashId.value, { + classNames(prefixCls.value, hashId.value, attrs.class, { [`${prefixCls.value}-${props.color}`]: isInternalColor.value, [`${prefixCls.value}-has-color`]: props.color && !isInternalColor.value, [`${prefixCls.value}-hidden`]: !visible.value, diff --git a/package.json b/package.json index 4595209a5..27836b080 100644 --- a/package.json +++ b/package.json @@ -246,6 +246,7 @@ "stylelint-order": "^5.0.0", "terser-webpack-plugin": "^5.1.1", "through2": "^3.0.0", + "tinycolor2": "^1.6.0", "ts-jest": "^28.0.5", "ts-loader": "^9.1.0", "ts-node": "^10.8.2", @@ -254,6 +255,7 @@ "umi-request": "^1.3.5", "unified": "9.2.2", "url-loader": "^3.0.0", + "vanilla-jsoneditor": "^0.15.1", "vite": "^3.0.0", "vue": "^3.2.0", "vue-antd-md-loader": "^1.2.1-beta.1", diff --git a/site/src/components/antdv-token-previewer/ColorPanel.tsx b/site/src/components/antdv-token-previewer/ColorPanel.tsx new file mode 100644 index 000000000..bedf45a0f --- /dev/null +++ b/site/src/components/antdv-token-previewer/ColorPanel.tsx @@ -0,0 +1,344 @@ +import type { InputProps } from 'ant-design-vue'; +import { Input, InputNumber, Select, theme } from 'ant-design-vue'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import type { PropType } from 'vue'; +import { defineComponent, watchEffect, watch, computed, toRefs, ref } from 'vue'; +import { HexColorPicker, RgbaColorPicker } from '../vue-colorful'; +import tinycolor from 'tinycolor2'; +import makeStyle from './utils/makeStyle'; + +const { useToken } = theme; + +const useStyle = makeStyle('ColorPanel', token => ({ + '.color-panel': { + padding: 12, + backgroundColor: '#fff', + borderRadius: 12, + border: '1px solid rgba(0, 0, 0, 0.06)', + boxShadow: token.boxShadow, + width: 224, + boxSizing: 'border-box', + + '.color-panel-mode': { + display: 'flex', + alignItems: 'center', + marginBottom: 6, + }, + '.color-panel-preview': { + width: 24, + height: 24, + borderRadius: 4, + boxShadow: '0 2px 3px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.09)', + flex: 'none', + overflow: 'hidden', + background: + 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAFpJREFUWAntljEKADAIA23p6v//qQ+wfUEcCu1yriEgp0FHRJSJcnehmmWm1Dv/lO4HIg1AAAKjTqm03ea88zMCCEDgO4HV5bS757f+7wRoAAIQ4B9gByAAgQ3pfiDmXmAeEwAAAABJRU5ErkJggg==) 0% 0% / 32px', + }, + '.color-panel-preset-colors': { + paddingTop: 12, + display: 'flex', + flexWrap: 'wrap', + width: 200, + }, + '.color-panel-preset-color-btn': { + borderRadius: 4, + width: 20, + height: 20, + border: 'none', + outline: 'none', + margin: 4, + cursor: 'pointer', + boxShadow: '0 2px 3px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.09)', + }, + '.color-panel-mode-title': { + color: token.colorTextPlaceholder, + marginTop: 2, + fontSize: 12, + textAlign: 'center', + }, + '.color-panel-rgba-input': { + display: 'flex', + alignItems: 'center', + '&-part': { + flex: 1, + width: 0, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + + '&-title': { + color: token.colorTextPlaceholder, + marginTop: 2, + fontSize: 12, + }, + + '&:not(:last-child)': { + marginRight: 4, + }, + + [`${token.rootCls}-input-number`]: { + width: '100%', + input: { + fontSize: 12, + padding: '0 4px', + }, + }, + }, + }, + }, +})); + +export type HexColorInputProps = { + value: string; + onChange?: (value: string) => void; + alpha?: boolean; +}; + +const getHexValue = (value: string, alpha: boolean = false) => { + return alpha ? tinycolor(value).toHex8() : tinycolor(value).toHex(); +}; +const HexColorInput = defineComponent({ + name: 'HexColorInput', + props: { + value: { type: String }, + alpha: { type: Boolean }, + onChange: { type: Function as PropType<(value: string) => void> }, + }, + setup(props) { + const { value, alpha } = toRefs(props); + + const hexValue = ref(value.value); + const focusRef = ref(false); + + const handleChange: InputProps['onChange'] = e => { + hexValue.value = e.target.value; + props.onChange(getHexValue(e.target.value, alpha.value)); + }; + + const handleBlur: InputProps['onBlur'] = (e: any) => { + focusRef.value = false; + hexValue.value = getHexValue(e.target.value, alpha.value); + }; + + const handleFocus = () => { + focusRef.value = true; + }; + + watchEffect(() => { + if (!focusRef.value) { + hexValue.value = getHexValue(value.value, alpha.value); + } + }); + + return () => { + return ( +
+ '#', + }} + /> +
HEX{alpha.value ? '8' : ''}
+
+ ); + }; + }, +}); + +type RgbaColor = tinycolor.ColorFormats.RGBA; + +export type RgbColorInputProps = { + value?: RgbaColor; + onChange?: (value: RgbaColor) => void; + alpha?: boolean; +}; + +const RgbColorInput = defineComponent({ + name: 'RgbColorInput', + props: { + value: { type: Object as PropType, default: () => ({ r: 0, g: 0, b: 0, a: 1 }) }, + onChange: { type: Function as PropType<(value: RgbaColor) => void> }, + alpha: { type: Boolean }, + }, + setup(props) { + const { value, alpha } = toRefs(props); + + watch(value, val => { + props.onChange(val); + }); + + return () => { + return ( +
+ {/* */} +
+ +
R
+
+
+ +
G
+
+
+ +
B
+
+ {alpha && ( +
+ +
A
+
+ )} + {/*
*/} +
+ ); + }; + }, +}); + +export type ColorPanelProps = { + color: string; + onChange: (color: string) => void; + alpha?: boolean; +}; + +const colorModes = ['HEX', 'HEX8', 'RGB', 'RGBA'] as const; + +type ColorMode = (typeof colorModes)[number]; + +const getColorStr = (color: any, mode: ColorMode) => { + switch (mode) { + case 'HEX': + return tinycolor(color).toHexString(); + case 'HEX8': + return tinycolor(color).toHex8String(); + case 'RGBA': + case 'RGB': + default: + return tinycolor(color).toRgbString(); + } +}; +const ColorPanel = defineComponent({ + name: 'ColorPanel', + props: { + color: { type: String }, + onChange: { type: Function as PropType<(color: string) => void> }, + alpha: { type: Boolean }, + }, + inheritAttrs: false, + setup(props, { attrs }) { + const { color, alpha } = toRefs(props); + + const { token } = useToken(); + const [wrapSSR, hashId] = useStyle(); + const colorMode = ref('HEX'); + + const presetColors = computed(() => { + return [ + token.value.blue, + token.value.purple, + token.value.cyan, + token.value.green, + token.value.magenta, + token.value.pink, + token.value.red, + token.value.orange, + token.value.yellow, + token.value.volcano, + token.value.geekblue, + token.value.gold, + token.value.lime, + '#000', + ]; + }); + + const handleColorModeChange = (value: ColorMode) => { + colorMode.value = value; + props.onChange(getColorStr(color.value, value)); + }; + return () => { + return wrapSSR( +
+ {(colorMode.value === 'HEX' || colorMode.value === 'RGB') && ( + { + props.onChange(getColorStr(value, colorMode.value)); + }} + /> + )} + {(colorMode.value === 'RGBA' || colorMode.value === 'HEX8') && ( + { + props.onChange(getColorStr(value, colorMode.value)); + }} + /> + )} +
+
+
+
+
+ { + handleTokenChange(v); + }} + /> + } + > + + + } + onChange={e => { + handleTokenChange(e.target.value); + }} + /> + ); + } else if (typeof valueRef.value === 'number') { + inputNode = ( + { + handleTokenChange(Number(newValue)); + }} + /> + ); + } else { + inputNode = ( + { + handleTokenChange( + typeof value.value === 'number' ? Number(e.target.value) : e.target.value, + ); + }} + /> + ); + } + return wrapSSR( +
+ {inputNode} +
, + ); + }; + }, +}); + +export default TokenInput; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/alert.tsx b/site/src/components/antdv-token-previewer/component-demos/alert/alert.tsx new file mode 100644 index 000000000..db1c32fb8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/alert.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { Alert, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorIconHover', 'colorIcon', 'colorText'], + key: 'alert', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/error.tsx b/site/src/components/antdv-token-previewer/component-demos/alert/error.tsx new file mode 100644 index 000000000..110725c43 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/error.tsx @@ -0,0 +1,28 @@ +import { defineComponent } from 'vue'; +import { Alert, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorErrorBg', 'colorErrorBorder', 'colorError'], + key: 'error', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/index.ts b/site/src/components/antdv-token-previewer/component-demos/alert/index.ts new file mode 100644 index 000000000..3398808cc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/index.ts @@ -0,0 +1,11 @@ +import Default from './alert'; +import error from './error'; +import info from './info'; +import success from './success'; +import warning from './warning'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, error, info, success, warning]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/info.tsx b/site/src/components/antdv-token-previewer/component-demos/alert/info.tsx new file mode 100644 index 000000000..6b173f7db --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/info.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { Alert, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo', 'colorInfoBorder', 'colorInfoBg'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/success.tsx b/site/src/components/antdv-token-previewer/component-demos/alert/success.tsx new file mode 100644 index 000000000..edf91e67a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/success.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { Alert, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess', 'colorSuccessBorder', 'colorSuccessBg'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/alert/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/alert/warning.tsx new file mode 100644 index 000000000..18d12d94a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/alert/warning.tsx @@ -0,0 +1,28 @@ +import { defineComponent } from 'vue'; +import { Alert, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBorder', 'colorWarningBg'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/anchor/anchor.tsx b/site/src/components/antdv-token-previewer/component-demos/anchor/anchor.tsx new file mode 100644 index 000000000..8fbd36510 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/anchor/anchor.tsx @@ -0,0 +1,26 @@ +import { Anchor } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Link } = Anchor; +const Demo = () => { + return ( +
+ + + + + + + + +
+ ); +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorSplit', 'colorBgContainer'], + key: 'anchor', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/anchor/anchorInLayout.tsx b/site/src/components/antdv-token-previewer/component-demos/anchor/anchorInLayout.tsx new file mode 100644 index 000000000..950a709cb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/anchor/anchorInLayout.tsx @@ -0,0 +1,33 @@ +import { defineComponent } from 'vue'; +import { Anchor, theme } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Link } = Anchor; +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( +
+ + + + + + + + +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSplit'], + key: 'anchorInLayout', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/anchor/index.ts b/site/src/components/antdv-token-previewer/component-demos/anchor/index.ts new file mode 100644 index 000000000..19a68f804 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/anchor/index.ts @@ -0,0 +1,8 @@ +import Demo from './anchor'; +import AnchorLayout from './anchorInLayout'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, AnchorLayout]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/autoComplete/auto-complete.tsx b/site/src/components/antdv-token-previewer/component-demos/autoComplete/auto-complete.tsx new file mode 100644 index 000000000..f0f05ef02 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/autoComplete/auto-complete.tsx @@ -0,0 +1,59 @@ +import { defineComponent, ref } from 'vue'; +import { AutoComplete } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const mockVal = (str: string, repeat: number = 1) => ({ + value: str.repeat(repeat), +}); + +const Demo = defineComponent({ + setup() { + const value = ref(''); + const options = ref<{ value: string }[]>([]); + const onSearch = (searchText: string) => { + options.value = !searchText + ? [] + : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)]; + }; + const onSelect = (data: string) => { + // eslint-disable-next-line no-console + console.log('onSelect', data); + }; + const onChange = (data: string) => { + value.value = data; + }; + + return () => { + return ( + <> + {' '} + {' '} +

{' '} + {' '} + + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [], + key: 'autoComplete', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/autoComplete/index.ts b/site/src/components/antdv-token-previewer/component-demos/autoComplete/index.ts new file mode 100644 index 000000000..e0d56f8cc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/autoComplete/index.ts @@ -0,0 +1,7 @@ +import Default from './auto-complete'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/avatar/avatar.tsx b/site/src/components/antdv-token-previewer/component-demos/avatar/avatar.tsx new file mode 100644 index 000000000..9ffecca5f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/avatar/avatar.tsx @@ -0,0 +1,19 @@ +import { Avatar, Space } from 'ant-design-vue'; +import { UserOutlined } from '@ant-design/icons-vue'; + +export default () => ( + + + } /> + } /> + } /> + } /> + + + } /> + } /> + } /> + } /> + + +); diff --git a/site/src/components/antdv-token-previewer/component-demos/avatar/index.tsx b/site/src/components/antdv-token-previewer/component-demos/avatar/index.tsx new file mode 100644 index 000000000..b19c81191 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/avatar/index.tsx @@ -0,0 +1,13 @@ +import Default from './avatar'; +// import Progress from './progress'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [ + { + demo: , + key: 'default', + }, +]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/badge/badge.tsx b/site/src/components/antdv-token-previewer/component-demos/badge/badge.tsx new file mode 100644 index 000000000..0f59aa3c9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/badge/badge.tsx @@ -0,0 +1,32 @@ +import { defineComponent } from 'vue'; +import { Badge, Avatar, Space, theme } from 'ant-design-vue'; +import { ClockCircleFilled } from '@ant-design/icons-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => ( + + + + + + + + }> + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorBorderBg', 'colorBgContainer'], + key: 'badge', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/badge/index.ts b/site/src/components/antdv-token-previewer/component-demos/badge/index.ts new file mode 100644 index 000000000..6bdca3bee --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/badge/index.ts @@ -0,0 +1,10 @@ +import Default from './badge'; +import Progress from './progress'; +import warning from './warning'; +import success from './success'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, Progress, warning, success]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/badge/progress.tsx b/site/src/components/antdv-token-previewer/component-demos/badge/progress.tsx new file mode 100644 index 000000000..cc308dfd7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/badge/progress.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Badge, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + Process + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary'], + key: 'progress', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/badge/success.tsx b/site/src/components/antdv-token-previewer/component-demos/badge/success.tsx new file mode 100644 index 000000000..46f56ce0b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/badge/success.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Badge, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + Success + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/badge/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/badge/warning.tsx new file mode 100644 index 000000000..8576beb4b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/badge/warning.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Badge, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + Warning + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/breadcrumb/breadcrumb.tsx b/site/src/components/antdv-token-previewer/component-demos/breadcrumb/breadcrumb.tsx new file mode 100644 index 000000000..54444c5d8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/breadcrumb/breadcrumb.tsx @@ -0,0 +1,28 @@ +import { defineComponent } from 'vue'; +import { Breadcrumb } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Home + + Application Center + + + Application List + + An Application + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorText', 'colorPrimary', 'colorPrimaryActive', 'colorPrimaryHover'], + key: 'breadcrumb', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/breadcrumb/index.ts b/site/src/components/antdv-token-previewer/component-demos/breadcrumb/index.ts new file mode 100644 index 000000000..d0832e372 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/breadcrumb/index.ts @@ -0,0 +1,7 @@ +import Default from './breadcrumb'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/button-icon.tsx b/site/src/components/antdv-token-previewer/component-demos/button/button-icon.tsx new file mode 100644 index 000000000..c47c04b1c --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/button-icon.tsx @@ -0,0 +1,32 @@ +import { defineComponent } from 'vue'; +import { Button, Space, Tooltip } from 'ant-design-vue'; +import { SearchOutlined } from '@ant-design/icons-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary'], + key: 'button-icon', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/button.tsx b/site/src/components/antdv-token-previewer/component-demos/button/button.tsx new file mode 100644 index 000000000..9eef310cb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/button.tsx @@ -0,0 +1,33 @@ +import { defineComponent } from 'vue'; +import { Button, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + +
+ + + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorText', + 'colorPrimary', + 'colorPrimaryActive', + 'colorPrimaryHover', + 'controlOutline', + 'controlTmpOutline', + ], + key: 'button', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/dangerButton.tsx b/site/src/components/antdv-token-previewer/component-demos/button/dangerButton.tsx new file mode 100644 index 000000000..6f1dc0e4b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/dangerButton.tsx @@ -0,0 +1,41 @@ +import { defineComponent } from 'vue'; +import { Button, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + {/**/} + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorError', + 'colorErrorActive', + 'colorErrorHover', + 'colorErrorBorder', + 'colorErrorOutline', + ], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/defaultButton.tsx b/site/src/components/antdv-token-previewer/component-demos/button/defaultButton.tsx new file mode 100644 index 000000000..69d0b496e --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/defaultButton.tsx @@ -0,0 +1,13 @@ +import { Button } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainer'], + key: 'defaultButton', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/button/disabled.tsx new file mode 100644 index 000000000..8cde5e9f8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/disabled.tsx @@ -0,0 +1,37 @@ +import { defineComponent } from 'vue'; +import { Button, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + +
+ + + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextDisabled', 'colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/button/index.ts b/site/src/components/antdv-token-previewer/component-demos/button/index.ts new file mode 100644 index 000000000..c1ff98c50 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/button/index.ts @@ -0,0 +1,17 @@ +import Default from './button'; +import DefaultButton from './defaultButton'; +import ButtonIconDemo from './button-icon'; +import DangerButton from './dangerButton'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [ + Default, + ButtonIconDemo, + DangerButton, + DefaultButton, + disabled, +]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/calendar/calendar.tsx b/site/src/components/antdv-token-previewer/component-demos/calendar/calendar.tsx new file mode 100644 index 000000000..6151a0ee9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/calendar/calendar.tsx @@ -0,0 +1,12 @@ +import { Calendar } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/calendar/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/calendar/disabled.tsx new file mode 100644 index 000000000..6731cf8b6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/calendar/disabled.tsx @@ -0,0 +1,12 @@ +import { Calendar } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => true} />; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled', 'colorTextDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/calendar/index.ts b/site/src/components/antdv-token-previewer/component-demos/calendar/index.ts new file mode 100644 index 000000000..29f387a7f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/calendar/index.ts @@ -0,0 +1,8 @@ +import Default from './calendar'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/card/card.tsx b/site/src/components/antdv-token-previewer/component-demos/card/card.tsx new file mode 100644 index 000000000..acb6908eb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/card/card.tsx @@ -0,0 +1,52 @@ +import { defineComponent } from 'vue'; +import { Card, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + More, + }} + > +

Card content

+

Card content

+

Card content

+
+ More, + }} + > +

Card content

+

Card content

+

Card content

+
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorText', + 'colorTextHeading', + 'colorTextSecondary', + 'colorBgContainer', + 'colorBorderSecondary', + 'colorPrimary', + 'colorBgContainer', + ], + key: 'card', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/card/cardGrid.tsx b/site/src/components/antdv-token-previewer/component-demos/card/cardGrid.tsx new file mode 100644 index 000000000..34ba562c8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/card/cardGrid.tsx @@ -0,0 +1,36 @@ +import { defineComponent } from 'vue'; +import type { CSSProperties } from 'vue'; + +import { Card } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const gridStyle: CSSProperties = { + width: '25%', + textAlign: 'center', +}; + +const Demo = defineComponent({ + setup() { + return () => ( + + Content + + Content + + Content + Content + Content + Content + Content + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBorderSecondary'], + key: 'cardGrid', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/card/index.ts b/site/src/components/antdv-token-previewer/component-demos/card/index.ts new file mode 100644 index 000000000..774f5c1f5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/card/index.ts @@ -0,0 +1,9 @@ +import Default from './card'; +import inner from './inner'; +import cardGrid from './cardGrid'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, inner, cardGrid]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/card/inner.tsx b/site/src/components/antdv-token-previewer/component-demos/card/inner.tsx new file mode 100644 index 000000000..357f37cc0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/card/inner.tsx @@ -0,0 +1,23 @@ +import { defineComponent } from 'vue'; +import { Card, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + Inner Card content + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter'], + key: 'inner', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/carousel/carousel.tsx b/site/src/components/antdv-token-previewer/component-demos/carousel/carousel.tsx new file mode 100644 index 000000000..b0b678614 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/carousel/carousel.tsx @@ -0,0 +1,42 @@ +import { defineComponent } from 'vue'; +import type { CSSProperties } from 'vue'; + +import { Carousel } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const contentStyle = { + height: '160px', + color: '#fff', + lineHeight: '160px', + textAlign: 'center', + background: '#364d79', +}; +const Demo = defineComponent({ + setup() { + return () => ( + +
+

1

+
+
+

2

+
+
+

3

+
+
+

4

+
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorText', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/carousel/index.ts b/site/src/components/antdv-token-previewer/component-demos/carousel/index.ts new file mode 100644 index 000000000..98fbb6d52 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/carousel/index.ts @@ -0,0 +1,7 @@ +import Default from './carousel'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/cascader/cascader.tsx b/site/src/components/antdv-token-previewer/component-demos/cascader/cascader.tsx new file mode 100644 index 000000000..db90ad482 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/cascader/cascader.tsx @@ -0,0 +1,14 @@ +import { Cascader } from 'ant-design-vue'; + +import options from './data'; +import type { ComponentDemo } from '../../interface'; + +const Demo = (props: any) => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainer', 'colorPrimary'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/cascader/data.ts b/site/src/components/antdv-token-previewer/component-demos/cascader/data.ts new file mode 100644 index 000000000..8ed4640e5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/cascader/data.ts @@ -0,0 +1,26 @@ +const options = [ + { + value: 'zhejiang', + label: 'Zhejiang', + children: [ + { + value: 'hangzhou', + label: 'Hangzhou', + children: [{ value: 'xihu', label: 'West Lake' }], + }, + ], + }, + { + value: 'jiangsu', + label: 'Jiangsu', + children: [ + { + value: 'nanjing', + label: 'Nanjing', + children: [{ value: 'zhonghuamen', label: 'Zhong Hua Men' }], + }, + ], + }, +]; + +export default options; diff --git a/site/src/components/antdv-token-previewer/component-demos/cascader/disable.tsx b/site/src/components/antdv-token-previewer/component-demos/cascader/disable.tsx new file mode 100644 index 000000000..02a5181a5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/cascader/disable.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue'; +import { Cascader } from 'ant-design-vue'; + +import options from './data'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/cascader/highlight.tsx b/site/src/components/antdv-token-previewer/component-demos/cascader/highlight.tsx new file mode 100644 index 000000000..a307cbeb5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/cascader/highlight.tsx @@ -0,0 +1,18 @@ +import { Cascader } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +import options from './data'; + +const Demo = () => { + return ( + + ); +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorHighlight'], + key: 'highlight', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/cascader/index.ts b/site/src/components/antdv-token-previewer/component-demos/cascader/index.ts new file mode 100644 index 000000000..4d1f0ddc9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/cascader/index.ts @@ -0,0 +1,9 @@ +import Default from './cascader'; +import HighLight from './highlight'; +import disable from './disable'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, HighLight, disable]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/checkbox/checkbox.tsx b/site/src/components/antdv-token-previewer/component-demos/checkbox/checkbox.tsx new file mode 100644 index 000000000..9ff3b0107 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/checkbox/checkbox.tsx @@ -0,0 +1,19 @@ +import { Checkbox, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = (props: any) => ( + + Checkbox + + 选中态 + + +); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorText', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/checkbox/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/checkbox/disabled.tsx new file mode 100644 index 000000000..05b463009 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/checkbox/disabled.tsx @@ -0,0 +1,12 @@ +import { Checkbox } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Checkbox; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextDisabled', 'colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/checkbox/index.ts b/site/src/components/antdv-token-previewer/component-demos/checkbox/index.ts new file mode 100644 index 000000000..55573f854 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/checkbox/index.ts @@ -0,0 +1,8 @@ +import Default from './checkbox'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/collapse/collapse.tsx b/site/src/components/antdv-token-previewer/component-demos/collapse/collapse.tsx new file mode 100644 index 000000000..941b2b6da --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/collapse/collapse.tsx @@ -0,0 +1,32 @@ +import { defineComponent } from 'vue'; +import { Collapse } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Panel } = Collapse; +const text = ` A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome guest in many households across the world.`; + +const Demo = defineComponent({ + setup() { + return () => ( + + +

{text}

+
+ +

{text}

+
+ +

{text}

+
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextSecondary', 'colorText', 'colorFillAlter', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/collapse/index.ts b/site/src/components/antdv-token-previewer/component-demos/collapse/index.ts new file mode 100644 index 000000000..9fac5c9c9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/collapse/index.ts @@ -0,0 +1,7 @@ +import Default from './collapse'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/datePicker/danger.tsx new file mode 100644 index 000000000..c4cfee021 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/danger.tsx @@ -0,0 +1,12 @@ +import { DatePicker } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorBorder', 'colorErrorHover', 'colorErrorOutline'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/date-picker.tsx b/site/src/components/antdv-token-previewer/component-demos/datePicker/date-picker.tsx new file mode 100644 index 000000000..e30ed444e --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/date-picker.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { DatePicker, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorPrimary', + 'colorPrimaryBorder', + 'colorPrimaryHover', + 'controlOutline', + 'colorBgElevated', + 'colorBgContainer', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/datePicker/disabled.tsx new file mode 100644 index 000000000..8d8b380b7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/disabled.tsx @@ -0,0 +1,25 @@ +import { defineComponent } from 'vue'; +import { DatePicker, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled', 'colorTextDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/icon.tsx b/site/src/components/antdv-token-previewer/component-demos/datePicker/icon.tsx new file mode 100644 index 000000000..2953335c5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/icon.tsx @@ -0,0 +1,12 @@ +import { DatePicker } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorIcon', 'colorIconHover'], + key: 'icon', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/index.ts b/site/src/components/antdv-token-previewer/component-demos/datePicker/index.ts new file mode 100644 index 000000000..ced0a2d62 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/index.ts @@ -0,0 +1,11 @@ +import Default from './date-picker'; +import danger from './danger'; +import warning from './warning'; +import icon from './icon'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, warning, icon, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/datePicker/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/datePicker/warning.tsx new file mode 100644 index 000000000..b002b8595 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/datePicker/warning.tsx @@ -0,0 +1,12 @@ +import { DatePicker } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBorder', 'colorWarningHover', 'colorWarningOutline'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/descriptions/descriptions.tsx b/site/src/components/antdv-token-previewer/component-demos/descriptions/descriptions.tsx new file mode 100644 index 000000000..82375c7c5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/descriptions/descriptions.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { Descriptions } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Cloud Database + Prepaid + YES + 2018-04-24 18:00:00 + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSplit', 'colorText', 'colorFillAlter'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/descriptions/index.ts b/site/src/components/antdv-token-previewer/component-demos/descriptions/index.ts new file mode 100644 index 000000000..159669a09 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/descriptions/index.ts @@ -0,0 +1,7 @@ +import Default from './descriptions'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/divider/divider.tsx b/site/src/components/antdv-token-previewer/component-demos/divider/divider.tsx new file mode 100644 index 000000000..a24bd68bb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/divider/divider.tsx @@ -0,0 +1,44 @@ +import { defineComponent } from 'vue'; +import { Divider } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + <> +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi + ista probare, quae sunt a te dicta? Refert tamen, quo modo. +

+ Text +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi + ista probare, quae sunt a te dicta? Refert tamen, quo modo. +

+ + Left Text + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi + ista probare, quae sunt a te dicta? Refert tamen, quo modo. +

+ + Right Text + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi + ista probare, quae sunt a te dicta? Refert tamen, quo modo. +

+ + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSplit', 'colorText'], + key: 'divider', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/divider/index.ts b/site/src/components/antdv-token-previewer/component-demos/divider/index.ts new file mode 100644 index 000000000..78f04999e --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/divider/index.ts @@ -0,0 +1,7 @@ +import Default from './divider'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/drawer/drawer.tsx b/site/src/components/antdv-token-previewer/component-demos/drawer/drawer.tsx new file mode 100644 index 000000000..9fc9123ff --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/drawer/drawer.tsx @@ -0,0 +1,39 @@ +import { Button, Drawer } from 'ant-design-vue'; +import { defineComponent, ref } from 'vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + () => { + const visible = ref(false); + + const showDrawer = () => { + visible.value = true; + }; + + const onClose = () => { + visible.value = false; + }; + + return ( + <> + + +

Some contents...

+

Some contents...

+

Some contents...

+
+ + ); + }; + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgMask', 'colorBgElevated'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/drawer/index.ts b/site/src/components/antdv-token-previewer/component-demos/drawer/index.ts new file mode 100644 index 000000000..1bd2be5b6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/drawer/index.ts @@ -0,0 +1,7 @@ +import Default from './drawer'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdown.tsx b/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdown.tsx new file mode 100644 index 000000000..19b0ecfca --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdown.tsx @@ -0,0 +1,33 @@ +import { defineComponent } from 'vue'; +import { Dropdown } from 'ant-design-vue'; +import { DownOutlined } from '@ant-design/icons-vue'; + +import menu from './menu'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorError', 'colorErrorHover', 'colorBgElevated'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdownError.tsx b/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdownError.tsx new file mode 100644 index 000000000..f65567eca --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/dropdown/dropdownError.tsx @@ -0,0 +1,48 @@ +import { defineComponent } from 'vue'; +import { DownOutlined } from '@ant-design/icons-vue'; +import { Dropdown, Typography } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + {' '} + + Hover me + + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorHover', 'colorBgElevated'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/dropdown/index.ts b/site/src/components/antdv-token-previewer/component-demos/dropdown/index.ts new file mode 100644 index 000000000..e675109d0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/dropdown/index.ts @@ -0,0 +1,7 @@ +import Default from './dropdown'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/dropdown/menu.tsx b/site/src/components/antdv-token-previewer/component-demos/dropdown/menu.tsx new file mode 100644 index 000000000..3fe2f31ca --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/dropdown/menu.tsx @@ -0,0 +1,25 @@ +import { Menu } from 'ant-design-vue'; +import { DownOutlined } from '@ant-design/icons-vue'; + +const menu = ( + + + + 1st menu item + + + } disabled> + + 2nd menu item (disabled) + + + + + 3rd menu item (disabled) + + + a danger item + +); + +export default menu; diff --git a/site/src/components/antdv-token-previewer/component-demos/empty/empty.tsx b/site/src/components/antdv-token-previewer/component-demos/empty/empty.tsx new file mode 100644 index 000000000..e05c7450c --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/empty/empty.tsx @@ -0,0 +1,12 @@ +import { Empty } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextDisabled'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/empty/index.ts b/site/src/components/antdv-token-previewer/component-demos/empty/index.ts new file mode 100644 index 000000000..eb21052ea --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/empty/index.ts @@ -0,0 +1,7 @@ +import Default from './empty'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/form/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/form/danger.tsx new file mode 100644 index 000000000..8e2bc9213 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/form/danger.tsx @@ -0,0 +1,43 @@ +import { defineComponent, ref, reactive } from 'vue'; +import { Form, FormItem, Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => { + const onFinish = () => {}; + const onFinishFailed = () => {}; + const formRef = ref(); + const formData = reactive({ + username: '', + }); + + return ( +
+ + + +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorBorder', 'colorErrorHover'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/form/form.tsx b/site/src/components/antdv-token-previewer/component-demos/form/form.tsx new file mode 100644 index 000000000..819148fe2 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/form/form.tsx @@ -0,0 +1,76 @@ +import { defineComponent, ref, toRaw, reactive } from 'vue'; +import { Form, FormItem, Input, Button, Checkbox } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => { + const onFinish = () => {}; + const onFinishFailed = () => {}; + const formRef = ref(); + const formData = reactive({ + username: '', + password: '', + }); + + const onSubmit = () => { + formRef.value + .validate() + .then(() => { + console.log('values', formData, toRaw(formData)); + }) + .catch(error => { + console.log('error', error); + }); + }; + const resetForm = () => { + formRef.value.resetFields(); + }; + + return ( +
+ + + + + + + + Remember me + + + + + +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'controlOutline', 'colorErrorBorder', 'colorErrorHover'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/form/index.tsx b/site/src/components/antdv-token-previewer/component-demos/form/index.tsx new file mode 100644 index 000000000..5ed998932 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/form/index.tsx @@ -0,0 +1,10 @@ +import Default from './form'; + +import warning from './warning'; +import danger from './danger'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, warning, danger]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/form/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/form/warning.tsx new file mode 100644 index 000000000..59f786dc7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/form/warning.tsx @@ -0,0 +1,43 @@ +import { defineComponent, ref, reactive } from 'vue'; +import { Form, FormItem, Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => { + const onFinish = () => {}; + const onFinishFailed = () => {}; + const formRef = ref(); + const formData = reactive({ + username: '', + }); + + return ( +
+ + + +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'controlOutline', 'colorWarningBorder', 'colorWarningHover'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/grid/grid.tsx b/site/src/components/antdv-token-previewer/component-demos/grid/grid.tsx new file mode 100644 index 000000000..a527b0b88 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/grid/grid.tsx @@ -0,0 +1,56 @@ +import { Row, Col } from 'ant-design-vue'; +import makeStyle from '../../utils/makeStyle'; +import type { ComponentDemo } from '../../interface'; +import { defineComponent } from 'vue'; + +const useStyle = makeStyle('GridDemo', token => ({ + '.previewer-grid-demo': { + [`${token.rootCls}-row`]: { + marginBottom: 16, + }, + [`${token.rootCls}-row > div:not(.gutter-row)`]: { + padding: '16px 0', + background: '#0092ff', + color: '#fff', + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + + '&:nth-child(2n + 1)': { + background: 'rgba(0,146,255,.75)', + }, + }, + }, +})); + +const Demo = defineComponent({ + setup() { + const [, hashId] = useStyle(); + + return () => ( +
+ + col + + + col-12 col-12 + + + col-8 col-8 + col-8 + + + col-6 col-6 + col-6 + col-6 + +
+ ); + }, +}); +const componentDemo: ComponentDemo = { + demo: , + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/grid/index.ts b/site/src/components/antdv-token-previewer/component-demos/grid/index.ts new file mode 100644 index 000000000..c1fa7d4dc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/grid/index.ts @@ -0,0 +1,7 @@ +import Default from './grid'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/icon/icon.tsx b/site/src/components/antdv-token-previewer/component-demos/icon/icon.tsx new file mode 100644 index 000000000..1f52a7cef --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/icon/icon.tsx @@ -0,0 +1,28 @@ +import { defineComponent } from 'vue'; +import { Space } from 'ant-design-vue'; +import { + HomeOutlined, + SettingFilled, + SmileOutlined, + SyncOutlined, + LoadingOutlined, +} from '@ant-design/icons-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/icon/index.ts b/site/src/components/antdv-token-previewer/component-demos/icon/index.ts new file mode 100644 index 000000000..1cdf4d935 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/icon/index.ts @@ -0,0 +1,7 @@ +import Default from './icon'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/image/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/image/disabled.tsx new file mode 100644 index 000000000..2ebfab64f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/image/disabled.tsx @@ -0,0 +1,15 @@ +import { Image } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => { + return ; +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/image/image.tsx b/site/src/components/antdv-token-previewer/component-demos/image/image.tsx new file mode 100644 index 000000000..13c636bc3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/image/image.tsx @@ -0,0 +1,20 @@ +import { Image } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => { + return ( + + ); +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgMask'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/image/index.ts b/site/src/components/antdv-token-previewer/component-demos/image/index.ts new file mode 100644 index 000000000..450e6dfef --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/image/index.ts @@ -0,0 +1,8 @@ +import Default from './image'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/index.ts b/site/src/components/antdv-token-previewer/component-demos/index.ts new file mode 100644 index 000000000..29c5fac85 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/index.ts @@ -0,0 +1,125 @@ +import Alert from './alert'; +import Anchor from './anchor'; +import AutoComplete from './autoComplete'; +import Avatar from './avatar'; +import Badge from './badge'; +import Breadcrumb from './breadcrumb'; +import Button from './button'; +import Calendar from './calendar'; +import Card from './card'; +import Carousel from './carousel'; +import Cascader from './cascader'; +import Checkbox from './checkbox'; +import Collapse from './collapse'; +import DatePicker from './datePicker'; +import Descriptions from './descriptions'; +import Dropdown from './dropdown'; +import Empty from './empty'; +import Form from './form'; +import Grid from './grid'; +import Icon from './icon'; +import Image from './image'; +import InputNumber from './inputNumber'; +import Input from './input'; +import List from './list'; +import Mentions from './mentions'; +import Modal from './modal'; +import Notification from './notification'; +import Pagination from './pagination'; +import Popconfirm from './popconfirm'; +import Popover from './popover'; +import Radio from './radio'; +import Rate from './rate'; +import Select from './select'; +import Skeleton from './skeleton'; +import Slider from './slider'; +import Spin from './spin'; +import Statistic from './statistic'; +import Switch from './switch'; +import Table from './table'; +import Tabs from './tabs'; +import Tag from './tag'; +import TimePicker from './timePicker'; +import Timeline from './timeline'; +import Tooltip from './tooltip'; +import Transfer from './transfer'; +import TreeSelect from './treeSelect'; +import Tree from './tree'; +import Typography from './typography'; +import Upload from './upload'; +import Divider from './divider'; +import Space from './space'; +import Menu from './menu'; +import Steps from './steps'; +import Segmented from './segmented'; +import Drawer from './drawer'; +import Message from './message'; +import Progress from './progress'; +import Result from './result'; + +import type { ComponentDemo } from '../interface'; + +export type PreviewerDemos = Record; + +const ComponentDemos: PreviewerDemos = { + Alert, + Anchor, + AutoComplete, + Avatar, + Badge, + Breadcrumb, + Button, + Calendar, + Card, + Carousel, + Cascader, + Checkbox, + Collapse, + DatePicker, + Descriptions, + Dropdown, + Empty, + Form, + Grid, + Icon, + Image, + InputNumber, + Input, + List, + Mentions, + Modal, + Notification, + Pagination, + Popconfirm, + Popover, + Radio, + Rate, + Select, + Skeleton, + Slider, + Spin, + Statistic, + Switch, + Table, + Tabs, + Tag, + TimePicker, + Timeline, + Tooltip, + Transfer, + TreeSelect, + Tree, + Typography, + Upload, + Divider, + Space, + Menu, + Steps, + Segmented, + Drawer, + Message, + Result, + Progress, +}; + +export default ComponentDemos; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/clearIcon.tsx b/site/src/components/antdv-token-previewer/component-demos/input/clearIcon.tsx new file mode 100644 index 000000000..87e333f66 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/clearIcon.tsx @@ -0,0 +1,17 @@ +import { defineComponent } from 'vue'; +import { Input } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorIcon', 'colorIconHover'], + key: 'clearIcon', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/input/danger.tsx new file mode 100644 index 000000000..f485a9a28 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/danger.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue'; +import { Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorOutline', 'colorErrorBorder', 'colorErrorHover'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/input/disabled.tsx new file mode 100644 index 000000000..829ae2ccb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/disabled.tsx @@ -0,0 +1,12 @@ +import { Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/index.ts b/site/src/components/antdv-token-previewer/component-demos/input/index.ts new file mode 100644 index 000000000..128e40ac0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/index.ts @@ -0,0 +1,12 @@ +import Default from './input'; +import clearIcon from './clearIcon'; +import danger from './danger'; +import warning from './warning'; +import withAddon from './withAddon'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, clearIcon, danger, warning, withAddon, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/input.tsx b/site/src/components/antdv-token-previewer/component-demos/input/input.tsx new file mode 100644 index 000000000..ff6ac923b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/input.tsx @@ -0,0 +1,12 @@ +import { Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'controlOutline', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/success.tsx b/site/src/components/antdv-token-previewer/component-demos/input/success.tsx new file mode 100644 index 000000000..32df97ef2 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/success.tsx @@ -0,0 +1,30 @@ +import { defineComponent } from 'vue'; +import { Input, theme } from 'ant-design-vue'; +import { CheckCircleFilled } from '@ant-design/icons-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( + } + onChange={onChange} + /> + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/input/warning.tsx new file mode 100644 index 000000000..2e0b476d3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/warning.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue'; +import { Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBorder', 'colorWarningHover', 'colorWarningOutline'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/input/withAddon.tsx b/site/src/components/antdv-token-previewer/component-demos/input/withAddon.tsx new file mode 100644 index 000000000..6e6fc553a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/input/withAddon.tsx @@ -0,0 +1,17 @@ +import { defineComponent } from 'vue'; +import { Input } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter'], + key: 'withAddon', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/inputNumber/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/inputNumber/danger.tsx new file mode 100644 index 000000000..15fa021b6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/inputNumber/danger.tsx @@ -0,0 +1,21 @@ +import { defineComponent } from 'vue'; +import { InputNumber } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorErrorBorder', 'colorErrorOutline', 'colorErrorHover', 'colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/inputNumber/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/inputNumber/disabled.tsx new file mode 100644 index 000000000..4fa502cfc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/inputNumber/disabled.tsx @@ -0,0 +1,12 @@ +import { InputNumber } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/inputNumber/index.ts b/site/src/components/antdv-token-previewer/component-demos/inputNumber/index.ts new file mode 100644 index 000000000..d15fcf4a6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/inputNumber/index.ts @@ -0,0 +1,10 @@ +import Default from './inputNumber'; +import danger from './danger'; +import warning from './warning'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, warning, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/inputNumber/inputNumber.tsx b/site/src/components/antdv-token-previewer/component-demos/inputNumber/inputNumber.tsx new file mode 100644 index 000000000..0553a6056 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/inputNumber/inputNumber.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { InputNumber } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorPrimaryBorder', + 'controlOutline', + 'colorPrimaryHover', + 'colorPrimary', + 'colorBgContainer', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/inputNumber/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/inputNumber/warning.tsx new file mode 100644 index 000000000..8bb552ba5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/inputNumber/warning.tsx @@ -0,0 +1,21 @@ +import { defineComponent } from 'vue'; +import { InputNumber } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBorder', 'colorWarningOutline', 'colorWarningHover'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/list/index.ts b/site/src/components/antdv-token-previewer/component-demos/list/index.ts new file mode 100644 index 000000000..091778a66 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/list/index.ts @@ -0,0 +1,7 @@ +import Default from './list'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/list/list.tsx b/site/src/components/antdv-token-previewer/component-demos/list/list.tsx new file mode 100644 index 000000000..7fcf6c7e5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/list/list.tsx @@ -0,0 +1,41 @@ +import { defineComponent } from 'vue'; +import { List, ListItem, ListItemMeta, Avatar } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const data = [ + { title: 'Ant Design Vue Title 1' }, + { title: 'Ant Design Vue Title 2' }, + { title: 'Ant Design Vue Title 3' }, + { title: 'Ant Design Vue Title 4' }, +]; +const Demo = defineComponent({ + setup() { + return () => ( + ( + + , + title: () => {item.title}, + }} + description="Ant Design, a design language for background applications, is refined by Ant UED Team" + /> + + ), + }} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/mentions/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/mentions/danger.tsx new file mode 100644 index 000000000..eab90ae83 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/mentions/danger.tsx @@ -0,0 +1,43 @@ +import { defineComponent } from 'vue'; +import { Mentions } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} +function onSelect() {} + +const Demo = defineComponent({ + setup() { + const options = [ + { + value: 'afc163', + label: 'afc163', + }, + { + value: 'zombieJ', + label: 'zombieJ', + }, + { + value: 'yesmeck', + label: 'yesmeck', + }, + ]; + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorOutline', 'colorErrorBorder', 'colorErrorHover'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/mentions/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/mentions/disabled.tsx new file mode 100644 index 000000000..1f6309f01 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/mentions/disabled.tsx @@ -0,0 +1,39 @@ +import { defineComponent } from 'vue'; +import { Mentions } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const options = [ + { + value: 'afc163', + label: 'afc163', + }, + { + value: 'zombieJ', + label: 'zombieJ', + }, + { + value: 'yesmeck', + label: 'yesmeck', + }, + ]; + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled', 'colorTextDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/mentions/index.ts b/site/src/components/antdv-token-previewer/component-demos/mentions/index.ts new file mode 100644 index 000000000..1448cfdf5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/mentions/index.ts @@ -0,0 +1,10 @@ +import Default from './mentions'; +import danger from './danger'; +import warning from './warning'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, warning, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/mentions/mentions.tsx b/site/src/components/antdv-token-previewer/component-demos/mentions/mentions.tsx new file mode 100644 index 000000000..d5543b5fc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/mentions/mentions.tsx @@ -0,0 +1,47 @@ +import { defineComponent } from 'vue'; +import { Mentions } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} +function onSelect() {} +const Demo = defineComponent({ + setup() { + const options = [ + { + value: 'afc163', + label: 'afc163', + }, + { + value: 'zombieJ', + label: 'zombieJ', + }, + { + value: 'yesmeck', + label: 'yesmeck', + }, + ]; + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorBgContainer', + 'colorBorder', + 'colorPrimary', + 'colorPrimaryHover', + 'controlOutline', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/mentions/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/mentions/warning.tsx new file mode 100644 index 000000000..3cac1e05b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/mentions/warning.tsx @@ -0,0 +1,43 @@ +import { defineComponent } from 'vue'; +import { Mentions } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function onChange() {} +function onSelect() {} + +const Demo = defineComponent({ + setup() { + const options = [ + { + value: 'afc163', + label: 'afc163', + }, + { + value: 'zombieJ', + label: 'zombieJ', + }, + { + value: 'yesmeck', + label: 'yesmeck', + }, + ]; + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBorder', 'colorWarningHover', 'colorWarningOutline'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/menu/data.tsx b/site/src/components/antdv-token-previewer/component-demos/menu/data.tsx new file mode 100644 index 000000000..043a34161 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/menu/data.tsx @@ -0,0 +1,42 @@ +import type { MenuProps } from 'ant-design-vue'; + +import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons-vue'; + +type MenuItem = Required['items'][number]; + +const getItem = ( + label: any, + key: string, + icon?: any, + children?: MenuItem[], + type?: 'group', +): MenuItem => + ({ + key, + icon, + children, + label, + type, + } as MenuItem); + +const items: MenuProps['items'] = [ + getItem('Navigation One', 'sub1', , [ + getItem('Item 1', 'g1', null, [getItem('Option 1', '1'), getItem('Option 2', '2')], 'group'), + getItem('Item 2', 'g2', null, [getItem('Option 3', '3'), getItem('Option 4', '4')], 'group'), + ]), + + getItem('Navigation Two', 'sub2', , [ + getItem('Option 5', '5'), + getItem('Option 6', '6'), + getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]), + ]), + + getItem('Navigation Three', 'sub4', , [ + getItem('Option 9', '9'), + getItem('Option 10', '10'), + getItem('Option 11', '11'), + getItem('Option 12', '12'), + ]), +]; + +export default items; diff --git a/site/src/components/antdv-token-previewer/component-demos/menu/index.ts b/site/src/components/antdv-token-previewer/component-demos/menu/index.ts new file mode 100644 index 000000000..3c6531279 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/menu/index.ts @@ -0,0 +1,9 @@ +import Default from './menu'; +import danger from './menuDanger'; +import MenuInLayout from './menuInLayout'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, MenuInLayout]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/menu/menu.tsx b/site/src/components/antdv-token-previewer/component-demos/menu/menu.tsx new file mode 100644 index 000000000..ebff1aea6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/menu/menu.tsx @@ -0,0 +1,45 @@ +import { defineComponent, ref } from 'vue'; +import type { MenuProps } from 'ant-design-vue'; +import { Menu } from 'ant-design-vue'; + +import items from './data'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => { + const onClick: MenuProps['onClick'] = e => { + console.log('click ', e); + }; + + const selectedKeys = ref(['1']); + const openKeys = ref(['sub1', 'sub2']); + + return ( +
+ (selectedKeys.value = val as any)} + onOpenChange={val => (openKeys.value = val as any)} + // v-model={[selectedKeys.value, 'selectedKeys']} + // v-model={[openKeys.value, 'openKeys']} + mode="inline" + items={items} + /> +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorBgContainer', 'colorFillAlter', 'colorSplit', 'colorPrimaryHover'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/menu/menuDanger.tsx b/site/src/components/antdv-token-previewer/component-demos/menu/menuDanger.tsx new file mode 100644 index 000000000..bf5c08a31 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/menu/menuDanger.tsx @@ -0,0 +1,39 @@ +import type { MenuProps } from 'ant-design-vue'; +import { Menu } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const items: MenuProps['items'] = [ + { + key: '0', + danger: true, + label: '危险', + }, + { + key: '1', + danger: true, + label: '危险选中', + }, + { + key: '2', + danger: true, + disabled: true, + label: '危险禁用', + }, +]; + +const Demo = () => { + const onClick: MenuProps['onClick'] = e => { + console.log('click ', e); + }; + + return ; +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorHover', 'colorErrorOutline'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/menu/menuInLayout.tsx b/site/src/components/antdv-token-previewer/component-demos/menu/menuInLayout.tsx new file mode 100644 index 000000000..c99822cd5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/menu/menuInLayout.tsx @@ -0,0 +1,34 @@ +import { defineComponent } from 'vue'; +import { Menu, theme } from 'ant-design-vue'; + +import items from './data'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( +
+ +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSplit'], + key: 'menuInLayout', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/error.tsx b/site/src/components/antdv-token-previewer/component-demos/message/error.tsx new file mode 100644 index 000000000..a45406b61 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/error.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { message } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = message; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + type={'error'} + content={'这是一条异常消息,会主动消失'} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'error', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/index.ts b/site/src/components/antdv-token-previewer/component-demos/message/index.ts new file mode 100644 index 000000000..0abb13d68 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/index.ts @@ -0,0 +1,11 @@ +import Default from './message'; +import error from './error'; +import info from './info'; +import success from './success'; +import warning from './warning'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, error, info, success, warning]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/info.tsx b/site/src/components/antdv-token-previewer/component-demos/message/info.tsx new file mode 100644 index 000000000..0e7513b6a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/info.tsx @@ -0,0 +1,19 @@ +import { defineComponent } from 'vue'; +import { message } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = message; + +const Demo = defineComponent({ + setup() { + return () => <_InternalPanelDoNotUseOrYouWillBeFired type={'info'} content={'Info'} />; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/message.tsx b/site/src/components/antdv-token-previewer/component-demos/message/message.tsx new file mode 100644 index 000000000..efdcd2f11 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/message.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { message } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = message; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired type={'info'} content={`Hello, Ant Design!`} /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorText', 'colorBgElevated'], + key: 'message', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/success.tsx b/site/src/components/antdv-token-previewer/component-demos/message/success.tsx new file mode 100644 index 000000000..10eff0951 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/success.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { message } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = message; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + type={'success'} + content={'这是一条成功消息,会主动消失'} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/message/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/message/warning.tsx new file mode 100644 index 000000000..9f65fc842 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/message/warning.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { message } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = message; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + type={'warning'} + content={'这是一条警告消息,会主动消失'} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/index.ts b/site/src/components/antdv-token-previewer/component-demos/modal/index.ts new file mode 100644 index 000000000..758367d36 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/index.ts @@ -0,0 +1,11 @@ +import Default from './modal'; +import info from './info'; +import withButton from './modalWithButton'; +import warning from './warning'; +import success from './success'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, info, withButton, warning, success]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/info.tsx b/site/src/components/antdv-token-previewer/component-demos/modal/info.tsx new file mode 100644 index 000000000..5889fba09 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/info.tsx @@ -0,0 +1,32 @@ +import { Modal, Button } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const info = () => { + Modal.info({ + title: 'This is a info message', + content: () => ( +
+

some messages...some messages...

+

some messages...some messages...

+
+ ), + onOk() { + console.log('i am ok'); + }, + }); + }; + + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo'], + key: 'info', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/modal.tsx b/site/src/components/antdv-token-previewer/component-demos/modal/modal.tsx new file mode 100644 index 000000000..7731e0bc8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/modal.tsx @@ -0,0 +1,43 @@ +import { Button, Modal } from 'ant-design-vue'; +import { defineComponent, ref } from 'vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const isModalVisible = ref(false); + const showModal = () => { + isModalVisible.value = true; + }; + const handleOk = () => { + isModalVisible.value = false; + }; + const handleCancel = () => { + isModalVisible.value = false; + }; + + return () => { + return ( + <> + + +

Some contents...

Some contents...

Some contents...

+
+ + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgMask', 'colorBgElevated'], + key: 'default', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/modalWithButton.tsx b/site/src/components/antdv-token-previewer/component-demos/modal/modalWithButton.tsx new file mode 100644 index 000000000..a6fe536dc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/modalWithButton.tsx @@ -0,0 +1,43 @@ +import { Button, Modal } from 'ant-design-vue'; +import { defineComponent, ref } from 'vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const isModalVisible = ref(false); + const showModal = () => { + isModalVisible.value = true; + }; + const handleOk = () => { + isModalVisible.value = false; + }; + const handleCancel = () => { + isModalVisible.value = false; + }; + + return () => { + return ( + <> + + +

Some contents...

Some contents...

Some contents...

+
+ + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgMask'], + key: 'modalWithButton', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/success.tsx b/site/src/components/antdv-token-previewer/component-demos/modal/success.tsx new file mode 100644 index 000000000..fee9edeb0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/success.tsx @@ -0,0 +1,29 @@ +import { Modal, Button } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const success = () => { + Modal.success({ + title: 'This is a success message', + content: () => ( +
+

some messages...some messages...

+

some messages...some messages...

+
+ ), + }); + }; + + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/modal/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/modal/warning.tsx new file mode 100644 index 000000000..38d1c6b82 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/modal/warning.tsx @@ -0,0 +1,29 @@ +import { Modal, Button } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const warning = () => { + Modal.warning({ + title: 'This is a warning message', + content: () => ( +
+

some messages...some messages...

+

some messages...some messages...

+
+ ), + }); + }; + + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/error.tsx b/site/src/components/antdv-token-previewer/component-demos/notification/error.tsx new file mode 100644 index 000000000..5a3c92aee --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/error.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { notification } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = notification; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + message={'Notification Title'} + type={'error'} + description={ + 'This is the content of the notification. This is the content of the notification. This is the content of the notification.' + } + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'error', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/index.ts b/site/src/components/antdv-token-previewer/component-demos/notification/index.ts new file mode 100644 index 000000000..7dbf50daa --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/index.ts @@ -0,0 +1,11 @@ +import Demo from './notification'; +import info from './info'; +import error from './error'; +import success from './success'; +import warning from './warning'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, info, error, success, warning]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/info.tsx b/site/src/components/antdv-token-previewer/component-demos/notification/info.tsx new file mode 100644 index 000000000..b0dbdb6d8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/info.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { notification } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = notification; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + message={'Notification Title'} + type={'info'} + description={ + 'This is the content of the notification. This is the content of the notification. This is the content of the notification.' + } + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/notification.tsx b/site/src/components/antdv-token-previewer/component-demos/notification/notification.tsx new file mode 100644 index 000000000..146dfac69 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/notification.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { notification } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = notification; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + message={'Notification Title'} + description={ + 'This is the content of the notification. This is the content of the notification. This is the content of the notification.' + } + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorIcon', 'colorIconHover', 'colorBgElevated'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/success.tsx b/site/src/components/antdv-token-previewer/component-demos/notification/success.tsx new file mode 100644 index 000000000..1a6982d4a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/success.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { notification } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = notification; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + message={'Notification Title'} + type={'success'} + description={ + 'This is the content of the notification. This is the content of the notification. This is the content of the notification.' + } + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/notification/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/notification/warning.tsx new file mode 100644 index 000000000..8a17e45b4 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/notification/warning.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { notification } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { _InternalPanelDoNotUseOrYouWillBeFired } = notification; + +const Demo = defineComponent({ + setup() { + return () => ( + <_InternalPanelDoNotUseOrYouWillBeFired + message={'Notification Title'} + type={'warning'} + description={ + 'This is the content of the notification. This is the content of the notification. This is the content of the notification.' + } + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/pagination/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/pagination/disabled.tsx new file mode 100644 index 000000000..5c07135b4 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/pagination/disabled.tsx @@ -0,0 +1,17 @@ +import { defineComponent } from 'vue'; +import { Pagination } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['controlItemBgActiveDisabled', 'colorBgContainerDisabled', 'colorFillAlter'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/pagination/index.tsx b/site/src/components/antdv-token-previewer/component-demos/pagination/index.tsx new file mode 100644 index 000000000..224c3cac5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/pagination/index.tsx @@ -0,0 +1,9 @@ +import Demo from './pagination'; +import disabled from './disabled'; +import outline from './outline'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, disabled, outline]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/pagination/outline.tsx b/site/src/components/antdv-token-previewer/component-demos/pagination/outline.tsx new file mode 100644 index 000000000..4088fffce --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/pagination/outline.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Pagination, Space } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'controlOutline', 'colorPrimaryHover', 'colorBgContainer'], + key: 'outline', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/pagination/pagination.tsx b/site/src/components/antdv-token-previewer/component-demos/pagination/pagination.tsx new file mode 100644 index 000000000..7822f4f2d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/pagination/pagination.tsx @@ -0,0 +1,23 @@ +import { defineComponent } from 'vue'; +import { Pagination, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/popconfirm/index.ts b/site/src/components/antdv-token-previewer/component-demos/popconfirm/index.ts new file mode 100644 index 000000000..9fac30374 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/popconfirm/index.ts @@ -0,0 +1,7 @@ +import Demo from './popconfirm'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/popconfirm/popconfirm.tsx b/site/src/components/antdv-token-previewer/component-demos/popconfirm/popconfirm.tsx new file mode 100644 index 000000000..1def06fef --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/popconfirm/popconfirm.tsx @@ -0,0 +1,50 @@ +import { defineComponent, ref } from 'vue'; +import { Popconfirm, message } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +function confirm() { + message.success('Click on Yes'); +} +function cancel() { + message.error('Click on No'); +} +const Demo = defineComponent({ + setup() { + const open = ref(true); + + return () => ( +
+ { + if (node) { + console.log(node.parentNode); + return node.parentNode as HTMLElement; + } + return document.body; + }} + > + Delete + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgElevated', 'colorWarning'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/popover/index.ts b/site/src/components/antdv-token-previewer/component-demos/popover/index.ts new file mode 100644 index 000000000..147db6bb0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/popover/index.ts @@ -0,0 +1,7 @@ +import Demo from './popover'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/popover/popover.tsx b/site/src/components/antdv-token-previewer/component-demos/popover/popover.tsx new file mode 100644 index 000000000..22b073d02 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/popover/popover.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { Popover, Button } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const content = () => ( +
+

Content

Content

+
+ ); + + return () => { + return ( +
+ + + +
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgElevated'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/progress/danger.tsx new file mode 100644 index 000000000..ba9742e73 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/danger.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { Progress, Space } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/index.ts b/site/src/components/antdv-token-previewer/component-demos/progress/index.ts new file mode 100644 index 000000000..50a629729 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/index.ts @@ -0,0 +1,11 @@ +import Demo from './progress'; +import info from './info'; +import danger from './danger'; +import success from './success'; +import progressInBg from './progressInBg'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, info, danger, success, progressInBg]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/info.tsx b/site/src/components/antdv-token-previewer/component-demos/progress/info.tsx new file mode 100644 index 000000000..26bb51c87 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/info.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { Progress } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + <> + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/progress.tsx b/site/src/components/antdv-token-previewer/component-demos/progress/progress.tsx new file mode 100644 index 000000000..2c5dcec3d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/progress.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import { Progress } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + <> + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillSecondary', 'colorText', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/progressInBg.tsx b/site/src/components/antdv-token-previewer/component-demos/progress/progressInBg.tsx new file mode 100644 index 000000000..05230d1d7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/progressInBg.tsx @@ -0,0 +1,30 @@ +import { defineComponent } from 'vue'; +import { Progress, theme } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( +
+ + + + + + +
+ ); + }; + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillSecondary', 'colorText', 'colorBgContainer'], + key: 'layout', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/progress/success.tsx b/site/src/components/antdv-token-previewer/component-demos/progress/success.tsx new file mode 100644 index 000000000..622e15dd3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/progress/success.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Progress, Space } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ( + + + + + + + +); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/radio/button.tsx b/site/src/components/antdv-token-previewer/component-demos/radio/button.tsx new file mode 100644 index 000000000..8ee3d0842 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/radio/button.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { Radio, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + Hangzhou + + Shanghai + + +
+ Apple + Orange +
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimaryActive', 'colorPrimaryHover'], + key: 'button', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/radio/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/radio/disabled.tsx new file mode 100644 index 000000000..8fc622a4a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/radio/disabled.tsx @@ -0,0 +1,12 @@ +import { Radio } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Radio; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/radio/index.ts b/site/src/components/antdv-token-previewer/component-demos/radio/index.ts new file mode 100644 index 000000000..5ea59c0b8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/radio/index.ts @@ -0,0 +1,9 @@ +import Default from './radio'; +import Button from './button'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, Button, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/radio/radio.tsx b/site/src/components/antdv-token-previewer/component-demos/radio/radio.tsx new file mode 100644 index 000000000..7c214d6ce --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/radio/radio.tsx @@ -0,0 +1,12 @@ +import { Radio } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Radio; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'controlOutline', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/rate/index.ts b/site/src/components/antdv-token-previewer/component-demos/rate/index.ts new file mode 100644 index 000000000..313c9da2d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/rate/index.ts @@ -0,0 +1,7 @@ +import Demo from './rate'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/rate/rate.tsx b/site/src/components/antdv-token-previewer/component-demos/rate/rate.tsx new file mode 100644 index 000000000..ba1699f2c --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/rate/rate.tsx @@ -0,0 +1,13 @@ +import { Rate } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillContent'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/result/danger.tsx new file mode 100644 index 000000000..c499977bc --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/danger.tsx @@ -0,0 +1,18 @@ +import { defineComponent } from 'vue'; +import { Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/index.ts b/site/src/components/antdv-token-previewer/component-demos/result/index.ts new file mode 100644 index 000000000..1434ce4fe --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/index.ts @@ -0,0 +1,11 @@ +import Demo from './result'; +import info from './info'; +import warning from './warning'; +import danger from './danger'; +import ResultWithDesc from './resultWithDesc'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, info, warning, danger, ResultWithDesc]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/info.tsx b/site/src/components/antdv-token-previewer/component-demos/result/info.tsx new file mode 100644 index 000000000..5d97915e3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/info.tsx @@ -0,0 +1,18 @@ +import { defineComponent } from 'vue'; +import { Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/result.tsx b/site/src/components/antdv-token-previewer/component-demos/result/result.tsx new file mode 100644 index 000000000..6a57f87f4 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/result.tsx @@ -0,0 +1,30 @@ +import { defineComponent } from 'vue'; +import { Button, Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Go Console + , + , + ]} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'result', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/resultWithDesc.tsx b/site/src/components/antdv-token-previewer/component-demos/result/resultWithDesc.tsx new file mode 100644 index 000000000..369c68d22 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/resultWithDesc.tsx @@ -0,0 +1,21 @@ +import { defineComponent } from 'vue'; +import { Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Order number: 2017182818828182881 Cloud server configuration takes 1-5 minutes, please wait. + + ); + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter'], + key: 'resultWithDesc', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/success.tsx b/site/src/components/antdv-token-previewer/component-demos/result/success.tsx new file mode 100644 index 000000000..afb9bc596 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/success.tsx @@ -0,0 +1,25 @@ +import { defineComponent } from 'vue'; +import { Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'result', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/result/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/result/warning.tsx new file mode 100644 index 000000000..7cad6ba16 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/result/warning.tsx @@ -0,0 +1,18 @@ +import { defineComponent } from 'vue'; +import { Result } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/segmented/index.ts b/site/src/components/antdv-token-previewer/component-demos/segmented/index.ts new file mode 100644 index 000000000..e9fc8e437 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/segmented/index.ts @@ -0,0 +1,7 @@ +import Demo from './segmented'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/segmented/segmented.tsx b/site/src/components/antdv-token-previewer/component-demos/segmented/segmented.tsx new file mode 100644 index 000000000..aece5017b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/segmented/segmented.tsx @@ -0,0 +1,20 @@ +import { defineComponent } from 'vue'; +import { Segmented } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + key: 'default', + tokens: [], +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/select/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/select/danger.tsx new file mode 100644 index 000000000..e5aa26736 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/select/danger.tsx @@ -0,0 +1,37 @@ +import { defineComponent } from 'vue'; +import { Select } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +import options from './data'; + +const handleChange = (value: any) => { + console.log(`selected ${value}`); +}; + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled', 'colorTextDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/select/icon.tsx b/site/src/components/antdv-token-previewer/component-demos/select/icon.tsx new file mode 100644 index 000000000..e26952089 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/select/icon.tsx @@ -0,0 +1,35 @@ +import { defineComponent } from 'vue'; +import { Select } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +import options from './data'; + +const handleChange = (value: any) => { + console.log(`selected ${value}`); +}; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'controlOutline', + 'colorPrimary', + 'colorPrimaryHover', + 'colorText', + 'colorBgElevated', + 'colorBgContainer', + ], + key: 'select', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/select/selectTag.tsx b/site/src/components/antdv-token-previewer/component-demos/select/selectTag.tsx new file mode 100644 index 000000000..dc05ebbd9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/select/selectTag.tsx @@ -0,0 +1,43 @@ +import { defineComponent } from 'vue'; +import { Select } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +import options from './data'; + +const handleChange = (value: any) => { + console.log(`selected ${value}`); +}; + +const Demo = defineComponent({ + setup() { + return () => ( + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarningHover', 'colorWarningOutline'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/skeleton/index.ts b/site/src/components/antdv-token-previewer/component-demos/skeleton/index.ts new file mode 100644 index 000000000..16f1d8dd2 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/skeleton/index.ts @@ -0,0 +1,7 @@ +import Demo from './skeleton'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/skeleton/skeleton.tsx b/site/src/components/antdv-token-previewer/component-demos/skeleton/skeleton.tsx new file mode 100644 index 000000000..58d0c9b78 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/skeleton/skeleton.tsx @@ -0,0 +1,13 @@ +import { Skeleton } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillContent', 'colorTextPlaceholder'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/slider/index.ts b/site/src/components/antdv-token-previewer/component-demos/slider/index.ts new file mode 100644 index 000000000..367112ba3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/slider/index.ts @@ -0,0 +1,8 @@ +import Demo from './slider'; +import SliderInBg from './sliderInBg'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, SliderInBg]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/slider/slider.tsx b/site/src/components/antdv-token-previewer/component-demos/slider/slider.tsx new file mode 100644 index 000000000..83a1c4adf --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/slider/slider.tsx @@ -0,0 +1,30 @@ +import { defineComponent } from 'vue'; +import { Slider } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + <> + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorFillSecondary', + 'colorFillContentHover', + 'colorBgContainer', + 'colorPrimary', + 'colorPrimaryHover', + 'colorPrimaryBorderHover', + 'colorPrimaryBorder', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/slider/sliderInBg.tsx b/site/src/components/antdv-token-previewer/component-demos/slider/sliderInBg.tsx new file mode 100644 index 000000000..7aca9b609 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/slider/sliderInBg.tsx @@ -0,0 +1,34 @@ +import { defineComponent } from 'vue'; +import { Slider, theme } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( +
+ + +
+ ); + }; + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorFillSecondary', + 'colorFillContentHover', + 'colorBgContainer', + 'colorPrimary', + 'colorPrimaryHover', + 'colorPrimaryBorderHover', + 'colorPrimaryBorder', + ], + key: 'sliderInBg', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/space/index.ts b/site/src/components/antdv-token-previewer/component-demos/space/index.ts new file mode 100644 index 000000000..78f5baf39 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/space/index.ts @@ -0,0 +1,7 @@ +import Demo from './space'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/space/space.tsx b/site/src/components/antdv-token-previewer/component-demos/space/space.tsx new file mode 100644 index 000000000..7e762de7a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/space/space.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { UploadOutlined } from '@ant-design/icons-vue'; +import { Button, Popconfirm, Space, Upload } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Space + + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/spin/index.ts b/site/src/components/antdv-token-previewer/component-demos/spin/index.ts new file mode 100644 index 000000000..221ad346d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/spin/index.ts @@ -0,0 +1,7 @@ +import Default from './spin'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/spin/spin.tsx b/site/src/components/antdv-token-previewer/component-demos/spin/spin.tsx new file mode 100644 index 000000000..7bba90967 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/spin/spin.tsx @@ -0,0 +1,12 @@ +import { Spin } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/statistic/index.ts b/site/src/components/antdv-token-previewer/component-demos/statistic/index.ts new file mode 100644 index 000000000..1ce48cd32 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/statistic/index.ts @@ -0,0 +1,7 @@ +import Demo from './statistic'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/statistic/statistic.tsx b/site/src/components/antdv-token-previewer/component-demos/statistic/statistic.tsx new file mode 100644 index 000000000..70c490d7f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/statistic/statistic.tsx @@ -0,0 +1,32 @@ +import { defineComponent } from 'vue'; +import { Statistic, Row, Col, Button } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + + + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/steps/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/steps/danger.tsx new file mode 100644 index 000000000..dfdc7bf5b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/steps/danger.tsx @@ -0,0 +1,30 @@ +import { defineComponent } from 'vue'; +import { Steps } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const { Step } = Steps; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/steps/index.ts b/site/src/components/antdv-token-previewer/component-demos/steps/index.ts new file mode 100644 index 000000000..53f7af41c --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/steps/index.ts @@ -0,0 +1,8 @@ +import Demo from './steps'; +import danger from './danger'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, danger]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/steps/steps.tsx b/site/src/components/antdv-token-previewer/component-demos/steps/steps.tsx new file mode 100644 index 000000000..46f293250 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/steps/steps.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { Steps } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const { Step } = Steps; + +const Demo = defineComponent({ + setup() { + return () => ( + + + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/switch/index.ts b/site/src/components/antdv-token-previewer/component-demos/switch/index.ts new file mode 100644 index 000000000..811e0d669 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/switch/index.ts @@ -0,0 +1,7 @@ +import Demo from './switch'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/switch/switch.tsx b/site/src/components/antdv-token-previewer/component-demos/switch/switch.tsx new file mode 100644 index 000000000..0611ae9c6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/switch/switch.tsx @@ -0,0 +1,20 @@ +import { defineComponent, ref } from 'vue'; +import { Switch } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +function onChange() {} +const Demo = defineComponent({ + setup() { + const checked = ref(true); + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'controlOutline', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/table/filterTable.tsx b/site/src/components/antdv-token-previewer/component-demos/table/filterTable.tsx new file mode 100644 index 000000000..65c0c584b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/table/filterTable.tsx @@ -0,0 +1,108 @@ +import { defineComponent } from 'vue'; +import type { TableProps } from 'ant-design-vue'; +import { Table } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +type TableData = { name: string; age: number; address: string }; + +const columns: TableProps['columns'] = [ + { + title: 'Name', + dataIndex: 'name', + filters: [ + { + text: 'Joe', + value: 'Joe', + }, + { + text: 'Jim', + value: 'Jim', + }, + { + text: 'Submenu', + value: 'Submenu', + children: [ + { + text: 'Green', + value: 'Green', + }, + { + text: 'Black', + value: 'Black', + }, + ], + }, + ], + // specify the condition of filtering result + // here is that finding the name started with `value` + onFilter: (value, record) => record.name.indexOf(String(value)) === 0, + sorter: (a, b) => a.name.length - b.name.length, + sortDirections: ['descend'], + }, + { + title: 'Age', + dataIndex: 'age', + defaultSortOrder: 'descend', + sorter: (a, b) => a.age - b.age, + }, + { + title: 'Address', + dataIndex: 'address', + filters: [ + { + text: 'London', + value: 'London', + }, + { + text: 'New York', + value: 'New York', + }, + ], + onFilter: (value, record) => record.address.indexOf(String(value)) === 0, + }, +]; +const data = [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + }, + { + key: '4', + name: 'Jim Red', + age: 32, + address: 'London No. 2 Lake Park', + }, +]; + +const onChange: TableProps['onChange'] = (pagination, filters, sorter, extra) => { + console.log('params', pagination, filters, sorter, extra); +}; + +const Demo = defineComponent({ + setup() { + return () => ; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillSecondary', 'colorFillContentHover', 'colorFillContent', 'colorFillAlter'], + key: 'filterTable', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/table/index.ts b/site/src/components/antdv-token-previewer/component-demos/table/index.ts new file mode 100644 index 000000000..31e987ad3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/table/index.ts @@ -0,0 +1,8 @@ +import Default from './table'; +import Filter from './filterTable'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, Filter]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/table/table.tsx b/site/src/components/antdv-token-previewer/component-demos/table/table.tsx new file mode 100644 index 000000000..6c0a9d82a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/table/table.tsx @@ -0,0 +1,95 @@ +import { defineComponent } from 'vue'; +import { Table, Tag, Space } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const columns = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + }, + { title: 'Age', dataIndex: 'age', key: 'age' }, + { title: 'Address', dataIndex: 'address', key: 'address' }, + { + title: 'Tags', + key: 'tags', + dataIndex: 'tags', + }, + { + title: 'Action', + key: 'action', + }, +]; +const data = [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + tags: ['nice', 'developer'], + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + tags: ['loser'], + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + tags: ['cool', 'teacher'], + }, +]; +const Demo = defineComponent({ + setup() { + return () => ( +
{ + if (column.key === 'name') { + return {record.name}; + } else if (column.key === 'tags') { + return ( + + {record.tags.map((tag: string) => { + let color = tag.length > 5 ? 'geekblue' : 'green'; + if (tag === 'loser') { + color = 'volcano'; + } + return ( + + {tag.toUpperCase()} + + ); + })} + + ); + } else if (column.key === 'action') { + return ( + + Invite {record.name} Delete + + ); + } else { + return text; + } + }, + }} + /> + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimaryActive', 'colorBgContainer'], + key: 'table', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tabs/cardTabs.tsx b/site/src/components/antdv-token-previewer/component-demos/tabs/cardTabs.tsx new file mode 100644 index 000000000..b6d6d83fb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tabs/cardTabs.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { Tabs } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { TabPane } = Tabs; + +const Demo = defineComponent({ + setup() { + return () => ( + + + Content of Tab Pane 1 + + + Content of Tab Pane 2 + + + Content of Tab Pane 3 + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter'], + key: 'cardTabs', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tabs/index.ts b/site/src/components/antdv-token-previewer/component-demos/tabs/index.ts new file mode 100644 index 000000000..46f9fa721 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tabs/index.ts @@ -0,0 +1,8 @@ +import Default from './tabs'; +import card from './cardTabs'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, card]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tabs/tabs.tsx b/site/src/components/antdv-token-previewer/component-demos/tabs/tabs.tsx new file mode 100644 index 000000000..71a827641 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tabs/tabs.tsx @@ -0,0 +1,31 @@ +import { defineComponent } from 'vue'; +import { Tabs } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { TabPane } = Tabs; +function callback() {} +const Demo = defineComponent({ + setup() { + return () => ( + + + Content of Tab Pane 1 + + + Content of Tab Pane 2 + + + Content of Tab Pane 3 + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'colorPrimaryActive', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/closable.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/closable.tsx new file mode 100644 index 000000000..67302e597 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/closable.tsx @@ -0,0 +1,12 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Error; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter', 'colorIcon', 'colorIconHover'], + key: 'closable', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/error.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/error.tsx new file mode 100644 index 000000000..08c50bca9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/error.tsx @@ -0,0 +1,12 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Error; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorBg', 'colorErrorBorder'], + key: 'error', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/index.ts b/site/src/components/antdv-token-previewer/component-demos/tag/index.ts new file mode 100644 index 000000000..2528cc00b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/index.ts @@ -0,0 +1,21 @@ +import Default from './tag'; +import error from './error'; +import info from './info'; +import success from './success'; +import warning from './warning'; +import multiTags from './multiTags'; +import closable from './closable'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [ + Default, + error, + info, + success, + warning, + multiTags, + closable, +]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/info.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/info.tsx new file mode 100644 index 000000000..9cb65ba4a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/info.tsx @@ -0,0 +1,12 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Info; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorInfo', 'colorInfoBg', 'colorInfoBorder'], + key: 'info', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/multiTags.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/multiTags.tsx new file mode 100644 index 000000000..0a40e63fe --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/multiTags.tsx @@ -0,0 +1,19 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { CheckableTag } = Tag; + +const Checkable = () => ( +
+ Error + Error +
+); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'colorPrimaryActive'], + key: 'multiTags', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/success.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/success.tsx new file mode 100644 index 000000000..58982e8a2 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/success.tsx @@ -0,0 +1,12 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Success; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess', 'colorSuccessBg', 'colorSuccessBorder'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/tag.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/tag.tsx new file mode 100644 index 000000000..a6619a6c1 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/tag.tsx @@ -0,0 +1,105 @@ +import { defineComponent } from 'vue'; +import { Divider, Space, Tag, theme } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + const { token } = theme.useToken(); + + return () => { + return ( + +
+ magenta + red + volcano + orange + gold + lime + green + cyan + blue + geekblue + purple +
+ +
+ magenta + red + volcano + orange + gold + lime + green + cyan + blue + geekblue + purple +
+
+ ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'blue-1', + 'blue-3', + 'blue-6', + 'blue-7', + 'cyan-1', + 'cyan-3', + 'cyan-6', + 'cyan-7', + 'geekblue-1', + 'geekblue-3', + 'geekblue-6', + 'geekblue-7', + 'gold-1', + 'gold-3', + 'gold-6', + 'gold-7', + 'green-1', + 'green-3', + 'green-6', + 'green-7', + 'lime-1', + 'lime-3', + 'lime-6', + 'lime-7', + 'magenta-1', + 'magenta-3', + 'magenta-6', + 'magenta-7', + 'orange-1', + 'orange-3', + 'orange-6', + 'orange-7', + 'pink-1', + 'pink-3', + 'pink-6', + 'pink-7', + 'purple-1', + 'purple-3', + 'purple-6', + 'purple-7', + 'volcano-1', + 'volcano-3', + 'volcano-6', + 'volcano-7', + 'yellow-1', + 'yellow-3', + 'yellow-6', + 'yellow-7', + 'red-1', + 'red-3', + 'red-6', + 'red-7', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tag/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/tag/warning.tsx new file mode 100644 index 000000000..17fb83cc6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tag/warning.tsx @@ -0,0 +1,12 @@ +import { Tag } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => Warning; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning', 'colorWarningBg', 'colorWarningBorder'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timePicker/index.ts b/site/src/components/antdv-token-previewer/component-demos/timePicker/index.ts new file mode 100644 index 000000000..37503face --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timePicker/index.ts @@ -0,0 +1,7 @@ +import Demo from './time-picker'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timePicker/time-picker.tsx b/site/src/components/antdv-token-previewer/component-demos/timePicker/time-picker.tsx new file mode 100644 index 000000000..36da52ec9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timePicker/time-picker.tsx @@ -0,0 +1,12 @@ +import { TimePicker } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = () => ; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timeline/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/timeline/danger.tsx new file mode 100644 index 000000000..d3f242da1 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timeline/danger.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { Timeline } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Create a services site 2015-09-01 + Solve initial network problems 2015-09-01 + Technical testing 2015-09-01 + Network problems being solved 2015-09-01 + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timeline/index.ts b/site/src/components/antdv-token-previewer/component-demos/timeline/index.ts new file mode 100644 index 000000000..cab0c6d38 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timeline/index.ts @@ -0,0 +1,9 @@ +import Default from './timeline'; +import danger from './danger'; +import success from './success'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, success]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timeline/success.tsx b/site/src/components/antdv-token-previewer/component-demos/timeline/success.tsx new file mode 100644 index 000000000..9b82bec77 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timeline/success.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { Timeline } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Create a services site 2015-09-01 + Solve initial network problems 2015-09-01 + Technical testing 2015-09-01 + Network problems being solved 2015-09-01 + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/timeline/timeline.tsx b/site/src/components/antdv-token-previewer/component-demos/timeline/timeline.tsx new file mode 100644 index 000000000..6b48bf634 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/timeline/timeline.tsx @@ -0,0 +1,24 @@ +import { defineComponent } from 'vue'; +import { Timeline } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( + + Create a services site 2015-09-01 + Solve initial network problems 2015-09-01 + Technical testing 2015-09-01 + {/*Network problems being solved 2015-09-01*/} + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorText', 'colorSplit', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tooltip/index.ts b/site/src/components/antdv-token-previewer/component-demos/tooltip/index.ts new file mode 100644 index 000000000..80c4f07c8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tooltip/index.ts @@ -0,0 +1,7 @@ +import Demo from './tooltip'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tooltip/tooltip.tsx b/site/src/components/antdv-token-previewer/component-demos/tooltip/tooltip.tsx new file mode 100644 index 000000000..620ab8cf9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tooltip/tooltip.tsx @@ -0,0 +1,22 @@ +import { defineComponent } from 'vue'; +import { Tooltip } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + Tooltip will show on mouse enter. + +
+ ); + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgSpotlight', 'colorTextLightSolid'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/transfer/danger.tsx new file mode 100644 index 000000000..100c159bb --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/danger.tsx @@ -0,0 +1,44 @@ +import { defineComponent, ref } from 'vue'; +import { Transfer } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +import mockData from './data'; + +const initialTargetKeys = mockData.filter(item => +item.key > 10).map(item => item.key); + +const Demo = defineComponent({ + setup() { + const targetKeys = ref(initialTargetKeys); + const selectedKeys = ref([]); + const onScroll = () => {}; + + return () => { + return ( + { + targetKeys.value = nextTargetKeys; + }} + onSelectChange={(sourceSelectedKeys, targetSelectedKeys) => { + selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys]; + }} + onScroll={onScroll} + render={item => item.title} + /> + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/data.ts b/site/src/components/antdv-token-previewer/component-demos/transfer/data.ts new file mode 100644 index 000000000..67a662b8a --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/data.ts @@ -0,0 +1,9 @@ +const mockData: any[] = []; +for (let i = 0; i < 20; i++) { + mockData.push({ + key: i.toString(), + title: `content${i + 1}`, + description: `description of content${i + 1}`, + }); +} +export default mockData; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/transfer/disabled.tsx new file mode 100644 index 000000000..62d42db4b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/disabled.tsx @@ -0,0 +1,48 @@ +import { defineComponent, ref } from 'vue'; +import { Transfer } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const mockData: any[] = []; +for (let i = 0; i < 20; i++) { + mockData.push({ + key: i.toString(), + title: `content${i + 1}`, + description: `description of content${i + 1}`, + }); +} + +const initialTargetKeys = mockData.filter(item => +item.key > 10).map(item => item.key); + +const Demo = defineComponent({ + setup() { + const targetKeys = ref(initialTargetKeys); + const selectedKeys = ref([]); + const onScroll = () => {}; + + return () => { + { + targetKeys.value = nextTargetKeys; + }} + onSelectChange={(sourceSelectedKeys, targetSelectedKeys) => { + selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys]; + }} + onScroll={onScroll} + render={item => item.title} + />; + }; + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/index.ts b/site/src/components/antdv-token-previewer/component-demos/transfer/index.ts new file mode 100644 index 000000000..d79330b96 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/index.ts @@ -0,0 +1,10 @@ +import Default from './transfer'; +import danger from './danger'; +import warning from './warning'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, warning, danger, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/transfer.tsx b/site/src/components/antdv-token-previewer/component-demos/transfer/transfer.tsx new file mode 100644 index 000000000..a49c7b7a3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/transfer.tsx @@ -0,0 +1,41 @@ +import { defineComponent, ref } from 'vue'; +import { Transfer } from 'ant-design-vue'; + +import mockData from './data'; +import type { ComponentDemo } from '../../interface'; + +const initialTargetKeys = mockData.filter(item => +item.key > 10).map(item => item.key); + +const Demo = defineComponent({ + setup() { + const targetKeys = ref(initialTargetKeys); + const selectedKeys = ref(['1', '2']); + const onScroll = () => {}; + return () => { + return ( + { + targetKeys.value = nextTargetKeys; + }} + onSelectChange={(sourceSelectedKeys, targetSelectedKeys) => { + selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys]; + }} + onScroll={onScroll} + render={item => item.title} + /> + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['controlItemBgActiveHover', 'controlItemBgActive', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/transfer/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/transfer/warning.tsx new file mode 100644 index 000000000..1b0c097d5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/transfer/warning.tsx @@ -0,0 +1,50 @@ +import { defineComponent, ref } from 'vue'; +import { Transfer } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const mockData: any[] = []; +for (let i = 0; i < 20; i++) { + mockData.push({ + key: i.toString(), + title: `content${i + 1}`, + description: `description of content${i + 1}`, + }); +} + +const initialTargetKeys = mockData.filter(item => +item.key > 10).map(item => item.key); + +const Demo = defineComponent({ + setup() { + const targetKeys = ref(initialTargetKeys); + const selectedKeys = ref([]); + const onScroll = () => {}; + + return () => { + return ( + { + targetKeys.value = nextTargetKeys; + }} + onSelectChange={(sourceSelectedKeys, targetSelectedKeys) => { + selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys]; + }} + onScroll={onScroll} + render={item => item.title} + /> + ); + }; + }, +}); +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tree/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/tree/disabled.tsx new file mode 100644 index 000000000..e098ed672 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tree/disabled.tsx @@ -0,0 +1,50 @@ +import { Tree } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const treeData = [ + { + title: 'parent 1', + key: '0-0', + children: [ + { + title: 'parent 1-0', + key: '0-0-0', + disabled: true, + children: [ + { title: 'leaf', key: '0-0-0-0', disableCheckbox: true }, + { title: 'leaf', key: '0-0-0-1' }, + ], + }, + { + title: 'parent 1-1', + key: '0-0-1', + children: [ + { + title: sss, + key: '0-0-1-0', + }, + ], + }, + ], + }, +]; +const Demo = () => { + return ( + + ); +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextDisabled', 'colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tree/index.ts b/site/src/components/antdv-token-previewer/component-demos/tree/index.ts new file mode 100644 index 000000000..8e76e31c9 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tree/index.ts @@ -0,0 +1,8 @@ +import Demo from './tree'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Demo, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/tree/tree.tsx b/site/src/components/antdv-token-previewer/component-demos/tree/tree.tsx new file mode 100644 index 000000000..58aeb9ce0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/tree/tree.tsx @@ -0,0 +1,49 @@ +import { Tree } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const treeData = [ + { + title: 'parent 1', + key: '0-0', + children: [ + { + title: 'parent 1-0', + key: '0-0-0', + disabled: true, + children: [ + { title: 'leaf', key: '0-0-0-0', disableCheckbox: true }, + { title: 'leaf', key: '0-0-0-1' }, + ], + }, + { + title: 'parent 1-1', + key: '0-0-1', + children: [ + { + title: sss, + key: '0-0-1-0', + }, + ], + }, + ], + }, +]; +const Demo = () => { + return ( + + ); +}; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'controlOutline', 'colorBgContainer'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/treeSelect/disabled.tsx b/site/src/components/antdv-token-previewer/component-demos/treeSelect/disabled.tsx new file mode 100644 index 000000000..7caedc3ee --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/treeSelect/disabled.tsx @@ -0,0 +1,47 @@ +import { defineComponent, ref } from 'vue'; +import { TreeSelect } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { TreeNode } = TreeSelect; + +const Demo = defineComponent({ + setup() { + const value = ref(undefined); + const onChange = () => { + value.value = value.value; + }; + return () => { + return ( + + + + + + + + + + + + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorTextDisabled', 'colorBgContainerDisabled'], + key: 'disabled', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/treeSelect/index.ts b/site/src/components/antdv-token-previewer/component-demos/treeSelect/index.ts new file mode 100644 index 000000000..63d0d2a08 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/treeSelect/index.ts @@ -0,0 +1,8 @@ +import Default from './tree-select'; +import disabled from './disabled'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, disabled]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/treeSelect/tree-select.tsx b/site/src/components/antdv-token-previewer/component-demos/treeSelect/tree-select.tsx new file mode 100644 index 000000000..f943b3f65 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/treeSelect/tree-select.tsx @@ -0,0 +1,52 @@ +import { defineComponent, ref } from 'vue'; +import { TreeSelect } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { TreeNode } = TreeSelect; + +const Demo = defineComponent({ + setup() { + const value = ref(undefined); + const onChange = () => { + value.value = value.value; + }; + return () => { + return ( + + + + + + + + + + + + ); + }; + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: [ + 'colorPrimary', + 'colorPrimaryActive', + 'controlOutline', + 'colorBgElevated', + 'colorBgContainer', + ], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/Heading4.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/Heading4.tsx new file mode 100644 index 000000000..00e7a06a4 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/Heading4.tsx @@ -0,0 +1,14 @@ +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Title } = Typography; + +const Demo = () => Heading 4; + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['fontSizeHeading4'], + key: 'heading4', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/error.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/error.tsx new file mode 100644 index 000000000..37415c1c8 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/error.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Title, Text } = Typography; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + Error Title + + error Text +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorHover', 'colorErrorActive'], + key: 'error', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/index.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/index.tsx new file mode 100644 index 000000000..ccd897567 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/index.tsx @@ -0,0 +1,11 @@ +import TypographyDemo from './typography'; +import Heading4 from './Heading4'; +import warning from './warning'; +import success from './success'; +import error from './error'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [TypographyDemo, Heading4, error, warning, success]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/success.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/success.tsx new file mode 100644 index 000000000..fe08180ee --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/success.tsx @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Title, Text } = Typography; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + Success Title + + success Text +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'success', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/typography.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/typography.tsx new file mode 100644 index 000000000..e0beb680f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/typography.tsx @@ -0,0 +1,42 @@ +import { defineComponent } from 'vue'; +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Title, Paragraph, Text, Link } = Typography; +const Demo = defineComponent({ + setup() { + return () => ( + + 《故乡》 + ——鲁迅 + + 深蓝的天空中挂着一轮金黄的圆月 + ,下面是海边的沙地,都种着一望无际的碧绿的西瓜,其间有一个十一二岁的少年,项带银圈,手捏一柄钢叉, + 向一匹猹尽力的刺去 + ,那猹却将身一扭,反从他的胯下逃走了。 + + +
    +
  • + 狂人日记 +
  • +
  • + 呐喊 +
  • +
  • + 彷徨 +
  • +
+
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorSuccess'], + key: 'default', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/typographyFull.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/typographyFull.tsx new file mode 100644 index 000000000..83d853fe1 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/typographyFull.tsx @@ -0,0 +1,100 @@ +import { Typography, Divider } from 'ant-design-vue'; + +const { Title, Paragraph, Text, Link } = Typography; +const blockContent = `AntV 是蚂蚁金服全新一代数据可视化解决方案,致力于提供一套简单方便、专业可靠、不限可能的数据可视化最佳实践。得益于丰富的业务场景和用户需求挑战,AntV 经历多年积累与不断打磨,已支撑整个阿里集团内外 20000+ 业务系统,通过了日均千万级 UV 产品的严苛考验。我们正在基础图表,图分析,图编辑,地理空间可视化,智能可视化等各个可视化的领域耕耘,欢迎同路人一起前行。`; +export default () => ( + + Introduction{' '} + + {' '} + In the process of internal desktop applications development, many different design specs and + implementations would be involved, which might cause designers and developers difficulties and + duplication and reduce the efficiency of development.{' '} + {' '} + + {' '} + After massive project practice and summaries, Ant Design, a design language for background + applications, is refined by Ant UED Team, which aims to{' '} + + {' '} + uniform the user interface specs for internal background projects, lower the unnecessary + cost of design differences and implementation and liberate the resources of design and + front-end development{' '} + {' '} + .{' '} + {' '} + Guidelines and Resources{' '} + + {' '} + We supply a series of design principles, practical patterns and high quality design resources + (Sketch and Axure), to help people create their product + prototypes beautifully and efficiently.{' '} + {' '} + + {' '} +
    + {' '} +
  • + {' '} + Principles{' '} +
  • {' '} +
  • + {' '} + Patterns{' '} +
  • {' '} +
  • + {' '} + Resource Download{' '} +
  • {' '} +
{' '} +
{' '} + + {' '} + Press Esc to exit...{' '} + {' '} + 介绍{' '} + + {' '} + 蚂蚁的企业级产品是一个庞大且复杂的体系。这类产品不仅量级巨大且功能复杂,而且变动和并发频繁,常常需要设计与开发能够快速的做出响应。同时这类产品中有存在很多类似的页面以及组件,可以通过抽象得到一些稳定且高复用性的内容。{' '} + {' '} + + {' '} + 随着商业化的趋势,越来越多的企业级产品对更好的用户体验有了进一步的要求。带着这样的一个终极目标,我们(蚂蚁金服体验技术部)经过大量的项目实践和总结,逐步打磨出一个服务于企业级产品的设计体系 + Ant Design。基于『确定』和『自然』{' '} + 的设计价值观,通过模块化的解决方案,降低冗余的生产成本,让设计者专注于{' '} + 更好的用户体验。{' '} + {' '} + 设计资源{' '} + + {' '} + 我们提供完善的设计原则、最佳实践和设计资源文件(Sketch 和{' '} + Axure),来帮助业务快速设计出高质量的产品原型。{' '} + {' '} + + {' '} +
    + {' '} +
  • + {' '} + 设计原则{' '} +
  • {' '} +
  • + {' '} + 设计模式{' '} +
  • {' '} +
  • + {' '} + 设计资源{' '} +
  • {' '} +
{' '} +
{' '} + + {' '} +
{blockContent}
{blockContent}
{' '} +
{' '} + + {' '} + 按Esc键退出阅读……{' '} + {' '} +
+); diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/warning.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/warning.tsx new file mode 100644 index 000000000..d554ca85c --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/warning.tsx @@ -0,0 +1,26 @@ +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +import { defineComponent } from 'vue'; +const { Title, Text } = Typography; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + Error Title + + error Text +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/warningText.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/warningText.tsx new file mode 100644 index 000000000..77cdc7cc7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/warningText.tsx @@ -0,0 +1,23 @@ +import { defineComponent } from 'vue'; +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Text } = Typography; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ Warning Title +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/typography/warningTitle.tsx b/site/src/components/antdv-token-previewer/component-demos/typography/warningTitle.tsx new file mode 100644 index 000000000..f51d9e66d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/typography/warningTitle.tsx @@ -0,0 +1,25 @@ +import { defineComponent } from 'vue'; +import { Typography } from 'ant-design-vue'; +import type { ComponentDemo } from '../../interface'; + +const { Title } = Typography; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + Warning Text + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorWarning'], + key: 'warning', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/upload/avatar.tsx b/site/src/components/antdv-token-previewer/component-demos/upload/avatar.tsx new file mode 100644 index 000000000..05f1e0d7f --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/upload/avatar.tsx @@ -0,0 +1,34 @@ +import { defineComponent } from 'vue'; +import { PlusOutlined } from '@ant-design/icons-vue'; +import { Upload } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ +
+ +
Upload
+
+
+
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorFillAlter'], + key: 'avatar', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/upload/danger.tsx b/site/src/components/antdv-token-previewer/component-demos/upload/danger.tsx new file mode 100644 index 000000000..9be0f8829 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/upload/danger.tsx @@ -0,0 +1,48 @@ +import { defineComponent } from 'vue'; +import { UploadOutlined } from '@ant-design/icons-vue'; +import { Upload, Button } from 'ant-design-vue'; + +import type { ComponentDemo } from '../../interface'; + +const Demo = defineComponent({ + setup() { + return () => ( +
+ + + + + + +
+ ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorError', 'colorErrorBg'], + key: 'danger', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/upload/index.ts b/site/src/components/antdv-token-previewer/component-demos/upload/index.ts new file mode 100644 index 000000000..2ddce0eb5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/upload/index.ts @@ -0,0 +1,9 @@ +import Default from './upload'; +import danger from './danger'; +import avatar from './avatar'; + +import type { ComponentDemo } from '../../interface'; + +const previewerDemo: ComponentDemo[] = [Default, danger, avatar]; + +export default previewerDemo; diff --git a/site/src/components/antdv-token-previewer/component-demos/upload/upload.tsx b/site/src/components/antdv-token-previewer/component-demos/upload/upload.tsx new file mode 100644 index 000000000..264dedc4b --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-demos/upload/upload.tsx @@ -0,0 +1,36 @@ +import { defineComponent } from 'vue'; +import type { UploadProps } from 'ant-design-vue'; +import { Upload, message, Button } from 'ant-design-vue'; +import { UploadOutlined } from '@ant-design/icons-vue'; + +import type { ComponentDemo } from '../../interface'; + +const props: UploadProps = { + name: 'file', + action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', + headers: { authorization: 'authorization-text' }, + onChange(info) { + if (info.file.status === 'done') { + message.success(`${info.file.name} file uploaded successfully`); + } else if (info.file.status === 'error') { + message.error(`${info.file.name} file upload failed.`); + } + }, +}; +const Demo = defineComponent({ + setup() { + return () => ( + + + + ); + }, +}); + +const componentDemo: ComponentDemo = { + demo: , + tokens: ['colorPrimary', 'colorPrimaryHover', 'colorPrimaryActive'], + key: 'upload', +}; + +export default componentDemo; diff --git a/site/src/components/antdv-token-previewer/component-panel/ComponentCard.tsx b/site/src/components/antdv-token-previewer/component-panel/ComponentCard.tsx new file mode 100644 index 000000000..7e1a3ec79 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-panel/ComponentCard.tsx @@ -0,0 +1,108 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, ref } from 'vue'; +import { Button, CardProps } from 'ant-design-vue'; +import { Card } from 'ant-design-vue'; +import { Control } from '../icons'; +import makeStyle from '../utils/makeStyle'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import type { MutableTheme, TokenName } from '../interface'; +import ComponentTokenDrawer from './ComponentTokenDrawer'; + +const useStyle = makeStyle('ComponentCard', token => ({ + [`${token.rootCls}-card.component-card`]: { + borderRadius: 6, + boxShadow: `0 1px 2px 0 rgba(25,15,15,0.07)`, + + [`${token.rootCls}-card-head`]: { + paddingInline: 18, + + [`${token.rootCls}-card-head-title`]: { + paddingBlock: token.paddingSM, + fontSize: token.fontSize, + }, + }, + + [`${token.rootCls}-card-body`]: { + padding: 18, + overflow: 'auto', + }, + + '.component-token-control-icon': { + color: token.colorIcon, + transition: `color ${token.motionDurationMid}`, + fontSize: token.fontSizeLG, + cursor: 'pointer', + + '&:hover': { + color: token.colorIconHover, + }, + }, + }, +})); + +export const getComponentDemoId = (component: string) => `antdv-token-previewer-${component}`; + +export interface ComponentCardProps { + title: CardProps['title']; + component?: string; + onTokenClick?: (token: TokenName) => void; + drawer?: boolean; + theme?: MutableTheme; +} + +const ComponentCard = defineComponent({ + name: 'ComponentCard', + inheritAttrs: false, + props: { + title: { type: String as PropType }, + component: { type: String }, + onTokenClick: { type: Function as PropType<(token: TokenName) => void> }, + drawer: { type: Boolean }, + theme: { type: Object as PropType }, + }, + setup(props, { attrs, slots }) { + const { component, title, theme, drawer } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + const drawerOpen = ref(false); + + return () => { + return wrapSSR( + <> + + drawer.value && + theme.value && ( + + ), + }} + > + {slots.default && slots.default()} + + {drawer.value && theme.value && ( + (drawerOpen.value = false)} + /> + )} + , + ); + }; + }, +}); + +export default ComponentCard; diff --git a/site/src/components/antdv-token-previewer/component-panel/ComponentDemoGroup.tsx b/site/src/components/antdv-token-previewer/component-panel/ComponentDemoGroup.tsx new file mode 100644 index 000000000..478cbacaf --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-panel/ComponentDemoGroup.tsx @@ -0,0 +1,228 @@ +import type { CSSProperties, PropType } from 'vue'; +import { defineComponent, toRefs } from 'vue'; +import { ConfigProvider, Tooltip } from 'ant-design-vue'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import ComponentDemos from '../component-demos'; +import type { ComponentDemo, MutableTheme, TokenName } from '../interface'; +import { useInjectLocaleContext } from '../locale'; +import makeStyle from '../utils/makeStyle'; +import ComponentCard, { getComponentDemoId } from './ComponentCard'; + +const useStyle = makeStyle('ComponentDemoGroup', token => ({ + '.previewer-component-demo-group': { + display: 'flex', + width: '100%', + overflow: 'hidden', + + '&:first-child': { + '.previewer-component-demo-group-item': { + paddingTop: token.padding, + }, + }, + + '&:last-child': { + '.previewer-component-demo-group-item': { + paddingBottom: token.padding, + }, + }, + }, +})); + +const useDemoStyle = makeStyle('ComponentDemoBlock', token => ({ + '.previewer-component-demo-group-item': { + flex: '1 1 50%', + paddingInline: token.padding, + paddingBlock: token.padding / 2, + width: 0, + backgroundColor: token.colorBgLayout, + + '.previewer-component-demo-group-item-relative-token': { + color: token.colorTextSecondary, + paddingBottom: 8, + + '&:not(:first-child)': { + marginTop: 12, + }, + }, + }, +})); + +export type ComponentDemoBlockProps = { + component: string; + onTokenClick?: (token: TokenName) => void; + size?: 'small' | 'middle' | 'large'; + disabled?: boolean; + demos?: (ComponentDemo & { active?: boolean })[]; + theme: MutableTheme; + componentDrawer?: boolean; +}; + +export const ComponentDemoBlock = defineComponent({ + name: 'ComponentDemoBlock', + inheritAttrs: false, + props: { + component: { type: String }, + onTokenClick: { type: Function as PropType<(token: TokenName) => void> }, + size: { type: String as PropType<'small' | 'middle' | 'large'>, default: 'middle' }, + disabled: { type: Boolean, default: false }, + demos: { + type: Object as PropType<(ComponentDemo & { active?: boolean })[]>, + default: () => [], + }, + theme: { type: Object as PropType }, + componentDrawer: { type: Boolean }, + }, + setup(props, { attrs }) { + const { component, size, disabled, demos, theme, componentDrawer } = toRefs(props); + + const [, hashId] = useDemoStyle(); + const locale = useInjectLocaleContext(); + + return () => { + return ( +
+ + + {demos.value.some(item => item.active) + ? demos.value.map(demo => ( +
+ {demo.tokens && ( +
+ + + {locale.value.demo.relatedTokens}:{' '} + {demo.tokens.slice(0, 2).join(', ')} + {demo.tokens.length > 2 ? '...' : ''} + + +
+ )} + {demo.demo} +
+ )) + : demos.value[0]?.demo} +
+
+
+ ); + }; + }, +}); + +export type ComponentDemoGroupProps = { + themes: MutableTheme[]; + components: Record; + activeComponents?: string[]; + size?: 'small' | 'middle' | 'large'; + disabled?: boolean; + selectedTokens?: string[]; + onTokenClick?: (token: TokenName) => void; + componentDrawer?: boolean; + hideTokens?: boolean; +}; + +const ComponentDemoGroup = defineComponent({ + name: 'ComponentDemoGroup', + inheritAttrs: false, + props: { + themes: { type: Array as PropType }, + components: { type: Object as PropType> }, + activeComponents: { type: Array as PropType }, + size: { type: String as PropType<'small' | 'middle' | 'large'> }, + disabled: { type: Boolean }, + selectedTokens: { type: Array as PropType }, + onTokenClick: { type: Function as PropType<(token: TokenName) => void> }, + componentDrawer: { type: Boolean }, + hideTokens: { type: Boolean }, + }, + setup(props, { attrs }) { + const { + themes, + components, + size, + disabled, + activeComponents, + selectedTokens, + componentDrawer, + hideTokens, + } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + + return () => { + return wrapSSR( + <> + {Object.entries(components.value) + .reduce((result, [, group]) => result.concat(group), []) + .map(item => { + const componentDemos = ComponentDemos[item]; + if (!componentDemos) { + return null; + } + const demos: ComponentDemo[] = componentDemos.map((demo, index) => { + return { + ...demo, + tokens: hideTokens.value ? undefined : demo.tokens, + active: + ((!selectedTokens.value || selectedTokens.value.length === 0) && index === 0) || + selectedTokens.value?.some(token => demo.tokens?.includes(token as any)), + }; + }); + + return ( +
+ {themes.value.length > 1 ? ( + themes.value.map(theme => ( + + + + )) + ) : ( + + )} +
+ ); + })} + , + ); + }; + }, +}); + +export default ComponentDemoGroup; diff --git a/site/src/components/antdv-token-previewer/component-panel/ComponentTokenDrawer.tsx b/site/src/components/antdv-token-previewer/component-panel/ComponentTokenDrawer.tsx new file mode 100644 index 000000000..d06bec045 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-panel/ComponentTokenDrawer.tsx @@ -0,0 +1,245 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, computed } from 'vue'; +import { BuildOutlined, CarOutlined } from '@ant-design/icons-vue'; +import { ConfigProvider, Drawer, Empty, Tag, theme as antdTheme, Tooltip } from 'ant-design-vue'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import ComponentDemos from '../component-demos'; +import type { AliasToken, ComponentDemo, MutableTheme, TokenName, TokenValue } from '../interface'; +import { useInjectLocaleContext } from '../locale'; +// import TokenCard from '../token-panel/token-card'; +import getDesignToken from '../utils/getDesignToken'; +import makeStyle from '../utils/makeStyle'; +import { getComponentToken } from '../utils/statistic'; +import ComponentCard from './ComponentCard'; + +const { defaultAlgorithm } = antdTheme; + +const useStyle = makeStyle('ComponentTokenDrawer', token => ({ + '.previewer-component-token-drawer': { + [`&${token.rootCls}-drawer ${token.rootCls}-drawer-body`]: { + padding: '0 !important', + }, + + '.previewer-component-drawer-subtitle': { + fontWeight: token.fontWeightStrong, + marginBottom: token.marginSM, + marginInlineStart: token.marginXS, + color: token.colorText, + }, + + '.previewer-component-token-drawer-theme': { + fontWeight: 'normal', + marginInlineStart: 8, + borderRadius: 4, + backgroundColor: token.colorInfoBg, + color: token.colorPrimary, + borderColor: token.colorInfoBg, + }, + }, +})); + +export type ComponentFullDemosProps = { + demos: ComponentDemo[]; +}; + +const useComponentFullDemosStyle = makeStyle('ComponentFullDemos', token => ({ + '.previewer-component-full-demos': { + flex: 1, + overflow: 'auto', + padding: 24, + backgroundColor: token.colorBgLayout, + '> *:not(:last-child)': { + marginBottom: 12, + }, + }, +})); + +const ComponentFullDemos = defineComponent({ + name: 'ComponentFullDemos', + inheritAttrs: false, + props: { + demos: { type: Array as PropType }, + }, + setup(props, { attrs }) { + const { demos } = toRefs(props); + const [, hashId] = useComponentFullDemosStyle(); + const locale = useInjectLocaleContext(); + + return () => { + return ( +
+ {demos.value?.map(demo => ( + + + {locale.value.demo.relatedTokens}: {demo.tokens?.join(', ')} + {(demo.tokens?.length || 0) > 2 ? '...' : ''} + + + } + > + {demo.demo} + + ))} +
+ ); + }; + }, +}); + +export type ComponentTokenDrawerProps = { + open?: boolean; + component?: string; + onClose?: () => void; + theme: MutableTheme; + onTokenClick?: (token: TokenName) => void; +}; + +const ComponentTokenDrawer = defineComponent({ + name: 'ComponentTokenDrawer', + inheritAttrs: false, + props: { + open: { type: Boolean }, + component: { type: String, default: 'Button' }, + onClose: { type: Function }, + theme: { type: Object as PropType }, + onTokenClick: { type: Function as PropType<(token: TokenName) => void> }, + }, + setup(props) { + const { open, component, theme } = toRefs(props); + + const [, hashId] = useStyle(); + + const { component: componentToken, global: aliasTokenNames } = getComponentToken( + component.value, + ) || { + global: [], + }; + + const componentTokenData = computed(() => Object.keys(componentToken.value ?? {})); + + const aliasTokenData = computed(() => { + return aliasTokenNames.value.sort(); + }); + + const handleComponentTokenChange = (token: string, value: TokenValue) => { + theme.value.onThemeChange?.( + { + ...theme.value.config, + components: { + ...theme.value.config.components, + [component.value]: { + ...(theme.value.config.components as any)?.[component.value], + [token]: value, + }, + }, + }, + ['components', component.value, token], + ); + }; + + return () => { + return ( + ( +
+ {`${component.value} 组件 Token`} + {theme.value.name} +
+ ), + }} + onClose={props.onClose as any} + width={1200} + class={classNames('previewer-component-token-drawer', hashId.value)} + > +
+ + + + + +
+
Related Tokens / 相关 token
+ {/* } + hideUsageCount + defaultOpen + title="Component Token" + tokenArr={componentTokenData} + tokenPath={['components', component]} + themes={[theme]} + fallback={() => componentToken} + onTokenChange={(_, tokenName, value) => + handleComponentTokenChange(tokenName, value) + } + placeholder={ + + } + /> + } + hideUsageCount + themes={[theme]} + defaultOpen + title="Alias Token" + tokenArr={aliasTokenData} + tokenPath={['components', component]} + fallback={themeConfig => getDesignToken(themeConfig) as AliasToken} + onTokenChange={(_, tokenName, value) => + handleComponentTokenChange(tokenName, value) + } + placeholder={ + + } + /> */} +
+
+
+ ); + }; + }, +}); + +export default defineComponent({ + name: 'ComponentTokenDrawerProvider', + inheritAttrs: false, + props: { + open: { type: Boolean }, + component: { type: String }, + onClose: { type: Function }, + theme: { type: Object as PropType }, + }, + setup(props, { attrs }) { + return () => ( + // + + // + ); + }, +}); diff --git a/site/src/components/antdv-token-previewer/component-panel/ComponentTree.tsx b/site/src/components/antdv-token-previewer/component-panel/ComponentTree.tsx new file mode 100644 index 000000000..2a145a97d --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-panel/ComponentTree.tsx @@ -0,0 +1,201 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, watch, computed, ref } from 'vue'; +import { SearchOutlined } from '@ant-design/icons-vue'; +import { Badge, Input, Tree } from 'ant-design-vue'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import type { FilterMode } from '../FilterPanel'; +import makeStyle from '../utils/makeStyle'; +import { getRelatedComponents } from '../utils/statistic'; + +const { DirectoryTree } = Tree; + +const useStyle = makeStyle('ComponentTree', token => ({ + '.component-tree-wrapper': { + minWidth: 200, + borderInlineEnd: `${token.lineWidth}px ${token.lineType} ${token.colorSplit}`, + height: '100%', + overflow: 'hidden', + display: 'flex', + flexDirection: 'column', + paddingBlock: token.paddingXS, + + '.component-tree-search': { + margin: '0 8px 12px', + width: 'calc(100% - 16px)', + backgroundColor: 'rgba(0, 0, 0, 2%)', + borderRadius: token.borderRadiusLG, + height: 24, + input: { + fontSize: 12, + }, + '&:hover': { + backgroundColor: 'rgba(0, 0, 0, 4%)', + }, + }, + + [`${token.rootCls}-tree.component-tree`]: { + fontSize: token.fontSizeSM, + + '.component-tree-item.component-tree-item-highlight': { + color: token.colorPrimary, + }, + + [`${token.rootCls}-tree-node-content-wrapper`]: { + transition: `background-color ${token.motionDurationSlow}`, + borderRadius: 4, + }, + + [`${token.rootCls}-tree-treenode-selected ${token.rootCls}-tree-node-content-wrapper`]: { + color: token.colorTextLightSolid, + + '.component-tree-item.component-tree-item-highlight': { + color: token.colorTextLightSolid, + }, + }, + + '.component-tree-item': { + transition: `color ${token.motionDurationMid}`, + lineHeight: `24px`, + height: 24, + display: 'inline-block', + }, + }, + }, +})); + +export type ComponentTreeProps = { + onSelect?: (component: string) => void; + components: Record; + selectedTokens?: string[]; + filterMode?: FilterMode; + activeComponent?: string; +}; + +const getTreeItemId = (component: string) => `component-tree-item-${component}`; + +const ComponentTree = defineComponent({ + name: 'ComponentTree', + inheritAttrs: false, + props: { + onSelect: { type: Function as PropType<(component: string) => void> }, + components: { type: Object as PropType> }, + selectedTokens: { type: Array as PropType }, + filterMode: { type: String as PropType, default: 'filter' }, + activeComponent: { type: String }, + }, + setup(props, { attrs }) { + const { components, selectedTokens, filterMode, activeComponent } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + const treeRef = ref(null); + const search = ref(''); + + const relatedComponents = computed(() => { + return selectedTokens.value ? getRelatedComponents(selectedTokens.value) : []; + }); + + watch(activeComponent, val => { + treeRef.value?.querySelector(`#${getTreeItemId(val || '')}`)?.scrollIntoView({ + block: 'nearest', + inline: 'nearest', + }); + }); + + const treeData = computed(() => + Object.entries(components.value) + .filter( + ([, group]) => + (filterMode.value === 'highlight' || + !relatedComponents.value.length || + group.some(item => relatedComponents.value.includes(item))) && + (!search.value || + group.some(item => item.toLowerCase().includes(search.value.toLowerCase()))), + ) + .map(([type, group]) => ({ + title: type, + key: `type-${type}`, + children: group + .filter( + item => + (filterMode.value === 'highlight' || + !relatedComponents.value.length || + relatedComponents.value.includes(item)) && + (!search.value || item.toLowerCase().includes(search.value.toLowerCase())), + ) + .map(item => ({ + title: ( + + {item} + + ), + switcherIcon: () => ( + + ), + key: item, + })), + })), + ); + + const watcher = filterMode => { + if (filterMode === 'highlight') { + setTimeout(() => { + treeRef.value?.getElementsByClassName('component-tree-item-active')[0]?.scrollIntoView({ + block: 'start', + inline: 'nearest', + behavior: 'smooth', + }); + }, 100); + } + }; + watch(selectedTokens, () => { + watcher(filterMode.value); + }); + + watch(filterMode, val => { + watcher(val); + }); + + return () => { + return wrapSSR( +
+ (search.value = e.target.value)} + prefix={} + bordered={false} + class="component-tree-search" + /> +
+ props.onSelect?.(node[0] as string)} + expandAction="doubleclick" + /> +
+
, + ); + }; + }, +}); + +export default ComponentTree; diff --git a/site/src/components/antdv-token-previewer/component-panel/index.tsx b/site/src/components/antdv-token-previewer/component-panel/index.tsx new file mode 100644 index 000000000..cfaed4c26 --- /dev/null +++ b/site/src/components/antdv-token-previewer/component-panel/index.tsx @@ -0,0 +1,346 @@ +import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons-vue'; +import { Breadcrumb, Segmented, Switch } from 'ant-design-vue'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import type { PropType } from 'vue'; +import { defineComponent, ref, watch, watchEffect, computed, toRefs } from 'vue'; +import type { FilterMode } from '../FilterPanel'; +import type { Theme, TokenName } from '../interface'; +import makeStyle from '../utils/makeStyle'; +import { getRelatedComponents } from '../utils/statistic'; +import { getComponentDemoId } from './ComponentCard'; +import ComponentDemoGroup from './ComponentDemoGroup'; +import ComponentTree from './ComponentTree'; + +const BREADCRUMB_HEIGHT = 40; + +const useStyle = makeStyle('ComponentPanel', token => ({ + '.component-panel': { + boxShadow: + '0 2px 4px 0 rgba(0,0,0,0.05), 0 1px 2px 0 rgba(25,15,15,0.07), 0 0 1px 0 rgba(0,0,0,0.08)', + backgroundColor: '#fff', + display: 'flex', + borderRadius: 6, + height: '100%', + overflow: 'hidden', + + '.component-panel-main': { + display: 'flex', + flexDirection: 'column', + flex: 1, + width: 0, + + '.component-panel-head': { + padding: `${token.paddingSM}px ${token.paddingSM}px`, + flex: 'none', + backgroundColor: token.colorBgContainer, + display: 'flex', + alignItems: 'center', + borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorBgContainer}`, + + '> *:not(:first-child)': { + marginInlineStart: token.margin, + }, + + [`${token.rootCls}-segmented-item`]: { + minWidth: 52, + }, + }, + + '.component-panel-toggle-side-icon': { + flex: 'none', + cursor: 'pointer', + marginInlineEnd: token.marginXS, + + '.anticon': { + color: token.colorIcon, + transition: `color ${token.motionDurationMid}`, + + '&:hover': { + color: token.colorIconHover, + }, + }, + }, + }, + + '.component-panel-side': { + flex: 'none', + width: 200, + overflow: 'hidden', + transition: `transform ${token.motionDurationMid}, width ${token.motionDurationMid}`, + }, + + '.component-panel-side.component-panel-side-hidden': { + width: 0, + transform: 'translateX(-200px)', + }, + + '.component-demos-wrapper': { + display: 'flex', + flex: 1, + height: 0, + position: 'relative', + + '.component-demos-breadcrumb-wrapper': { + position: 'absolute', + top: 0, + insetInlineStart: 0, + width: '100%', + height: BREADCRUMB_HEIGHT, + zIndex: 20, + backgroundColor: token.colorBgContainer, + padding: '8px 16px', + transition: 'opacity 0.3s', + background: 'rgba(255, 255, 255, .6)', + backdropFilter: 'blur(10px)', + borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorBgContainer}`, + }, + }, + + '.component-demos': { + height: '100%', + overflow: 'auto', + flex: 1, + }, + }, +})); + +export const antdComponents = { + General: ['Button', 'Icon', 'Typography'], + Layout: ['Divider', 'Grid', 'Space'], + Navigation: ['Breadcrumb', 'Dropdown', 'Menu', 'Pagination', 'Steps'], + 'Date Entry': [ + 'AutoComplete', + 'Cascader', + 'Checkbox', + 'DatePicker', + 'Form', + 'Input', + 'InputNumber', + 'Mentions', + 'Radio', + 'Rate', + 'Select', + 'Slider', + 'Switch', + 'TimePicker', + 'Transfer', + 'TreeSelect', + 'Upload', + ], + 'Data Display': [ + 'Avatar', + 'Badge', + 'Calendar', + 'Card', + 'Carousel', + 'Collapse', + 'Descriptions', + 'Empty', + 'Image', + 'List', + 'Popover', + 'Segmented', + 'Statistic', + 'Table', + 'Tabs', + 'Tag', + 'Timeline', + 'Tooltip', + 'Tree', + ], + Feedback: [ + 'Alert', + 'Drawer', + 'Message', + 'Modal', + 'Notification', + 'Popconfirm', + 'Progress', + 'Result', + 'Skeleton', + 'Spin', + ], + Other: ['Anchor'], +}; + +export type ComponentPanelProps = { + themes: Theme[]; + selectedTokens?: string[]; + filterMode?: FilterMode; + onTokenClick?: (token: TokenName) => void; +}; + +const Index = defineComponent({ + name: 'Index', + inheritAttrs: false, + props: { + themes: { type: Array as PropType }, + selectedTokens: { type: Array as PropType }, + filterMode: { type: String as PropType }, + onTokenClick: { type: Function as PropType<(token: TokenName) => void> }, + }, + setup(props, { attrs }) { + const { themes, selectedTokens, filterMode } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + const showSide = ref(true); + const demosRef = ref(null); + const componentSize = ref<'large' | 'small' | 'middle'>('middle'); + const componentDisabled = ref(false); + const activeComponent = ref(); + const showBreadcrumb = ref(false); + + const relatedComponents = computed(() => { + return selectedTokens.value ? getRelatedComponents(selectedTokens.value) : []; + }); + + watch(selectedTokens, () => { + showSide.value = true; + }); + + watchEffect(() => { + const handleScroll = () => { + if (demosRef.value) { + showBreadcrumb.value = demosRef.value.scrollTop > 10; + for (let i = 0; i < demosRef.value.children.length; i++) { + if ( + demosRef.value.children[i].getBoundingClientRect().top + + demosRef.value.children[i].clientHeight - + demosRef.value.getBoundingClientRect().top > + BREADCRUMB_HEIGHT + ) { + activeComponent.value = demosRef.value.children[i]?.id.split('-').pop(); + break; + } + } + } + }; + + demosRef.value?.addEventListener('scroll', handleScroll); + const demosWrapper = demosRef.value; + return () => { + demosWrapper?.removeEventListener('scroll', handleScroll); + }; + }); + + const scrollToComponent = (component: string) => { + demosRef.value?.scrollTo({ + top: + (demosRef.value?.querySelector(`#${getComponentDemoId(component)}`) + ?.offsetTop || 0) - 38, + behavior: 'smooth', + }); + }; + + const activeComponentCategory = computed(() => { + if (!activeComponent.value) { + return undefined; + } + const key = Object.entries(antdComponents).find(([, value]) => + value.includes(activeComponent.value), + )?.[0]; + if (key) { + return (antdComponents as any)[key]; + } else { + return undefined; + } + }); + + return () => { + const demoGroup = () => ( + + ); + return wrapSSR( +
+
+ { + if (component.startsWith('type-')) { + scrollToComponent((antdComponents as any)[component.split('-')[1]][0]); + } else { + scrollToComponent(component); + } + }} + /> +
+
+
+
(showSide.value = !showSide.value)} + > + {showSide.value ? : } +
+
+ 组件尺寸: + (componentSize.value = value as any)} + options={[ + { label: '大', value: 'large' }, + { label: '中', value: 'middle' }, + { label: '小', value: 'small' }, + ]} + /> +
+
+ 禁用: + (componentDisabled.value = checked as boolean)} + /> +
+
+ +
+
, + ); + }; + }, +}); + +export default Index; diff --git a/site/src/components/antdv-token-previewer/hooks/useControlledTheme.tsx b/site/src/components/antdv-token-previewer/hooks/useControlledTheme.tsx new file mode 100644 index 000000000..b975b66a6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/hooks/useControlledTheme.tsx @@ -0,0 +1,98 @@ +import type { DerivativeFunc } from 'ant-design-vue/es/_util/cssinjs'; +import { theme as antTheme } from 'ant-design-vue'; +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; +import type { Ref } from 'vue'; +import { watchEffect, ref, computed } from 'vue'; +import type { MutableTheme, Theme } from '../interface'; +import deepUpdateObj from '../utils/deepUpdateObj'; +import getDesignToken from '../utils/getDesignToken'; +import getValueByPath from '../utils/getValueByPath'; + +const { darkAlgorithm: defaultDark, compactAlgorithm, defaultAlgorithm } = antTheme; + +export type ThemeCode = 'default' | 'dark' | 'compact'; +export const themeMap: Record> = { + dark: defaultDark, + compact: compactAlgorithm, + default: defaultAlgorithm, +}; + +export type SetThemeState = (theme: Theme, modifiedPath: string[], updated?: boolean) => void; + +export type UseControlledTheme = (options: { + theme?: Ref; + defaultTheme: Theme; + onChange?: (theme: Theme) => void; + darkAlgorithm?: Ref>; +}) => { + theme: Ref; + infoFollowPrimary: Ref; + onInfoFollowPrimaryChange: (value: boolean) => void; + updateRef: () => void; +}; + +const useControlledTheme: UseControlledTheme = ({ theme: customTheme, defaultTheme, onChange }) => { + const theme = ref(customTheme.value ?? defaultTheme); + const infoFollowPrimary = ref(false); + const themeRef = ref(theme.value); + const renderHolder = ref(0); + + const forceUpdate = () => (renderHolder.value = renderHolder.value + 1); + + const getNewTheme = (newTheme: Theme, force?: boolean): Theme => { + const newToken = { ...newTheme.config.token }; + if (infoFollowPrimary || force) { + newToken.colorInfo = getDesignToken(newTheme.config).colorPrimary; + } + return { ...newTheme, config: { ...newTheme.config, token: newToken } }; + }; + + const handleSetTheme: SetThemeState = newTheme => { + if (customTheme.value) { + onChange?.(getNewTheme(newTheme)); + } else { + theme.value = getNewTheme(newTheme); + } + }; + + const handleResetTheme = (path: string[]) => { + let newConfig = { ...theme.value.config }; + newConfig = deepUpdateObj(newConfig, path, getValueByPath(themeRef.value?.config, path)); + handleSetTheme({ ...theme.value, config: newConfig }, path); + }; + + const getCanReset = (origin: ThemeConfig, current: ThemeConfig) => (path: string[]) => { + return getValueByPath(origin, path) !== getValueByPath(current, path); + }; + + // Controlled theme change + watchEffect(() => { + if (customTheme.value) { + theme.value = customTheme.value; + } + }); + + const handleInfoFollowPrimaryChange = (value: boolean) => { + infoFollowPrimary.value = value; + if (value) { + theme.value = getNewTheme(theme.value, true); + } + }; + + return { + theme: computed(() => ({ + ...theme.value, + onThemeChange: (config, path) => handleSetTheme({ ...theme.value, config }, path), + onReset: handleResetTheme, + getCanReset: getCanReset(themeRef.value?.config, theme.value.config), + })), + infoFollowPrimary, + onInfoFollowPrimaryChange: handleInfoFollowPrimaryChange, + updateRef: () => { + themeRef.value = theme.value; + forceUpdate(); + }, + }; +}; + +export default useControlledTheme; diff --git a/site/src/components/antdv-token-previewer/icons/Arrow.js b/site/src/components/antdv-token-previewer/icons/Arrow.js new file mode 100644 index 000000000..4ddce1044 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Arrow.js @@ -0,0 +1,81 @@ +import { createVNode } from 'vue'; + +function Arrow(props) { + return /*#__PURE__*/ React.createElement( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 16 16', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ React.createElement( + 'g', + { + id: 'Arrow-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + }, + /*#__PURE__*/ React.createElement( + 'g', + { + id: 'Arrow-\u4E3B\u9898\u9884\u89C8\u5668---\u7EC4\u4EF6\u9884\u89C8', + transform: 'translate(-335.000000, -153.000000)', + fill: 'currentColor', + fillRule: 'nonzero', + }, + /*#__PURE__*/ React.createElement( + 'g', + { + id: 'Arrow-\u7F16\u7EC4-18', + transform: 'translate(0.000000, 70.000000)', + }, + /*#__PURE__*/ React.createElement( + 'g', + { + id: 'Arrow-\u7F16\u7EC4-13', + transform: 'translate(331.000000, 79.000000)', + }, + /*#__PURE__*/ React.createElement( + 'g', + { + id: 'Arrow-\u6298\u53E0\u7BAD\u5934_Black@2x', + transform: + 'translate(12.000000, 12.000000) rotate(90.000000) translate(-12.000000, -12.000000) translate(4.000000, 4.000000)', + }, + /*#__PURE__*/ React.createElement('rect', { + id: 'Arrow-\u77E9\u5F62', + opacity: 0, + x: 0, + y: 0, + width: 16, + height: 16, + }), + /*#__PURE__*/ React.createElement('path', { + d: 'M8.576,10.6224 C8.46400007,10.7357654 8.31136002,10.7997014 8.152,10.8 L7.848,10.8 C7.68897547,10.7980619 7.53693306,10.7343763 7.424,10.6224 L3.3184,6.4672 C3.16044703,6.30862179 3.16044703,6.05217821 3.3184,5.8936 L3.8864,5.3192 C3.95991079,5.24354153 4.06091047,5.20085176 4.1664,5.20085176 C4.27188953,5.20085176 4.37288921,5.24354153 4.4464,5.3192 L8,8.9168 L11.5536,5.3192 C11.6284927,5.24307539 11.7308111,5.20020394 11.8376,5.20020394 C11.9443889,5.20020394 12.0467073,5.24307539 12.1216,5.3192 L12.6816,5.8936 C12.839553,6.05217821 12.839553,6.30862179 12.6816,6.4672 L8.576,10.6224 Z', + id: 'Arrow-\u8DEF\u5F84', + }), + ), + ), + ), + ), + ), + ); +} + +export default Arrow; diff --git a/site/src/components/antdv-token-previewer/icons/Brush.js b/site/src/components/antdv-token-previewer/icons/Brush.js new file mode 100644 index 000000000..dbfca47a1 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Brush.js @@ -0,0 +1,59 @@ +import { createVNode } from 'vue'; + +function Brush(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 14 18', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Brush-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + fillOpacity: 0.649999976, + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Brush-\u4E3B\u9898\u7F16\u8F91\u5668---\u591A\u4E3B\u9898', + transform: 'translate(-17.000000, -121.000000)', + fill: 'currentColor', + fillRule: 'nonzero', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Brush-brush', + transform: 'translate(14.000000, 120.000000)', + }, + /*#__PURE__*/ createVNode('path', { + d: 'M8.20652175,3.2826087 L8.20652175,4.10326086 C8.20652175,4.55649455 7.83910325,4.92391304 7.38586957,4.92391304 C6.93263588,4.92391304 6.56521738,4.55649455 6.56521738,4.10326086 L6.56521738,3.2826087 L4.92391304,3.2826087 L4.92391304,8.20652175 L14.7717391,8.20652175 L14.7717391,3.2826087 L13.1304348,3.2826087 L13.1304348,5.74456522 C13.1304348,6.19779891 12.7630163,6.5652174 12.3097826,6.5652174 C11.8565489,6.5652174 11.4891304,6.19779891 11.4891304,5.74456522 L11.4891304,3.2826087 L8.20652175,3.2826087 Z M4.92391304,9.84782609 L4.92391304,11.4891304 L7.72233695,11.4891304 C8.08431263,11.4890155 8.42799204,11.6482243 8.66197039,11.9244136 C8.89594874,12.2006029 8.99650752,12.5657753 8.93690217,12.9228098 L8.60043479,14.9399728 C8.51784643,15.435105 8.73592476,15.9322123 9.15616576,16.2067558 C9.57640676,16.4812994 10.1192454,16.4812994 10.5394864,16.2067558 C10.9597274,15.9322123 11.1778057,15.435105 11.0952174,14.9399728 L10.75875,12.9228098 C10.6991446,12.5657753 10.7997034,12.2006029 11.0336818,11.9244136 C11.2676601,11.6482243 11.6113395,11.4890155 11.9733152,11.4891304 L14.7717391,11.4891304 L14.7717391,9.84782609 L4.92391304,9.84782609 Z M12.7143641,14.6699783 C12.9035912,15.807501 12.4022968,16.9492894 11.4368082,17.5798421 C10.4713197,18.2103948 9.2243325,18.2103948 8.25884395,17.5798421 C7.2933554,16.9492894 6.79206095,15.807501 6.98128804,14.6699783 L7.23815217,13.1304348 L4.92391304,13.1304348 C4.48861206,13.1304348 4.07113988,12.9575121 3.76333561,12.6497079 C3.45553133,12.3419036 3.2826087,11.9244314 3.2826087,11.4891304 L3.2826087,3.2826087 C3.2826087,2.84730772 3.45553133,2.42983554 3.76333561,2.12203126 C4.07113988,1.81422698 4.48861206,1.64130434 4.92391304,1.64130434 L14.7717391,1.64130434 C15.2070401,1.64130434 15.6245123,1.81422698 15.9323166,2.12203126 C16.2401208,2.42983554 16.4130435,2.84730772 16.4130435,3.2826087 L16.4130435,11.4891304 C16.4130435,11.9244314 16.2401208,12.3419036 15.9323166,12.6497079 C15.6245123,12.9575121 15.2070401,13.1304348 14.7717391,13.1304348 L12.4575,13.1304348 L12.7143641,14.6699783 L12.7143641,14.6699783 Z', + id: 'Brush-\u5F62\u72B6', + }), + ), + ), + ), + ); +} + +export default Brush; diff --git a/site/src/components/antdv-token-previewer/icons/Compact.tsx b/site/src/components/antdv-token-previewer/icons/Compact.tsx new file mode 100644 index 000000000..fa41cb766 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Compact.tsx @@ -0,0 +1,59 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent } from 'vue'; + +const Compact = defineComponent({ + name: 'Compact', + emits: ['click'], + setup(_, { attrs }) { + return () => { + return ( + + + + + + + + + + + + + ); + }; + }, +}); + +export default Compact; diff --git a/site/src/components/antdv-token-previewer/icons/Control.tsx b/site/src/components/antdv-token-previewer/icons/Control.tsx new file mode 100644 index 000000000..8fbd3d9d6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Control.tsx @@ -0,0 +1,100 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent } from 'vue'; + +const Control = defineComponent({ + name: 'Control', + emits: ['click'], + setup(_, { attrs }) { + return () => { + return ( + + + + + + + + + + + + + + + + + + + + + + ); + }; + }, +}); + +export default Control; diff --git a/site/src/components/antdv-token-previewer/icons/Dark.tsx b/site/src/components/antdv-token-previewer/icons/Dark.tsx new file mode 100644 index 000000000..e7cbfde35 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Dark.tsx @@ -0,0 +1,59 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent } from 'vue'; + +const Dark = defineComponent({ + name: 'Dark', + emits: ['click'], + setup(_, { attrs }) { + return () => { + return ( + + + + + + + + + + + + + ); + }; + }, +}); + +export default Dark; diff --git a/site/src/components/antdv-token-previewer/icons/Light.tsx b/site/src/components/antdv-token-previewer/icons/Light.tsx new file mode 100644 index 000000000..63622cdd0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Light.tsx @@ -0,0 +1,66 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent } from 'vue'; + +const Light = defineComponent({ + name: 'Light', + emits: ['click'], + setup(_, { attrs }) { + return () => { + return ( + + + + + + + + + + + + + + + + + ); + }; + }, +}); + +export default Light; diff --git a/site/src/components/antdv-token-previewer/icons/Margin.js b/site/src/components/antdv-token-previewer/icons/Margin.js new file mode 100644 index 000000000..6824c8471 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Margin.js @@ -0,0 +1,59 @@ +import { createVNode } from 'vue'; + +function Margin(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 16 17', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Margin-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Margin-margin', + transform: 'translate(0.000000, 0.942377)', + fill: 'currentColor', + fillRule: 'nonzero', + }, + /*#__PURE__*/ createVNode('rect', { + id: 'Margin-\u77E9\u5F62', + opacity: 0, + x: 0, + y: 0, + width: 16, + height: 15.9807923, + }), + /*#__PURE__*/ createVNode('path', { + d: 'M11.6666667,2.75858915 L4.33333333,2.75858915 C4.01904762,2.75858915 3.80952382,2.54931688 3.80952382,2.23540845 C3.80952382,1.92150003 4.01904763,1.71222775 4.33333334,1.71222775 L11.6666667,1.71222775 C11.9809524,1.71222775 12.1904762,1.92150003 12.1904762,2.23540845 C12.1904762,2.54931688 11.9809524,2.75858915 11.6666667,2.75858915 Z M11.6666667,14.2685646 L4.33333333,14.2685646 C4.01904762,14.2685646 3.8095238,14.0592923 3.8095238,13.7453839 C3.8095238,13.4314755 4.01904762,13.2222032 4.33333333,13.2222032 L11.6666667,13.2222032 C11.9809524,13.2222032 12.1904762,13.4314755 12.1904762,13.7453839 C12.1904762,14.0592923 11.9809524,14.2685646 11.6666667,14.2685646 Z M13.7619048,12.1758418 C13.447619,12.1758418 13.2380952,11.9665695 13.2380952,11.6526611 L13.2380952,4.32813125 C13.2380952,4.01422283 13.4476191,3.80495055 13.7619048,3.80495055 C14.0761905,3.80495055 14.2857143,4.01422283 14.2857143,4.32813125 L14.2857143,11.6526611 C14.2857143,11.9665695 14.0761905,12.1758418 13.7619048,12.1758418 Z M2.23809524,12.1758418 C1.92380953,12.1758418 1.71428572,11.9665695 1.71428572,11.6526611 L1.71428572,4.32813125 C1.71428572,4.01422283 1.92380953,3.80495055 2.23809524,3.80495055 C2.55238096,3.80495055 2.76190477,4.01422283 2.76190477,4.32813125 L2.76190477,11.6526611 C2.76190477,11.9665695 2.55238096,12.1758418 2.23809524,12.1758418 Z M11.6666667,12.1758418 L4.33333333,12.1758418 C4.01904762,12.1758418 3.8095238,11.9665695 3.8095238,11.6526611 L3.8095238,4.32813125 C3.8095238,4.01422283 4.01904763,3.80495055 4.33333334,3.80495055 L11.6666667,3.80495055 C11.9809524,3.80495055 12.1904762,4.01422283 12.1904762,4.32813125 L12.1904762,11.6526611 C12.1904762,11.9665695 11.9809524,12.1758418 11.6666667,12.1758418 Z M4.85714286,11.1294804 L11.1428571,11.1294804 L11.1428571,4.85131196 L4.85714286,4.85131196 L4.85714286,11.1294804 Z', + id: 'Margin-\u5F62\u72B6', + }), + ), + ), + ); +} + +export default Margin; diff --git a/site/src/components/antdv-token-previewer/icons/Motion.js b/site/src/components/antdv-token-previewer/icons/Motion.js new file mode 100644 index 000000000..b3de8a4e6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Motion.js @@ -0,0 +1,59 @@ +import { createVNode } from 'vue'; + +function Motion(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 16 17', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Motion-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'Motion-\u5BCC\u6587\u672C\u7F16\u8F91\u5668_\u52A8\u6548', + transform: 'translate(0.000000, 0.903962)', + fill: 'currentColor', + fillRule: 'nonzero', + }, + /*#__PURE__*/ createVNode('rect', { + id: 'Motion-\u77E9\u5F62', + opacity: 0, + x: 0, + y: 0, + width: 16, + height: 15.9807923, + }), + /*#__PURE__*/ createVNode('path', { + d: 'M6.55644444,12.5262777 L7.99555556,13.9627734 C8.13290682,14.0984321 8.18701716,14.2971622 8.13737053,14.4836147 C8.0877239,14.6700672 7.94192169,14.8156943 7.75524511,14.8652814 C7.56856853,14.9148684 7.36959959,14.860823 7.23377778,14.7236366 L5.79555556,13.2862532 C5.60250935,13.0737079 5.61045949,12.7472435 5.8136232,12.5443237 C6.01678692,12.3414038 6.3436437,12.3334632 6.55644444,12.5262777 L6.55644444,12.5262777 Z M12.2435556,12.6630023 L13.3857778,13.8038533 C13.5231286,13.9395121 13.5772386,14.138242 13.527592,14.3246942 C13.4779453,14.5111464 13.3321433,14.6567734 13.145467,14.7063605 C12.9587906,14.7559476 12.7598219,14.7019025 12.624,14.5647165 L11.4817778,13.4238655 C11.3444269,13.2882067 11.2903169,13.0894768 11.3399636,12.9030246 C11.3896103,12.7165724 11.5354123,12.5709454 11.7220886,12.5213583 C11.9087649,12.4717712 12.1077337,12.5258163 12.2435556,12.6630023 L12.2435556,12.6630023 Z M7.29511111,0.990809123 C7.37066667,1.03342457 7.43377778,1.09645992 7.47644444,1.17192476 L9.23911111,4.29439403 L12.7564444,5.00376364 C12.9258902,5.03768098 13.0638332,5.16026877 13.1172645,5.32441904 C13.1706959,5.4885693 13.1313024,5.66874209 13.0142222,5.79570068 L10.5866667,8.43430705 L10.9982222,11.9953603 C11.018176,12.1667991 10.94398,12.3356549 10.8041422,12.4370491 C10.6643043,12.5384432 10.4805781,12.5566027 10.3235556,12.4845501 L7.06133333,10.9930095 L3.79733333,12.4845501 C3.64031082,12.5566027 3.45658456,12.5384432 3.3167467,12.4370491 C3.17690884,12.3356549 3.10271286,12.1667991 3.12266667,11.9953603 L3.53511111,8.43519487 L1.10577778,5.79570068 C0.988697555,5.66874209 0.949304077,5.4885693 1.00273546,5.32441904 C1.05616684,5.16026877 1.19410976,5.03768098 1.36355556,5.00376364 L4.88177778,4.29439403 L6.64266667,1.17192476 C6.70502264,1.06136833 6.80886024,0.980137913 6.93126543,0.94615878 C7.05367063,0.912179648 7.18458201,0.928244805 7.29511111,0.990809123 Z M7.05955556,2.62440123 L5.57688889,5.25235374 L2.61688889,5.84808216 L4.65955556,8.07030012 L4.31288889,11.0666987 L7.05955556,9.81131866 L9.80533333,11.0666987 L9.45866667,8.07030012 L11.5031111,5.84896999 L8.54222222,5.25235374 L7.05866667,2.62440123 L7.05955556,2.62440123 Z M13.1528889,7.76045031 L14.5911111,9.19694597 C14.7892424,9.40878705 14.7837079,9.73933037 14.5785954,9.9444359 C14.373483,10.1495414 14.0425491,10.1554552 13.8302222,9.95780926 L12.3911111,8.5213136 C12.2537603,8.38565475 12.1996502,8.18692487 12.2492969,8.00047265 C12.2989436,7.81402043 12.4447456,7.66839345 12.6314219,7.61880637 C12.8180983,7.56921929 13.017067,7.62326436 13.1528889,7.76045031 L13.1528889,7.76045031 Z', + id: 'Motion-\u5F62\u72B6', + }), + ), + ), + ); +} + +export default Motion; diff --git a/site/src/components/antdv-token-previewer/icons/Pick.tsx b/site/src/components/antdv-token-previewer/icons/Pick.tsx new file mode 100644 index 000000000..d4f65b4ee --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/Pick.tsx @@ -0,0 +1,58 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent } from 'vue'; + +const Pick = defineComponent({ + name: 'Pick', + emits: ['click'], + setup(_, { attrs }) { + return () => { + return ( + + + + + + + + + + + + + + + + + + ); + }; + }, +}); + +export default Pick; diff --git a/site/src/components/antdv-token-previewer/icons/SearchDropdown.js b/site/src/components/antdv-token-previewer/icons/SearchDropdown.js new file mode 100644 index 000000000..d24126309 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/SearchDropdown.js @@ -0,0 +1,86 @@ +import { createVNode } from 'vue'; + +function SearchDropdown(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 18 18', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'SearchDropdown-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'SearchDropdown-\u4E3B\u9898\u9884\u89C8\u5668---\u7EC4\u4EF6\u9884\u89C8', + transform: 'translate(-23.000000, -198.000000)', + fillRule: 'nonzero', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'SearchDropdown-\u7F16\u7EC4-18', + transform: 'translate(0.000000, 70.000000)', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'SearchDropdown-\u7F16\u7EC4-15', + transform: 'translate(16.000000, 123.000000)', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'SearchDropdown-search-outlined', + transform: 'translate(7.000000, 5.000000)', + }, + /*#__PURE__*/ createVNode('rect', { + id: 'SearchDropdown-\u77E9\u5F62', + fill: '#000000', + opacity: 0, + x: 0, + y: 0, + width: 18, + height: 18, + }), + /*#__PURE__*/ createVNode('path', { + d: 'M15.958,14.99375 L11.41325,10.449 C12.1185,9.53725 12.5,8.4225 12.5,7.25 C12.5,5.8465 11.95225,4.5305 10.96175,3.53825 C9.97125,2.546 8.65175,2 7.25,2 C5.84825,2 4.52875,2.54775 3.53825,3.53825 C2.546,4.52875 2,5.8465 2,7.25 C2,8.65175 2.54775,9.97125 3.53825,10.96175 C4.52875,11.954 5.8465,12.5 7.25,12.5 C8.4225,12.5 9.5355,12.1185 10.44725,11.415 L14.992,15.958 C15.048,16.014 15.139,16.014 15.195,15.958 L15.958,15.19675 C16.014,15.14075 16.014,15.04975 15.958,14.99375 Z M10.022,10.022 C9.28,10.76225 8.2965,11.17 7.25,11.17 C6.2035,11.17 5.22,10.76225 4.478,10.022 C3.73775,9.28 3.33,8.2965 3.33,7.25 C3.33,6.2035 3.73775,5.21825 4.478,4.478 C5.22,3.73775 6.2035,3.33 7.25,3.33 C8.2965,3.33 9.28175,3.736 10.022,4.478 C10.76225,5.22 11.17,6.2035 11.17,7.25 C11.17,8.2965 10.76225,9.28175 10.022,10.022 Z', + id: 'SearchDropdown-\u5F62\u72B6', + fill: 'currentColor', + }), + /*#__PURE__*/ createVNode('path', { + d: 'M17.8616348,7.7578125 L14.0131973,7.7578125 C13.8977676,7.7578125 13.8333145,7.8796875 13.9047988,7.96289062 L15.8290176,10.1941406 C15.8840957,10.2580078 15.9901504,10.2580078 16.0458145,10.1941406 L17.9700332,7.96289062 C18.0415176,7.8796875 17.9770645,7.7578125 17.8616348,7.7578125 Z', + id: 'SearchDropdown-\u8DEF\u5F84', + fill: 'currentColor', + }), + ), + ), + ), + ), + ), + ); +} + +export default SearchDropdown; diff --git a/site/src/components/antdv-token-previewer/icons/ShapeLine.js b/site/src/components/antdv-token-previewer/icons/ShapeLine.js new file mode 100644 index 000000000..dae42b4ea --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/ShapeLine.js @@ -0,0 +1,59 @@ +import { createVNode } from 'vue'; + +function ShapeLine(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 16 17', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'ShapeLine-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'ShapeLine-shape-line', + transform: 'translate(0.000000, 0.923169)', + fill: 'currentColor', + fillRule: 'nonzero', + }, + /*#__PURE__*/ createVNode('rect', { + id: 'ShapeLine-\u77E9\u5F62', + opacity: 0, + x: 0, + y: 0, + width: 16, + height: 15.9807923, + }), + /*#__PURE__*/ createVNode('path', { + d: 'M5.22,13.3173269 C4.90928357,14.1946577 4.03334945,14.7416208 3.10760502,14.6363783 C2.18186059,14.5311359 1.45139881,13.801551 1.34602985,12.8769179 C1.24066088,11.9522848 1.78828141,11.0774022 2.66666667,10.7670588 L2.66666667,5.21373349 C1.78828141,4.90339007 1.24066088,4.02850749 1.34602985,3.1038744 C1.45139881,2.1792413 2.18186059,1.44965643 3.10760502,1.34441396 C4.03334945,1.23917149 4.90928357,1.78613461 5.22,2.66346539 L10.78,2.66346539 C11.0907164,1.78613461 11.9666505,1.23917149 12.892395,1.34441396 C13.8181394,1.44965643 14.5486012,2.1792413 14.6539702,3.1038744 C14.7593391,4.02850749 14.2117186,4.90339007 13.3333333,5.21373349 L13.3333333,10.7670588 C14.2117186,11.0774022 14.7593391,11.9522848 14.6539702,12.8769179 C14.5486012,13.801551 13.8181394,14.5311359 12.892395,14.6363783 C11.9666505,14.7416208 11.0907164,14.1946577 10.78,13.3173269 L5.22,13.3173269 Z M5.22,11.9855942 L10.78,11.9855942 C10.9819939,11.4165133 11.430235,10.9688103 12,10.7670588 L12,5.21373349 C11.430235,5.01198206 10.9819939,4.56427905 10.78,3.99519808 L5.22,3.99519808 C5.01800608,4.56427905 4.56976496,5.01198206 4,5.21373349 L4,10.7670588 C4.56976496,10.9688103 5.01800608,11.4165133 5.22,11.9855942 Z M3.33333333,3.99519809 C3.5715347,3.9952345 3.79165744,3.86832906 3.91076865,3.66229434 C4.02987987,3.45625961 4.02987987,3.20240385 3.91076865,2.99636913 C3.79165744,2.79033441 3.5715347,2.66342897 3.33333333,2.66346538 C2.96518335,2.66352168 2.66676872,2.96162371 2.66676872,3.32933173 C2.66676872,3.69703976 2.96518335,3.99514178 3.33333333,3.99519809 L3.33333333,3.99519809 Z M12.6666667,3.99519809 C12.904868,3.9952345 13.1249908,3.86832906 13.244102,3.66229434 C13.3632132,3.45625961 13.3632132,3.20240385 13.244102,2.99636913 C13.1249908,2.79033441 12.904868,2.66342897 12.6666667,2.66346538 C12.2985167,2.66352168 12.0001021,2.96162371 12.0001021,3.32933173 C12.0001021,3.69703976 12.2985167,3.99514178 12.6666667,3.99519809 L12.6666667,3.99519809 Z M12.6666667,13.3173269 C12.904868,13.3173633 13.1249908,13.1904579 13.244102,12.9844232 C13.3632132,12.7783885 13.3632132,12.5245327 13.244102,12.318498 C13.1249908,12.1124633 12.904868,11.9855578 12.6666667,11.9855942 C12.2985167,11.9856505 12.0001021,12.2837526 12.0001021,12.6514606 C12.0001021,13.0191686 12.2985167,13.3172706 12.6666667,13.3173269 L12.6666667,13.3173269 Z M3.33333333,13.3173269 C3.5715347,13.3173633 3.79165744,13.1904579 3.91076865,12.9844232 C4.02987987,12.7783885 4.02987987,12.5245327 3.91076865,12.318498 C3.79165744,12.1124633 3.5715347,11.9855578 3.33333333,11.9855942 C2.96518335,11.9856505 2.66676872,12.2837526 2.66676872,12.6514606 C2.66676872,13.0191686 2.96518335,13.3172706 3.33333333,13.3173269 L3.33333333,13.3173269 Z', + id: 'ShapeLine-\u5F62\u72B6', + }), + ), + ), + ); +} + +export default ShapeLine; diff --git a/site/src/components/antdv-token-previewer/icons/TokenPanel.js b/site/src/components/antdv-token-previewer/icons/TokenPanel.js new file mode 100644 index 000000000..0feeb0b0b --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/TokenPanel.js @@ -0,0 +1,87 @@ +import { createVNode } from 'vue'; + +function TokenPanel(props) { + return /*#__PURE__*/ createVNode( + 'svg', + Object.assign( + { + width: '1em', + height: '1em', + viewBox: '0 0 20 19', + xmlns: 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + }, + props, + { + style: Object.assign( + { + verticalAlign: '-0.125em', + }, + props.style, + ), + className: ['nanqu-token-panel-icon', props.className].filter(Boolean).join(' '), + }, + ), + /*#__PURE__*/ createVNode( + 'g', + { + id: 'TokenPanel-\u9875\u9762-1', + stroke: 'none', + strokeWidth: 1, + fill: 'none', + fillRule: 'evenodd', + fillOpacity: 0.85, + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'TokenPanel-\u4E3B\u9898\u7F16\u8F91\u5668---\u591A\u4E3B\u9898', + transform: 'translate(-14.000000, -70.000000)', + fill: 'currentColor', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'TokenPanel-\u7F16\u7EC4-3', + transform: 'translate(10.000000, 66.000000)', + }, + /*#__PURE__*/ createVNode( + 'g', + { + id: 'TokenPanel-\u7F16\u7EC4-20', + transform: 'translate(4.000000, 4.000000)', + }, + /*#__PURE__*/ createVNode('rect', { + id: 'TokenPanel-\u77E9\u5F62', + opacity: 0.600000024, + x: 1, + y: 12, + width: 7, + height: 7, + rx: 0.434782594, + }), + /*#__PURE__*/ createVNode('path', { + d: 'M12.3540059,0 L19.5652174,0 C19.8053412,8.08981097e-16 20,0.194658804 20,0.434782609 L20,7.6459941 C20,7.88611791 19.8053412,8.08077671 19.5652174,8.08077671 C19.4499059,8.08077671 19.3393172,8.03496939 19.2577797,7.95343183 L12.0465682,0.74222034 C11.876775,0.572427169 11.876775,0.297138048 12.0465682,0.127344878 C12.1281057,0.0458073219 12.2386944,-6.44951433e-16 12.3540059,0 Z', + id: 'TokenPanel-\u77E9\u5F62', + opacity: 0.400000006, + }), + /*#__PURE__*/ createVNode('circle', { + id: 'TokenPanel-\u692D\u5706\u5F62', + cx: 4.34782609, + cy: 4.34782609, + r: 4.34782609, + }), + /*#__PURE__*/ createVNode('circle', { + id: 'TokenPanel-\u692D\u5706\u5F62', + cx: 15.5, + cy: 15.5, + r: 3.5, + }), + ), + ), + ), + ), + ); +} + +export default TokenPanel; diff --git a/site/src/components/antdv-token-previewer/icons/index.ts b/site/src/components/antdv-token-previewer/icons/index.ts new file mode 100644 index 000000000..8e4dcfad4 --- /dev/null +++ b/site/src/components/antdv-token-previewer/icons/index.ts @@ -0,0 +1,15 @@ +export { default as Margin } from './Margin.js'; +export { default as Motion } from './Motion.js'; + +export { default as ShapeLine } from './ShapeLine.js'; + +export { default as Arrow } from './Arrow.js'; +export { default as SearchDropdown } from './SearchDropdown.js'; +export { default as TokenPanelIcon } from './TokenPanel.js'; +export { default as Brush } from './Brush.js'; + +export { default as Light } from './Light'; +export { default as DarkTheme } from './Dark'; +export { default as Pick } from './Pick'; +export { default as CompactTheme } from './Compact'; +export { default as Control } from './Control'; diff --git a/site/src/components/antdv-token-previewer/index.tsx b/site/src/components/antdv-token-previewer/index.tsx new file mode 100644 index 000000000..b6aa50e82 --- /dev/null +++ b/site/src/components/antdv-token-previewer/index.tsx @@ -0,0 +1,2 @@ +export * from './locale'; +export { default as ThemeEditor } from './ThemeEditor'; diff --git a/site/src/components/antdv-token-previewer/interface.ts b/site/src/components/antdv-token-previewer/interface.ts new file mode 100644 index 000000000..71d0f5ca7 --- /dev/null +++ b/site/src/components/antdv-token-previewer/interface.ts @@ -0,0 +1,38 @@ +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; +import { VueNode } from 'ant-design-vue/es/_util/type'; + +export type Theme = { + name: string; + key: string; + config: ThemeConfig; +}; + +export type AliasToken = Exclude; +export type TokenValue = string | number | string[] | number[] | boolean; +export type TokenName = keyof AliasToken; + +// 修改线 以上都是改过的 +export interface ComponentDemo { + tokens?: TokenName[]; + demo: VueNode; + key: string; +} + +export interface MutableTheme extends Theme { + onThemeChange?: (newTheme: ThemeConfig, path: string[]) => void; + onReset?: (path: string[]) => void; + getCanReset?: (path: string[]) => boolean; +} + +export type PreviewerProps = { + onSave?: (themeConfig: ThemeConfig) => void; + showTheme?: boolean; + theme?: Theme; + onThemeChange?: (config: ThemeConfig) => void; +}; + +export type SelectedToken = { + seed?: string[]; + map?: string[]; + alias?: string[]; +}; diff --git a/site/src/components/antdv-token-previewer/locale/context.ts b/site/src/components/antdv-token-previewer/locale/context.ts new file mode 100644 index 000000000..7d50b7c80 --- /dev/null +++ b/site/src/components/antdv-token-previewer/locale/context.ts @@ -0,0 +1,19 @@ +import type { Ref, InjectionKey } from 'vue'; +import { inject, provide, computed } from 'vue'; + +import type { Locale } from './interface'; +import zhCN from './zh-CN'; + +const contextKey: InjectionKey> = Symbol('localeContext'); + +export const useProvideLocaleContext = (props: Ref) => { + provide(contextKey, props); + return props; +}; + +export const useInjectLocaleContext = () => { + return inject( + contextKey, + computed(() => zhCN), + ); +}; diff --git a/site/src/components/antdv-token-previewer/locale/en-US.ts b/site/src/components/antdv-token-previewer/locale/en-US.ts new file mode 100644 index 000000000..af8160e2f --- /dev/null +++ b/site/src/components/antdv-token-previewer/locale/en-US.ts @@ -0,0 +1,20 @@ +import type { Locale } from './interface'; + +const locale: Locale = { + _lang: 'en-US', + followPrimary: 'Follow Brand Color', + reset: 'Reset', + next: 'Next', + groupView: 'Group View', + fill: 'Fill', + border: 'Border', + background: 'Background', + text: 'Text', + demo: { + overview: 'Overview', + components: 'Components', + relatedTokens: 'Related Tokens', + }, +}; + +export default locale; diff --git a/site/src/components/antdv-token-previewer/locale/index.ts b/site/src/components/antdv-token-previewer/locale/index.ts new file mode 100644 index 000000000..6eb5d1088 --- /dev/null +++ b/site/src/components/antdv-token-previewer/locale/index.ts @@ -0,0 +1,4 @@ +export { useProvideLocaleContext, useInjectLocaleContext } from './context'; +export { default as enUS } from './en-US'; +export type { Locale } from './interface'; +export { default as zhCN } from './zh-CN'; diff --git a/site/src/components/antdv-token-previewer/locale/interface.tsx b/site/src/components/antdv-token-previewer/locale/interface.tsx new file mode 100644 index 000000000..877d2a8db --- /dev/null +++ b/site/src/components/antdv-token-previewer/locale/interface.tsx @@ -0,0 +1,16 @@ +export type Locale = { + _lang: string; + followPrimary: string; + reset: string; + next: string; + groupView: string; + fill: string; + background: string; + border: string; + text: string; + demo: { + overview: string; + components: string; + relatedTokens: string; + }; +}; diff --git a/site/src/components/antdv-token-previewer/locale/zh-CN.ts b/site/src/components/antdv-token-previewer/locale/zh-CN.ts new file mode 100644 index 000000000..d969874bd --- /dev/null +++ b/site/src/components/antdv-token-previewer/locale/zh-CN.ts @@ -0,0 +1,20 @@ +import type { Locale } from './interface'; + +const locale: Locale = { + _lang: 'zh-CN', + followPrimary: '跟随主色', + reset: '重置', + next: '下一步', + groupView: '分组显示', + fill: '填充', + border: '描边', + background: '背景', + text: '文本', + demo: { + overview: '概览', + components: '组件', + relatedTokens: '关联 Token', + }, +}; + +export default locale; diff --git a/site/src/components/antdv-token-previewer/meta/TokenRelation.ts b/site/src/components/antdv-token-previewer/meta/TokenRelation.ts new file mode 100644 index 000000000..5e4e761a5 --- /dev/null +++ b/site/src/components/antdv-token-previewer/meta/TokenRelation.ts @@ -0,0 +1,188 @@ +import type { AliasToken, MapToken, SeedToken } from 'ant-design-vue/es/theme/interface'; +import defaultMap from 'ant-design-vue/es/theme/themes/default'; +import seedToken from 'ant-design-vue/es/theme/themes/seed'; +import formatToken from 'ant-design-vue/es/theme/util/alias'; + +export type PureAliasToken = Omit; + +type SeedRelatedMap = { + [key in keyof SeedToken]?: (keyof MapToken)[]; +}; + +type SeedRelatedAlias = { + [key in keyof SeedToken]?: (keyof PureAliasToken)[]; +}; + +type MapRelatedAlias = { + [key in keyof MapToken]?: (keyof PureAliasToken)[]; +}; + +// Alias Token 优先级排序,数字小的排在前面,在 map 中的优先级比不在 map 中的优先级高,都不在 map 中的按字母顺序排序 +const tokenOrder: { + [key in keyof AliasToken]?: number; +} = { + // example + // 0-20 留给 text + colorTextHeading: 1, + colorTextLabel: 2, + colorTextDescription: 3, + colorTextDisabled: 4, + colorTextPlaceholder: 5, + colorIcon: 10, + colorIconHover: 11, + // 21-40 留给 border + colorBorderBg: 21, + controlTmpOutline: 22, + // 41-60 留给 fill + colorFillAlter: 41, + colorFillContent: 42, + colorFillContentHover: 43, + + // 61-80 留给 bg + controlItemBgActive: 61, + controlItemBgActiveHover: 62, + controlItemBgHover: 63, +}; + +export function sortToken(arr: T): T { + if (!arr) { + return arr; + } + return arr.sort((a, b) => { + if (tokenOrder[a] && !tokenOrder[b]) { + return -1; + } + if (!tokenOrder[a] && tokenOrder[b]) { + return 1; + } + if (tokenOrder[a] && tokenOrder[b]) { + return tokenOrder[a]! - tokenOrder[b]!; + } + return a.localeCompare(b); + }); +} + +export const seedRelatedMap: SeedRelatedMap = { + colorPrimary: [ + 'colorPrimaryBg', + 'colorPrimaryBgHover', + 'colorPrimaryBorder', + 'colorPrimaryBorderHover', + 'colorPrimaryHover', + 'colorPrimary', + 'colorPrimaryActive', + 'colorPrimaryTextHover', + 'colorPrimaryText', + 'colorPrimaryTextActive', + ], + colorError: [ + 'colorErrorBg', + 'colorErrorBgHover', + 'colorErrorBorder', + 'colorErrorBorderHover', + 'colorErrorHover', + 'colorError', + 'colorErrorActive', + 'colorErrorTextHover', + 'colorErrorText', + 'colorErrorTextActive', + ], + colorWarning: [ + 'colorWarningBg', + 'colorWarningBgHover', + 'colorWarningBorder', + 'colorWarningBorderHover', + 'colorWarningHover', + 'colorWarning', + 'colorWarningActive', + 'colorWarningTextHover', + 'colorWarningText', + 'colorWarningTextActive', + ], + colorSuccess: [ + 'colorSuccessBg', + 'colorSuccessBgHover', + 'colorSuccessBorder', + 'colorSuccessBorderHover', + 'colorSuccessHover', + 'colorSuccess', + 'colorSuccessActive', + 'colorSuccessTextHover', + 'colorSuccessText', + 'colorSuccessTextActive', + ], + colorInfo: [ + 'colorInfoBg', + 'colorInfoBgHover', + 'colorInfoBorder', + 'colorInfoBorderHover', + 'colorInfoHover', + 'colorInfo', + 'colorInfoActive', + 'colorInfoTextHover', + 'colorInfoText', + 'colorInfoTextActive', + ], + colorTextBase: ['colorText', 'colorTextSecondary', 'colorTextTertiary', 'colorTextQuaternary'], + colorBgBase: [ + 'colorBgContainer', + 'colorBgElevated', + 'colorBgLayout', + 'colorBgSpotlight', + 'colorBgMask', + 'colorBorder', + 'colorBorderSecondary', + 'colorFill', + 'colorFillSecondary', + 'colorFillTertiary', + 'colorFillQuaternary', + ], +}; + +const getMapRelatedAlias = () => { + const mapRelatedAlias: any = {}; + const mapFn = defaultMap; + const mapToken = mapFn({ ...seedToken }); + const aliasToken = formatToken({ ...mapToken, override: {} }); + Object.keys(mapToken).forEach(mapKey => { + delete (aliasToken as any)[mapKey]; + }); + + Object.keys(mapToken).forEach(mapKey => { + const newAlias = formatToken({ + ...mapToken, + [mapKey]: 'changed', + override: {}, + }); + Object.keys(aliasToken).forEach(aliasKey => { + if ((aliasToken as any)[aliasKey] !== (newAlias as any)[aliasKey]) { + if (!mapRelatedAlias[mapKey]) { + mapRelatedAlias[mapKey] = []; + } + mapRelatedAlias[mapKey].push(aliasKey); + } + }); + mapRelatedAlias[mapKey] = sortToken(mapRelatedAlias[mapKey]); + }); + + return mapRelatedAlias; +}; + +export const mapRelatedAlias: MapRelatedAlias = getMapRelatedAlias(); + +const getSeedRelatedAlias = (): SeedRelatedAlias => { + const result: SeedRelatedAlias = {}; + Object.keys(seedToken).forEach(key => { + const seedKey = key as keyof SeedToken; + const arr = mapRelatedAlias[seedKey] || []; + seedRelatedMap[seedKey]?.forEach(mapKey => { + arr.push(...(mapRelatedAlias[mapKey] ?? [])); + }); + if (arr.length) { + (result as any)[key] = sortToken(Array.from(new Set(arr))); + } + }); + return result; +}; + +export const seedRelatedAlias = getSeedRelatedAlias(); diff --git a/site/src/components/antdv-token-previewer/meta/category.ts b/site/src/components/antdv-token-previewer/meta/category.ts new file mode 100644 index 000000000..e60678247 --- /dev/null +++ b/site/src/components/antdv-token-previewer/meta/category.ts @@ -0,0 +1,238 @@ +import type { AliasToken } from '../interface'; +import type { TokenTree } from './interface'; +import { seedRelatedAlias, seedRelatedMap } from './TokenRelation'; + +const category: TokenTree = [ + { + name: '颜色', + nameEn: 'Color', + desc: '', + descEn: '', + groups: [ + { + key: 'brandColor', + type: 'Color', + name: '品牌色', + nameEn: 'Brand Color', + desc: '品牌色是体现产品特性和传播理念最直观的视觉元素之一。在你完成品牌主色的选取之后,我们会自动帮你生成一套完整的色板,并赋予它们有效的设计语义。', + descEn: '', + seedToken: ['colorPrimary'], + mapToken: seedRelatedMap.colorPrimary, + aliasToken: seedRelatedAlias.colorPrimary, + }, + { + key: 'successColor', + type: 'Color', + name: '成功色', + nameEn: 'Success Color', + desc: '', + descEn: '', + seedToken: ['colorSuccess'], + mapToken: seedRelatedMap.colorSuccess, + aliasToken: seedRelatedAlias.colorSuccess, + }, + { + key: 'warningColor', + type: 'Color', + name: '警戒色', + nameEn: 'Warning Color', + desc: '', + descEn: '', + seedToken: ['colorWarning'], + mapToken: seedRelatedMap.colorWarning, + aliasToken: seedRelatedAlias.colorWarning, + }, + { + key: 'errorColor', + type: 'Color', + name: '错误色', + nameEn: 'Error Color', + desc: '', + descEn: '', + seedToken: ['colorError'], + mapToken: seedRelatedMap.colorError, + aliasToken: seedRelatedAlias.colorError, + }, + { + key: 'infoColor', + type: 'Color', + name: '信息色', + nameEn: 'Info Color', + desc: '', + descEn: '', + seedToken: ['colorInfo'], + mapToken: seedRelatedMap.colorInfo, + aliasToken: seedRelatedAlias.colorInfo, + }, + { + key: 'neutralColor', + type: 'Color', + name: '中性色', + nameEn: 'Neutral Color', + desc: '中性色主要被大量的应用在界面的文字、背景、边框和填充的 4 种场景。合理地选择中性色能够令页面信息具备良好的主次关系,助力阅读体验。', + descEn: '', + seedToken: ['colorTextBase', 'colorBgBase'], + mapToken: seedRelatedMap.colorTextBase?.concat(seedRelatedMap.colorBgBase ?? []), + aliasToken: seedRelatedAlias.colorTextBase?.concat(seedRelatedAlias.colorBgBase ?? []), + aliasTokenDescription: + '你可以利用 Alias Token 来精准控制部分组件的效果。例如 Input 、InputNumber、Select 等Control 类组件都共享了相同的 controlXX token 。只需修改值,即可实现不改变 Button 的情况下,修改 Control 类组件的效果。', + mapTokenGroups: ['text', 'border', 'fill', 'background'], + }, + ], + }, + { + name: '尺寸', + nameEn: 'Size', + desc: '', + descEn: '', + groups: [ + { + key: 'font', + name: '文字', + nameEn: 'Font', + desc: '', + descEn: '', + seedToken: ['fontSize'], + groups: [ + { + key: 'fontSize', + type: 'FontSize', + name: '字号', + nameEn: 'Font Size', + desc: '', + descEn: '', + mapToken: [ + 'fontSize', + 'fontSizeSM', + 'fontSizeLG', + 'fontSizeXL', + 'fontSizeHeading1', + 'fontSizeHeading2', + 'fontSizeHeading3', + 'fontSizeHeading4', + 'fontSizeHeading5', + ], + aliasToken: ['fontSizeIcon'], + }, + { + key: 'lineHeight', + type: 'LineHeight', + name: '行高', + nameEn: 'Line Height', + desc: '', + descEn: '', + mapToken: [ + 'lineHeight', + 'lineHeightSM', + 'lineHeightLG', + 'lineHeightHeading1', + 'lineHeightHeading2', + 'lineHeightHeading3', + 'lineHeightHeading4', + 'lineHeightHeading5', + ], + }, + ], + }, + { + key: 'spacing', + name: '间距', + nameEn: 'Spacing', + desc: '', + descEn: '', + seedToken: ['sizeStep', 'sizeUnit'], + groups: [ + { + key: 'margin', + type: 'Margin', + name: '外间距', + nameEn: 'Margin', + desc: '', + descEn: '', + mapToken: [ + 'marginXXS', + 'marginXS', + 'marginSM', + 'margin', + 'marginMD', + 'marginLG', + 'marginXL', + 'marginXXL', + ], + }, + { + key: 'padding', + type: 'Padding', + name: '内间距', + nameEn: 'Padding', + desc: '', + descEn: '', + mapToken: [ + 'paddingXXS', + 'paddingXS', + 'paddingSM', + 'padding', + 'paddingMD', + 'paddingLG', + 'paddingXL', + ], + aliasToken: [ + 'paddingContentHorizontal', + 'paddingContentVertical', + 'paddingContentHorizontalSM', + 'paddingContentVerticalSM', + 'paddingContentHorizontalLG', + 'paddingContentVerticalLG', + ], + }, + ], + }, + ], + }, + { + name: '风格', + nameEn: 'Style', + desc: '', + descEn: '', + groups: [ + { + key: 'borderRadius', + type: 'BorderRadius', + name: '圆角', + nameEn: 'Border Radius', + desc: '', + descEn: '', + seedToken: ['borderRadius'], + mapToken: ['borderRadius', 'borderRadiusSM', 'borderRadiusLG', 'borderRadiusXS'], + }, + { + key: 'boxShadow', + type: 'BoxShadow', + name: '阴影', + nameEn: 'Shadow', + desc: '', + descEn: '', + mapToken: ['boxShadow', 'boxShadowSecondary'], + }, + ], + }, + { + name: '其他', + nameEn: 'Others', + desc: '', + descEn: '', + groups: [ + { + key: 'other', + type: 'other', + name: '其他', + nameEn: 'Others', + desc: '', + descEn: '', + seedToken: ['wireframe'], + }, + ], + }, +]; + +export default category; diff --git a/site/src/components/antdv-token-previewer/meta/index.ts b/site/src/components/antdv-token-previewer/meta/index.ts new file mode 100644 index 000000000..b9dd30057 --- /dev/null +++ b/site/src/components/antdv-token-previewer/meta/index.ts @@ -0,0 +1 @@ +export { default as tokenCategory } from './category'; diff --git a/site/src/components/antdv-token-previewer/meta/interface.ts b/site/src/components/antdv-token-previewer/meta/interface.ts new file mode 100644 index 000000000..92347afe6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/meta/interface.ts @@ -0,0 +1,61 @@ +import type { ComponentTokenMap } from 'ant-design-vue/es/theme/interface'; + +export interface TokenMeta { + type: string; + + // Name + name: string; + nameEn: string; + + // Description + desc: string; + descEn: string; + + // Source + source: 'seed' | 'map' | 'alias' | 'custom' | keyof ComponentTokenMap; +} + +export type TokenMetaMap = Record; + +// 二级分类,如品牌色、中性色等 +export type TokenGroup = { + key: string; + + // Group name + name: string; + nameEn: string; + + // Description + desc: string; + descEn: string; + + // Type + type?: string; + + // Seed token + seedToken?: T[]; + mapToken?: T[]; + aliasToken?: T[]; + + // Children Group + groups?: TokenGroup[]; + + // Extra + mapTokenGroups?: string[]; + aliasTokenDescription?: string; +}; + +// 一级分类,如颜色、尺寸等 +export type TokenCategory = { + // Category name + name: string; + nameEn: string; + + // Description + desc: string; + descEn: string; + + groups: TokenGroup[]; +}; + +export type TokenTree = TokenCategory[]; diff --git a/site/src/components/antdv-token-previewer/overviews/Error.tsx b/site/src/components/antdv-token-previewer/overviews/Error.tsx new file mode 100644 index 000000000..8fff9f9b3 --- /dev/null +++ b/site/src/components/antdv-token-previewer/overviews/Error.tsx @@ -0,0 +1,49 @@ +import { Card, Space } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import Alert from '../component-demos/alert/error'; +import Button from '../component-demos/button/dangerButton'; +import Message from '../component-demos/message/error'; +import Progress from '../component-demos/progress/danger'; +import Tag from '../component-demos/tag/error'; +import Badge from '../component-demos/badge/badge'; +import Menu from '../component-demos/menu/menuDanger'; +import Upload from '../component-demos/upload/danger'; +import Dropdown from '../component-demos/dropdown/dropdownError'; +import Notification from '../component-demos/notification/error'; +import Timeline from '../component-demos/timeline/danger'; + +export const Error = defineComponent({ + name: 'Error', + setup() { + return () => { + return ( + + + + + {Button.demo} +
{Tag.demo}
+ {Badge.demo} +
+ {Alert.demo} +
+ + {Message.demo} + {Progress.demo} + +
+ +
{Notification.demo}
+
{Timeline.demo}
+
+ + {Menu.demo} +
{Upload.demo}
+ {Dropdown.demo} +
+
+ ); + }; + }, +}); diff --git a/site/src/components/antdv-token-previewer/overviews/Primary.tsx b/site/src/components/antdv-token-previewer/overviews/Primary.tsx new file mode 100644 index 000000000..1350cb6bf --- /dev/null +++ b/site/src/components/antdv-token-previewer/overviews/Primary.tsx @@ -0,0 +1,55 @@ +import { Card, Space } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import Menu from '../component-demos/menu/menu'; +import SelectTag from '../component-demos/select/selectTag'; +import Button from '../component-demos/button/button-icon'; +import Switch from '../component-demos/switch/switch'; +import Radio from '../component-demos/radio/radio'; +import RadioButton from '../component-demos/radio/button'; +import Checkbox from '../component-demos/checkbox/checkbox'; +import Tabs from '../component-demos/tabs/tabs'; +import Pagination from '../component-demos/pagination/outline'; +import Steps from '../component-demos/steps/steps'; +import Popconfirm from '../component-demos/popconfirm/popconfirm'; +import Timeline from '../component-demos/timeline/timeline'; +import Table from '../component-demos/table/table'; + +export const Primary = defineComponent({ + name: 'Primary', + setup() { + return () => { + return ( + + + + {Menu.demo} + + + +
{Button.demo}
+
+ {Radio.demo} + {Checkbox.demo} + {Switch.demo} +
+
{RadioButton.demo}
+ {Tabs.demo} +
+ {SelectTag.demo} +
+ {Pagination.demo} +
{Steps.demo}
+ + {Popconfirm.demo} + {Timeline.demo} + +
+
+ {Table.demo} +
+
+ ); + }; + }, +}); diff --git a/site/src/components/antdv-token-previewer/overviews/Success.tsx b/site/src/components/antdv-token-previewer/overviews/Success.tsx new file mode 100644 index 000000000..16335c143 --- /dev/null +++ b/site/src/components/antdv-token-previewer/overviews/Success.tsx @@ -0,0 +1,41 @@ +import { Card, Space } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import Alert from '../component-demos/alert/success'; +import Message from '../component-demos/message/success'; +import Progress from '../component-demos/progress/success'; +import Tag from '../component-demos/tag/success'; +import Input from '../component-demos/input/success'; +import Result from '../component-demos/result/success'; +import Notification from '../component-demos/notification/success'; +import Timeline from '../component-demos/timeline/success'; + +export const Success = defineComponent({ + name: 'Success', + setup() { + return () => { + return ( + + + + +
{Tag.demo}
+ {Input.demo} +
+ {Alert.demo} +
+ + {Message.demo} + {Progress.demo} + +
+ +
{Notification.demo}
+
{Timeline.demo}
+
+ {Result.demo} +
+ ); + }; + }, +}); diff --git a/site/src/components/antdv-token-previewer/overviews/Warning.tsx b/site/src/components/antdv-token-previewer/overviews/Warning.tsx new file mode 100644 index 000000000..8fa276a25 --- /dev/null +++ b/site/src/components/antdv-token-previewer/overviews/Warning.tsx @@ -0,0 +1,49 @@ +import { Card, Space } from 'ant-design-vue'; +import { defineComponent } from 'vue'; + +import Alert from '../component-demos/alert/warning'; +import Message from '../component-demos/message/warning'; +import Popconfirm from '../component-demos/popconfirm/popconfirm'; +import Modal from '../component-demos/modal/warning'; +import Badge from '../component-demos/badge/warning'; +import Text from '../component-demos/typography/warningText'; +import Title from '../component-demos/typography/warningTitle'; +import Tag from '../component-demos/tag/warning'; +import Input from '../component-demos/input/warning'; +import Result from '../component-demos/result/warning'; +import Notification from '../component-demos/notification/warning'; + +export const Warning = defineComponent({ + name: 'Warning', + setup() { + return () => { + return ( + + + + +
{Title.demo}
+
{Input.demo}
+
+ {Alert.demo} +
+ + {Message.demo} + {Popconfirm.demo} + + {Badge.demo} + {Tag.demo} + {Text.demo} + + +
+ +
{Notification.demo}
+
{Modal.demo}
+
+ {Result.demo} +
+ ); + }; + }, +}); diff --git a/site/src/components/antdv-token-previewer/overviews/index.ts b/site/src/components/antdv-token-previewer/overviews/index.ts new file mode 100644 index 000000000..5ade0532e --- /dev/null +++ b/site/src/components/antdv-token-previewer/overviews/index.ts @@ -0,0 +1,4 @@ +export * from './Primary'; +export * from './Success'; +export * from './Warning'; +export * from './Error'; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/AliasPanel.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/AliasPanel.tsx new file mode 100644 index 000000000..d23936f6c --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/AliasPanel.tsx @@ -0,0 +1,259 @@ +import { + CaretRightOutlined, + QuestionCircleOutlined, + RightOutlined, + ShrinkOutlined, +} from '@ant-design/icons-vue'; +import { Button, Collapse, Empty, Tooltip } from 'ant-design-vue'; +import type { MutableTheme } from '../interface'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import useMergedState from 'ant-design-vue/es/_util/hooks/useMergedState'; +import { PropType, Ref } from 'vue'; +import { defineComponent, toRefs, computed } from 'vue'; +import { Pick } from '../icons'; +import type { AliasToken, SelectedToken } from '../interface'; +import { mapRelatedAlias, seedRelatedAlias } from '../meta/TokenRelation'; +import makeStyle from '../utils/makeStyle'; +import { getRelatedComponents } from '../utils/statistic'; +import TokenDetail from './TokenDetail'; + +const { Panel } = Collapse; + +const useStyle = makeStyle('TokenPanelProAlias', token => ({ + '.token-panel-pro-color-alias': { + display: 'flex', + flexDirection: 'column', + marginTop: 45, + borderTop: `1px solid ${token.colorSplit}`, + + '.token-panel-pro-color-alias-title': { + display: 'flex', + alignItems: 'center', + padding: '0 16px', + flex: '0 0 60px', + + '&-text': { + fontSize: token.fontSizeLG, + fontWeight: token.fontWeightStrong, + }, + }, + + '.token-panel-pro-color-alias-description': { + color: token.colorTextTertiary, + fontSize: token.fontSizeSM, + lineHeight: token.lineHeightSM, + padding: '0 16px 12px', + }, + + [`.token-panel-pro-alias-collapse${token.rootCls}-collapse`]: { + [`> ${token.rootCls}-collapse-item > ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]: + { + paddingBlock: '0', + }, + + [`> ${token.rootCls}-collapse-item`]: { + [`> ${token.rootCls}-collapse-header`]: { + alignItems: 'center', + padding: '8px 16px', + [`> ${token.rootCls}-collapse-header-text`]: { + flex: 1, + + '.token-panel-pro-token-collapse-map-collapse-count': { + color: token.colorTextSecondary, + display: 'inline-block', + fontSize: 12, + lineHeight: '16px', + padding: '0 6px', + backgroundColor: token.colorFillAlter, + borderRadius: 999, + }, + }, + + '.token-panel-pro-token-picked': { + color: token.colorPrimary, + }, + }, + }, + }, + + '.token-panel-pro-color-alias-expand': { + height: '100%', + width: 20, + transform: 'translateX(-50%)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + + '&:hover': { + '.token-panel-pro-color-alias-expand-handler': { + opacity: 1, + }, + }, + + '.token-panel-pro-color-alias-expand-handler': { + height: 100, + width: 16, + borderRadius: 999, + border: `1px solid ${token.colorSplit}`, + backgroundColor: '#fff', + margin: 'auto', + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + opacity: 0, + transition: 'box-shadow 0.2s', + + '&:hover': { + boxShadow: token.boxShadow, + }, + }, + }, + }, +})); + +export type AliasPanelProps = { + theme: MutableTheme; + activeSeeds?: string[]; + selectedTokens?: SelectedToken; + onTokenSelect?: (token: string, type: keyof SelectedToken) => void; + open?: boolean; + onOpenChange?: (open: boolean) => void; + description?: string; +}; + +const AliasPanel = defineComponent({ + name: 'AliasPanel', + inheritAttrs: false, + props: { + theme: { type: Object as PropType }, + activeSeeds: { type: Array as PropType }, + selectedTokens: { type: Object as PropType }, + onTokenSelect: { + type: Function as PropType<(token: string, type: keyof SelectedToken) => void>, + }, + open: { type: Boolean }, + onOpenChange: { type: Function as PropType<(open: boolean) => void> }, + description: { type: String }, + }, + setup(props, { attrs }) { + const { activeSeeds, theme, selectedTokens, open: customOpen, description } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + + const [open, setOpen] = useMergedState(customOpen.value ?? true, { + value: customOpen, + onChange: props.onOpenChange, + }); + + const shownAlias = computed(() => + (selectedTokens as Ref).value?.map?.length + ? Array.from( + new Set( + (selectedTokens as Ref).value?.map.reduce((result, map) => { + return result.concat(...((mapRelatedAlias as any)[map] ?? [])); + }, []), + ), + ) + : activeSeeds.value?.reduce<(keyof AliasToken)[]>( + (result, item) => result.concat((seedRelatedAlias as any)[item] ?? []), + [], + ), + ); + + return () => { + return wrapSSR( +
+ {open.value ? ( + <> +
+ Alias Token + + + +
+ {description.value && ( +
{description.value}
+ )} +
+ ( + + ), + }} + > + {shownAlias.value?.map(aliasToken => ( + ( +
+ {aliasToken} + + {getRelatedComponents(aliasToken).length} + +
{ + e.stopPropagation(); + props.onTokenSelect?.(aliasToken, 'alias'); + }} + > + + ).value?.alias?.includes(aliasToken), + })} + /> +
+
+ ), + }} + > + +
+ ))} +
+ {!shownAlias.value?.length && ( + + )} +
+ + ) : ( +
+
setOpen(true)}> + +
+
+ )} +
, + ); + }; + }, +}); + +export default AliasPanel; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/ComponentDemoPro.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/ComponentDemoPro.tsx new file mode 100644 index 000000000..e4ba0a983 --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/ComponentDemoPro.tsx @@ -0,0 +1,148 @@ +import { ConfigProvider, Segmented, Space, theme as antdTheme } from 'ant-design-vue'; +import type { MutableTheme } from '../interface'; +import type { PropType, CSSProperties } from 'vue'; +import { defineComponent, toRefs, ref, computed } from 'vue'; +import ComponentDemoGroup from '../component-panel/ComponentDemoGroup'; +import { useInjectLocaleContext } from '../locale'; +import { Error, Primary, Success, Warning } from '../overviews'; + +export type ComponentDemoProProps = { + selectedTokens?: string[]; + theme: MutableTheme; + components: Record; + activeComponents?: string[]; + componentDrawer?: boolean; + showAll?: boolean; +}; + +const ComponentDemoPro = defineComponent({ + name: 'ComponentDemoPro', + inheritAttrs: false, + props: { + selectedTokens: { type: Array as PropType }, + theme: { type: Object as PropType }, + components: { type: Object as PropType> }, + activeComponents: { type: Array as PropType }, + componentDrawer: { type: Boolean }, + showAll: { type: Boolean }, + }, + setup(props, { attrs }) { + const { selectedTokens, theme, components, activeComponents, componentDrawer, showAll } = + toRefs(props); + + const mode = ref<'overview' | 'component'>('overview'); + + const { token } = antdTheme.useToken(); + + const locale = useInjectLocaleContext(); + + const overviewDemo = computed(() => { + if (showAll.value) { + return ( + + + + + + + ); + } + if (selectedTokens.value?.includes('colorError')) { + return ; + } + if (selectedTokens.value?.includes('colorSuccess')) { + return ; + } + if (selectedTokens.value?.includes('colorWarning')) { + return ; + } + return ; + }); + + return () => { + return ( +
+
+ (mode.value = val as any)} + style={{ margin: '12px 0 0 12px' }} + /> + + {/* */} + {mode.value === 'overview' ? ( +
{overviewDemo.value}
+ ) : ( + + )} + {/*
*/} +
+
+ ); + }; + }, +}); + +export default defineComponent({ + name: 'ComponentDemoProProvider', + inheritAttrs: false, + props: { + selectedTokens: { type: Array as PropType }, + theme: { type: Object as PropType }, + components: { type: Object as PropType> }, + activeComponents: { type: Array as PropType }, + componentDrawer: { type: Boolean }, + showAll: { type: Boolean }, + }, + setup(props, { attrs }) { + return () => ( + // + + // + ); + }, +}); diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/InputNumberPlus.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/InputNumberPlus.tsx new file mode 100644 index 000000000..f00994efd --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/InputNumberPlus.tsx @@ -0,0 +1,45 @@ +import { InputNumber, Slider } from 'ant-design-vue'; +import type { PropType } from 'vue'; +import { defineComponent, toRefs } from 'vue'; + +export type InputNumberPlusProps = { + value?: number; + onChange?: (value: number | null) => void; + min?: number; + max?: number; +}; + +const InputNumberPlus = defineComponent({ + name: 'InputNumberPlus', + props: { + value: { type: Number }, + onChange: { type: Function as PropType<(value: number | null) => void> }, + min: { type: Number }, + max: { type: Number }, + }, + setup(props) { + const { value, min, max } = toRefs(props); + return () => { + return ( +
+ + +
+ ); + }; + }, +}); + +export default InputNumberPlus; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/TokenContent.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/TokenContent.tsx new file mode 100644 index 000000000..95471899d --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/TokenContent.tsx @@ -0,0 +1,860 @@ +import { CaretRightOutlined, ExpandOutlined, QuestionCircleOutlined } from '@ant-design/icons-vue'; +import { + Button, + Checkbox, + Collapse, + // ConfigProvider, + Popover, + Switch, + Tooltip, + Typography, +} from 'ant-design-vue'; +import type { MutableTheme } from '../interface'; +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; +import seed from 'ant-design-vue/es/theme/themes/seed'; +import tokenMeta from 'ant-design-vue/es/version/token-meta.json'; +import classNames from 'ant-design-vue/es/_util/classNames'; + +import { PropType, toRefs } from 'vue'; +import { defineComponent, watchEffect, computed, watch, ref } from 'vue'; +import { debounce } from 'lodash'; + +import type { ThemeCode } from '../hooks/useControlledTheme'; +import { themeMap } from '../hooks/useControlledTheme'; +import { CompactTheme, DarkTheme, Light, Pick } from '../icons'; + +import type { SelectedToken } from '../interface'; +import { useInjectLocaleContext } from '../locale'; +import type { TokenCategory, TokenGroup } from '../meta/interface'; +import getDesignToken from '../utils/getDesignToken'; +import makeStyle from '../utils/makeStyle'; +import ColorPanel from '../ColorPanel'; +import IconSwitch from '../IconSwitch'; +import InputNumberPlus from './InputNumberPlus'; +import TokenDetail from './TokenDetail'; +import TokenPreview from './TokenPreview'; + +const { Panel } = Collapse; + +const useStyle = makeStyle('ColorTokenContent', token => ({ + '.token-panel-pro-color': { + height: '100%', + display: 'flex', + '.token-panel-pro-color-seeds': { + height: '100%', + flex: 1, + width: 0, + borderInlineEnd: `1px solid ${token.colorBorderSecondary}`, + display: 'flex', + flexDirection: 'column', + boxSizing: 'border-box', + + '.token-panel-pro-color-themes': { + display: 'flex', + alignItems: 'center', + padding: '0 16px', + flex: '0 0 60px', + + '> span': { + fontSize: token.fontSizeLG, + fontWeight: token.fontWeightStrong, + }, + }, + }, + [`.token-panel-pro-token-collapse${token.rootCls}-collapse`]: { + flex: 1, + overflow: 'auto', + [`> ${token.rootCls}-collapse-item-active`]: { + backgroundColor: '#fff', + boxShadow: + '0 6px 16px -8px rgba(0,0,0,0.08), 0 9px 28px 0 rgba(0,0,0,0.05), 0 12px 48px -8px rgba(0,0,0,0.03), inset 0 0 0 2px #1677FF', + transition: 'box-shadow 0.2s ease-in-out', + borderRadius: 8, + }, + [`> ${token.rootCls}-collapse-item > ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]: + { + paddingBlock: '0 12px', + }, + + '.token-panel-pro-token-collapse-description': { + color: token.colorTextTertiary, + marginBottom: 16, + }, + + '.token-panel-pro-token-collapse-subtitle': { + color: token.colorTextSecondary, + fontSize: 12, + }, + + '.token-panel-pro-token-collapse-seed-block': { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + + '+ .token-panel-pro-token-collapse-seed-block': { + marginTop: 8, + }, + + '&-name-cn': { + fontWeight: token.fontWeightStrong, + marginInlineEnd: 4, + }, + + '&-name': { + color: token.colorTextTertiary, + }, + + '&-sample': { + flex: 'none', + + '&:not(:last-child)': { + marginInlineEnd: 16, + }, + + '&-theme': { + color: token.colorTextTertiary, + marginBottom: 2, + fontSize: '12px', + textAlign: 'end', + }, + + '&-card': { + cursor: 'pointer', + border: `1px solid ${token.colorBorderSecondary}`, + borderRadius: 4, + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + padding: '4px 8px', + + '&-value': { + fontFamily: 'Monaco,'.concat(token.fontFamily), + }, + }, + }, + }, + + [`.token-panel-pro-token-collapse-map-collapse${token.rootCls}-collapse`]: { + borderRadius: 4, + backgroundColor: '#fff', + + [`> ${token.rootCls}-collapse-item`]: { + '&:not(:first-child)': { + [`> ${token.rootCls}-collapse-header`]: { + [`> ${token.rootCls}-collapse-header-text`]: { + '.token-panel-pro-token-collapse-map-collapse-preview': { + '.token-panel-pro-token-collapse-map-collapse-preview-color': { + marginTop: -1, + }, + }, + }, + }, + }, + [`> ${token.rootCls}-collapse-header`]: { + padding: { value: '0 12px 0 16px', _skip_check_: true }, + + [`> ${token.rootCls}-collapse-expand-icon`]: { + alignSelf: 'center', + }, + + [`> ${token.rootCls}-collapse-header-text`]: { + flex: 1, + + '.token-panel-pro-token-collapse-map-collapse-token': { + color: token.colorTextSecondary, + marginInlineStart: 4, + marginInlineEnd: 8, + }, + + '.token-panel-pro-token-collapse-map-collapse-preview': { + display: 'flex', + flex: 'none', + '.token-panel-pro-token-collapse-map-collapse-preview-color': { + height: 56, + width: 56, + position: 'relative', + borderInline: '1px solid #e8e8e8', + }, + '> *': { + marginInlineEnd: 8, + }, + }, + }, + }, + + [`> ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]: { + padding: '0', + }, + }, + }, + }, + + '.token-panel-pro-token-collapse-map-collapse-count': { + color: token.colorTextSecondary, + // display: 'inline-block', + fontSize: '12px', + lineHeight: '16px', + padding: '0 6px', + backgroundColor: token.colorFillAlter, + borderRadius: 999, + overflow: 'hidden', + textOverflow: 'ellipsis', + }, + + '.token-panel-pro-token-pick': { + transition: 'color 0.3s', + }, + + '.token-panel-pro-token-picked': { + color: token.colorPrimary, + }, + + [`.token-panel-pro-grouped-map-collapse${token.rootCls}-collapse`]: { + borderRadius: '4px', + [`> ${token.rootCls}-collapse-item`]: { + [`> ${token.rootCls}-collapse-header`]: { + padding: '6px 12px', + color: token.colorIcon, + fontSize: '12px', + lineHeight: token.lineHeightSM, + + [`> ${token.rootCls}-collapse-header-text`]: { + fontSize: '12px', + }, + + [`${token.rootCls}-collapse-expand-icon`]: { + lineHeight: '20px', + height: '20px', + }, + }, + [`> ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]: { + padding: 0, + + [`.token-panel-pro-token-collapse-map-collapse${token.rootCls}-collapse`]: { + border: 'none', + + [`${token.rootCls}-collapse-item:last-child`]: { + borderBottom: 'none', + }, + }, + }, + }, + }, + }, +})); + +export type SeedTokenProps = { + theme: MutableTheme; + tokenName: string; + disabled?: boolean; +}; + +const getSeedValue = (config: ThemeConfig, token: string) => { + // @ts-ignore + return config.token?.[token] || seed[token] || getDesignToken(config)[token]; +}; + +const seedRange: Record = { + borderRadius: { + min: 0, + max: 16, + }, + fontSize: { + min: 12, + max: 32, + }, + sizeStep: { + min: 0, + max: 16, + }, + sizeUnit: { + min: 0, + max: 16, + }, +}; + +const SeedTokenPreview = defineComponent({ + name: 'SeedTokenPreview', + props: { + theme: { type: Object as PropType }, + tokenName: { type: String }, + disabled: { type: Boolean }, + }, + setup(props) { + const { theme, tokenName, disabled } = toRefs(props); + + const tokenPath = computed(() => ['token', tokenName.value]); + const tokenValue = ref(getSeedValue(theme.value.config, tokenName.value)); + + const locale = useInjectLocaleContext(); + + const debouncedOnChange = debounce((newValue: number | string) => { + theme.value.onThemeChange?.( + { + ...theme.value.config, + token: { + ...theme.value.config.token, + [tokenName.value]: newValue, + }, + }, + ['token', tokenName.value], + ); + }, 500); + + const handleChange = (value: any) => { + tokenValue.value = value; + debouncedOnChange(value); + }; + + watchEffect(() => { + tokenValue.value = getSeedValue(theme.value.config, tokenName.value); + }); + + const showReset = computed(() => theme.value.getCanReset?.(tokenPath.value)); + + return () => { + return ( +
+
+ theme.value.onReset?.(tokenPath.value)} + > + {locale.value.reset} + +
+ {tokenName.value.startsWith('color') && ( + ( + + ), + }} + > +
+
+
+ {tokenValue.value} +
+
+ + )} + {['fontSize', 'sizeUnit', 'sizeStep', 'borderRadius'].includes(tokenName.value) && ( + + )} + {tokenName.value === 'wireframe' && ( + + )} +
+ ); + }; + }, +}); + +export type MapTokenCollapseContentProps = { + mapTokens?: string[]; + theme: MutableTheme; + selectedTokens?: SelectedToken; + onTokenSelect?: (token: string | string[], type: keyof SelectedToken) => void; + type?: string; +}; + +const MapTokenCollapseContent = defineComponent({ + name: 'MapTokenCollapseContent', + props: { + mapTokens: { type: Array as PropType }, + theme: { type: Object as PropType }, + selectedTokens: { type: Object as PropType }, + onTokenSelect: { + type: Function as PropType<(token: string | string[], type: keyof SelectedToken) => void>, + }, + type: { type: String }, + }, + setup(props) { + const { mapTokens, theme, selectedTokens, type } = toRefs(props); + + const locale = useInjectLocaleContext(); + + return () => { + return ( + + {mapTokens.value?.map(mapToken => ( + +
+ {locale.value._lang === 'zh-CN' && ( + + {(tokenMeta as any)[mapToken]?.name} + + )} + + {mapToken} + + + {(getDesignToken(theme.value.config) as any)[mapToken]} + +
+
+
+ +
+
+
{ + e.stopPropagation(); + props.onTokenSelect(mapToken, 'map'); + }} + > + +
+
+ } + key={mapToken} + > + + + ))} + + ); + }; + }, +}); + +export type MapTokenCollapseProps = { + theme: MutableTheme; + group: TokenGroup; + selectedTokens?: SelectedToken; + onTokenSelect?: (token: string | string[], type: keyof SelectedToken) => void; + groupFn?: (token: string) => string; +}; + +const MapTokenCollapse = defineComponent({ + name: 'MapTokenCollapse', + props: { + theme: { type: Object as PropType }, + group: { type: Object as PropType> }, + selectedTokens: { type: Object as PropType }, + onTokenSelect: { + type: Function as PropType<(token: string | string[], type: keyof SelectedToken) => void>, + }, + groupFn: { type: Function as PropType<(token: string) => string> }, + }, + setup(props) { + const { theme, selectedTokens, groupFn, group } = toRefs(props); + + const locale = useInjectLocaleContext(); + + const groupedTokens = computed(() => { + const grouped: Record = {}; + if (groupFn.value) { + group.value.mapToken?.forEach(token => { + const key = groupFn.value(token) ?? 'default'; + grouped[key] = [...(grouped[key] ?? []), token]; + }); + } + return grouped; + }); + + return () => { + if (groupFn.value) { + return ( + ( + + )} + > + {(group.value.mapTokenGroups ?? Object.keys(groupedTokens.value)).map(key => ( + + + + ))} + + ); + } + + if (group.value.groups) { + return ( + item.key)} + expandIconPosition="end" + expandIcon={({ isActive }) => ( + + )} + > + {group.value.groups.map(item => ( + + + + ))} + + ); + } + + return ( + + ); + }; + }, +}); + +const groupMapToken = (token: string): string => { + if (token.startsWith('colorFill')) { + return 'fill'; + } + if (token.startsWith('colorBorder') || token.startsWith('colorSplit')) { + return 'border'; + } + if (token.startsWith('colorBg')) { + return 'background'; + } + if (token.startsWith('colorText')) { + return 'text'; + } + return ''; +}; + +export type ColorTokenContentProps = { + category: TokenCategory; + theme: MutableTheme; + selectedTokens?: SelectedToken; + infoFollowPrimary?: boolean; + activeGroup: string; + onTokenSelect?: (token: string | string[], type: keyof SelectedToken) => void; + onInfoFollowPrimaryChange?: (value: boolean) => void; + onActiveGroupChange: (value: string) => void; +}; + +const TokenContent = defineComponent({ + name: 'TokenContent', + inheritAttrs: false, + props: { + category: { type: Object as PropType> }, + theme: { type: Object as PropType }, + selectedTokens: { type: Object as PropType }, + infoFollowPrimary: { type: Boolean }, + activeGroup: { type: String }, + onTokenSelect: { + type: Function as PropType<(token: string | string[], type: keyof SelectedToken) => void>, + }, + onInfoFollowPrimaryChange: { + type: Function as PropType<(value: boolean) => void>, + }, + onActiveGroupChange: { + type: Function as PropType<(value: string) => void>, + }, + }, + emits: ['update:activeGroup'], + setup(props, { attrs, emit }) { + const { category, theme, selectedTokens, infoFollowPrimary, activeGroup } = toRefs(props); + + const curActiveGroup = ref(''); + + watch( + activeGroup, + val => { + curActiveGroup.value = val; + }, + { immediate: true }, + ); + + watch(curActiveGroup, val => { + props.onActiveGroupChange?.(val); + emit('update:activeGroup', val); + }); + + const [wrapSSR, hashId] = useStyle(); + + const grouped = ref(true); + const locale = useInjectLocaleContext(); + + const switchAlgorithm = (themeStr: 'dark' | 'compact') => () => { + let newAlgorithm = theme.value.config.algorithm; + if (!newAlgorithm) { + newAlgorithm = themeMap[themeStr]; + } else if (Array.isArray(newAlgorithm)) { + newAlgorithm = newAlgorithm.includes(themeMap[themeStr]) + ? newAlgorithm.filter(item => item !== themeMap[themeStr]) + : [...newAlgorithm, themeMap[themeStr]]; + } else { + newAlgorithm = + newAlgorithm === themeMap[themeStr] ? undefined : [newAlgorithm, themeMap[themeStr]]; + } + theme.value.onThemeChange?.({ ...theme.value.config, algorithm: newAlgorithm }, [ + 'config', + 'algorithm', + ]); + }; + + const isLeftChecked = (str: ThemeCode) => { + if (!theme.value.config.algorithm) { + return true; + } + return Array.isArray(theme.value.config.algorithm) + ? !theme.value.config.algorithm.includes(themeMap[str]) + : theme.value.config.algorithm !== themeMap[str]; + }; + + return () => { + return wrapSSR( +
+
+
+ + {locale.value._lang === 'zh-CN' ? category.value.name : category.value.nameEn} + + {category.value.nameEn === 'Color' && ( + , + rightIcon: () => , + }} + style={{ marginLeft: 'auto' }} + /> + )} + + {category.value.nameEn === 'Size' && ( + , + rightIcon: () => , + }} + style={{ marginLeft: 'auto' }} + /> + )} +
+ {/* */} + ( + + ), + }} + > + {category.value.groups.map((group, index) => { + return ( + + {locale.value._lang === 'zh-CN' ? group.name : group.nameEn} + + } + key={group.key} + > +
+
+ {locale.value._lang === 'zh-CN' ? group.desc : group.descEn} +
+ {group.seedToken?.map(seedToken => ( +
+
+
+ Seed Token + + + +
+
+ + {locale.value._lang === 'zh-CN' + ? (tokenMeta as any)[seedToken]?.name + : (tokenMeta as any)[seedToken]?.nameEn} + + {seedToken === 'colorInfo' && ( + props.onInfoFollowPrimaryChange(e.target.checked)} + > + {locale.value.followPrimary} + + )} +
+
+ +
+ ))} + {(group.mapToken || group.groups) && ( +
+
+ Map Token + + + + {group.mapTokenGroups && ( +
+ + (grouped.value = v as boolean)} + size="small" + /> +
+ )} +
+ +
+ )} + {index < category.value.groups.length - 1 && ( + + )} +
+
+ ); + })} +
+ {/*
*/} +
+
, + ); + }; + }, +}); + +export default TokenContent; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/TokenDetail.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/TokenDetail.tsx new file mode 100644 index 000000000..4623db517 --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/TokenDetail.tsx @@ -0,0 +1,138 @@ +import { Tooltip } from 'ant-design-vue'; +import type { MutableTheme } from '../interface'; +import tokenMeta from 'ant-design-vue/es/version/token-meta.json'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import type { PropType } from 'vue'; +import { defineComponent, computed, toRefs } from 'vue'; +import type { TokenValue } from '../interface'; +import { useInjectLocaleContext } from '../locale'; +import { mapRelatedAlias } from '../meta/TokenRelation'; +import TokenInput from '../TokenInput'; +import deepUpdateObj from '../utils/deepUpdateObj'; +import getDesignToken from '../utils/getDesignToken'; +import getValueByPath from '../utils/getValueByPath'; +import makeStyle from '../utils/makeStyle'; +import { getRelatedComponents } from '../utils/statistic'; + +const useStyle = makeStyle('TokenDetail', token => ({ + '.token-panel-token-detail': { + '.token-panel-pro-token-collapse-map-collapse-token-description': { + color: token.colorTextPlaceholder, + marginBottom: 8, + fontSize: 12, + }, + + '.token-panel-pro-token-collapse-map-collapse-token-usage-tag-container': { + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + color: token.colorTextSecondary, + }, + + '.token-panel-pro-token-collapse-map-collapse-token-usage-tag': { + display: 'inline-block', + marginInlineEnd: 8, + borderRadius: 4, + height: 20, + padding: '0 8px', + fontSize: 12, + lineHeight: '20px', + backgroundColor: 'rgba(0,0,0,0.015)', + }, + + '.token-panel-pro-token-collapse-map-collapse-token-inputs': { + padding: '8px 10px', + backgroundColor: 'rgba(0,0,0,0.02)', + marginTop: 12, + '> *:not(:last-child)': { + marginBottom: 8, + }, + }, + }, +})); + +export type TokenDetailProps = { + themes: MutableTheme[]; + path: string[]; + tokenName: string; +}; + +const TokenDetail = defineComponent({ + name: 'TokenDetail', + inheritAttrs: false, + props: { + themes: { type: Array as PropType }, + path: { type: Array as PropType }, + tokenName: { type: String }, + }, + setup(props, { attrs }) { + const { themes, path, tokenName } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + const tokenPath = computed(() => [...path.value, tokenName.value]); + const locale = useInjectLocaleContext(); + + const handleTokenChange = (theme: MutableTheme) => (value: TokenValue) => { + theme.onThemeChange?.(deepUpdateObj(theme.config, [...path.value, tokenName.value], value), [ + ...path.value, + tokenName.value, + ]); + }; + + const relatedComponents = computed(() => { + return getRelatedComponents([ + tokenName.value, + ...((mapRelatedAlias as any)[tokenName.value] ?? []), + ]); + }); + + return () => { + return wrapSSR( +
+
+ { + (tokenMeta as any)[tokenName.value]?.[ + locale.value._lang === 'zh-CN' ? 'desc' : 'descEn' + ] + } +
+ {relatedComponents.value.length > 0 && ( + +
+ {relatedComponents.value.map(item => ( + + {item} + + ))} +
+
+ )} +
+ {themes.value.map(themeItem => { + return ( +
+ themeItem.onReset?.(tokenPath.value)} + onChange={handleTokenChange(themeItem)} + value={ + getValueByPath(themeItem.config, tokenPath.value) ?? + (getDesignToken(themeItem.config) as any)[tokenName.value] + } + /> +
+ ); + })} +
+
, + ); + }; + }, +}); + +export default TokenDetail; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/TokenPreview.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/TokenPreview.tsx new file mode 100644 index 000000000..4d44d717d --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/TokenPreview.tsx @@ -0,0 +1,223 @@ +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; +import { PropType, toRefs } from 'vue'; +import { defineComponent } from 'vue'; + +import getColorBgImg from '../utils/getColorBgImg'; +import getDesignToken from '../utils/getDesignToken'; + +export type TokenPreviewProps = { + theme: ThemeConfig; + tokenName: string; + type?: string; +}; + +const TokenPreview = defineComponent({ + name: 'TokenPreview', + props: { + theme: { type: Object as PropType }, + tokenName: { type: String }, + type: { type: String }, + }, + setup(props) { + const { theme, tokenName, type } = toRefs(props); + + return () => { + if (type.value === 'Color') { + return ( +
+
+
+ ); + } + if (type.value === 'FontSize') { + return ( +
+ Aa +
+ ); + } + if (type.value === 'LineHeight') { + return ( +
+ + Aa + +
+ ); + } + if (type.value === 'Margin') { + const margin = (getDesignToken(theme.value) as any)[tokenName.value]; + return ( +
+
+
+
+
+ ); + } + if (type.value === 'Padding') { + const padding = `${(getDesignToken(theme.value) as any)[tokenName.value]}px`; + return ( +
+
+
+
+
+ ); + } + if (type.value === 'BorderRadius') { + return ( +
+
+
+ ); + } + if (type.value === 'BoxShadow') { + return ( +
+
+
+ ); + } + return null; + }; + }, +}); + +export default TokenPreview; diff --git a/site/src/components/antdv-token-previewer/token-panel-pro/index.tsx b/site/src/components/antdv-token-previewer/token-panel-pro/index.tsx new file mode 100644 index 000000000..077f886ee --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel-pro/index.tsx @@ -0,0 +1,125 @@ +import { Tabs } from 'ant-design-vue'; +import type { Theme } from '../interface'; +import classNames from 'ant-design-vue/es/_util/classNames'; +import { PropType, toRefs } from 'vue'; +import { defineComponent, watchEffect, computed, ref } from 'vue'; +import type { SelectedToken } from '../interface'; +import { useInjectLocaleContext } from '../locale'; +import { tokenCategory } from '../meta'; +import type { TokenGroup } from '../meta/interface'; +import makeStyle from '../utils/makeStyle'; +import AliasPanel from './AliasPanel'; +import TokenContent from './TokenContent'; + +const { TabPane } = Tabs; + +const useStyle = makeStyle('TokenPanelPro', token => ({ + '.token-panel-pro': { + height: '100%', + display: 'flex', + borderInlineEnd: `1px solid ${token.colorBorderSecondary}`, + [`.token-panel-pro-tabs${token.rootCls}-tabs`]: { + height: '100%', + overflow: 'auto', + [`${token.rootCls}-tabs-content`]: { + height: '100%', + [`${token.rootCls}-tabs-tabpane`]: { + height: '100%', + }, + }, + }, + }, +})); + +export type TokenPanelProProps = { + theme: Theme; + selectedTokens?: SelectedToken; + infoFollowPrimary?: boolean; + aliasOpen?: boolean; + activeTheme?: string; + onTokenSelect?: (token: string | string[], type: keyof SelectedToken) => void; + onInfoFollowPrimaryChange?: (value: boolean) => void; + onAliasOpenChange?: (value: boolean) => void; +}; + +const TokenPanelPro = defineComponent({ + name: 'TokenPanelPro', + inheritAttrs: false, + props: { + theme: { type: Object as PropType }, + selectedTokens: { type: Object as PropType }, + infoFollowPrimary: { type: Boolean }, + aliasOpen: { type: Boolean }, + activeTheme: { type: String }, + onTokenSelect: { + type: Function as PropType<(token: string | string[], type: keyof SelectedToken) => void>, + }, + onInfoFollowPrimaryChange: { type: Function as PropType<(value: boolean) => void> }, + onAliasOpenChange: { type: Function as PropType<(value: boolean) => void> }, + }, + setup(props, { attrs }) { + const { theme, selectedTokens, infoFollowPrimary, aliasOpen } = toRefs(props); + + const [wrapSSR, hashId] = useStyle(); + + const activeGroup = ref('brandColor'); + const locale = useInjectLocaleContext(); + + const activeCategory = computed(() => { + return tokenCategory.reduce | undefined>((result, category) => { + return result ?? category.groups.find(group => group.key === activeGroup.value); + }, undefined); + }); + + watchEffect(() => { + props.onTokenSelect(activeCategory.value?.seedToken ?? [], 'seed'); + }); + + return () => { + return wrapSSR( +
+ { + activeGroup.value = + tokenCategory.find(category => category.nameEn === key)?.groups[0].key ?? ''; + }} + > + {tokenCategory.map(category => ( + + + + ))} + + +
, + ); + }; + }, +}); + +export default TokenPanelPro; diff --git a/site/src/components/antdv-token-previewer/token-panel/index.tsx b/site/src/components/antdv-token-previewer/token-panel/index.tsx new file mode 100644 index 000000000..8937f52b1 --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel/index.tsx @@ -0,0 +1,315 @@ +import { CheckOutlined } from '@ant-design/icons'; +import { Dropdown, Input, Menu, Switch, theme as antdTheme } from 'antd'; +import classNames from 'classnames'; +import useMergedState from 'rc-util/lib/hooks/useMergedState'; +import React, { + forwardRef, + useEffect, + useImperativeHandle, + useMemo, + useRef, + useState, +} from 'react'; +import { SearchDropdown } from '../icons'; +import type { AliasToken, MutableTheme, TokenValue } from '../interface'; +import type { TokenType } from '../utils/classifyToken'; +import { classifyToken, getTypeOfToken, TOKEN_SORTS } from '../utils/classifyToken'; +import getDesignToken from '../utils/getDesignToken'; +import makeStyle from '../utils/makeStyle'; +import TokenCard, { IconMap, TextMap } from './token-card'; +import { getTokenItemId } from './token-item'; + +const { useToken } = antdTheme; + +const useStyle = makeStyle('AliasTokenPreview', token => ({ + '.preview-panel-wrapper': { + overflow: 'auto', + height: '100%', + '.preview-panel': { + height: '100%', + minWidth: 300, + backgroundColor: 'white', + display: 'flex', + flexDirection: 'column', + '.preview-panel-token-wrapper': { + position: 'relative', + flex: 1, + overflow: 'hidden', + '&::before, &::after': { + position: 'absolute', + zIndex: 1, + opacity: 0, + transition: 'opacity .3s', + content: '""', + pointerEvents: 'none', + insetInlineStart: 0, + insetInlineEnd: 0, + height: 40, + }, + + '&::before': { + top: 0, + boxShadow: 'inset 0 10px 8px -8px #00000014', + }, + + '&::after': { + bottom: 0, + boxShadow: 'inset 0 -10px 8px -8px #00000014', + }, + + '&.preview-panel-token-wrapper-ping-top': { + '&::before': { + opacity: 1, + }, + }, + }, + '.preview-panel-space': { + marginBottom: 20, + paddingInlineStart: token.paddingXS, + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + + '.preview-hide-token': { + color: token.colorTextSecondary, + fontSize: token.fontSizeSM, + lineHeight: token.lineHeightSM, + display: 'flex', + alignItems: 'center', + '>*:first-child': { + marginInlineEnd: 2, + }, + }, + }, + '.preview-panel-search': { + backgroundColor: 'rgba(0, 0, 0, 2%)', + borderRadius: token.borderRadiusLG, + + [`${token.rootCls}-input-group-addon`]: { + backgroundColor: 'inherit', + border: 'none', + padding: 0, + transition: `background-color ${token.motionDurationSlow}`, + + '&:hover': { + backgroundColor: 'rgba(0, 0, 0, 4%)', + }, + }, + + input: { + fontSize: token.fontSizeSM, + paddingInlineStart: 4, + }, + + '.previewer-token-type-dropdown-icon-active': { + color: token.colorPrimary, + }, + }, + }, + }, +})); + +export interface TokenPreviewProps { + themes: MutableTheme[]; + selectedTokens?: string[]; + onTokenSelect?: (token: string) => void; + filterTypes?: TokenType[]; + onFilterTypesChange?: (types: TokenType[]) => void; + enableTokenSelect?: boolean; +} + +export type TokenPanelRef = { + scrollToToken: (token: string) => void; +}; + +export default forwardRef((props: TokenPreviewProps, ref) => { + const { + filterTypes, + onFilterTypesChange, + themes, + selectedTokens, + onTokenSelect, + enableTokenSelect, + } = props; + const [wrapSSR, hashId] = useStyle(); + const [search, setSearch] = useState(''); + const [showAll, setShowAll] = useState(false); + const [showTokenListShadowTop, setShowTokenListShadowTop] = useState(false); + const cardWrapperRef = useRef(null); + const [activeCards, setActiveCards] = useState([]); + const [activeToken, setActiveToken] = useState(); + const { token } = useToken(); + const [mergedFilterTypes, setMergedFilterTypes] = useMergedState(filterTypes || []); + + // TODO: Split AliasToken and SeedToken + const groupedToken = useMemo(() => classifyToken(token as any), [token]); + + useEffect(() => { + const handleTokenListScroll = () => { + setShowTokenListShadowTop((cardWrapperRef.current?.scrollTop ?? 0) > 0); + }; + cardWrapperRef.current?.addEventListener('scroll', handleTokenListScroll); + const wrapper = cardWrapperRef.current; + return () => { + wrapper?.removeEventListener('scroll', handleTokenListScroll); + }; + }, []); + + useImperativeHandle(ref, () => ({ + scrollToToken: tokenName => { + const type = getTypeOfToken(tokenName); + if (!activeCards.includes(type)) { + setActiveCards(prev => [...prev, type]); + } + setActiveToken(tokenName); + setTimeout(() => { + const node = cardWrapperRef.current?.querySelector( + `#${getTokenItemId(tokenName)}`, + ); + if (!node) { + return; + } + node?.scrollIntoView({ + block: 'center', + inline: 'nearest', + }); + }, 100); + }, + })); + + const handleAliasTokenChange = (theme: MutableTheme, tokenName: string, value: TokenValue) => { + theme.onThemeChange?.( + { + ...theme.config, + token: { + ...theme.config.token, + [tokenName]: value, + }, + }, + ['token', tokenName], + ); + }; + + return wrapSSR( +
+
+
+

+ Alias Token 预览 + + 显示所有 + setShowAll(value)} size="small" /> + +

+ { + setSearch(e.target.value); + }} + bordered={false} + addonBefore={ + <> + ({ + icon: ( + + + {IconMap[type]} + + ), + label: TextMap[type], + key: type, + onClick: () => { + const newTypes = mergedFilterTypes.includes(type) + ? mergedFilterTypes.filter(item => type !== item) + : [...mergedFilterTypes, type]; + setMergedFilterTypes(newTypes); + onFilterTypesChange?.(newTypes); + }, + })), + ]} + /> + } + trigger={['click']} + > + 0, + })} + /> + + + } + className="preview-panel-search" + placeholder="搜索 Token / 色值 / 文本 / 圆角等" + /> +
+
+
+
+ {TOKEN_SORTS.filter( + type => + type !== 'seed' && + (mergedFilterTypes.includes(type) || mergedFilterTypes.length === 0) && + (!search || + groupedToken[type].some(item => + item.toLowerCase().includes(search.toLowerCase()), + )), + ).map(key => ( + + setActiveCards(prev => + open ? [...prev, key] : prev.filter(item => item !== key), + ) + } + onTokenChange={handleAliasTokenChange} + activeToken={activeToken} + onActiveTokenChange={tokenName => setActiveToken(tokenName)} + themes={themes} + selectedTokens={selectedTokens} + onTokenSelect={onTokenSelect} + enableTokenSelect={enableTokenSelect} + fallback={config => getDesignToken(config) as AliasToken} + /> + ))} +
+
+
+
+
, + ); +}); diff --git a/site/src/components/antdv-token-previewer/token-panel/token-card/index.tsx b/site/src/components/antdv-token-previewer/token-panel/token-card/index.tsx new file mode 100644 index 000000000..f8ee97755 --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel/token-card/index.tsx @@ -0,0 +1,193 @@ +import { + AlignLeftOutlined, + BgColorsOutlined, + BorderHorizontalOutlined, + BulbOutlined, + CaretRightOutlined, + ControlOutlined, + FileUnknownOutlined, + FontColorsOutlined, + FontSizeOutlined, + FormatPainterOutlined, + HighlightOutlined, + RadiusSettingOutlined, + TabletOutlined, +} from '@ant-design/icons'; +import { Collapse, Space } from 'antd'; +import type { ThemeConfig } from 'antd/es/config-provider/context'; +import classNames from 'classnames'; +import useMergedState from 'rc-util/es/hooks/useMergedState'; +import type { ReactNode } from 'react'; +import React from 'react'; +import { Motion, ShapeLine } from '../../icons'; +import type { MutableTheme, TokenValue } from '../../interface'; +import type { TokenType } from '../../utils/classifyToken'; +import makeStyle from '../../utils/makeStyle'; +import { getRelatedComponents } from '../../utils/statistic'; +import TokenItem from '../token-item'; + +const { Panel } = Collapse; + +interface TokenCardProps { + title: string; + icon?: ReactNode; + tokenArr: string[]; + tokenPath: string[]; + keyword?: string; + hideUseless?: boolean; + defaultOpen?: boolean; + open?: boolean; + onOpenChange?: (open: boolean) => void; + activeToken?: string; + onActiveTokenChange?: (token: string | undefined) => void; + onTokenChange?: (theme: MutableTheme, tokenName: string, value: TokenValue) => void; + themes: MutableTheme[]; + selectedTokens?: string[]; + onTokenSelect?: (token: string) => void; + enableTokenSelect?: boolean; + hideUsageCount?: boolean; + placeholder?: ReactNode; + fallback?: (config: ThemeConfig) => Record; +} + +export const IconMap: Record = { + seed: , + colorText: , + colorBg: , + colorSplit: , + colorFill: , + colorCommon: , + space: , + font: , + line: , + screen: , + motion: , + radius: , + control: , + others: , +}; +export const TextMap: Record = { + seed: 'Seed Token', + colorCommon: 'Common Color 通用颜色', + colorText: 'Text Color 文本颜色', + colorBg: 'Background Color 背景颜色', + colorFill: 'Fill Color 填充颜色', + colorSplit: 'Split Color 分割线颜色', + space: 'Space 间距', + font: 'Font 文本', + line: 'Line 线', + screen: 'Screen 屏幕', + motion: 'Motion 动画', + radius: 'Radius 圆角', + control: 'Control 控件', + others: 'Others 未分类', +}; + +const useStyle = makeStyle('TokenCard', token => ({ + '.token-card': { + width: '100%', + height: 'auto', + borderRadius: token.borderRadiusLG, + border: `1px solid rgba(0,0,0,0.09)`, + marginBottom: token.marginSM, + + [`${token.rootCls}-collapse.token-card-collapse`]: { + [`> ${token.rootCls}-collapse-item > ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]: + { + padding: { + _skip_check_: true, + value: `0 ${token.paddingXS}px 12px !important`, + }, + }, + }, + }, + [`.token-card ${token.rootCls}-input-group >${token.rootCls}-input:not(:first-child):not(:last-child)`]: + { + background: 'white', + borderRadius: token.borderRadiusLG, + }, +})); + +export default ({ + title, + icon, + tokenArr, + keyword, + hideUseless, + defaultOpen, + open: customOpen, + onOpenChange, + activeToken, + onActiveTokenChange, + onTokenChange, + tokenPath, + selectedTokens, + themes, + onTokenSelect, + enableTokenSelect, + hideUsageCount, + fallback, + placeholder, +}: TokenCardProps) => { + const [wrapSSR, hashId] = useStyle(); + const [open, setOpen] = useMergedState(false, { + onChange: onOpenChange, + defaultValue: defaultOpen, + value: customOpen, + }); + + return wrapSSR( +
+ ( + + )} + expandIconPosition="right" + className="token-card-collapse" + activeKey={open ? '1' : undefined} + onChange={keys => { + // onOpenChange?.(keys.length > 0); + setOpen(keys.length > 0); + }} + > + + {title} + {icon} + + } + key="1" + > + {tokenArr + .filter( + tokenName => + (!keyword || tokenName.toLowerCase().includes(keyword.toLowerCase())) && + (!hideUseless || getRelatedComponents(tokenName).length > 0), + ) + .map(tokenName => ( + onActiveTokenChange?.(active ? tokenName : undefined)} + active={activeToken === tokenName} + tokenName={tokenName} + key={tokenName} + onTokenChange={onTokenChange} + themes={themes} + selectedTokens={selectedTokens} + onTokenSelect={onTokenSelect} + enableTokenSelect={enableTokenSelect} + hideUsageCount={hideUsageCount} + fallback={fallback} + /> + ))} + {tokenArr.length === 0 && placeholder} + + +
, + ); +}; diff --git a/site/src/components/antdv-token-previewer/token-panel/token-item/index.tsx b/site/src/components/antdv-token-previewer/token-panel/token-item/index.tsx new file mode 100644 index 000000000..ca157bf61 --- /dev/null +++ b/site/src/components/antdv-token-previewer/token-panel/token-item/index.tsx @@ -0,0 +1,328 @@ +import { CaretRightOutlined } from '@ant-design/icons'; +import { Collapse, Space } from 'antd'; +import type { ThemeConfig } from 'antd/es/config-provider/context'; +import classNames from 'classnames'; +import type { CSSProperties } from 'react'; +import React, { useEffect, useMemo } from 'react'; +import ColorPreview from '../../ColorPreview'; +import { Pick } from '../../icons'; +import type { MutableTheme, TokenValue } from '../../interface'; +import TokenInput from '../../TokenInput'; +import getValueByPath from '../../utils/getValueByPath'; +import isColor from '../../utils/isColor'; +import makeStyle from '../../utils/makeStyle'; +import { getRelatedComponents } from '../../utils/statistic'; + +const { Panel } = Collapse; + +interface TokenItemProps { + tokenName: string; + tokenPath: string[]; + active?: boolean; + onActiveChange?: (active: boolean) => void; + onTokenChange?: (theme: MutableTheme, tokenName: string, value: TokenValue) => void; + themes: MutableTheme[]; + selectedTokens?: string[]; + onTokenSelect?: (token: string) => void; + enableTokenSelect?: boolean; + hideUsageCount?: boolean; + fallback?: (config: ThemeConfig) => Record; +} + +const AdditionInfo = ({ + info, + visible, + tokenName, + style, + dark, + ...rest +}: { + info: string | number; + visible: boolean; + tokenName: string; + dark?: boolean; + style?: CSSProperties; + className?: string; +}) => { + if (typeof info === 'string' && isColor(info)) { + return ( + + ); + } + + if (info.toString().length < 6 && String(info) !== '') { + return ( +
+ {info} +
+ ); + } + + return null; +}; + +const ShowUsageButton = ({ + selected, + toggleSelected, +}: { + selected: boolean; + toggleSelected: (v: boolean) => void; +}) => { + return ( + toggleSelected(!selected)} + /> + ); +}; + +const useStyle = makeStyle('TokenItem', token => ({ + [`${token.rootCls}-collapse.previewer-token-item-collapse`]: { + [`.previewer-token-item${token.rootCls}-collapse-item`]: { + transition: `background-color ${token.motionDurationSlow}`, + borderRadius: { _skip_check_: true, value: `4px !important` }, + + [`&:not(${token.rootCls}-collapse-item-active):hover`]: { + backgroundColor: '#f5f5f5', + }, + + [`> ${token.rootCls}-collapse-header`]: { + padding: '12px 8px', + }, + + [`${token.rootCls}-collapse-header-text`]: { + flex: 1, + width: 0, + }, + [`${token.rootCls}-collapse-content-box`]: { + padding: '0 4px', + }, + [`${token.rootCls}-collapse-expand-icon`]: { + paddingInlineEnd: `${token.paddingXXS}px !important`, + }, + '.previewer-token-count': { + height: 16, + fontSize: token.fontSizeSM, + lineHeight: '16px', + borderRadius: 100, + paddingInline: token.paddingXXS * 1.5, + color: token.colorTextSecondary, + backgroundColor: token.colorFillAlter, + }, + + '.previewer-token-item-name': { + transition: 'color 0.3s', + }, + + '.previewer-token-item-highlighted.previewer-token-item-name': { + color: `${token.colorPrimary} !important`, + }, + + '&:hover .previewer-token-preview': { + '> .previewer-color-preview:not(:last-child)': { + transform: 'translateX(-100%)', + marginInlineEnd: 4, + }, + }, + + '.previewer-token-preview': { + display: 'flex', + alignItems: 'center', + position: 'relative', + + '> .previewer-color-preview': { + position: 'absolute', + insetInlineEnd: 0, + top: 0, + bottom: 0, + margin: 'auto', + }, + + '> .previewer-color-preview:not(:last-child)': { + transform: 'translateX(-50%)', + marginInlineEnd: 0, + transition: 'transform 0.3s, margin-right 0.3s', + }, + + '> *:not(:last-child)': { + marginInlineEnd: 4, + }, + }, + }, + }, +})); + +export const getTokenItemId = (token: string) => `previewer-token-panel-item-${token}`; + +export default ({ + tokenName, + active, + onActiveChange, + onTokenChange, + tokenPath, + selectedTokens, + themes, + onTokenSelect, + enableTokenSelect, + hideUsageCount, + fallback, +}: TokenItemProps) => { + const [infoVisible, setInfoVisible] = React.useState(false); + const [wrapSSR, hashId] = useStyle(); + + useEffect(() => { + if (active) { + setInfoVisible(true); + } + }, [active]); + + const handleTokenChange = (theme: MutableTheme, value: TokenValue) => { + onTokenChange?.(theme, tokenName, value); + }; + + const count = useMemo(() => getRelatedComponents(tokenName).length, [tokenName]); + + return wrapSSR( +
onActiveChange?.(false)}> + setInfoVisible(key.length > 0)} + className={classNames('previewer-token-item-collapse', hashId)} + expandIcon={({ isActive }) => ( + + )} + activeKey={infoVisible ? tokenName : undefined} + > + + + + {tokenName} + + {!hideUsageCount && {count}} + + {!infoVisible && ( +
+ {themes.map(({ config, key }, index) => { + return ( + + ); + })} +
+ )} +
+ } + extra={ + enableTokenSelect ? ( + { + onTokenSelect?.(tokenName); + }} + /> + ) : undefined + } + > + + {themes.map(theme => { + return ( +
+ handleTokenChange(theme, value)} + value={ + getValueByPath(theme.config, [...tokenPath, tokenName]) ?? + fallback?.(theme.config)[tokenName] + } + /> +
+ ); + })} +
+ + +
, + ); +}; diff --git a/site/src/components/antdv-token-previewer/utils/classifyToken.ts b/site/src/components/antdv-token-previewer/utils/classifyToken.ts new file mode 100644 index 000000000..7197789e2 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/classifyToken.ts @@ -0,0 +1,85 @@ +import type { GlobalToken } from 'ant-design-vue/es/theme/interface'; +import type { TokenValue } from '../interface'; + +function defineTokenType(types: T[]) { + return types; +} + +export const TOKEN_SORTS = defineTokenType([ + 'seed', + 'colorCommon', + 'colorText', + 'colorBg', + 'colorFill', + 'colorSplit', + 'font', + 'radius', + 'space', + 'screen', + 'line', + 'motion', + 'control', + 'others', +]); + +export type TokenType = (typeof TOKEN_SORTS)[number]; + +export function getTypeOfToken(tokenName: string): TokenType { + if (tokenName.startsWith('color')) { + if ( + tokenName.startsWith('colorLink') || + tokenName.startsWith('colorText') || + tokenName.startsWith('colorIcon') || + tokenName.startsWith('colorPlaceholder') || + tokenName.startsWith('colorIcon') + ) { + return 'colorText'; + } + if (tokenName.startsWith('colorBg') || tokenName.startsWith('colorPopupBg')) { + return 'colorBg'; + } + if (tokenName.startsWith('colorBorder') || tokenName.startsWith('colorSplit')) { + return 'colorSplit'; + } + if (tokenName.startsWith('colorFill')) { + return 'colorFill'; + } + return 'colorCommon'; + } + if (tokenName.startsWith('font')) { + return 'font'; + } + if (tokenName.startsWith('screen')) { + return 'screen'; + } + if (tokenName.startsWith('line')) { + return 'line'; + } + if (tokenName.startsWith('motion')) { + return 'motion'; + } + if (tokenName.startsWith('borderRadius')) { + return 'radius'; + } + if (tokenName.startsWith('control')) { + return 'control'; + } + if (tokenName.startsWith('margin') || tokenName.startsWith('padding')) { + return 'space'; + } + return 'others'; +} + +export const classifyToken = (token: Record): Record => { + const groupedToken: Record = {}; + Object.keys(token || {}) + .sort((a, b) => a.localeCompare(b)) + .forEach(key => { + const type = getTypeOfToken(key as keyof GlobalToken); + if (!groupedToken[type]) { + groupedToken[type] = []; + } + groupedToken[type].push(key); + }); + return groupedToken; +}; diff --git a/site/src/components/antdv-token-previewer/utils/deepUpdateObj.ts b/site/src/components/antdv-token-previewer/utils/deepUpdateObj.ts new file mode 100644 index 000000000..9e0c88889 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/deepUpdateObj.ts @@ -0,0 +1,22 @@ +const deepUpdateObj = (obj: any, path: string[], value: any): any => { + if (path.length === 0) { + return obj; + } + if (path.length === 1) { + if (value === null || value === undefined) { + const newObj = { ...obj }; + delete newObj[path[0]]; + return newObj; + } + return { + ...obj, + [path[0]]: value, + }; + } + return { + ...obj, + [path[0]]: deepUpdateObj(obj[path[0]] ?? {}, path.slice(1), value), + }; +}; + +export default deepUpdateObj; diff --git a/site/src/components/antdv-token-previewer/utils/getColorBgImg.ts b/site/src/components/antdv-token-previewer/utils/getColorBgImg.ts new file mode 100644 index 000000000..c90b4e328 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/getColorBgImg.ts @@ -0,0 +1,7 @@ +const getColorBgImg = (dark?: boolean) => { + return dark + ? 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAIKADAAQAAAABAAAAIAAAAACPTkDJAAAAZUlEQVRIDe2VMQoAMAgDa9/g/1/oIzrpZBCh2dLFkkoDF0Fz99OdiOjks+2/7S8fRRmMMIVoRGSoYzvvqF8ZIMKlC1GhQBc6IkPzq32QmdAzkEGihpWOSPsAss8HegYySNSw0hE9WQ4StafZFqkAAAAASUVORK5CYII=)' + : 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAFpJREFUWAntljEKADAIA23p6v//qQ+wfUEcCu1yriEgp0FHRJSJcnehmmWm1Dv/lO4HIg1AAAKjTqm03ea88zMCCEDgO4HV5bS757f+7wRoAAIQ4B9gByAAgQ3pfiDmXmAeEwAAAABJRU5ErkJggg==)'; +}; + +export default getColorBgImg; diff --git a/site/src/components/antdv-token-previewer/utils/getDesignToken.ts b/site/src/components/antdv-token-previewer/utils/getDesignToken.ts new file mode 100644 index 000000000..ecbc563e0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/getDesignToken.ts @@ -0,0 +1,19 @@ +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; +import type { GlobalToken, MapToken } from 'ant-design-vue/es/theme/interface'; +import defaultMap from 'ant-design-vue/es/theme/themes/default'; +import seed from 'ant-design-vue/es/theme/themes/seed'; +import formatToken from 'ant-design-vue/es/theme/util/alias'; + +export default function getDesignToken(config: ThemeConfig = {}): GlobalToken { + const seedToken = { ...seed, ...config.token }; + const mapFn = config.algorithm ?? defaultMap; + const mapToken = Array.isArray(mapFn) + ? mapFn.reduce((result, fn) => fn(seedToken, result), undefined as any) + : mapFn(seedToken); + const mergedMapToken = { + ...mapToken, + ...config.components, + override: config.token ?? {}, + }; + return formatToken(mergedMapToken); +} diff --git a/site/src/components/antdv-token-previewer/utils/getValueByPath.ts b/site/src/components/antdv-token-previewer/utils/getValueByPath.ts new file mode 100644 index 000000000..aa98af4dc --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/getValueByPath.ts @@ -0,0 +1,11 @@ +export default function getValueByPath(obj: any, path: string[]): any { + if (!obj) { + return undefined; + } + return path.reduce((prev, key) => { + if (prev) { + return prev[key]; + } + return undefined; + }, obj); +} diff --git a/site/src/components/antdv-token-previewer/utils/isColor.ts b/site/src/components/antdv-token-previewer/utils/isColor.ts new file mode 100644 index 000000000..e43cdfca0 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/isColor.ts @@ -0,0 +1,3 @@ +export default function isColor(str: string) { + return str.startsWith('rgb') || str.startsWith('#'); +} diff --git a/site/src/components/antdv-token-previewer/utils/makeStyle.tsx b/site/src/components/antdv-token-previewer/utils/makeStyle.tsx new file mode 100644 index 000000000..9ef243291 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/makeStyle.tsx @@ -0,0 +1,43 @@ +import type { CSSInterpolation } from 'ant-design-vue/es/_util/cssinjs'; +import { useStyleRegister } from 'ant-design-vue/es/_util/cssinjs'; +import { theme as antdTheme } from 'ant-design-vue'; +import type { GlobalToken } from 'ant-design-vue/es/theme/interface'; +import { mergeToken } from 'ant-design-vue/es/theme/internal'; +import { computed } from 'vue'; +import useConfigInject from 'ant-design-vue/es/config-provider/hooks/useConfigInject'; + +import type { UseComponentStyleResult } from 'ant-design-vue/es/theme/internal'; +const makeStyle = ( + path: string, + styleFn: (token: GlobalToken & { rootCls: string }) => CSSInterpolation, +) => { + return (): UseComponentStyleResult => { + const { theme, token, hashId } = antdTheme.useToken(); + + const { getPrefixCls } = useConfigInject('', {}); + + const rootCls = getPrefixCls(); + + const componentInfo = computed(() => { + return { + theme: theme.value, + token: token.value, + hashId: hashId.value, + path: [path], + }; + }); + return [ + useStyleRegister(componentInfo, () => { + const mergedToken = mergeToken(token.value, { + rootCls: `.${rootCls}`, + }); + const styleInterpolation = styleFn(mergedToken); + + return [styleInterpolation]; + }), + hashId, + ]; + }; +}; + +export default makeStyle; diff --git a/site/src/components/antdv-token-previewer/utils/statistic.ts b/site/src/components/antdv-token-previewer/utils/statistic.ts new file mode 100644 index 000000000..ce8ee3ce6 --- /dev/null +++ b/site/src/components/antdv-token-previewer/utils/statistic.ts @@ -0,0 +1,29 @@ +import tokenStatistic from 'ant-design-vue/es/version/token.json'; + +const tokenRelatedComponents: { + [key in string]?: string[]; +} = {}; + +const getRelatedComponentsSingle = (token: string): string[] => { + if (!tokenRelatedComponents[token]) { + tokenRelatedComponents[token] = Object.entries(tokenStatistic) + .filter(([, tokens]) => { + return ((tokens as any).global as string[]).includes(token); + }) + .map(([component]) => component); + } + return tokenRelatedComponents[token] ?? []; +}; + +export const getRelatedComponents = (token: string | string[]): string[] => { + const mergedTokens = Array.isArray(token) ? token : [token]; + return Array.from( + new Set( + mergedTokens.reduce((result, item) => { + return result.concat(getRelatedComponentsSingle(item)); + }, []), + ), + ); +}; + +export const getComponentToken = (component: string) => (tokenStatistic as any)[component]; diff --git a/site/src/components/vue-colorful/components/HexColorPicker.tsx b/site/src/components/vue-colorful/components/HexColorPicker.tsx new file mode 100644 index 000000000..310f65385 --- /dev/null +++ b/site/src/components/vue-colorful/components/HexColorPicker.tsx @@ -0,0 +1,27 @@ +import type { PropType } from 'vue'; +import { defineComponent } from 'vue'; + +import { ColorPicker } from './common/ColorPicker'; +import { ColorModel } from '../types'; +import { equalHex } from '../utils/compare'; +import { hexToHsva, hsvaToHex } from '../utils/convert'; + +const colorModel: ColorModel = { + defaultColor: '000', + toHsva: hexToHsva, + fromHsva: ({ h, s, v }) => hsvaToHex({ h, s, v, a: 1 }), + equal: equalHex, +}; + +export const HexColorPicker = defineComponent({ + name: 'HexColorPicker', + inheritAttrs: false, + props: { + colorModel: { type: Object as PropType> }, + color: { type: String as PropType }, + onChange: { type: Function as PropType<(newColor: string) => void> }, + }, + setup(props, { attrs }) { + return () => ; + }, +}); diff --git a/site/src/components/vue-colorful/components/RgbaColorPicker.tsx b/site/src/components/vue-colorful/components/RgbaColorPicker.tsx new file mode 100644 index 000000000..b34492d74 --- /dev/null +++ b/site/src/components/vue-colorful/components/RgbaColorPicker.tsx @@ -0,0 +1,27 @@ +import type { PropType } from 'vue'; +import { defineComponent } from 'vue'; + +import { AlphaColorPicker } from './common/AlphaColorPicker'; +import { ColorModel, RgbaColor } from '../types'; +import { equalColorObjects } from '../utils/compare'; +import { rgbaToHsva, hsvaToRgba } from '../utils/convert'; + +const colorModel: ColorModel = { + defaultColor: { r: 0, g: 0, b: 0, a: 1 }, + toHsva: rgbaToHsva, + fromHsva: hsvaToRgba, + equal: equalColorObjects, +}; + +export const RgbaColorPicker = defineComponent({ + name: 'RgbaColorPicker', + inheritAttrs: false, + props: { + colorModel: { type: Object as PropType> }, + color: { type: Object as PropType }, + onChange: { type: Function as PropType<(newColor: RgbaColor) => void> }, + }, + setup(props, { attrs }) { + return () => ; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/Alpha.tsx b/site/src/components/vue-colorful/components/common/Alpha.tsx new file mode 100644 index 000000000..24d134993 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/Alpha.tsx @@ -0,0 +1,72 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, computed } from 'vue'; + +import { Interactive, Interaction } from './Interactive'; +import { Pointer } from './Pointer'; + +import { hsvaToHslaString } from '../../utils/convert'; +import { formatClassName } from '../../utils/format'; +import { clamp } from '../../utils/clamp'; +import { round } from '../../utils/round'; +import { HsvaColor } from '../../types'; + +export interface AlphaProps { + hsva: HsvaColor; + onChange: (newAlpha: { a: number }) => void; +} + +export const Alpha = defineComponent({ + name: 'Alpha', + props: { + hsva: { type: Object as PropType }, + onChange: { type: Function as PropType<(newAlpha: { a: number }) => void> }, + }, + setup(props, { attrs }) { + const { hsva } = toRefs(props); + + const handleMove = (interaction: Interaction) => { + props.onChange({ a: interaction.left }); + }; + + const handleKey = (offset: Interaction) => { + // Alpha always fit into [0, 1] range + props.onChange({ a: clamp(hsva.value.a + offset.left) }); + }; + + // We use `Object.assign` instead of the spread operator + // to prevent adding the polyfill (about 150 bytes gzipped) + const colorFrom = computed(() => hsvaToHslaString(Object.assign({}, hsva.value, { a: 0 }))); + const colorTo = computed(() => hsvaToHslaString(Object.assign({}, hsva.value, { a: 1 }))); + + return () => { + const gradientStyle = { + backgroundImage: `linear-gradient(90deg, ${colorFrom.value}, ${colorTo.value})`, + }; + + const nodeClassName = formatClassName(['vue-colorful__alpha', attrs.class]); + + const ariaValue = round(hsva.value.a * 100); + + return ( +
+
+ + + +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/AlphaColorPicker.tsx b/site/src/components/vue-colorful/components/common/AlphaColorPicker.tsx new file mode 100644 index 000000000..813f5c57b --- /dev/null +++ b/site/src/components/vue-colorful/components/common/AlphaColorPicker.tsx @@ -0,0 +1,46 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, computed, ref } from 'vue'; + +import { Hue } from './Hue'; +import { Saturation } from './Saturation'; +import { Alpha } from './Alpha'; + +import { ColorModel, ColorPickerBaseProps, AnyColor } from '../../types'; +import { useColorManipulation } from '../../hooks/useColorManipulation'; +import { useStyleSheet } from '../../hooks/useStyleSheet'; +import { formatClassName } from '../../utils/format'; + +export interface AlphaColorPicker extends Partial> { + colorModel: ColorModel; +} + +export const AlphaColorPicker = defineComponent({ + name: 'AlphaColorPicker', + props: { + colorModel: { type: Object as PropType> }, + color: { type: [String, Object] as PropType }, + onChange: { type: Function as PropType<(newColor: AnyColor) => void> }, + }, + setup(props, { attrs }) { + const { colorModel, color } = toRefs(props); + + const nodeRef = ref(null); + useStyleSheet(nodeRef); + + const mergedColor = computed(() => color.value || colorModel.value.defaultColor); + + const [hsva, updateHsva] = useColorManipulation(colorModel, mergedColor, props.onChange); + + return () => { + const nodeClassName = formatClassName(['vue-colorful', attrs.class]); + + return ( +
+ + + +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/ColorInput.tsx b/site/src/components/vue-colorful/components/common/ColorInput.tsx new file mode 100644 index 000000000..07097239f --- /dev/null +++ b/site/src/components/vue-colorful/components/common/ColorInput.tsx @@ -0,0 +1,68 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, ref, watchEffect } from 'vue'; + +import { ColorInputBaseProps } from '../../types'; + +export interface ColorInputProps extends ColorInputBaseProps { + /** Blocks typing invalid characters and limits string length */ + escape: (value: string) => string; + /** Checks that value is valid color string */ + validate: (value: string) => boolean; + /** Processes value before displaying it in the input */ + format?: (value: string) => string; + /** Processes value before sending it in `onChange` */ + process?: (value: string) => string; +} + +export const ColorInput = defineComponent({ + name: 'ColorInput', + props: { + color: { type: String as PropType, default: '' }, + onChange: { type: Function as PropType<(newColor: string) => void> }, + onBlur: { type: Function as PropType<(newColor: string) => void> }, + escape: { type: Function as PropType<(value: string) => string> }, + validate: { type: Function as PropType<(value: string) => boolean> }, + format: { type: Function as PropType<(value: string) => string> }, + process: { type: Function as PropType<(value: string) => string> }, + }, + setup(props, { attrs }) { + const { color } = toRefs(props); + const { escape, validate, format, process } = props; + + const value = ref(escape(color.value)); + + // Trigger `onChange` handler only if the input value is a valid color + const handleChange = e => { + const inputValue = escape(e.target.value); + value.value = inputValue; + if (validate(inputValue)) { + props.onChange(process ? process(inputValue) : inputValue); + } + }; + + // Take the color from props if the last typed color (in local state) is not valid + const handleBlur = e => { + if (!validate(e.target.value)) { + value.value = escape(color.value); + } + props.onBlur(e); + }; + + // Update the local state when `color` property value is changed + watchEffect(() => { + value.value = escape(color.value); + }); + + return () => { + return ( + + ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/ColorPicker.tsx b/site/src/components/vue-colorful/components/common/ColorPicker.tsx new file mode 100644 index 000000000..86f8c7f48 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/ColorPicker.tsx @@ -0,0 +1,48 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, ref, computed } from 'vue'; + +import { Hue } from './Hue'; +import { Saturation } from './Saturation'; + +import { ColorModel, ColorPickerBaseProps, AnyColor } from '../../types'; +import { useColorManipulation } from '../../hooks/useColorManipulation'; +import { useStyleSheet } from '../../hooks/useStyleSheet'; +import { formatClassName } from '../../utils/format'; + +export interface ColorPickerProps extends Partial> { + colorModel: ColorModel; +} + +export const ColorPicker = defineComponent({ + name: 'ColorPicker', + props: { + colorModel: { type: Object as PropType> }, + color: { type: [String, Object] as PropType }, + onChange: { type: Function as PropType<(newColor: AnyColor) => void> }, + }, + setup(props, { attrs }) { + const { colorModel, color } = toRefs(props); + + const nodeRef = ref(null); + useStyleSheet(nodeRef); + + const mergedColor = computed(() => color.value || colorModel.value.defaultColor); + + const [hsva, updateHsva] = useColorManipulation( + colorModel, + mergedColor, + props.onChange, + ); + + return () => { + const nodeClassName = formatClassName(['vue-colorful', attrs.class]); + + return ( +
+ + +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/Hue.tsx b/site/src/components/vue-colorful/components/common/Hue.tsx new file mode 100644 index 000000000..c5ed24fb1 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/Hue.tsx @@ -0,0 +1,60 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs } from 'vue'; + +import { Interactive, Interaction } from './Interactive'; +import { Pointer } from './Pointer'; + +import { hsvaToHslString } from '../../utils/convert'; +import { formatClassName } from '../../utils/format'; +import { clamp } from '../../utils/clamp'; +import { round } from '../../utils/round'; + +export interface Props { + className?: string; + hue: number; + onChange: (newHue: { h: number }) => void; +} + +export const Hue = defineComponent({ + name: 'Hue', + props: { + hue: { type: Number }, + onChange: { type: Function as PropType<(newHue: { h: number }) => void> }, + }, + setup(props, { attrs }) { + const { hue } = toRefs(props); + + const handleMove = (interaction: Interaction) => { + props.onChange({ h: 360 * interaction.left }); + }; + + const handleKey = (offset: Interaction) => { + // Hue measured in degrees of the color circle ranging from 0 to 360 + props.onChange({ + h: clamp(hue.value + offset.left * 360, 0, 360), + }); + }; + return () => { + const nodeClassName = formatClassName(['vue-colorful__hue', attrs.class]); + + return ( +
+ + + +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/Interactive.tsx b/site/src/components/vue-colorful/components/common/Interactive.tsx new file mode 100644 index 000000000..e42299dd1 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/Interactive.tsx @@ -0,0 +1,171 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs, ref, onUnmounted } from 'vue'; + +import { clamp } from '../../utils/clamp'; + +export interface Interaction { + left: number; + top: number; +} + +// Check if an event was triggered by touch +const isTouch = (event: MouseEvent | TouchEvent): event is TouchEvent => 'touches' in event; + +// Finds a proper touch point by its identifier +const getTouchPoint = (touches: TouchList, touchId: null | number): Touch => { + for (let i = 0; i < touches.length; i++) { + if (touches[i].identifier === touchId) return touches[i]; + } + return touches[0]; +}; + +// Finds the proper window object to fix iframe embedding issues +const getParentWindow = (node?: HTMLDivElement | null): Window => { + return (node && node.ownerDocument.defaultView) || self; +}; + +// Returns a relative position of the pointer inside the node's bounding box +const getRelativePosition = ( + node: HTMLDivElement, + event: MouseEvent | TouchEvent, + touchId: null | number, +): Interaction => { + const rect = node.getBoundingClientRect(); + + // Get user's pointer position from `touches` array if it's a `TouchEvent` + const pointer = isTouch(event) ? getTouchPoint(event.touches, touchId) : (event as MouseEvent); + + return { + left: clamp((pointer.pageX - (rect.left + getParentWindow(node).pageXOffset)) / rect.width), + top: clamp((pointer.pageY - (rect.top + getParentWindow(node).pageYOffset)) / rect.height), + }; +}; + +// Browsers introduced an intervention, making touch events passive by default. +// This workaround removes `preventDefault` call from the touch handlers. +// https://github.com/facebook/react/issues/19651 +const preventDefaultMove = (event: MouseEvent | TouchEvent): void => { + !isTouch(event) && event.preventDefault(); +}; + +// Prevent mobile browsers from handling mouse events (conflicting with touch ones). +// If we detected a touch interaction before, we prefer reacting to touch events only. +const isInvalid = (event: MouseEvent | TouchEvent, hasTouch: boolean): boolean => { + return hasTouch && !isTouch(event); +}; + +export interface InteractiveProps { + onMove: (interaction: Interaction) => void; + onKey: (offset: Interaction) => void; +} + +export const Interactive = defineComponent({ + name: 'Interactive', + props: { + onMove: { type: Function as PropType<(interaction: Interaction) => void> }, + onKey: { type: Function as PropType<(offset: Interaction) => void> }, + }, + setup(props, { attrs, slots }) { + const { onMove, onKey } = toRefs(props); + + const container = ref(null); + const touchId = ref(null); + const hasTouch = ref(false); + + const dragEventObj = () => { + const handleMoveStart = (event: MouseEvent | TouchEvent) => { + const el = container.value; + if (!el) return; + + // Prevent text selection + preventDefaultMove(event); + + if (isInvalid(event, hasTouch.value) || !el) return; + + if (isTouch(event)) { + hasTouch.value = true; + const changedTouches = event.changedTouches || []; + if (changedTouches.length) touchId.value = changedTouches[0].identifier; + } + + el.focus(); + onMove.value(getRelativePosition(el, event, touchId.value)); + toggleDocumentEvents(true); + }; + + const handleMove = (event: MouseEvent | TouchEvent) => { + // Prevent text selection + preventDefaultMove(event); + + // If user moves the pointer outside of the window or iframe bounds and release it there, + // `mouseup`/`touchend` won't be fired. In order to stop the picker from following the cursor + // after the user has moved the mouse/finger back to the document, we check `event.buttons` + // and `event.touches`. It allows us to detect that the user is just moving his pointer + // without pressing it down + const isDown = isTouch(event) ? event.touches.length > 0 : event.buttons > 0; + + if (isDown && container.value) { + onMove.value(getRelativePosition(container.value, event, touchId.value)); + } else { + toggleDocumentEvents(false); + } + }; + + const handleMoveEnd = () => toggleDocumentEvents(false); + + const handleKeyDown = (event: any) => { + const keyCode = event.which || event.keyCode; + + // Ignore all keys except arrow ones + if (keyCode < 37 || keyCode > 40) return; + // Do not scroll page by arrow keys when document is focused on the element + event.preventDefault(); + // Send relative offset to the parent component. + // We use codes (37←, 38↑, 39→, 40↓) instead of keys ('ArrowRight', 'ArrowDown', etc) + // to reduce the size of the library + onKey.value({ + left: keyCode === 39 ? 0.05 : keyCode === 37 ? -0.05 : 0, + top: keyCode === 40 ? 0.05 : keyCode === 38 ? -0.05 : 0, + }); + }; + + function toggleDocumentEvents(state?: boolean) { + const touch = hasTouch.value; + const el = container.value; + const parentWindow = getParentWindow(el); + + // Add or remove additional pointer event listeners + const toggleEvent = state + ? parentWindow.addEventListener + : parentWindow.removeEventListener; + toggleEvent(touch ? 'touchmove' : 'mousemove', handleMove); + toggleEvent(touch ? 'touchend' : 'mouseup', handleMoveEnd); + } + + return { handleMoveStart, handleKeyDown, toggleDocumentEvents }; + }; + + const { handleMoveStart, handleKeyDown, toggleDocumentEvents } = dragEventObj(); + + // Remove window event listeners before unmounting + onUnmounted(() => { + toggleDocumentEvents(false); + }); + + return () => { + return ( +
+ {slots.default && slots.default()} +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/Pointer.tsx b/site/src/components/vue-colorful/components/common/Pointer.tsx new file mode 100644 index 000000000..b9e999605 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/Pointer.tsx @@ -0,0 +1,37 @@ +import type { CSSProperties } from 'vue'; +import { defineComponent, toRefs } from 'vue'; +import { formatClassName } from '../../utils/format'; + +export interface PointerProps { + top?: number; + left: number; + color: string; +} + +export const Pointer = defineComponent({ + name: 'Pointer', + props: { + top: { type: Number, default: 0.5 }, + left: { type: Number }, + color: { type: String }, + }, + setup(props, { attrs }) { + const { color, left, top } = toRefs(props); + + return () => { + const nodeClassName = formatClassName(['vue-colorful__pointer', attrs.class]); + + const style = { + top: `${top.value * 100}%`, + left: `${left.value * 100}%`, + ...(attrs.style as CSSProperties), + }; + + return ( +
+
+
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/components/common/Saturation.tsx b/site/src/components/vue-colorful/components/common/Saturation.tsx new file mode 100644 index 000000000..c8fc8ff86 --- /dev/null +++ b/site/src/components/vue-colorful/components/common/Saturation.tsx @@ -0,0 +1,66 @@ +import type { PropType } from 'vue'; +import { defineComponent, toRefs } from 'vue'; + +import { Interactive, Interaction } from './Interactive'; +import { Pointer } from './Pointer'; +import { HsvaColor } from '../../types'; +import { hsvaToHslString } from '../../utils/convert'; +import { clamp } from '../../utils/clamp'; +import { round } from '../../utils/round'; + +export interface SaturationProps { + hsva: HsvaColor; + onChange: (newColor: { s: number; v: number }) => void; +} + +export const Saturation = defineComponent({ + name: 'Saturation', + props: { + hsva: { type: Object as PropType }, + onChange: { type: Function as PropType<(newColor: { s: number; v: number }) => void> }, + }, + setup(props, { attrs }) { + const { hsva } = toRefs(props); + + const handleMove = (interaction: Interaction) => { + props.onChange({ + s: interaction.left * 100, + v: 100 - interaction.top * 100, + }); + }; + + const handleKey = (offset: Interaction) => { + // Saturation and brightness always fit into [0, 100] range + props.onChange({ + s: clamp(hsva.value.s + offset.left * 100, 0, 100), + v: clamp(hsva.value.v - offset.top * 100, 0, 100), + }); + }; + + return () => { + const containerStyle = { + backgroundColor: hsvaToHslString({ h: hsva.value.h, s: 100, v: 100, a: 1 }), + }; + + return ( +
+ + + +
+ ); + }; + }, +}); diff --git a/site/src/components/vue-colorful/css/styles.css b/site/src/components/vue-colorful/css/styles.css new file mode 100644 index 000000000..63fbf2ef3 --- /dev/null +++ b/site/src/components/vue-colorful/css/styles.css @@ -0,0 +1,107 @@ +.vue-colorful { + position: relative; + display: flex; + flex-direction: column; + width: 200px; + height: 200px; + user-select: none; + cursor: default; +} + +.vue-colorful__saturation { + position: relative; + flex-grow: 1; + border-color: transparent; + border-bottom: 12px solid #000; + border-radius: 8px 8px 0 0; + background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0)), + linear-gradient(to right, #fff, rgba(255, 255, 255, 0)); +} + +.vue-colorful__pointer-fill, +.vue-colorful__alpha-gradient { + content: ''; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + pointer-events: none; + border-radius: inherit; +} + +/* Improve elements rendering on light backgrounds */ +.vue-colorful__alpha-gradient, +.vue-colorful__saturation { + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.05); +} + +.vue-colorful__hue, +.vue-colorful__alpha { + position: relative; + height: 24px; +} + +.vue-colorful__hue { + background: linear-gradient( + to right, + #f00 0%, + #ff0 17%, + #0f0 33%, + #0ff 50%, + #00f 67%, + #f0f 83%, + #f00 100% + ); +} + +/* Round bottom corners of the last element: `Hue` for `ColorPicker` or `Alpha` for `AlphaColorPicker` */ +.vue-colorful__last-control { + border-radius: 0 0 8px 8px; +} + +.vue-colorful__interactive { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border-radius: inherit; + outline: none; + /* Don't trigger the default scrolling behavior when the event is originating from this element */ + touch-action: none; +} + +.vue-colorful__pointer { + position: absolute; + z-index: 1; + box-sizing: border-box; + width: 28px; + height: 28px; + transform: translate(-50%, -50%); + background-color: #fff; + border: 2px solid #fff; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.vue-colorful__interactive:focus .vue-colorful__pointer { + transform: translate(-50%, -50%) scale(1.1); +} + +/* Chessboard-like pattern for alpha related elements */ +.vue-colorful__alpha, +.vue-colorful__alpha-pointer { + background-color: #fff; + background-image: url('data:image/svg+xml,'); +} + +/* Display the saturation pointer over the hue one */ +.vue-colorful__saturation-pointer { + z-index: 3; +} + +/* Display the hue pointer over the alpha one */ +.vue-colorful__hue-pointer { + z-index: 2; +} diff --git a/site/src/components/vue-colorful/css/styles.css.d.ts b/site/src/components/vue-colorful/css/styles.css.d.ts new file mode 100644 index 000000000..cff8ab624 --- /dev/null +++ b/site/src/components/vue-colorful/css/styles.css.d.ts @@ -0,0 +1,2 @@ +declare const cssString: string; +export default cssString; diff --git a/site/src/components/vue-colorful/hooks/useColorManipulation.ts b/site/src/components/vue-colorful/hooks/useColorManipulation.ts new file mode 100644 index 000000000..5e87ba3b9 --- /dev/null +++ b/site/src/components/vue-colorful/hooks/useColorManipulation.ts @@ -0,0 +1,69 @@ +import { Ref, ref, watch } from 'vue'; +import { ColorModel, AnyColor, HsvaColor } from '../types'; +import { equalColorObjects } from '../utils/compare'; +import { useEventCallback } from './useEventCallback'; + +export function useColorManipulation( + colorModel: Ref>, + color: Ref, + onChange?: (color: T) => void, +): [Ref, (color: Partial) => void] { + // Save onChange callback in the ref for avoiding "useCallback hell" + const onChangeCallback = useEventCallback(onChange); + + // No matter which color model is used (HEX, RGB(A) or HSL(A)), + // all internal calculations are based on HSVA model + const hsva = ref(colorModel.value.toHsva(color.value)); + + // By using this ref we're able to prevent extra updates + // and the effects recursion during the color conversion + const cache = ref({ color, hsva: hsva.value }); + + // Update local HSVA-value if `color` property value is changed, + // but only if that's not the same color that we just sent to the parent + + watch(color, val => { + if (!colorModel.value.equal(val, cache.value.color)) { + const newHsva = colorModel.value.toHsva(val); + cache.value = { hsva: newHsva, color: val }; + hsva.value = newHsva; + } + }); + watch(colorModel, val => { + if (!val.equal(color.value, cache.value.color)) { + const newHsva = val.toHsva(color.value); + cache.value = { hsva: newHsva, color: color.value }; + hsva.value = newHsva; + } + + let newColor; + if ( + !equalColorObjects(hsva.value, cache.value.hsva) && + !val.equal((newColor = val.fromHsva(hsva.value)), cache.value.color) + ) { + cache.value = { hsva: hsva.value, color: newColor }; + onChangeCallback(newColor); + } + }); + // Trigger `onChange` callback only if an updated color is different from cached one; + // save the new color to the ref to prevent unnecessary updates + + watch(hsva, val => { + let newColor; + if ( + !equalColorObjects(val, cache.value.hsva) && + !colorModel.value.equal((newColor = colorModel.value.fromHsva(val)), cache.value.color) + ) { + cache.value = { hsva: val, color: newColor }; + onChangeCallback(newColor); + } + }); + + // Merge the current HSVA color object with updated params. + // For example, when a child component sends `h` or `s` only + const handleChange = (params: Partial) => { + hsva.value = Object.assign({}, hsva.value, params); + }; + + return [hsva, handleChange]; +} diff --git a/site/src/components/vue-colorful/hooks/useEventCallback.ts b/site/src/components/vue-colorful/hooks/useEventCallback.ts new file mode 100644 index 000000000..ab0e39fce --- /dev/null +++ b/site/src/components/vue-colorful/hooks/useEventCallback.ts @@ -0,0 +1,12 @@ +import { ref } from 'vue'; + +// Saves incoming handler to the ref in order to avoid "useCallback hell" +export function useEventCallback(handler?: (value: T) => void): (value: T) => void { + const callbackRef = ref(handler); + const fn = ref((value: T) => { + callbackRef.value && callbackRef.value(value); + }); + callbackRef.value = handler; + + return fn.value; +} diff --git a/site/src/components/vue-colorful/hooks/useStyleSheet.ts b/site/src/components/vue-colorful/hooks/useStyleSheet.ts new file mode 100644 index 000000000..c635fdbf1 --- /dev/null +++ b/site/src/components/vue-colorful/hooks/useStyleSheet.ts @@ -0,0 +1,29 @@ +import type { Ref } from 'vue'; +import { watchEffect, computed } from 'vue'; + +import { getNonce } from '../utils/nonce'; + +// Bundler is configured to load this as a processed minified CSS-string +import styles from '../css/styles.css'; + +const styleElementMap: Map = new Map(); + +/** + * Injects CSS code into the document's + */ +export const useStyleSheet = (nodeRef: Ref): void => { + const parentDocument = computed(() => (nodeRef.value ? nodeRef.value.ownerDocument : document)); + watchEffect(() => { + if (typeof parentDocument.value !== 'undefined' && !styleElementMap.has(parentDocument.value)) { + const styleElement = parentDocument.value.createElement('style'); + styleElement.innerHTML = styles; + styleElementMap.set(parentDocument.value, styleElement); + + // Conform to CSP rules by setting `nonce` attribute to the inline styles + const nonce = getNonce(); + if (nonce) styleElement.setAttribute('nonce', nonce); + + parentDocument.value.head.appendChild(styleElement); + } + }); +}; diff --git a/site/src/components/vue-colorful/index.ts b/site/src/components/vue-colorful/index.ts new file mode 100644 index 000000000..13dfc8de1 --- /dev/null +++ b/site/src/components/vue-colorful/index.ts @@ -0,0 +1,2 @@ +export { HexColorPicker } from './components/HexColorPicker'; +export { RgbaColorPicker } from './components/RgbaColorPicker'; diff --git a/site/src/components/vue-colorful/types.ts b/site/src/components/vue-colorful/types.ts new file mode 100644 index 000000000..4e413294d --- /dev/null +++ b/site/src/components/vue-colorful/types.ts @@ -0,0 +1,59 @@ +import { InputHTMLAttributes } from 'vue'; + +export interface RgbColor { + r: number; + g: number; + b: number; +} + +export interface RgbaColor extends RgbColor { + a: number; +} + +export interface HslColor { + h: number; + s: number; + l: number; +} + +export interface HslaColor extends HslColor { + a: number; +} + +export interface HsvColor { + h: number; + s: number; + v: number; +} + +export interface HsvaColor extends HsvColor { + a: number; +} + +export type ObjectColor = RgbColor | HslColor | HsvColor | RgbaColor | HslaColor | HsvaColor; + +export type AnyColor = string | ObjectColor; + +export interface ColorModel { + defaultColor: T; + toHsva: (defaultColor: T) => HsvaColor; + fromHsva: (hsva: HsvaColor) => T; + equal: (first: T, second: T) => boolean; +} + +type ColorPickerHTMLAttributes = Omit< + InputHTMLAttributes, + 'color' | 'onChange' | 'onChangeCapture' +>; + +export interface ColorPickerBaseProps extends ColorPickerHTMLAttributes { + color: T; + onChange: (newColor: T) => void; +} + +type ColorInputHTMLAttributes = Omit; + +export interface ColorInputBaseProps extends ColorInputHTMLAttributes { + color?: string; + onChange?: (newColor: string) => void; +} diff --git a/site/src/components/vue-colorful/utils/clamp.ts b/site/src/components/vue-colorful/utils/clamp.ts new file mode 100644 index 000000000..74e52fd0e --- /dev/null +++ b/site/src/components/vue-colorful/utils/clamp.ts @@ -0,0 +1,6 @@ +// Clamps a value between an upper and lower bound. +// We use ternary operators because it makes the minified code +// 2 times shorter then `Math.min(Math.max(a,b),c)` +export const clamp = (number: number, min = 0, max = 1): number => { + return number > max ? max : number < min ? min : number; +}; diff --git a/site/src/components/vue-colorful/utils/compare.ts b/site/src/components/vue-colorful/utils/compare.ts new file mode 100644 index 000000000..712ea1015 --- /dev/null +++ b/site/src/components/vue-colorful/utils/compare.ts @@ -0,0 +1,32 @@ +import { hexToRgba } from './convert'; +import { ObjectColor } from '../types'; + +export const equalColorObjects = (first: ObjectColor, second: ObjectColor): boolean => { + if (first === second) return true; + + for (const prop in first) { + // The following allows for a type-safe calling of this function (first & second have to be HSL, HSV, or RGB) + // with type-unsafe iterating over object keys. TS does not allow this without an index (`[key: string]: number`) + // on an object to define how iteration is normally done. To ensure extra keys are not allowed on our types, + // we must cast our object to unknown (as RGB demands `r` be a key, while `Record` does not care if + // there is or not), and then as a type TS can iterate over. + if ( + (first as unknown as Record)[prop] !== + (second as unknown as Record)[prop] + ) + return false; + } + + return true; +}; + +export const equalColorString = (first: string, second: string): boolean => { + return first.replace(/\s/g, '') === second.replace(/\s/g, ''); +}; + +export const equalHex = (first: string, second: string): boolean => { + if (first.toLowerCase() === second.toLowerCase()) return true; + + // To compare colors like `#FFF` and `ffffff` we convert them into RGB objects + return equalColorObjects(hexToRgba(first), hexToRgba(second)); +}; diff --git a/site/src/components/vue-colorful/utils/convert.ts b/site/src/components/vue-colorful/utils/convert.ts new file mode 100644 index 000000000..9d7013030 --- /dev/null +++ b/site/src/components/vue-colorful/utils/convert.ts @@ -0,0 +1,209 @@ +import { round } from './round'; +import { RgbaColor, RgbColor, HslaColor, HslColor, HsvaColor, HsvColor } from '../types'; + +/** + * Valid CSS units. + * https://developer.mozilla.org/en-US/docs/Web/CSS/angle + */ +const angleUnits: Record = { + grad: 360 / 400, + turn: 360, + rad: 360 / (Math.PI * 2), +}; + +export const hexToHsva = (hex: string): HsvaColor => rgbaToHsva(hexToRgba(hex)); + +export const hexToRgba = (hex: string): RgbaColor => { + if (hex[0] === '#') hex = hex.substring(1); + + if (hex.length < 6) { + return { + r: parseInt(hex[0] + hex[0], 16), + g: parseInt(hex[1] + hex[1], 16), + b: parseInt(hex[2] + hex[2], 16), + a: hex.length === 4 ? round(parseInt(hex[3] + hex[3], 16) / 255, 2) : 1, + }; + } + + return { + r: parseInt(hex.substring(0, 2), 16), + g: parseInt(hex.substring(2, 4), 16), + b: parseInt(hex.substring(4, 6), 16), + a: hex.length === 8 ? round(parseInt(hex.substring(6, 8), 16) / 255, 2) : 1, + }; +}; + +export const parseHue = (value: string, unit = 'deg'): number => { + return Number(value) * (angleUnits[unit] || 1); +}; + +export const hslaStringToHsva = (hslString: string): HsvaColor => { + const matcher = + /hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i; + const match = matcher.exec(hslString); + + if (!match) return { h: 0, s: 0, v: 0, a: 1 }; + + return hslaToHsva({ + h: parseHue(match[1], match[2]), + s: Number(match[3]), + l: Number(match[4]), + a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1), + }); +}; + +export const hslStringToHsva = hslaStringToHsva; + +export const hslaToHsva = ({ h, s, l, a }: HslaColor): HsvaColor => { + s *= (l < 50 ? l : 100 - l) / 100; + + return { + h: h, + s: s > 0 ? ((2 * s) / (l + s)) * 100 : 0, + v: l + s, + a, + }; +}; + +export const hsvaToHex = (hsva: HsvaColor): string => rgbaToHex(hsvaToRgba(hsva)); + +export const hsvaToHsla = ({ h, s, v, a }: HsvaColor): HslaColor => { + const hh = ((200 - s) * v) / 100; + + return { + h: round(h), + s: round(hh > 0 && hh < 200 ? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100 : 0), + l: round(hh / 2), + a: round(a, 2), + }; +}; + +export const hsvaToHslString = (hsva: HsvaColor): string => { + const { h, s, l } = hsvaToHsla(hsva); + return `hsl(${h}, ${s}%, ${l}%)`; +}; + +export const hsvaToHsvString = (hsva: HsvaColor): string => { + const { h, s, v } = roundHsva(hsva); + return `hsv(${h}, ${s}%, ${v}%)`; +}; + +export const hsvaToHsvaString = (hsva: HsvaColor): string => { + const { h, s, v, a } = roundHsva(hsva); + return `hsva(${h}, ${s}%, ${v}%, ${a})`; +}; + +export const hsvaToHslaString = (hsva: HsvaColor): string => { + const { h, s, l, a } = hsvaToHsla(hsva); + return `hsla(${h}, ${s}%, ${l}%, ${a})`; +}; + +export const hsvaToRgba = ({ h, s, v, a }: HsvaColor): RgbaColor => { + h = (h / 360) * 6; + s = s / 100; + v = v / 100; + + const hh = Math.floor(h), + b = v * (1 - s), + c = v * (1 - (h - hh) * s), + d = v * (1 - (1 - h + hh) * s), + module = hh % 6; + + return { + r: round([v, c, b, b, d, v][module] * 255), + g: round([d, v, v, c, b, b][module] * 255), + b: round([b, b, d, v, v, c][module] * 255), + a: round(a, 2), + }; +}; + +export const hsvaToRgbString = (hsva: HsvaColor): string => { + const { r, g, b } = hsvaToRgba(hsva); + return `rgb(${r}, ${g}, ${b})`; +}; + +export const hsvaToRgbaString = (hsva: HsvaColor): string => { + const { r, g, b, a } = hsvaToRgba(hsva); + return `rgba(${r}, ${g}, ${b}, ${a})`; +}; + +export const hsvaStringToHsva = (hsvString: string): HsvaColor => { + const matcher = + /hsva?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i; + const match = matcher.exec(hsvString); + + if (!match) return { h: 0, s: 0, v: 0, a: 1 }; + + return roundHsva({ + h: parseHue(match[1], match[2]), + s: Number(match[3]), + v: Number(match[4]), + a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1), + }); +}; + +export const hsvStringToHsva = hsvaStringToHsva; + +export const rgbaStringToHsva = (rgbaString: string): HsvaColor => { + const matcher = + /rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i; + const match = matcher.exec(rgbaString); + + if (!match) return { h: 0, s: 0, v: 0, a: 1 }; + + return rgbaToHsva({ + r: Number(match[1]) / (match[2] ? 100 / 255 : 1), + g: Number(match[3]) / (match[4] ? 100 / 255 : 1), + b: Number(match[5]) / (match[6] ? 100 / 255 : 1), + a: match[7] === undefined ? 1 : Number(match[7]) / (match[8] ? 100 : 1), + }); +}; + +export const rgbStringToHsva = rgbaStringToHsva; + +const format = (number: number) => { + const hex = number.toString(16); + return hex.length < 2 ? '0' + hex : hex; +}; + +export const rgbaToHex = ({ r, g, b, a }: RgbaColor): string => { + const alphaHex = a < 1 ? format(round(a * 255)) : ''; + return '#' + format(r) + format(g) + format(b) + alphaHex; +}; + +export const rgbaToHsva = ({ r, g, b, a }: RgbaColor): HsvaColor => { + const max = Math.max(r, g, b); + const delta = max - Math.min(r, g, b); + + // prettier-ignore + const hh = delta + ? max === r + ? (g - b) / delta + : max === g + ? 2 + (b - r) / delta + : 4 + (r - g) / delta + : 0; + + return { + h: round(60 * (hh < 0 ? hh + 6 : hh)), + s: round(max ? (delta / max) * 100 : 0), + v: round((max / 255) * 100), + a, + }; +}; + +export const roundHsva = (hsva: HsvaColor): HsvaColor => ({ + h: round(hsva.h), + s: round(hsva.s), + v: round(hsva.v), + a: round(hsva.a, 2), +}); + +export const rgbaToRgb = ({ r, g, b }: RgbaColor): RgbColor => ({ r, g, b }); + +export const hslaToHsl = ({ h, s, l }: HslaColor): HslColor => ({ h, s, l }); + +export const hsvaToHsv = (hsva: HsvaColor): HsvColor => { + const { h, s, v } = roundHsva(hsva); + return { h, s, v }; +}; diff --git a/site/src/components/vue-colorful/utils/format.ts b/site/src/components/vue-colorful/utils/format.ts new file mode 100644 index 000000000..af9797b53 --- /dev/null +++ b/site/src/components/vue-colorful/utils/format.ts @@ -0,0 +1 @@ +export const formatClassName = (names: unknown[]): string => names.filter(Boolean).join(' '); diff --git a/site/src/components/vue-colorful/utils/nonce.ts b/site/src/components/vue-colorful/utils/nonce.ts new file mode 100644 index 000000000..328b689e2 --- /dev/null +++ b/site/src/components/vue-colorful/utils/nonce.ts @@ -0,0 +1,21 @@ +declare const __webpack_nonce__: string | undefined; +let nonce: string | undefined; + +/** + * Returns a nonce hash included by Webpack or the one defined manually by developer. + * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce + * https://webpack.js.org/guides/csp/ + */ +export const getNonce = (): string | undefined => { + if (nonce) return nonce; + if (typeof __webpack_nonce__ !== 'undefined') return __webpack_nonce__; + return undefined; +}; + +/** + * Signs the style tag with a base64-encoded string (nonce) to conforms to Content Security Policies. + * This function has to be invoked before any picker is rendered if you aren't using Webpack for CSP. + */ +export const setNonce = (hash: string): void => { + nonce = hash; +}; diff --git a/site/src/components/vue-colorful/utils/round.ts b/site/src/components/vue-colorful/utils/round.ts new file mode 100644 index 000000000..7e8ac0d43 --- /dev/null +++ b/site/src/components/vue-colorful/utils/round.ts @@ -0,0 +1,3 @@ +export const round = (number: number, digits = 0, base = Math.pow(10, digits)): number => { + return Math.round(base * number) / base; +}; diff --git a/site/src/components/vue-colorful/utils/validate.ts b/site/src/components/vue-colorful/utils/validate.ts new file mode 100644 index 000000000..4d2f84667 --- /dev/null +++ b/site/src/components/vue-colorful/utils/validate.ts @@ -0,0 +1,13 @@ +const matcher = /^#?([0-9A-F]{3,8})$/i; + +export const validHex = (value: string, alpha?: boolean): boolean => { + const match = matcher.exec(value); + const length = match ? match[1].length : 0; + + return ( + length === 3 || // '#rgb' format + length === 6 || // '#rrggbb' format + (!!alpha && length === 4) || // '#rgba' format + (!!alpha && length === 8) // '#rrggbbaa' format + ); +}; diff --git a/site/src/i18n.js b/site/src/i18n.js index 39bf8971f..cb08cfb97 100644 --- a/site/src/i18n.js +++ b/site/src/i18n.js @@ -1,4 +1,5 @@ -import { createI18n } from 'vue-i18n'; +import { computed } from 'vue'; +import { createI18n, useI18n } from 'vue-i18n'; import enUS from './locale/en-US'; import zhCN from './locale/zh-CN'; import { isZhCN } from './utils/util'; @@ -13,4 +14,19 @@ const i18n = createI18n({ }, }); +/** + * @description: 传入localMap,根据当前的语言类型输入i18nmessage,只是中英两种 + * @param {object} localeMap {en:{xxx:xxx},cn:{xxx:xxx} } + * @return {object} [i18nMessage, localeType] + */ +export function useLocale(localeMap = {}) { + const { locale } = useI18n(); + + const localeType = computed(() => (locale.value === 'zh-CN' ? 'cn' : 'en')); + + const i18nMessage = computed(() => (localeMap && localeMap[localeType.value]) || {}); + + return [i18nMessage, localeType]; +} + export default i18n; diff --git a/site/src/views/theme-editor/JSONEditor/index.vue b/site/src/views/theme-editor/JSONEditor/index.vue new file mode 100644 index 000000000..b7dfd3a3f --- /dev/null +++ b/site/src/views/theme-editor/JSONEditor/index.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/site/src/views/theme-editor/index.vue b/site/src/views/theme-editor/index.vue index 75eb481d7..0c12a1d78 100644 --- a/site/src/views/theme-editor/index.vue +++ b/site/src/views/theme-editor/index.vue @@ -1,8 +1,241 @@ - + + diff --git a/site/src/views/theme-editor/locales.ts b/site/src/views/theme-editor/locales.ts new file mode 100644 index 000000000..276214e2f --- /dev/null +++ b/site/src/views/theme-editor/locales.ts @@ -0,0 +1,24 @@ +export default { + cn: { + title: '主题编辑器', + save: '保存', + edit: '编辑', + export: '导出', + editModelTitle: '编辑主题配置', + editJsonContentTypeError: '主题 JSON 格式错误', + editSuccessfully: '编辑成功', + saveSuccessfully: '保存成功', + initialEditor: '正在初始化编辑器...', + }, + en: { + title: 'Theme Editor', + save: 'Save', + edit: 'Edit', + export: 'Export', + editModelTitle: 'edit Theme Config', + editJsonContentTypeError: 'The theme of the JSON format is incorrect', + editSuccessfully: 'Edited successfully', + saveSuccessfully: 'Saved successfully', + initialEditor: 'Initializing Editor...', + }, +};