This commit is contained in:
oneao committed 2025-09-04 17:31:49 +08:00
1 parent 068fcb7649
commit 1a33497c5d
29 files changed
+889 -306

No files matched your search

@@ -2,45 +2,85 @@
$prefix: 'ao' !default; $prefix: 'ao' !default;
// 基础颜色 // 基础颜色
$primary: var(--ao-primary); // 色彩-品牌-可操作 $default-color: var(--ao-default-color); // 色彩-品牌-可操作
$warning: var(--ao-warning); // 色彩-功能-警告 $primary-color: var(--ao-primary-color); // 色彩-品牌-可操作
$danger: var(--ao-danger); // 色彩-功能-失败 $warning-color: var(--ao-warning-color); // 色彩-功能-警告
$success: var(--ao-success); // 色彩-功能-成功 $danger-color: var(--ao-danger-color); // 色彩-功能-失败
$success-color: var(--ao-success-color); // 色彩-功能-成功
// 默认颜色的扩展 用于 hover / 聚焦 / 禁用 / 点击 等状态
$default-color-hover: var(--ao-default-color-hover); // hover态
$default-color-focus: var(--ao-default-color-focus); // focus态,包括鼠标和键盘
$default-color-active: var(--ao-default-color-active); // 点击态
$default-color-disabled: var(--ao-default-color-disabled); // 禁用态
// 基础颜色的扩展 用于 hover / 聚焦 / 禁用 / 点击 等状态 // 基础颜色的扩展 用于 hover / 聚焦 / 禁用 / 点击 等状态
$primary-hover: var(--ao-primary-hover); // hover态 $primary-color-hover: var(--ao-primary-color-hover); // hover态
$primary-focus: var(--ao-primary-focus); // focus态,包括鼠标和键盘 $primary-color-focus: var(--ao-primary-color-focus); // focus态,包括鼠标和键盘
$primary-active: var(--ao-primary-active); // 点击态 $primary-color-active: var(--ao-primary-color-active); // 点击态
$primary-disabled: var(--ao-primary-disabled); // 禁用态 $primary-color-disabled: var(--ao-primary-color-disabled); // 禁用态
// 警告色扩展 // 警告色扩展
$warning-hover: var(--ao-warning-hover); $warning-color-hover: var(--ao-warning-color-hover);
$warning-focus: var(--ao-warning-focus); $warning-color-focus: var(--ao-warning-color-focus);
$warning-active: var(--ao-warning-active); $warning-color-active: var(--ao-warning-color-active);
$warning-disabled: var(--ao-warning-disabled); $warning-color-disabled: var(--ao-warning-color-disabled);
// 失败/错误色扩展 // 失败/错误色扩展
$danger-hover: var(--ao-danger-hover); $danger-color-hover: var(--ao-danger-color-hover);
$danger-focus: var(--ao-danger-focus); $danger-color-focus: var(--ao-danger-color-focus);
$danger-active: var(--ao-danger-active); $danger-color-active: var(--ao-danger-color-active);
$danger-disabled: var(--ao-danger-disabled); $danger-color-disabled: var(--ao-danger-color-disabled);
// 成功色扩展 // 成功色扩展
$success-hover: var(--ao-success-hover); $success-color-hover: var(--ao-success-color-hover);
$success-focus: var(--ao-success-focus); $success-color-focus: var(--ao-success-color-focus);
$success-active: var(--ao-success-active); $success-color-active: var(--ao-success-color-active);
$success-disabled: var(--ao-success-disabled); $success-color-disabled: var(--ao-success-color-disabled);
// 文本颜色 // 文本颜色
$text-primary: var(--ao-text-primary); // 色彩-文字-主要 $text-color-base: var(--ao-text-color-base); // 色彩-文字-主要
$text-secondary: var(--ao-text-secondary); // 色彩-文字-次要 $text-color-secondary: var(--ao-text-color-secondary); // 色彩-文字-次要
$text-assist: var(--ao-text-secondary); // 色彩-文字-次要 $text-color-assist: var(--ao-text-color-assist); // 色彩-文字-次要
$text-placeholder: var(--ao-text-placeholder); // 色彩-文字-占位符/说明 $text-color-placeholder: var(--ao-text-color-placeholder); // 色彩-文字-占位符/说明
$text-disabled: var(--ao-text-disabled); // 色彩-文字-禁用 $text-color-disabled: var(--ao-text-color-disabled); // 色彩-文字-禁用
$text-anti: var(--ao-text-anti); // 色彩-文字-反色 $text-color-anti: var(--ao-text-color-anti); // 色彩-文字-反色
$text-primary: var(--ao-text-primary); // 色彩-文字-品牌 $text-color-link: var(--ao-text-color-link); // 色彩-文字-链接
$text-link: var(--ao-text-link); // 色彩-文字-链接
$border-radius: 2px; $border-radius: 2px;
$border-divider: var(--ao-stroke); // 分割线(内容区域之间的分隔,如列表、面板内部) $stroke-color: var(--ao-stroke-color); // 分割线(内容区域之间的分隔,如列表、面板内部)
$border-component: var(--ao-border); // 组件边框(Input、Select、Card 等容器的外部边框) $border-color: var(--ao-border-color); // 组件边框(Input、Select、Card 等容器的外部边框)
$bg-color-control: var(
--ao-bg-color-control
); // 特殊组件背景色,目前只用于 button、input 组件多主题场景,浅色主题下固定为白色,深色主题下为 transparent 适配背景颜色
// 高度
$size-height-small: 24px;
$size-height-medium: 28px;
$size-height-large: 32px;
// 字体大小
$size-font-small: 12px;
$size-font-medium: 13px;
$size-font-large: 14px;
// 滚动条颜色
$scrollbar-color: var(--ao-scrollbar-color);
// 滚动条悬浮颜色
$scrollbar-hover-color: var(--ao-scrollbar-hover-color);
// 滚动条轨道颜色
$scroll-track-color: var(--ao-scroll-track-color);
// 容器颜色,使用的组件:popup
$bg-color-container: var(--ao-bg-color-container);
$bg-color-container-hover: var(--ao-bg-color-container-hover);
$bg-color-container-active: var(--ao-bg-color-container-active);
// shadow
// 基础/下层 投影 hover 使用的组件包括:表格 /
$shadow-surface: var(--ao-shadow-surface);
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
$shadow-popup: var(--ao-shadow-popup);
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
$shadow-overlay: var(--ao-shadow-overlay);
@@ -1,39 +1,66 @@
:root[theme-mode='dark'] { :root[theme-mode='dark'] {
--ao-primary: #4582e6; --ao-default-color: #393939;
--ao-warning: #cf6e2d; --ao-primary-color: #4582e6;
--ao-danger: #c64751; --ao-warning-color: #cf6e2d;
--ao-success: #059465; --ao-danger-color: #c64751;
--ao-success-color: #059465;
--ao-primary-hover: #2667d4; --ao-default-color-hover: #4b4b4b;
--ao-primary-focus: #173463; --ao-default-color-focus: #505050;
--ao-primary-active: #699ef5; --ao-default-color-active: #5c5c5c;
--ao-primary-disabled: #143975; --ao-default-color-disabled: #2c2c2c;
--ao-warning-hover: #a75d2b; --ao-primary-color-hover: #2667d4;
--ao-warning-focus: #582f21; --ao-primary-color-focus: #173463;
--ao-warning-active: #dc7633; --ao-primary-color-active: #699ef5;
--ao-warning-disabled: #733c23; --ao-primary-color-disabled: #143975;
--ao-danger-hover: #a03f46; --ao-warning-color-hover: #a75d2b;
--ao-danger-focus: #5e2a2d; --ao-warning-color-focus: #582f21;
--ao-danger-active: #de6670; --ao-warning-color-active: #dc7633;
--ao-danger-disabled: #703439; --ao-warning-color-disabled: #733c23;
--ao-success-hover: #0d7a55; --ao-danger-color-hover: #a03f46;
--ao-success-focus: #1a4230; --ao-danger-color-focus: #5e2a2d;
--ao-success-active: #43af8a; --ao-danger-color-active: #de6670;
--ao-success-disabled: #17533d; --ao-danger-color-disabled: #703439;
--ao-text-primary: rgba(255, 255, 255, 90%); /* 主要文字 */ --ao-success-color-hover: #0d7a55;
--ao-text-secondary: rgba(255, 255, 255, 55%); /* 次要文字 / 辅助信息 */ --ao-success-color-focus: #1a4230;
--ao-text-assist: rgba(255, 255, 255, 45%); /* 输入框内部辅助元素(icon/count) */ --ao-success-color-active: #43af8a;
--ao-text-placeholder: rgba(255, 255, 255, 35%); /* 占位符 / 说明文字 */ --ao-success-color-disabled: #17533d;
--ao-text-disabled: rgba(255, 255, 255, 22%); /* 禁用文字 */
--ao-text-anti: #fff; /* 反色文字(深色背景上) */
--ao-text-brand: #4582e6; /* 品牌色文字 / 主操作色 */
--ao-text-link: #4582e6; /* 链接文字 */
--ao-text-watermark: rgba(255, 255, 255, 10%); /* 水印 / 背景文字 */
--ao-stroke: #393939; // 分割线 --ao-text-color-base: rgba(255, 255, 255, 90%); /* 主要文字 */
--ao-border: #5e5e5e; // 边框 --ao-text-color-secondary: rgba(255, 255, 255, 55%); /* 次要文字 / 辅助信息 */
--ao-text-color-assist: rgba(255, 255, 255, 45%); /* 输入框内部辅助元素(icon/count) */
--ao-text-color-placeholder: rgba(255, 255, 255, 35%); /* 占位符 / 说明文字 */
--ao-text-color-disabled: rgba(255, 255, 255, 22%); /* 禁用文字 */
--ao-text-color-anti: #fff; /* 反色文字(深色背景上) */
--ao-text-color-link: #4582e6; /* 链接文字 */
--ao-text-color-watermark: rgba(255, 255, 255, 10%); /* 水印 / 背景文字 */
--ao-stroke-color: #393939; // 分割线
--ao-border-color: #5e5e5e; // 边框
--ao-bg-color-control: transparent; // 特殊组件背景色,目前只用于 button、input 组件多主题场景,浅色主题下固定为白色,深色主题下为 transparent 适配背景颜色
// 滚动条颜色
--ao-scrollbar-color: rgba(255, 255, 255, 10%);
// 滚动条悬浮颜色( hover )
--ao-scrollbar-hover-color: rgba(255, 255, 255, 30%);
// 滚动条轨道颜色,不能是带透明度,否则纵向滚动时,横向滚动条会穿透
--ao-scroll-track-color: #333;
// 容器颜色,使用的组件:popup
--ao-bg-color-container: #242424;
--ao-bg-color-container-hover: #2c2c2c;
--ao-bg-color-container-active: #4b4b4b;
// shadow阴影
// 基础/下层 投影 hover 使用的组件包括:表格 /
--ao-shadow-surface: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
--ao-shadow-popup: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
--ao-shadow-overlay: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);
} }
@@ -1,40 +1,69 @@
:root, :root,
:root[theme-mode='light'] { :root[theme-mode='light'] {
--ao-primary: #0052d9; --ao-default-color: #e7e7e7;
--ao-warning: #e37318; --ao-primary-color: #0052d9;
--ao-danger: #d54941; --ao-warning-color: #e37318;
--ao-success: #2ba471; --ao-danger-color: #d54941;
--ao-success-color: #2ba471;
--ao-primary-hover: #366ef4; --ao-default-color-hover: #dddddd;
--ao-primary-focus: #d9e1ff; --ao-default-color-focus: #cfcfcf;
--ao-primary-active: #003cab; --ao-default-color-active: #ababab;
--ao-primary-disabled: #b5c7ff; --ao-default-color-disabled: #eeeeee;
--ao-warning-hover: #fa9550; --ao-primary-color-hover: #366ef4;
--ao-warning-focus: #ffd9c2; --ao-primary-color-focus: #d9e1ff;
--ao-warning-active: #be5a00; --ao-primary-color-active: #003cab;
--ao-warning-disabled: #ffb98c; --ao-primary-color-disabled: #b5c7ff;
--ao-danger-hover: #f6685d; --ao-warning-color-hover: #fa9550;
--ao-danger-focus: #ffd8d2; --ao-warning-color-focus: #ffd9c2;
--ao-danger-active: #ad352f; --ao-warning-color-active: #be5a00;
--ao-danger-disabled: #ffb9b0; --ao-warning-color-disabled: #ffb98c;
--ao-success-hover: #56c08d; --ao-danger-color-hover: #f6685d;
--ao-success-focus: #c6f3d7; --ao-danger-color-focus: #ffd8d2;
--ao-success-active: #008858; --ao-danger-color-active: #ad352f;
--ao-success-disabled: #92dab2; --ao-danger-color-disabled: #ffb9b0;
--ao-text-primary: rgba(0, 0, 0, 90%); /* 主要文字 */ --ao-success-color-hover: #56c08d;
--ao-text-secondary: rgba(0, 0, 0, 60%); /* 次要文字 / 辅助信息 */ --ao-success-color-focus: #c6f3d7;
--ao-text-assist: rgba(0, 0, 0, 50%); /* 输入框内部辅助元素(icon/count) */ --ao-success-color-active: #008858;
--ao-text-placeholder: rgba(0, 0, 0, 40%); /* 占位符 / 说明文字 */ --ao-success-color-disabled: #92dab2;
--ao-text-disabled: rgba(0, 0, 0, 26%); /* 禁用文字 */
--ao-text-anti: #fff; /* 反色文字(深色背景上) */
--ao-text-brand: #0052d9; /* 品牌色文字 / 主操作色 */
--ao-text-link: #003cab; /* 链接文字 */
--ao-text-watermark: rgba(0, 0, 0, 10%); /* 水印 / 背景文字 */
--ao-stroke: #e8e8e8; // 分割线 --ao-text-color-base: rgba(0, 0, 0, 90%); /* 主要文字 */
--ao-border: #ddd; // 边框 --ao-text-color-secondary: rgba(0, 0, 0, 60%); /* 次要文字 / 辅助信息 */
--ao-text-color-assist: rgba(0, 0, 0, 50%); /* 输入框内部辅助元素(icon/count) */
--ao-text-color-placeholder: rgba(0, 0, 0, 40%); /* 占位符 / 说明文字 */
--ao-text-color-disabled: rgba(0, 0, 0, 26%); /* 禁用文字 */
--ao-text-color-anti: #fff; /* 反色文字(深色背景上) */
--ao-text-color-link: #003cab; /* 链接文字 */
--ao-text-color-watermark: rgba(0, 0, 0, 10%); /* 水印 / 背景文字 */
--ao-stroke-color: #e8e8e8; // 分割线
--ao-border-color: #ddd; // 边框
--ao-bg-color-control: #fff; // 特殊组件背景色,目前只用于 button、input 组件多主题场景,浅色主题下固定为白色,深色主题下为 transparent 适配背景颜色
// 滚动条颜色
--ao-scrollbar-color: rgba(0, 0, 0, 10%);
// 滚动条悬浮颜色( hover )
--ao-scrollbar-hover-color: rgba(0, 0, 0, 30%);
// 滚动条轨道颜色,不能是带透明度,否则纵向滚动时,横向滚动条会穿透
--ao-scroll-track-color: #fff;
// 容器颜色,使用的组件:popup
--ao-bg-color-container: #fff;
--ao-bg-color-container-hover: #f3f3f3;
--ao-bg-color-container-active: #e8e8e8;
// shadow阴影
// 基础/下层 投影 hover 使用的组件包括:表格 /
--ao-shadow-surface: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
--ao-shadow-popup:
0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
--ao-shadow-overlay:
0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
} }
@@ -1,7 +1,6 @@
<template> <template>
<!-- 状态按钮 (solid) --> <div style="display: flex; gap: 8px;">
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <AButton>
<AButton status="normal">
Normal Normal
</AButton> </AButton>
<AButton status="primary"> <AButton status="primary">
@@ -18,8 +17,8 @@
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="normal" type="outline"> <AButton type="outline">
Normal Normal
</AButton> </AButton>
<AButton status="primary" type="outline"> <AButton status="primary" type="outline">
@@ -36,8 +35,8 @@
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="normal" type="dashed"> <AButton type="dashed">
Normal Normal
</AButton> </AButton>
<AButton status="primary" type="dashed"> <AButton status="primary" type="dashed">
@@ -54,8 +53,8 @@
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="normal" type="text"> <AButton type="text">
Normal Normal
</AButton> </AButton>
<AButton status="primary" type="text"> <AButton status="primary" type="text">
@@ -72,8 +71,8 @@
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="normal" disabled> <AButton disabled>
禁用 禁用
</AButton> </AButton>
<AButton status="primary" disabled> <AButton status="primary" disabled>
@@ -90,8 +89,8 @@
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="normal" loading> <AButton loading>
loading loading
</AButton> </AButton>
<AButton status="primary" loading> <AButton status="primary" loading>
@@ -107,7 +106,7 @@
loading loading
</AButton> </AButton>
</div> </div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="primary" size="small"> <AButton status="primary" size="small">
small small
</AButton> </AButton>
@@ -17,6 +17,7 @@ $btn-prefix: #{$prefix}-btn;
transition: all 0.2s ease; transition: all 0.2s ease;
font-weight: 500; font-weight: 500;
border: 1px solid transparent; border: 1px solid transparent;
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
&-small { &-small {
height: 24px; height: 24px;
@@ -64,47 +65,47 @@ $btn-prefix: #{$prefix}-btn;
} }
&-solid { &-solid {
&.#{$btn-prefix}-status-normal { &.#{$btn-prefix}-status-default {
background: $bg-color-component; background: $default-color;
color: $text-color-primary; color: $text-color-base;
&:hover:enabled { &:hover:enabled {
background: $bg-color-component-hover; background: $default-color-hover;
} }
&:active:enabled { &:active:enabled {
background: $bg-color-component-active; background: $default-color-active;
} }
} }
&.#{$btn-prefix}-status-primary { &.#{$btn-prefix}-status-primary {
background: $primary; background: $primary-color;
color: $text-anti; color: $text-color-anti;
&:hover:enabled { &:hover:enabled {
background: $primary-hover; background: $primary-color-hover;
} }
&:active:enabled { &:active:enabled {
background: $primary-active; background: $primary-color-active;
} }
} }
&.#{$btn-prefix}-status-danger { &.#{$btn-prefix}-status-danger {
background: $danger; background: $danger-color;
color: $text-anti; color: $text-color-anti;
&:hover:enabled { &:hover:enabled {
background: $danger-hover; background: $danger-color-hover;
} }
&:active:enabled { &:active:enabled {
background: $danger-active; background: $danger-color-active;
} }
} }
&.#{$btn-prefix}-status-warning { &.#{$btn-prefix}-status-warning {
background: $danger; background: $warning-color;
color: $text-anti; color: $text-color-anti;
&:hover:enabled { &:hover:enabled {
background: $danger-hover; background: $warning-color-hover;
} }
&:active:enabled { &:active:enabled {
background: $danger-active; background: $warning-color-active;
} }
} }
&.#{$btn-prefix}-status-success { &.#{$btn-prefix}-status-success {
@@ -118,4 +119,208 @@ $btn-prefix: #{$prefix}-btn;
} }
} }
} }
&-outline {
&.#{$btn-prefix}-status-default {
background: $bg-color-control;
color: $text-color-base;
border-color: $border-color;
&:hover:enabled {
color: $primary-color-hover;
border-color: $primary-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-primary {
background: $bg-color-control;
color: $primary-color;
border-color: $primary-color;
&:hover:enabled {
color: $primary-color-hover;
border-color: $primary-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-danger {
background: $bg-color-control;
color: $danger-color;
border-color: $danger-color;
&:hover:enabled {
color: $danger-color-hover;
border-color: $danger-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-warning {
background: $bg-color-control;
color: $warning-color;
border-color: $warning-color;
&:hover:enabled {
color: $warning-color-hover;
border-color: $warning-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-success {
background: $bg-color-control;
color: $success-color;
border-color: $success-color;
&:hover:enabled {
color: $success-color-hover;
border-color: $success-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
}
&-dashed {
&.#{$btn-prefix}-status-default {
background: $bg-color-control;
color: $text-color-base;
border-color: $border-color;
border-style: dashed;
&:hover:enabled {
color: $primary-color-hover;
border-color: $primary-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-primary {
background: $bg-color-control;
color: $primary-color;
border-color: $primary-color;
border-style: dashed;
&:hover:enabled {
color: $primary-color-hover;
border-color: $primary-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-danger {
background: $bg-color-control;
color: $danger-color;
border-color: $danger-color;
border-style: dashed;
&:hover:enabled {
color: $danger-color-hover;
border-color: $danger-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-warning {
background: $bg-color-control;
color: $warning-color;
border-color: $warning-color;
border-style: dashed;
&:hover:enabled {
color: $warning-color-hover;
border-color: $warning-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
&.#{$btn-prefix}-status-success {
background: $bg-color-control;
color: $success-color;
border-color: $success-color;
border-style: dashed;
&:hover:enabled {
color: $success-color-hover;
border-color: $success-color-hover;
}
&:active:enabled {
background: $default-color-hover;
}
}
}
&-text {
&.#{$btn-prefix}-status-default {
color: $text-color-base;
background-color: transparent;
border-color: transparent;
&:hover:enabled {
color: $text-color-base;
background-color: $default-color-hover;
}
&:active:enabled {
background-color: $default-color-active;
}
}
&.#{$btn-prefix}-status-primary {
color: $primary-color;
background-color: transparent;
border-color: transparent;
&:hover:enabled {
color: $primary-color-hover;
background-color: $default-color-hover;
}
&:active:enabled {
background-color: $default-color-active;
}
}
&.#{$btn-prefix}-status-danger {
color: $danger-color;
background-color: transparent;
border-color: transparent;
&:hover:enabled {
color: $danger-color-hover;
background-color: $default-color-hover;
}
&:active:enabled {
background-color: $default-color-active;
}
}
&.#{$btn-prefix}-status-warning {
color: $warning-color;
background-color: transparent;
border-color: transparent;
&:hover:enabled {
color: $warning-color-hover;
background-color: $default-color-hover;
}
&:active:enabled {
background-color: $default-color-active;
}
}
&.#{$btn-prefix}-status-success {
color: $success-color;
background-color: transparent;
border-color: transparent;
&:hover:enabled {
color: $success-color-hover;
background-color: $default-color-hover;
}
&:active:enabled {
background-color: $default-color-active;
}
}
}
} }
@@ -11,8 +11,8 @@ export default defineComponent({
default: 'solid', default: 'solid',
}, },
status: { status: {
type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'normal', type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'default',
default: 'normal', default: 'default',
}, },
disabled: { type: Boolean, default: false }, disabled: { type: Boolean, default: false },
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
@@ -3,5 +3,6 @@ export { default as Button } from './button'
export { default as Group } from './group' export { default as Group } from './group'
export { default as Icon } from './icon' export { default as Icon } from './icon'
export { default as Input } from './input' export { default as Input } from './input'
export { default as Popup } from './popup'
export { default as Spin } from './spin' export { default as Spin } from './spin'
export { default as Textarea } from './textarea' export { default as Textarea } from './textarea'
@@ -0,0 +1,4 @@
@use 'sass:color';
@use '../_styles/_variables.scss' as *;
$btn-prefix: #{$prefix}-btn;
Whitespace-only changes.
@@ -3,36 +3,66 @@
$group-prefix: #{$prefix}-group; $group-prefix: #{$prefix}-group;
.#{$group-prefix}-size {
&-small {
height: $size-height-small;
font-size: $size-font-small;
}
&-medium {
height: $size-height-medium;
font-size: $size-font-medium;
}
&-large {
height: $size-height-large;
font-size: $size-font-large;
}
}
.#{$group-prefix}-wrapper { .#{$group-prefix}-wrapper {
display: flex; display: flex;
width: 100%; width: 100%;
border-radius: $border-radius; border-radius: $border-radius;
overflow: hidden; overflow: hidden;
position: relative;
.#{$group-prefix}-prepend,
.#{$group-prefix}-append {
background-color: $default-color;
color: $text-color-base;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid $border-color;
}
> * { > * {
flex: 1; flex: 1;
margin: 0; margin: 0;
border-radius: 0;
position: relative; position: relative;
border-radius: 0;
z-index: 0;
border: $border-outline-color; // 抵消左边 border,避免叠加
border-left: none; & + * {
box-shadow: none; margin-left: -1px;
&:hover {
border-left: $brand-color;
z-index: 1;
box-shadow: none;
} }
// hover / focus / active 高亮
&:hover,
&:focus-within, &:focus-within,
&:active { &:active {
border-left: $brand-color;
z-index: 1; z-index: 1;
box-shadow: none;
// 高亮边框
outline: 1px solid $primary-color;
outline-offset: -1px;
} }
} }
// 首尾圆角
> *:first-child { > *:first-child {
border-left: $border-outline-color;
border-top-left-radius: $border-radius; border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius; border-bottom-left-radius: $border-radius;
} }
@@ -1,16 +1,30 @@
import type { PropType } from 'vue'
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { getPrefixCls } from '../_utils/getPrefixCls' import { getPrefixCls } from '../_utils/getPrefixCls'
export default defineComponent({ export default defineComponent({
name: 'Group', name: 'Group',
props: {}, props: {
prepend: { type: String, default: '' },
append: { type: String, default: '' },
size: { type: String as () => 'small' | 'medium' | 'large', default: 'medium' },
},
setup(props, { slots }) { setup(props, { slots }) {
const prefixCls = getPrefixCls('group') const prefixCls = getPrefixCls('group')
const renderNode = (slotName: 'prepend' | 'append', propValue: string) => {
// slot 优先
if (slots[slotName])
return slots[slotName]!()
if (propValue)
return <div class={`${prefixCls}-${slotName}`}>{propValue}</div>
return null
}
return () => ( return () => (
<div class={[`${prefixCls}-wrapper`]}> <div class={[`${prefixCls}-wrapper`, `${prefixCls}-size-${props.size}`]}>
{renderNode('prepend', props.prepend)}
{slots.default?.()} {slots.default?.()}
{renderNode('append', props.append)}
</div> </div>
) )
}, },
@@ -5,7 +5,7 @@ import { getPrefixCls } from '../_utils/getPrefixCls'
import './index.scss' import './index.scss'
export default defineComponent({ export default defineComponent({
name: 'AIcon', name: 'Icon',
props: { props: {
icon: { type: String as PropType<string>, required: true }, icon: { type: String as PropType<string>, required: true },
size: { type: Number, default: 16 }, size: { type: Number, default: 16 },
@@ -4,10 +4,5 @@
@use './input/index.scss' as *; @use './input/index.scss' as *;
@use './textarea/index.scss' as *; @use './textarea/index.scss' as *;
@use './group/index.scss' as *; @use './group/index.scss' as *;
@use "./popup/tooltip.scss" as *;
input,
button,
select,
textarea {
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
@@ -5,18 +5,18 @@ $input-prefix: #{$prefix}-input;
.#{$input-prefix}-size { .#{$input-prefix}-size {
&-small { &-small {
height: 24px; height: $size-height-small;
font-size: 12px; font-size: $size-font-small;
} }
&-medium { &-medium {
height: 28px; height: $size-height-medium;
font-size: 13px; font-size: $size-font-medium;
} }
&-large { &-large {
height: 32px; height: $size-height-large;
font-size: 14px; font-size: $size-font-large;
} }
} }
@@ -24,21 +24,22 @@ $input-prefix: #{$prefix}-input;
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%; width: 100%;
border: 1px solid $border-outline-color; border: 1px solid $border-color;
border-radius: $border-radius; border-radius: $border-radius;
box-sizing: border-box; box-sizing: border-box;
padding: 0 8px; padding: 0 8px;
background: $bg-color-control;
transition: transition:
border cubic-bezier(0.38, 0, 0.24, 1) 0.2s, border cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
box-shadow cubic-bezier(0.38, 0, 0.24, 1) 0.2s, box-shadow cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
background-color cubic-bezier(0.38, 0, 0.24, 1) 0.2s; background-color cubic-bezier(0.38, 0, 0.24, 1) 0.2s;
.#{$input-prefix}-inner { .#{$input-prefix}-inner {
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
width: 100%; width: 100%;
border: none; border: none;
outline: none; outline: none;
background: transparent;
box-sizing: border-box; box-sizing: border-box;
padding: 0; padding: 0;
font-size: inherit; font-size: inherit;
@@ -46,19 +47,20 @@ $input-prefix: #{$prefix}-input;
display: flex; display: flex;
align-items: center; align-items: center;
height: 100%; height: 100%;
color: $text-color-base;
background-color: transparent;
&::placeholder { &::placeholder {
color: $text-color-placeholder; color: $text-color-placeholder;
} }
} }
&:hover { &:hover {
border-color: $brand-color; border-color: $primary-color;
} }
&:focus-within { &:focus-within {
border-color: $brand-color; border-color: $primary-color;
box-shadow: 0 0 0 2px $brand-color-focus; box-shadow: 0 0 0 2px $primary-color-focus;
} }
.#{$input-prefix}-align { .#{$input-prefix}-align {
@@ -90,7 +92,7 @@ $input-prefix: #{$prefix}-input;
} }
&.#{$input-prefix}-disabled { &.#{$input-prefix}-disabled {
background-color: $bg-color-component-disabled; background-color: $default-color-disabled;
cursor: not-allowed; cursor: not-allowed;
.#{$input-prefix}-input { .#{$input-prefix}-input {
@@ -106,13 +108,13 @@ $input-prefix: #{$prefix}-input;
&:hover, &:hover,
&:focus-within { &:focus-within {
border: $border-outline-color; border: $border-color;
box-shadow: none; box-shadow: none;
} }
} }
&.#{$input-prefix}-readonly { &.#{$input-prefix}-readonly {
background-color: $bg-color-component-readonly; // background-color: $bg-color-component-readonly;
} }
.#{$input-prefix}-icon { .#{$input-prefix}-icon {
@@ -120,7 +122,7 @@ $input-prefix: #{$prefix}-input;
transition: transition:
color 0.2s, color 0.2s,
background-color 0.2s; background-color 0.2s;
color: $text-color-secondary; color: $text-color-assist;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -130,7 +132,7 @@ $input-prefix: #{$prefix}-input;
border-radius: 50%; border-radius: 50%;
&:hover { &:hover {
background-color: $bg-color-component-hover; background-color: $default-color-hover;
} }
} }
@@ -138,6 +140,6 @@ $input-prefix: #{$prefix}-input;
flex-shrink: 0; flex-shrink: 0;
margin-left: 4px; margin-left: 4px;
white-space: nowrap; white-space: nowrap;
color: $text-color-secondary; color: $text-color-assist;
} }
} }
@@ -25,7 +25,7 @@ export default defineComponent({
maxlength: Number, maxlength: Number,
password: Boolean, password: Boolean,
}, },
emits: ['update:modelValue'], emits: ['update:modelValue', 'focus', 'blur'],
setup(props, { slots, emit }) { setup(props, { slots, emit }) {
const prefixCls = getPrefixCls('input') const prefixCls = getPrefixCls('input')
const inputValue = ref(props.modelValue || '') const inputValue = ref(props.modelValue || '')
@@ -85,6 +85,8 @@ export default defineComponent({
disabled={props.disabled} disabled={props.disabled}
readonly={props.readonly} readonly={props.readonly}
onInput={(e: Event) => updateValue((e.target as HTMLInputElement).value)} onInput={(e: Event) => updateValue((e.target as HTMLInputElement).value)}
onFocus={e => emit('focus', e)}
onBlur={e => emit('blur', e)}
/> />
{props.clearable && inputValue.value && !props.disabled && !props.readonly && ( {props.clearable && inputValue.value && !props.disabled && !props.readonly && (
@@ -0,0 +1,140 @@
import type { PropType } from 'vue'
import { cloneVNode, defineComponent, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
interface Position {
top: number
left: number
}
export default defineComponent({
name: 'Tooltip',
props: {
content: { type: String, required: true },
placement: { type: String as PropType<'top' | 'bottom' | 'left' | 'right'>, default: 'top' },
trigger: { type: String as PropType<'hover' | 'click'>, default: 'hover' },
offset: { type: Number, default: 6 },
},
setup(props, { slots }) {
const visible = ref(false)
const targetEl = ref<HTMLElement | null>(null)
const tooltipEl = ref<HTMLDivElement | null>(null)
const createTooltip = () => {
const el = document.createElement('div')
el.className = `tooltip tooltip-${props.placement}` // 初始隐藏,不加 visible
el.innerHTML = `${props.content}<div class="tooltip-arrow"></div>`
document.body.appendChild(el)
tooltipEl.value = el
}
const updatePosition = () => {
const target = targetEl.value
const tooltip = tooltipEl.value
if (!target || !tooltip)
return
let dom: HTMLElement | null = null
if (target instanceof HTMLElement)
dom = target
else if ((target as any)?.$el instanceof HTMLElement)
dom = (target as any).$el
if (!dom)
return
const rect = dom.getBoundingClientRect()
const tooltipRect = tooltip.getBoundingClientRect()
const scrollX = window.scrollX || window.pageXOffset
const scrollY = window.scrollY || window.pageYOffset
let top = 0
let left = 0
const offset = props.offset
switch (props.placement) {
case 'top':
top = rect.top + scrollY - tooltipRect.height - offset
left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2
break
case 'bottom':
top = rect.bottom + scrollY + offset
left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2
break
case 'left':
top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2
left = rect.left + scrollX - tooltipRect.width - offset
break
case 'right':
top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2
left = rect.right + scrollX + offset
break
}
tooltip.style.top = `${top}px`
tooltip.style.left = `${left}px`
}
const show = () => {
const tooltip = tooltipEl.value
if (!tooltip || !targetEl.value)
return
visible.value = true
nextTick(() => {
updatePosition()
tooltip.classList.add('visible') // CSS 控制动画
})
}
const hide = () => {
const tooltip = tooltipEl.value
if (!tooltip)
return
visible.value = false
tooltip.classList.remove('visible')
}
const toggle = () => {
visible.value ? hide() : show()
}
onMounted(() => {
createTooltip()
window.addEventListener('scroll', () => {
if (visible.value)
updatePosition()
})
window.addEventListener('resize', () => {
if (visible.value)
updatePosition()
})
})
onBeforeUnmount(() => {
window.removeEventListener('scroll', () => {
if (visible.value)
updatePosition()
})
window.removeEventListener('resize', () => {
if (visible.value)
updatePosition()
})
if (tooltipEl.value && tooltipEl.value.parentNode) {
tooltipEl.value.parentNode.removeChild(tooltipEl.value)
}
})
return () => {
const child = slots.default?.()[0]
if (!child)
return null
return cloneVNode(child, {
ref: targetEl,
onMouseenter: props.trigger === 'hover' ? show : undefined,
onMouseleave: props.trigger === 'hover' ? hide : undefined,
onClick: props.trigger === 'click' ? toggle : undefined,
})
}
},
})
@@ -0,0 +1,56 @@
@use '../_styles/_variables.scss' as *;
.tooltip {
position: absolute;
z-index: 9999;
padding: 6px 10px;
background: #fff;
border-radius: 4px;
color: #333;
font-size: 12px;
white-space: nowrap;
pointer-events: none;
/* ---------------- 动画 ---------------- */
opacity: 0;
transition: opacity 0.2s ease-in-out;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
&.visible {
opacity: 1;
pointer-events: auto;
}
.tooltip-arrow {
position: absolute;
width: 8px;
height: 8px;
background: #fff;
transform: rotate(45deg);
z-index: 0;
}
&.tooltip-top .tooltip-arrow {
bottom: -4px;
left: 50%;
transform: translateX(-50%) rotate(45deg);
}
&.tooltip-bottom .tooltip-arrow {
top: -4px;
left: 50%;
transform: translateX(-50%) rotate(45deg);
}
&.tooltip-left .tooltip-arrow {
right: -4px;
top: 50%;
transform: translateY(-50%) rotate(45deg);
}
&.tooltip-right .tooltip-arrow {
left: -4px;
top: 50%;
transform: translateY(-50%) rotate(45deg);
}
}
@@ -20,13 +20,13 @@ $spin-prefix: #{$prefix}-spin;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: $brand-color; color: $text-color-base;
} }
&-tip { &-tip {
margin-top: 4px; margin-top: 4px;
font-size: 12px; font-size: 12px;
color: #000; color: $text-color-base;
} }
&.rounded { &.rounded {
@@ -12,6 +12,8 @@ $textarea-prefix: #{$prefix}-textarea;
width: 100%; width: 100%;
.#{$textarea-prefix}-inner { .#{$textarea-prefix}-inner {
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100%;
width: 100%; width: 100%;
display: flex; display: flex;
padding: 5px 8px; padding: 5px 8px;
@@ -23,20 +25,21 @@ $textarea-prefix: #{$prefix}-textarea;
transition: transition:
all cubic-bezier(0.38, 0, 0.24, 1) 0.2s, all cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
height 0s; height 0s;
border: 1px solid $border-outline-color; border: 1px solid $border-color;
border-radius: $border-radius; border-radius: $border-radius;
background-color: $bg-color-control;
color: $text-color-base;
&::placeholder { &::placeholder {
color: $text-color-placeholder; color: $text-color-placeholder;
} }
&:hover { &:hover {
border-color: $brand-color; border-color: $primary-color;
} }
&:focus-within { &:focus-within {
border-color: $brand-color; border-color: $primary-color;
box-shadow: 0 0 0 2px $brand-color-focus; box-shadow: 0 0 0 2px $primary-color-focus;
} }
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -44,33 +47,33 @@ $textarea-prefix: #{$prefix}-textarea;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background: transparent; background: $scroll-track-color;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: #e5e5e5; background-color: $scrollbar-color;
border-radius: 0px; border-radius: 0px;
} }
&::-webkit-scrollbar-thumb:hover { &::-webkit-scrollbar-thumb:hover {
background-color: #b2b2b2; background-color: $scrollbar-hover-color;
} }
} }
.#{$textarea-prefix}-disabled { .#{$textarea-prefix}-disabled {
background-color: $bg-color-component-disabled; background-color: $default-color-disabled;
cursor: not-allowed; cursor: not-allowed;
color: $text-color-disabled; color: $text-color-disabled;
&:hover, &:hover,
&:focus-within { &:focus-within {
border: $border-outline-color; border: $border-color;
box-shadow: none; box-shadow: none;
} }
} }
.#{$textarea-prefix}-readonly { .#{$textarea-prefix}-readonly {
background-color: $bg-color-component-readonly; // background-color: $bg-color-component-readonly;
} }
.#{$textarea-prefix}-clear { .#{$textarea-prefix}-clear {
@@ -88,13 +91,13 @@ $textarea-prefix: #{$prefix}-textarea;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: $text-color-secondary; color: $text-color-assist;
transition: transition:
color 0.2s, color 0.2s,
background-color 0.2s; background-color 0.2s;
&:hover { &:hover {
background-color: $bg-color-component-hover; background-color: $default-color-hover;
} }
} }
@@ -103,6 +106,6 @@ $textarea-prefix: #{$prefix}-textarea;
right: 8px; right: 8px;
bottom: 0px; bottom: 0px;
font-size: 12px; font-size: 12px;
color: $text-color-secondary; color: $text-color-assist;
} }
} }
+8 -124
View File
@@ -1,15 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
function setDark() { function setDark() {
document.documentElement.setAttribute('theme-mode', 'dark') document.documentElement.setAttribute('theme-mode', 'dark')
document.body.style.backgroundColor = '#242424'
} }
function setLight() { function setLight() {
document.documentElement.setAttribute('theme-mode', 'light') document.documentElement.setAttribute('theme-mode', 'light')
document.body.style.backgroundColor = '#ffffff'
} }
</script> </script>
<template> <template>
<div style="height: 100vh;width: 100%;display: flex;align-items: center;flex-direction: column;justify-content: center;"> <div style="height: 100vh;width: 100%;display: flex;align-items: center;flex-direction: column;justify-content: center;gap:16px">
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <div style="display: flex; gap: 8px;">
<AButton status="primary" size="medium" @click="setDark"> <AButton status="primary" size="medium" @click="setDark">
黑色主题 黑色主题
</AButton> </AButton>
@@ -18,127 +21,8 @@ function setLight() {
白色主题 白色主题
</AButton> </AButton>
</div> </div>
<APopup content="2222222222222222222222" trigger="click">
<div style="display: flex; gap: 8px; margin-bottom: 16px;"> <AButton>测试</AButton>
<AButton status="normal"> </APopup>
Normal
</AButton>
<AButton status="primary">
主按钮
</AButton>
<AButton status="warning">
警告
</AButton>
<AButton status="danger">
危险
</AButton>
<AButton status="success">
成功
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="normal" type="outline">
Normal
</AButton>
<AButton status="primary" type="outline">
主按钮
</AButton>
<AButton status="warning" type="outline">
警告
</AButton>
<AButton status="danger" type="outline">
危险
</AButton>
<AButton status="success" type="outline">
成功
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="normal" type="dashed">
Normal
</AButton>
<AButton status="primary" type="dashed">
主按钮
</AButton>
<AButton status="warning" type="dashed">
警告
</AButton>
<AButton status="danger" type="dashed">
危险
</AButton>
<AButton status="success" type="dashed">
成功
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="normal" type="text">
Normal
</AButton>
<AButton status="primary" type="text">
主按钮
</AButton>
<AButton status="warning" type="text">
警告
</AButton>
<AButton status="danger" type="text">
危险
</AButton>
<AButton status="success" type="text">
成功
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="normal" disabled>
禁用
</AButton>
<AButton status="primary" disabled>
禁用
</AButton>
<AButton type="outline" disabled>
禁用
</AButton>
<AButton type="dashed" disabled>
禁用
</AButton>
<AButton type="text" disabled>
禁用
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="normal" loading>
loading
</AButton>
<AButton status="primary" loading>
loading
</AButton>
<AButton type="outline" loading>
loading
</AButton>
<AButton type="dashed" loading>
loading
</AButton>
<AButton type="text" loading>
loading
</AButton>
</div>
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
<AButton status="primary" size="small">
small
</AButton>
<AButton status="primary" size="medium">
medium
</AButton>
<AButton status="primary" size="large">
large
</AButton>
</div>
<AInput style="width: 200px;" clearable show-count />
<ATextarea style="width: 200px;" clearable show-count />
</div> </div>
</template> </template>
+2
View File
@@ -9,6 +9,7 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
A: typeof import('@ao/ao-design')['default'] A: typeof import('@ao/ao-design')['default']
AB: typeof import('@ao/ao-design')['B']
AButton: typeof import('@ao/ao-design')['Button'] AButton: typeof import('@ao/ao-design')['Button']
AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider'] AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider']
AGroup: typeof import('@ao/ao-design')['Group'] AGroup: typeof import('@ao/ao-design')['Group']
@@ -16,6 +17,7 @@ declare module 'vue' {
AInput: typeof import('@ao/ao-design')['Input'] AInput: typeof import('@ao/ao-design')['Input']
ALoading: typeof import('@ao/ao-design')['Loading'] ALoading: typeof import('@ao/ao-design')['Loading']
ALoding: typeof import('@ao/ao-design')['Loding'] ALoding: typeof import('@ao/ao-design')['Loding']
APopup: typeof import('@ao/ao-design')['Popup']
ASpin: typeof import('@ao/ao-design')['Spin'] ASpin: typeof import('@ao/ao-design')['Spin']
AT: typeof import('@ao/ao-design')['T'] AT: typeof import('@ao/ao-design')['T']
ATex: typeof import('@ao/ao-design')['Tex'] ATex: typeof import('@ao/ao-design')['Tex']
@@ -99,6 +99,8 @@ public class EmailServiceImpl implements EmailService {
Long folderId = emailSummaryPageDTO.getFolderId(); Long folderId = emailSummaryPageDTO.getFolderId();
EmailFolder emailFolder = emailFolderMapper.selectById(folderId); EmailFolder emailFolder = emailFolderMapper.selectById(folderId);
String category = emailFolder.getCategory(); String category = emailFolder.getCategory();
boolean showRecipient = EmailFolderTypeEnum.DRAFT.name().equals(category) boolean showRecipient = EmailFolderTypeEnum.DRAFT.name().equals(category)
|| EmailFolderTypeEnum.SENT.name().equals(category); || EmailFolderTypeEnum.SENT.name().equals(category);
@@ -0,0 +1,12 @@
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
export function getBuildTime() {
dayjs.extend(utc)
dayjs.extend(timezone)
const buildTime = dayjs.tz(Date.now(), 'Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss')
return buildTime
}
@@ -0,0 +1 @@
export * from './time'
@@ -0,0 +1,34 @@
import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'
import { ArcoResolver } from 'unplugin-vue-components/resolvers'
import type { PluginOption } from 'vite'
export function setupAutoImport(viteEnv: Env.ImportMeta) {
// 从环境变量中提取图标相关的前缀
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv
// 从本地图标前缀中提取图标集合名称
const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, '')
const plugins: PluginOption[] = [
Components({
// 自动导入的组件类型声明文件
dts: 'src/types/auto-import.d.ts',
types: [
{
from: 'vue-router',
names: ['RouterLink', 'RouterView'],
},
],
// 配置图标解析器
resolvers: [
IconsResolver({
customCollections: [collectionName], // 本地图标集合
componentPrefix: VITE_ICON_PREFIX, // 图标组件的前缀
}),
ArcoResolver(),
],
}),
]
return plugins
}
@@ -0,0 +1,13 @@
import type { Plugin } from 'vite'
export function setupHtmlPlugin(buildTime: string) {
const plugin: Plugin = {
name: 'html-plugin',
apply: 'build',
transformIndexHtml(html) {
return html.replace('<head>', `<head>\n <meta name="buildTime" content="${buildTime}">`)
},
}
return plugin
}
@@ -0,0 +1,22 @@
import type { PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueDevtools from 'vite-plugin-vue-devtools'
import progress from 'vite-plugin-progress'
import { setupUnocss } from './unocss'
import { setupHtmlPlugin } from './html'
import { setupUnPluginIcon } from './unplugin-icon'
import { setupAutoImport } from './auto-import'
export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
const plugins: PluginOption = [
vue(),
VueDevtools(),
progress(),
setupUnocss(viteEnv),
setupHtmlPlugin(buildTime),
setupAutoImport(viteEnv),
...setupUnPluginIcon(viteEnv),
]
return plugins
}
@@ -0,0 +1,32 @@
import process from 'node:process'
import path from 'node:path'
import unocss from '@unocss/vite'
import presetIcons from '@unocss/preset-icons'
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'
export function setupUnocss(viteEnv: Env.ImportMeta) {
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv
const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon')
/** The name of the local icon collection */
const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, '')
return unocss({
presets: [
presetIcons({
prefix: `${VITE_ICON_PREFIX}-`,
scale: 1,
extraProperties: {
display: 'inline-block',
},
collections: {
[collectionName]: FileSystemIconLoader(localIconPath, (svg) =>
svg.replace(/^<svg\s/, '<svg width="1em" height="1em" '),
),
},
warn: true,
}),
],
})
}
@@ -0,0 +1,34 @@
import path from 'node:path'
import process from 'node:process'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import type { PluginOption } from 'vite'
import Icons from 'unplugin-icons/vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export function setupUnPluginIcon(viteEnv: Env.ImportMeta) {
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv
const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon')
/** The name of the local icon collection */
const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, '')
const plugins: PluginOption[] = [
createSvgIconsPlugin({
iconDirs: [localIconPath],
symbolId: `${VITE_ICON_LOCAL_PREFIX}-[dir]-[name]`,
inject: 'body-last',
customDomId: '__SVG_ICON_LOCAL__',
}),
Icons({
compiler: 'vue3',
customCollections: {
[collectionName]: FileSystemIconLoader(localIconPath, (svg) =>
svg.replace(/^<svg\s/, '<svg width="1em" height="1em" '),
),
},
scale: 1,
defaultClass: 'inline-block',
}),
]
return plugins
}