From 554fe2945fd841b597d5e8f41dfb4eafabbf6012 Mon Sep 17 00:00:00 2001 From: ZhangAo Date: Mon, 1 Sep 2025 17:30:41 +0800 Subject: [PATCH] u --- .../ao-design/src/_styles/theme/index.scss | 20 +- .../packages/ao-design/src/button/index.scss | 203 ++++++++++++++++-- .../packages/ao-design/src/button/index.tsx | 64 +++++- .../packages/ao-design/src/components.ts | 1 + .../packages/ao-design/src/icon/index.scss | 12 ++ .../packages/ao-design/src/icon/index.tsx | 20 +- .../packages/ao-design/src/index.scss | 3 +- .../packages/ao-design/src/input/index.scss | 7 + .../packages/ao-design/src/input/index.tsx | 62 +----- .../packages/ao-design/src/spin/index.scss | 35 +++ .../packages/ao-design/src/spin/index.tsx | 52 +++++ code/base-project/base-vue/src/App.vue | 113 +++++++++- .../base-project/base-vue/src/components.d.ts | 3 + code/base-project/base-vue/src/style.scss | 6 +- code/base-project/base-vue/test.html | 89 +++----- 15 files changed, 531 insertions(+), 159 deletions(-) create mode 100644 code/base-project/base-vue/packages/ao-design/src/icon/index.scss create mode 100644 code/base-project/base-vue/packages/ao-design/src/input/index.scss create mode 100644 code/base-project/base-vue/packages/ao-design/src/spin/index.scss create mode 100644 code/base-project/base-vue/packages/ao-design/src/spin/index.tsx diff --git a/code/base-project/base-vue/packages/ao-design/src/_styles/theme/index.scss b/code/base-project/base-vue/packages/ao-design/src/_styles/theme/index.scss index db598211..44bd9c27 100644 --- a/code/base-project/base-vue/packages/ao-design/src/_styles/theme/index.scss +++ b/code/base-project/base-vue/packages/ao-design/src/_styles/theme/index.scss @@ -1,17 +1,7 @@ $prefix: 'ao' !default; -// 主色系 -$primary-color: #1677ff !default; -$primary-hover-color: #0958d9 !default; - -// 功能色 -$success-color: #52c41a !default; -$danger-color: #ff4d4f !default; -$warning-color: #faad14 !default; -$info-color: #13c2c2 !default; - -// 中性色 -$background-color: #f5f7fa !default; -$border-color: #d9d9d9 !default; -$text-color: #000000de !default; -$text-secondary-color: #595959 !default; +$default-color: #0064fa !default; +$primary-color: $default-color !default; +$danger-color: #f93920 !default; +$warning-color: #fc8800 !default; +$success-color: #22c55e !default; diff --git a/code/base-project/base-vue/packages/ao-design/src/button/index.scss b/code/base-project/base-vue/packages/ao-design/src/button/index.scss index da9af92a..4ba4df9c 100644 --- a/code/base-project/base-vue/packages/ao-design/src/button/index.scss +++ b/code/base-project/base-vue/packages/ao-design/src/button/index.scss @@ -1,29 +1,198 @@ -@import '../_styles/theme/index.scss'; +@use 'sass:color'; +@use '../_styles/theme/index' as *; -// 按钮基础样式示例 -.#{$prefix}-btn { - padding: 6px 16px; - border-radius: 4px; +$btn-prefix: #{$prefix}-btn; +$btn-hover-bgcolor: #f4f5f5; +$btn-active-bgcolor: #eceded; + +/* ====== 通用颜色交互函数 ====== */ +@function color-hover($color, $amount: 8%) { + $l: color.lightness($color); + @if $l > 50% { + @return color.adjust($color, $lightness: -$amount); + } @else { + @return color.adjust($color, $lightness: $amount); + } +} + +@function color-active($color, $amount: 12%) { + $l: color.lightness($color); + @if $l > 50% { + @return color.adjust($color, $lightness: -$amount); + } @else { + @return color.adjust($color, $lightness: $amount); + } +} + +.#{$btn-prefix} { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 4px; + box-sizing: border-box; + user-select: none; + border-radius: 3px; border: 1px solid transparent; cursor: pointer; + transition: all 0.2s ease; + font-weight: 600; - &-default { - background: #fff; - border-color: $border-color; - color: $text-secondary-color; + &-block { + width: 100%; } - &-primary { - background: $primary-color; - color: #fff; + &-icon-left { + margin-right: 4px; + display: inline-flex; + align-items: center; + } + &-icon-right { + margin-left: 4px; + display: inline-flex; + align-items: center; + } - &:hover { - background: $primary-hover-color; + &:disabled { + cursor: not-allowed; + opacity: 0.6; + } + + /* ===== Solid 按钮 ===== */ + &-solid { + @each $status, + $color + in ( + normal: #d9d9d9, + primary: $primary-color, + danger: $danger-color, + warning: $warning-color, + success: $success-color + ) + { + &.#{$btn-prefix}-status-#{$status} { + @if $status == normal { + background: #f4f5f5; + color: #000; + &:hover:enabled { + background: #eceded; + } + &:active:enabled { + background: #e4e4e5; + } + } @else { + background: $color; + color: #fff; + border: 1px solid transparent; + &:hover:enabled { + background: color-hover($color, 5%); + } + &:active:enabled { + background: color-active($color, -5%); + } + } + } } } - &-danger { - background: $danger-color; - color: #fff; + /* ===== Outline 按钮 ===== */ + &-outline { + font-weight: 500; + background: transparent; + + @each $status, + $color + in ( + normal: $primary-color, + primary: $primary-color, + danger: $danger-color, + warning: $warning-color, + success: $success-color + ) + { + &.#{$btn-prefix}-status-#{$status} { + color: if($status == normal, #000, $color); + border-color: if($status == normal, #d9d9d9, $color); + &:hover:enabled { + background-color: $btn-hover-bgcolor; + } + &:active:enabled { + background-color: $btn-active-bgcolor; + } + } + } + } + + /* ===== Dashed 按钮 ===== */ + &-dashed { + font-weight: 500; + background: transparent; + border: 1px dashed currentColor; + + @each $status, + $color + in ( + normal: #000, + primary: $primary-color, + danger: $danger-color, + warning: $warning-color, + success: $success-color + ) + { + &.#{$btn-prefix}-status-#{$status} { + color: $color; + border-color: if($status == normal, #d9d9d9, $color); + &:hover:enabled { + background-color: $btn-hover-bgcolor; + } + &:active:enabled { + background-color: $btn-active-bgcolor; + } + } + } + } + + /* ===== Text 按钮 ===== */ + &-text { + font-weight: 500; + background: transparent; + border: none; + + @each $status, + $color + in ( + normal: #000, + primary: $primary-color, + danger: $danger-color, + warning: $warning-color, + success: $success-color + ) + { + &.#{$btn-prefix}-status-#{$status} { + color: $color; + &:hover:enabled { + background-color: $btn-hover-bgcolor; + } + &:active:enabled { + background-color: $btn-active-bgcolor; + } + } + } + } + + /* ===== 尺寸 ===== */ + &-small { + height: 24px; + padding: 0 12px; + font-size: 12px; + } + &-medium { + height: 28px; + padding: 0 14px; + font-size: 14px; + } + &-large { + height: 32px; + padding: 0 16px; + font-size: 14px; } } diff --git a/code/base-project/base-vue/packages/ao-design/src/button/index.tsx b/code/base-project/base-vue/packages/ao-design/src/button/index.tsx index ea8420ef..98573f77 100644 --- a/code/base-project/base-vue/packages/ao-design/src/button/index.tsx +++ b/code/base-project/base-vue/packages/ao-design/src/button/index.tsx @@ -1,14 +1,70 @@ import { computed, defineComponent } from 'vue' import { getPrefixCls } from '../_utils/getPrefixCls' +import Icon from '../icon' +import './index.scss' export default defineComponent({ - name: 'AButton', + name: 'Button', props: { - type: { type: String as () => 'primary' | 'danger' | 'default', default: 'default' }, + type: { + type: String as () => 'solid' | 'outline' | 'text' | 'dashed', + default: 'solid', + }, + status: { + type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'normal', + default: 'normal', + }, + disabled: { type: Boolean, default: false }, + loading: { type: Boolean, default: false }, + icon: { type: String, default: '' }, + iconPosition: { type: String as () => 'left' | 'right', default: 'left' }, + size: { type: String as () => 'small' | 'medium' | 'large', default: 'medium' }, + block: { type: Boolean, default: false }, }, setup(props, { slots }) { const prefixCls = getPrefixCls('btn') - const cls = computed(() => [prefixCls, `${prefixCls}-${props.type}`]) - return () => + + const cls = computed(() => [ + prefixCls, + `${prefixCls}-${props.type}`, + `${prefixCls}-status-${props.status}`, + `${prefixCls}-${props.size}`, + props.block && `${prefixCls}-block`, + ]) + + const iconSize = computed(() => { + const map = { small: 14, medium: 16, large: 16 } + return map[props.size] + }) + + return () => ( + + ) }, }) diff --git a/code/base-project/base-vue/packages/ao-design/src/components.ts b/code/base-project/base-vue/packages/ao-design/src/components.ts index fb3205af..6a4f8fd5 100644 --- a/code/base-project/base-vue/packages/ao-design/src/components.ts +++ b/code/base-project/base-vue/packages/ao-design/src/components.ts @@ -2,3 +2,4 @@ export { default as ConfigProvider } from './_config' export { default as Button } from './button' export { default as Icon } from './icon' export { default as Input } from './input' +export { default as Spin } from './spin' diff --git a/code/base-project/base-vue/packages/ao-design/src/icon/index.scss b/code/base-project/base-vue/packages/ao-design/src/icon/index.scss new file mode 100644 index 00000000..779060cf --- /dev/null +++ b/code/base-project/base-vue/packages/ao-design/src/icon/index.scss @@ -0,0 +1,12 @@ +@use '../_styles/theme/index' as *; + +.#{$prefix}-icon-spin { + animation: spin 1s linear infinite; + --rotate-angle: 360deg; +} + +@keyframes spin { + to { + transform: rotate(var(--rotate-angle)); + } +} diff --git a/code/base-project/base-vue/packages/ao-design/src/icon/index.tsx b/code/base-project/base-vue/packages/ao-design/src/icon/index.tsx index a873816e..a7ff4ff3 100644 --- a/code/base-project/base-vue/packages/ao-design/src/icon/index.tsx +++ b/code/base-project/base-vue/packages/ao-design/src/icon/index.tsx @@ -1,22 +1,32 @@ import type { PropType } from 'vue' import { Icon } from '@iconify/vue' import { defineComponent } from 'vue' +import { getPrefixCls } from '../_utils/getPrefixCls' +import './index.scss' export default defineComponent({ - name: 'AIcon', + name: 'Icon', props: { icon: { type: String as PropType, required: true }, - width: { type: String, default: '24px' }, - height: { type: String, default: '24px' }, - color: { type: String, default: 'currentColor' }, // 默认颜色使用 currentColor,支持继承父元素的颜色 + width: { type: Number, default: 16 }, + height: { type: Number, default: 16 }, + color: { type: String, default: 'currentColor' }, + spin: { type: Boolean, default: false }, + rotate: { type: Number, default: 360 }, }, setup(props) { + const prefixCls = getPrefixCls('icon') return () => ( ) }, diff --git a/code/base-project/base-vue/packages/ao-design/src/index.scss b/code/base-project/base-vue/packages/ao-design/src/index.scss index 6cb4bcb1..b54fa760 100644 --- a/code/base-project/base-vue/packages/ao-design/src/index.scss +++ b/code/base-project/base-vue/packages/ao-design/src/index.scss @@ -1 +1,2 @@ -@import './button/index.scss'; +@use './button/index.scss' as *; +@use './input/index.scss' as *; diff --git a/code/base-project/base-vue/packages/ao-design/src/input/index.scss b/code/base-project/base-vue/packages/ao-design/src/input/index.scss new file mode 100644 index 00000000..270049f7 --- /dev/null +++ b/code/base-project/base-vue/packages/ao-design/src/input/index.scss @@ -0,0 +1,7 @@ +@use '../_styles/theme/index' as *; + +$input-prefix: #{$prefix}-input; + +.#{$input-prefix} { + border-color: #d9d9d9; +} diff --git a/code/base-project/base-vue/packages/ao-design/src/input/index.tsx b/code/base-project/base-vue/packages/ao-design/src/input/index.tsx index 1aaab33b..b38d2259 100644 --- a/code/base-project/base-vue/packages/ao-design/src/input/index.tsx +++ b/code/base-project/base-vue/packages/ao-design/src/input/index.tsx @@ -1,63 +1,23 @@ -import type { PropType } from 'vue' -import { computed, defineComponent, ref, toRefs } from 'vue' +import { computed, defineComponent, ref } from 'vue' +import { getPrefixCls } from '../_utils/getPrefixCls' export default defineComponent({ - name: 'Input', - props: { - modelValue: { type: String, default: '' }, - placeholder: { type: String, default: '' }, - type: { type: String as PropType<'text' | 'password' | 'number'>, default: 'text' }, - disabled: { type: Boolean, default: false }, - clearable: { type: Boolean, default: false }, - }, - emits: ['update:modelValue', 'change', 'focus', 'blur'], - setup(props, { emit }) { + name: 'AInput', + setup() { const inputRef = ref(null) - const handleInput = (e: Event) => { - const value = (e.target as HTMLInputElement).value - emit('update:modelValue', value) - emit('change', value) - } - - const handleClear = () => { - emit('update:modelValue', '') - inputRef.value?.focus() - emit('change', '') - } - - const showClear = computed(() => props.clearable && !!props.modelValue && !props.disabled) + // 使用统一前缀 + const prefixCls = getPrefixCls('input') + const cls = computed(() => [prefixCls]) return () => ( -
+
emit('focus', e)} - onBlur={e => emit('blur', e)} - style={{ paddingRight: showClear.value ? '24px' : '8px' }} + class={cls.value} + type="text" + placeholder="请输入" /> - {showClear.value && ( - - × - - )}
) }, diff --git a/code/base-project/base-vue/packages/ao-design/src/spin/index.scss b/code/base-project/base-vue/packages/ao-design/src/spin/index.scss new file mode 100644 index 00000000..7b8b31d1 --- /dev/null +++ b/code/base-project/base-vue/packages/ao-design/src/spin/index.scss @@ -0,0 +1,35 @@ +@use '../_styles/theme/index' as *; + +$spin-prefix: #{$prefix}-spin; + +.#{$spin-prefix}-wrapper { + position: relative; + display: inline-block; +} + +.#{$spin-prefix} { + position: absolute; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + z-index: 10; + + &-content { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: $primary-color; + } + + &-tip { + margin-top: 4px; + font-size: 12px; + color: #000; + } + + &.rounded { + border-radius: inherit; + } +} diff --git a/code/base-project/base-vue/packages/ao-design/src/spin/index.tsx b/code/base-project/base-vue/packages/ao-design/src/spin/index.tsx new file mode 100644 index 00000000..2ee2ac5b --- /dev/null +++ b/code/base-project/base-vue/packages/ao-design/src/spin/index.tsx @@ -0,0 +1,52 @@ +import type { PropType } from 'vue' +import { defineComponent } from 'vue' +import { getPrefixCls } from '../_utils/getPrefixCls' +import Icon from '../icon' +import './index.scss' + +export default defineComponent({ + name: 'Spin', + props: { + loading: { type: Boolean, default: false }, + opacity: { type: Number as PropType, default: 0.6 }, + rounded: { type: Boolean, default: true }, + icon: { type: String as PropType, default: 'mingcute:loading-line' }, + size: { type: Number as PropType, default: 16 }, + rotate: { type: Number as PropType, default: 360 }, + tip: { type: String as PropType, default: '' }, + }, + setup(props, { slots }) { + const prefixCls = getPrefixCls('spin') + + return () => { + if (!props.loading && !slots.default) + return null + + return ( +
+ {slots.default?.()} + {props.loading && ( +
+
+ + {props.tip && {props.tip}} +
+
+ )} +
+ ) + } + }, +}) diff --git a/code/base-project/base-vue/src/App.vue b/code/base-project/base-vue/src/App.vue index 35585bab..b006b0a9 100644 --- a/code/base-project/base-vue/src/App.vue +++ b/code/base-project/base-vue/src/App.vue @@ -2,9 +2,114 @@ diff --git a/code/base-project/base-vue/src/components.d.ts b/code/base-project/base-vue/src/components.d.ts index a387ef24..809002f2 100644 --- a/code/base-project/base-vue/src/components.d.ts +++ b/code/base-project/base-vue/src/components.d.ts @@ -12,5 +12,8 @@ declare module 'vue' { AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider'] AIcon: typeof import('@ao/ao-design')['Icon'] AInput: typeof import('@ao/ao-design')['Input'] + ALoading: typeof import('@ao/ao-design')['Loading'] + ALoding: typeof import('@ao/ao-design')['Loding'] + ASpin: typeof import('@ao/ao-design')['Spin'] } } diff --git a/code/base-project/base-vue/src/style.scss b/code/base-project/base-vue/src/style.scss index 08524c01..a808722e 100644 --- a/code/base-project/base-vue/src/style.scss +++ b/code/base-project/base-vue/src/style.scss @@ -1 +1,5 @@ -@import '@ao/ao-design/index.scss'; +@use '@ao/ao-design/index.scss' as *; + +body { + font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif; +} diff --git a/code/base-project/base-vue/test.html b/code/base-project/base-vue/test.html index deca4c4f..691297eb 100644 --- a/code/base-project/base-vue/test.html +++ b/code/base-project/base-vue/test.html @@ -1,79 +1,46 @@ - + - - 后台低交互按钮(纯 CSS 自动亮暗) + + + AntD 风格按钮点击反馈 -

后台低交互按钮(纯 CSS 自动亮暗)

- -
- - - -
+ +