From 3473009b28c0f5d85a52800effa5453c2d7978b8 Mon Sep 17 00:00:00 2001 From: tobegold574 <2386340403@qq.com> Date: Sun, 16 Nov 2025 16:32:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(scss,=20types):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E6=89=93=E5=8C=85=E4=BA=A7=E7=89=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新SCSS导出方式,支持引用SCSS变量系统(编译为CSS) - 修复SCSS类名不对应问题 - 修复无types导出问题 - 修改导出路径,避免vite build覆盖其余编译产物 - 支持tree-shaking,不暴露内部路径 BREAKING CHANGES: 1.0.0->2.0.0 --- .gitignore | 1 + README.md | 9 + package.json | 16 +- src/components/Avatar/index.scss | 4 +- src/components/Avatar/index.vue | 4 + src/components/Button/index.scss | 1 + src/components/Button/index.vue | 2 +- src/components/ChatBubble/index.scss | 525 ++-- src/components/ChatBubble/index.vue | 4 + src/components/Container/index.scss | 7 +- src/components/Container/index.vue | 4 + src/components/Divider/index.scss | 1 + src/components/Divider/index.vue | 4 + src/components/Empty/index.scss | 17 +- src/components/Empty/index.vue | 4 + src/components/Grid/index.scss | 1 + src/components/Grid/index.vue | 4 + src/components/Icon/index.scss | 3501 +----------------------- src/components/Icon/index.vue | 20 +- src/components/Image/index.scss | 10 +- src/components/Image/index.test.ts | 273 -- src/components/Image/index.vue | 4 + src/components/Loading/index.scss | 5 +- src/components/Loading/index.test.ts | 245 -- src/components/Loading/index.vue | 4 + src/components/Message/index.scss | 25 +- src/components/Message/index.vue | 4 + src/components/Notification/index.scss | 27 +- src/components/Notification/index.vue | 4 + src/components/Result/index.scss | 19 +- src/components/Result/index.vue | 4 + src/components/Space/index.scss | 1 + src/components/Space/index.vue | 4 + src/components/Tag/index.scss | 47 +- src/components/Tag/index.vue | 4 + src/components/Text/index.scss | 39 +- src/components/Text/index.vue | 4 + src/components/index.ts | 74 +- src/index.ts | 32 +- src/styles/index.scss | 4 + tsconfig.json | 5 +- vite.config.ts | 13 +- 42 files changed, 520 insertions(+), 4460 deletions(-) delete mode 100644 src/components/Image/index.test.ts delete mode 100644 src/components/Loading/index.test.ts diff --git a/.gitignore b/.gitignore index c5451e2..786d689 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules # 测试与打包 coverage/ +dist/ # 编辑器 .vscode/* diff --git a/README.md b/README.md index 4f65596..9642cea 100644 --- a/README.md +++ b/README.md @@ -85,3 +85,12 @@ knowai-ui/ ### 2025-11-14 - 完成tsc eslint测试,因框架内部通信问题放弃Vitest测试(但保留测试文件),推送1.0.0镜像。 +### 2025-11-16 +- 更新SCSS导出,支持引用对应css类 +- 修复SCSS类名不对应问题 +- 修复SCSS类名无法导出问题 +- 修复1.0.0未导出types的问题(没有用vue-tsc编译.d.ts文件) +- 修复打包产物被覆盖问题 +- 支持tree-shaking,不暴露内部路径 + + diff --git a/package.json b/package.json index 861bdd3..82befc3 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,22 @@ "name": "knowai-ui", "version": "1.0.0", "description": "KnowAI UI组件库", - "main": "index.ts", + "main": "dist/client/knowai-ui.umd.js", + "module": "dist/client/knowai-ui.es.js", + "types": "dist/types/index.d.ts", + "style": "dist/index.css", "type": "module", + "exports": { + ".": { + "import": "./dist/client/knowai-ui.es.js", + "require": "./dist/client/knowai-ui.umd.js" + }, + "./style.css": "./dist/index.css" + }, "scripts": { - "build": "vite build", + "build:types": "vue-tsc --emitDeclarationOnly", + "build:css": "sass src/styles/index.scss dist/index.css", + "build": "pnpm build:types && pnpm build:css && vite build", "dev": "vite", "preview": "vite preview", "test": "vitest", diff --git a/src/components/Avatar/index.scss b/src/components/Avatar/index.scss index 5748558..45d09e3 100644 --- a/src/components/Avatar/index.scss +++ b/src/components/Avatar/index.scss @@ -1,5 +1,5 @@ // Avatar组件样式 - +@use "@/styles/index.scss" as *; .k-avatar { position: relative; @@ -35,7 +35,7 @@ } &--square { - border-radius: $border-radius-base; + border-radius: $rounded-md; } &__img { diff --git a/src/components/Avatar/index.vue b/src/components/Avatar/index.vue index d487d0d..0c6c045 100644 --- a/src/components/Avatar/index.vue +++ b/src/components/Avatar/index.vue @@ -115,3 +115,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Button/index.scss b/src/components/Button/index.scss index 48e9d8b..4e46328 100644 --- a/src/components/Button/index.scss +++ b/src/components/Button/index.scss @@ -1,4 +1,5 @@ // Button组件样式 +@use "@/styles/index.scss" as *; .k-button { display: inline-flex; align-items: center; diff --git a/src/components/Button/index.vue b/src/components/Button/index.vue index 32b4a1d..8f8d788 100644 --- a/src/components/Button/index.vue +++ b/src/components/Button/index.vue @@ -110,5 +110,5 @@ export default defineComponent({ diff --git a/src/components/ChatBubble/index.scss b/src/components/ChatBubble/index.scss index 3da116f..9eec21c 100644 --- a/src/components/ChatBubble/index.scss +++ b/src/components/ChatBubble/index.scss @@ -1,10 +1,9 @@ // ChatBubble组件样式 - -@import '../../styles/mixins.scss'; +@use "@/styles/index.scss" as *; .k-chat-bubble { display: flex; - margin-bottom: $spacing-md; + margin-bottom: $spacing-4; max-width: 80%; // 自己的消息 @@ -22,302 +21,302 @@ margin-left: 0; margin-right: auto; } -} -// 头像 -.k-chat-bubble__avatar { - flex-shrink: 0; - margin: 0 $spacing-sm; -} - -// 消息内容 -.k-chat-bubble__content { - display: flex; - flex-direction: column; - min-width: 0; - flex: 1; -} - -// 发送者名称 -.k-chat-bubble__sender { - font-size: $font-size-xs; - color: $text-color-tertiary; - margin-bottom: $spacing-xs; - padding-left: $spacing-xs; -} - -// 消息气泡 -.k-chat-bubble__bubble { - position: relative; - padding: $spacing-sm $spacing-md; - border-radius: $border-radius-lg; - word-wrap: break-word; - max-width: 100%; - - // 自己的消息气泡 - &--own { - background-color: $primary-color; - color: #fff; - border-top-right-radius: $border-radius-sm; - - &::after { - content: ''; - position: absolute; - top: 10px; - right: -6px; - width: 0; - height: 0; - border-style: solid; - border-width: 6px 0 6px 6px; - border-color: transparent transparent transparent $primary-color; - } + // 头像 + &__avatar { + flex-shrink: 0; + margin: 0 $spacing-3; } - // 其他人的消息气泡 - &--other { - background-color: $background-color-light; - color: $text-color; - border-top-left-radius: $border-radius-sm; + // 消息内容 + &__content { + display: flex; + flex-direction: column; + min-width: 0; + flex: 1; + } - &::after { - content: ''; - position: absolute; - top: 10px; - left: -6px; - width: 0; - height: 0; - border-style: solid; - border-width: 6px 6px 6px 0; - border-color: transparent $background-color-light transparent transparent; + // 发送者名称 + &__sender { + font-size: $text-xs; + color: $gray-400; + margin-bottom: $spacing-2; + padding-left: $spacing-2; + } + + // 消息气泡 + &__bubble { + position: relative; + padding: $spacing-3 $spacing-4; + border-radius: $rounded-lg; + word-wrap: break-word; + max-width: 100%; + + // 自己的消息气泡 + &--own { + background-color: $primary-color; + color: $white; + border-top-right-radius: $rounded-sm; + + &::after { + content: ''; + position: absolute; + top: 10px; + right: -6px; + width: 0; + height: 0; + border-style: solid; + border-width: 6px 0 6px 6px; + border-color: transparent transparent transparent $primary-color; + } + } + + // 其他人的消息气泡 + &--other { + background-color: $white; + color: $gray-700; + border-top-left-radius: $rounded-sm; + + &::after { + content: ''; + position: absolute; + top: 10px; + left: -6px; + width: 0; + height: 0; + border-style: solid; + border-width: 6px 6px 6px 0; + border-color: transparent $white transparent transparent; + } + } + + // 文本消息 + &--type-text { + line-height: 1.5; + } + + // 图片消息 + &--type-image { + padding: 0; + background-color: transparent; + border-radius: $rounded-md; + overflow: hidden; + + .k-chat-bubble__bubble--own::after, + .k-chat-bubble__bubble--other::after { + display: none; + } + } + + // 文件消息 + &--type-file { + padding: $spacing-3; + } + + // 语音消息 + &--type-voice { + padding: $spacing-3; + } + + // 系统消息 + &--type-system { + background-color: $gray-100; + color: $gray-500; + text-align: center; + font-size: $text-sm; + padding: $spacing-2 $spacing-3; + margin: 0 auto; + max-width: 60%; + + &::after { + display: none; + } } } // 文本消息 - &--type-text { - line-height: 1.5; + &__text { + white-space: pre-wrap; } // 图片消息 - &--type-image { - padding: 0; - background-color: transparent; - border-radius: $border-radius-base; - overflow: hidden; + &__image { + img { + max-width: 200px; + max-height: 200px; + border-radius: $rounded-md; + cursor: pointer; + transition: transform 0.2s; - .k-chat-bubble__bubble--own::after, - .k-chat-bubble__bubble--other::after { - display: none; + &:hover { + transform: scale(1.02); + } } } // 文件消息 - &--type-file { - padding: $spacing-sm; + &__file { + display: flex; + align-items: center; + gap: $spacing-3; + min-width: 200px; + + &-icon { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + background-color: $gray-100; + border-radius: $rounded-md; + color: $gray-500; + font-size: 20px; + } + + &-info { + flex: 1; + min-width: 0; + } + + &-name { + font-weight: 500; + @extend .k-ui-text-ellipsis; + } + + &-size { + font-size: $text-xs; + color: $gray-400; + } } // 语音消息 - &--type-voice { - padding: $spacing-sm; + &__voice { + display: flex; + align-items: center; + gap: $spacing-3; + min-width: 120px; + + &-btn--playing { + color: $primary-color; + } + + &-duration { + font-size: $text-xs; + color: $gray-500; + white-space: nowrap; + } + + &-waveform { + display: flex; + align-items: center; + height: 20px; + gap: 2px; + flex: 1; + } + + &-bar { + width: 3px; + background-color: currentColor; + border-radius: 3px; + opacity: 0.6; + transition: opacity 0.2s; + + &:hover { + opacity: 1; + } + } } // 系统消息 - &--type-system { - background-color: $background-color-base; - color: $text-color-secondary; + &__system { + padding: $spacing-2 $spacing-3; + font-size: $text-sm; + color: $gray-500; + background-color: $gray-100; + border-radius: $rounded-md; text-align: center; - font-size: $font-size-sm; - padding: $spacing-xs $spacing-sm; margin: 0 auto; max-width: 60%; - - &::after { - display: none; - } } -} -// 文本消息 -.k-chat-bubble__text { - white-space: pre-wrap; -} + // 消息状态和时间 + &__meta { + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: $spacing-2; + padding: 0 $spacing-2; + font-size: $text-xs; + color: $gray-400; + gap: $spacing-2; -// 图片消息 -.k-chat-bubble__image { - img { - max-width: 200px; - max-height: 200px; - border-radius: $border-radius-base; - cursor: pointer; - transition: transform 0.2s; - - &:hover { - transform: scale(1.02); - } - } -} - -// 文件消息 -.k-chat-bubble__file { - display: flex; - align-items: center; - gap: $spacing-sm; - min-width: 200px; -} - -.k-chat-bubble__file-icon { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - background-color: $background-color-base; - border-radius: $border-radius-base; - color: $text-color-secondary; - font-size: 20px; -} - -.k-chat-bubble__file-info { - flex: 1; - min-width: 0; -} - -.k-chat-bubble__file-name { - font-weight: 500; - @include text-ellipsis; -} - -.k-chat-bubble__file-size { - font-size: $font-size-xs; - color: $text-color-tertiary; -} - -// 语音消息 -.k-chat-bubble__voice { - display: flex; - align-items: center; - gap: $spacing-sm; - min-width: 120px; -} - -.k-chat-bubble__voice-btn--playing { - color: $primary-color; -} - -.k-chat-bubble__voice-duration { - font-size: $font-size-xs; - color: $text-color-secondary; - white-space: nowrap; -} - -.k-chat-bubble__voice-waveform { - display: flex; - align-items: center; - height: 20px; - gap: 2px; - flex: 1; -} - -.k-chat-bubble__voice-bar { - width: 3px; - background-color: currentColor; - border-radius: 3px; - opacity: 0.6; - transition: opacity 0.2s; - - &:hover { - opacity: 1; - } -} - -// 系统消息 -.k-chat-bubble__system { - padding: $spacing-xs $spacing-sm; - font-size: $font-size-sm; - color: $text-color-secondary; - background-color: $background-color-base; - border-radius: $border-radius-base; - text-align: center; - margin: 0 auto; - max-width: 60%; -} - -// 消息状态和时间 -.k-chat-bubble__meta { - display: flex; - align-items: center; - justify-content: flex-end; - margin-top: $spacing-xs; - padding: 0 $spacing-xs; - font-size: $font-size-xs; - color: $text-color-tertiary; - gap: $spacing-xs; - - .k-chat-bubble--other & { - justify-content: flex-start; - } -} - -.k-chat-bubble__time { - white-space: nowrap; -} - -.k-chat-bubble__status-icon--sending { - color: $text-color-tertiary; - animation: spin 1s linear infinite; -} - -.k-chat-bubble__status-icon--sent { - color: $text-color-tertiary; -} - -.k-chat-bubble__status-icon--delivered { - color: $text-color-tertiary; -} - -.k-chat-bubble__status-icon--read { - color: $primary-color; -} - -.k-chat-bubble__status-icon--failed { - color: $error-color; - cursor: pointer; - - &:hover { - color: darken($error-color, 10%); - } -} - -// 样式变体 -// 默认样式(占位,保持与后续变体结构一致) -.k-chat-bubble--style-default { - // 默认样式已在基础规则中定义,此处无需额外覆盖 -} - - -.k-chat-bubble--style-rounded { - .k-chat-bubble__bubble { - border-radius: 20px; - - &--own { - border-top-right-radius: 8px; + .k-chat-bubble--other & { + justify-content: flex-start; } - &--other { - border-top-left-radius: 8px; + // 时间 + &-time { + white-space: nowrap; + } + + // 状态图标 + &-status-icon { + &--sending { + color: $gray-400; + animation: spin 1s linear infinite; + } + + &--sent, + &--delivered { + color: $gray-400; + } + + &--read { + color: $primary-color; + } + + &--failed { + color: $danger-color; + cursor: pointer; + + &:hover { + color: darken($danger-color, 10%); + } + } } } -} -.k-chat-bubble--style-sharp { - .k-chat-bubble__bubble { - border-radius: $border-radius-sm; + // 样式变体 + // 默认样式(占位,保持与后续变体结构一致) + &--style-default { + // 默认样式已在基础规则中定义,此处无需额外覆盖 + } - &--own { - border-top-right-radius: 0; + &--style-rounded { + .k-chat-bubble__bubble { + border-radius: 20px; + + &--own { + border-top-right-radius: 8px; + } + + &--other { + border-top-left-radius: 8px; + } } + } - &--other { - border-top-left-radius: 0; + &--style-sharp { + .k-chat-bubble__bubble { + border-radius: $rounded-sm; + + &--own { + border-top-right-radius: 0; + } + + &--other { + border-top-left-radius: 0; + } } } } diff --git a/src/components/ChatBubble/index.vue b/src/components/ChatBubble/index.vue index 5240f43..0c1c55e 100644 --- a/src/components/ChatBubble/index.vue +++ b/src/components/ChatBubble/index.vue @@ -197,3 +197,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Container/index.scss b/src/components/Container/index.scss index 7ee603e..b857e8a 100644 --- a/src/components/Container/index.scss +++ b/src/components/Container/index.scss @@ -1,4 +1,5 @@ // Container组件样式 +@use "@/styles/index.scss" as *; .k-container { @@ -18,14 +19,14 @@ // 阴影样式 &--shadow-always { - box-shadow: $box-shadow-light; + box-shadow: $shadow-sm; } &--shadow-hover { - transition: box-shadow $transition-duration $transition-timing-function; + transition: box-shadow $transition-normal; &:hover { - box-shadow: $box-shadow-light; + box-shadow: $shadow-sm; } } diff --git a/src/components/Container/index.vue b/src/components/Container/index.vue index 12212d5..06c58e5 100644 --- a/src/components/Container/index.vue +++ b/src/components/Container/index.vue @@ -129,3 +129,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Divider/index.scss b/src/components/Divider/index.scss index da7605c..6b58501 100644 --- a/src/components/Divider/index.scss +++ b/src/components/Divider/index.scss @@ -1,4 +1,5 @@ // Divider组件样式 +@use "@/styles/index.scss" as *; .k-divider { diff --git a/src/components/Divider/index.vue b/src/components/Divider/index.vue index a613144..6adae00 100644 --- a/src/components/Divider/index.vue +++ b/src/components/Divider/index.vue @@ -97,3 +97,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Empty/index.scss b/src/components/Empty/index.scss index d801ff8..b6f1880 100644 --- a/src/components/Empty/index.scss +++ b/src/components/Empty/index.scss @@ -1,12 +1,13 @@ // Empty组件样式 +@use "@/styles/index.scss" as *; .k-empty { box-sizing: border-box; margin: 0; padding: 0; - color: $color-text-primary; - font-size: $font-size-md; + color: $gray-700; + font-size: $text-base; line-height: 1.5715; text-align: center; @@ -30,16 +31,20 @@ } &__image { - margin-bottom: 16px; + height: $spacing-20; + width: $spacing-20; + margin-bottom: $spacing-6; + color: $gray-400; } &__icon { - color: $color-text-disabled; + color: $gray-300; } &__description { - margin-bottom: 16px; - color: $color-text-secondary; + margin-bottom: $spacing-6; + color: $gray-400; + font-size: $text-base; } &__content { diff --git a/src/components/Empty/index.vue b/src/components/Empty/index.vue index 90cde51..23e896d 100644 --- a/src/components/Empty/index.vue +++ b/src/components/Empty/index.vue @@ -73,3 +73,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Grid/index.scss b/src/components/Grid/index.scss index 40df8f9..7af7b2f 100644 --- a/src/components/Grid/index.scss +++ b/src/components/Grid/index.scss @@ -1,4 +1,5 @@ // Grid组件样式 +@use "@/styles/index.scss" as *; .k-grid { diff --git a/src/components/Grid/index.vue b/src/components/Grid/index.vue index 7296d6c..8925620 100644 --- a/src/components/Grid/index.vue +++ b/src/components/Grid/index.vue @@ -128,3 +128,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Icon/index.scss b/src/components/Icon/index.scss index 1a7428f..158a28c 100644 --- a/src/components/Icon/index.scss +++ b/src/components/Icon/index.scss @@ -1,5 +1,5 @@ // Icon组件样式 - +@use "@/styles/index.scss" as *; .k-icon { display: inline-flex; @@ -27,3503 +27,4 @@ 100% { transform: rotate(360deg); } -} - -// 常用图标样式 -.k-icon--close { - &::before { - content: "×"; - } -} - -.k-icon--check { - &::before { - content: "✓"; - } -} - -.k-icon--arrow-left { - &::before { - content: "←"; - } -} - -.k-icon--arrow-right { - &::before { - content: "→"; - } -} - -.k-icon--arrow-up { - &::before { - content: "↑"; - } -} - -.k-icon--arrow-down { - &::before { - content: "↓"; - } -} - -.k-icon--loading { - &::before { - content: "⏳"; - } -} - -.k-icon--search { - &::before { - content: "🔍"; - } -} - -.k-icon--plus { - &::before { - content: "+"; - } -} - -.k-icon--minus { - &::before { - content: "-"; - } -} - -.k-icon--edit { - &::before { - content: "✏️"; - } -} - -.k-icon--delete { - &::before { - content: "🗑️"; - } -} - -.k-icon--download { - &::before { - content: "⬇️"; - } -} - -.k-icon--upload { - &::before { - content: "⬆️"; - } -} - -.k-icon--refresh { - &::before { - content: "🔄"; - } -} - -.k-icon--warning { - &::before { - content: "⚠️"; - } -} - -.k-icon--error { - &::before { - content: "❌"; - } -} - -.k-icon--success { - &::before { - content: "✅"; - } -} - -.k-icon--info { - &::before { - content: "ℹ️"; - } -} - -.k-icon--question { - &::before { - content: "❓"; - } -} - -.k-icon--eye { - &::before { - content: "👁️"; - } -} - -.k-icon--eye-off { - &::before { - content: "👁️‍🗨️"; - } -} - -.k-icon--heart { - &::before { - content: "❤️"; - } -} - -.k-icon--heart-filled { - &::before { - content: "💖"; - } -} - -.k-icon--star { - &::before { - content: "⭐"; - } -} - -.k-icon--star-filled { - &::before { - content: "⭐"; - } -} - -.k-icon--menu { - &::before { - content: "☰"; - } -} - -.k-icon--more { - &::before { - content: "⋯"; - } -} - -.k-icon--setting { - &::before { - content: "⚙️"; - } -} - -.k-icon--user { - &::before { - content: "👤"; - } -} - -.k-icon--users { - &::before { - content: "👥"; - } -} - -.k-icon--home { - &::before { - content: "🏠"; - } -} - -.k-icon--folder { - &::before { - content: "📁"; - } -} - -.k-icon--file { - &::before { - content: "📄"; - } -} - -.k-icon--image { - &::before { - content: "🖼️"; - } -} - -.k-icon--video { - &::before { - content: "🎥"; - } -} - -.k-icon--audio { - &::before { - content: "🎵"; - } -} - -.k-icon--link { - &::before { - content: "🔗"; - } -} - -.k-icon--share { - &::before { - content: "🔗"; - } -} - -.k-icon--copy { - &::before { - content: "📋"; - } -} - -.k-icon--paste { - &::before { - content: "📋"; - } -} - -.k-icon--cut { - &::before { - content: "✂️"; - } -} - -.k-icon--calendar { - &::before { - content: "📅"; - } -} - -.k-icon--clock { - &::before { - content: "🕐"; - } -} - -.k-icon--bell { - &::before { - content: "🔔"; - } -} - -.k-icon--mail { - &::before { - content: "✉️"; - } -} - -.k-icon--phone { - &::before { - content: "📞"; - } -} - -.k-icon--location { - &::before { - content: "📍"; - } -} - -.k-icon--map { - &::before { - content: "🗺️"; - } -} - -.k-icon--cart { - &::before { - content: "🛒"; - } -} - -.k-icon--tag { - &::before { - content: "🏷️"; - } -} - -.k-icon--bookmark { - &::before { - content: "🔖"; - } -} - -.k-icon--filter { - &::before { - content: "🔍"; - } -} - -.k-icon--sort { - &::before { - content: "↕️"; - } -} - -.k-icon--expand { - &::before { - content: "⬇️"; - } -} - -.k-icon--collapse { - &::before { - content: "⬆️"; - } -} - -.k-icon--fullscreen { - &::before { - content: "⛶"; - } -} - -.k-icon--exit-fullscreen { - &::before { - content: "⛶"; - } -} - -.k-icon--lock { - &::before { - content: "🔒"; - } -} - -.k-icon--unlock { - &::before { - content: "🔓"; - } -} - -.k-icon--shield { - &::before { - content: "🛡️"; - } -} - -.k-icon--key { - &::before { - content: "🔑"; - } -} - -.k-icon--database { - &::before { - content: "🗄️"; - } -} - -.k-icon--server { - &::before { - content: "🖥️"; - } -} - -.k-icon--cloud { - &::before { - content: "☁️"; - } -} - -.k-icon--wifi { - &::before { - content: "📶"; - } -} - -.k-icon--battery { - &::before { - content: "🔋"; - } -} - -.k-icon--signal { - &::before { - content: "📶"; - } -} - -.k-icon--bluetooth { - &::before { - content: "📶"; - } -} - -.k-icon--usb { - &::before { - content: "🔌"; - } -} - -.k-icon--print { - &::before { - content: "🖨️"; - } -} - -.k-icon--scan { - &::before { - content: "📷"; - } -} - -.k-icon--camera { - &::before { - content: "📷"; - } -} - -.k-icon--microphone { - &::before { - content: "🎤"; - } -} - -.k-icon--volume { - &::before { - content: "🔊"; - } -} - -.k-icon--mute { - &::before { - content: "🔇"; - } -} - -.k-icon--play { - &::before { - content: "▶️"; - } -} - -.k-icon--pause { - &::before { - content: "⏸️"; - } -} - -.k-icon--stop { - &::before { - content: "⏹️"; - } -} - -.k-icon--next { - &::before { - content: "⏭️"; - } -} - -.k-icon--previous { - &::before { - content: "⏮️"; - } -} - -.k-icon--forward { - &::before { - content: "⏩"; - } -} - -.k-icon--backward { - &::before { - content: "⏪"; - } -} - -.k-icon--record { - &::before { - content: "⏺️"; - } -} - -.k-icon--replay { - &::before { - content: "🔄"; - } -} - -.k-icon--shuffle { - &::before { - content: "🔀"; - } -} - -.k-icon--repeat { - &::before { - content: "🔁"; - } -} - -.k-icon--loop { - &::before { - content: "🔁"; - } -} - -.k-icon--zoom-in { - &::before { - content: "🔍"; - } -} - -.k-icon--zoom-out { - &::before { - content: "🔍"; - } -} - -.k-icon--fit { - &::before { - content: "🔍"; - } -} - -.k-icon--fullscreen-exit { - &::before { - content: "⛶"; - } -} - -.k-icon--grid { - &::before { - content: "⊞"; - } -} - -.k-icon--list { - &::before { - content: "☰"; - } -} - -.k-icon--th-large { - &::before { - content: "⊞"; - } -} - -.k-icon--th { - &::before { - content: "⊞"; - } -} - -.k-icon--th-list { - &::before { - content: "☰"; - } -} - -.k-icon--align-left { - &::before { - content: "⬅️"; - } -} - -.k-icon--align-center { - &::before { - content: "↔️"; - } -} - -.k-icon--align-right { - &::before { - content: "➡️"; - } -} - -.k-icon--align-justify { - &::before { - content: "↔️"; - } -} - -.k-icon--bold { - &::before { - content: "B"; - } -} - -.k-icon--italic { - &::before { - content: "I"; - } -} - -.k-icon--underline { - &::before { - content: "U"; - } -} - -.k-icon--strikethrough { - &::before { - content: "S"; - } -} - -.k-icon--subscript { - &::before { - content: "ₓ"; - } -} - -.k-icon--superscript { - &::before { - content: "ˣ"; - } -} - -.k-icon--quote-left { - &::before { - content: """; - } -} - -.k-icon--quote-right { - &::before { - content: """; - } -} - -.k-icon--code { - &::before { - content: ""; - } -} - -.k-icon--terminal { - &::before { - content: ">"; - } -} - -.k-icon--terminal-square { - &::before { - content: "⧉"; - } -} - -.k-icon--file-code { - &::before { - content: ""; - } -} - -.k-icon--file-excel { - &::before { - content: "📊"; - } -} - -.k-icon--file-pdf { - &::before { - content: "📄"; - } -} - -.k-icon--file-word { - &::before { - content: "📄"; - } -} - -.k-icon--file-powerpoint { - &::before { - content: "📊"; - } -} - -.k-icon--file-archive { - &::before { - content: "📦"; - } -} - -.k-icon--file-audio { - &::before { - content: "🎵"; - } -} - -.k-icon--file-video { - &::before { - content: "🎥"; - } -} - -.k-icon--file-image { - &::before { - content: "🖼️"; - } -} - -.k-icon--file-text { - &::before { - content: "📄"; - } -} - -.k-icon--folder-open { - &::before { - content: "📂"; - } -} - -.k-icon--folder-plus { - &::before { - content: "📁"; - } -} - -.k-icon--folder-minus { - &::before { - content: "📁"; - } -} - -.k-icon--smile { - &::before { - content: "😊"; - } -} - -.k-icon--meh { - &::before { - content: "😐"; - } -} - -.k-icon--frown { - &::before { - content: "😞"; - } -} - -.k-icon--angry { - &::before { - content: "😠"; - } -} - -.k-icon--tired { - &::before { - content: "😫"; - } -} - -.k-icon--dizzy { - &::before { - content: "😵"; - } -} - -.k-icon--sad-tear { - &::before { - content: "😢"; - } -} - -.k-icon--grin { - &::before { - content: "😃"; - } -} - -.k-icon--grin-hearts { - &::before { - content: "😍"; - } -} - -.k-icon--grin-beam { - &::before { - content: "😄"; - } -} - -.k-icon--grin-stars { - &::before { - content: "🤩"; - } -} - -.k-icon--grin-tongue { - &::before { - content: "😛"; - } -} - -.k-icon--grin-wink { - &::before { - content: "😉"; - } -} - -.k-icon--laugh { - &::before { - content: "😆"; - } -} - -.k-icon--laugh-beam { - &::before { - content: "😄"; - } -} - -.k-icon--laugh-squint { - &::before { - content: "😆"; - } -} - -.k-icon--laugh-wink { - &::before { - content: "😉"; - } -} - -.k-icon--kiss { - &::before { - content: "😗"; - } -} - -.k-icon--kiss-beam { - &::before { - content: "😗"; - } -} - -.k-icon--kiss-wink-heart { - &::before { - content: "😘"; - } -} - -.k-icon--surprise { - &::before { - content: "😮"; - } -} - -.k-icon--tongue { - &::before { - content: "😛"; - } -} - -.k-icon--wink { - &::before { - content: "😉"; - } -} - -.k-icon--thumbs-up { - &::before { - content: "👍"; - } -} - -.k-icon--thumbs-down { - &::before { - content: "👎"; - } -} - -.k-icon--hand-peace { - &::before { - content: "✌️"; - } -} - -.k-icon--hand-rock { - &::before { - content: "✊"; - } -} - -.k-icon--hand-paper { - &::before { - content: "✋"; - } -} - -.k-icon--hand-scissors { - &::before { - content: "✌️"; - } -} - -.k-icon--hand-spock { - &::before { - content: "🖖"; - } -} - -.k-icon--hand-point-left { - &::before { - content: "👈"; - } -} - -.k-icon--hand-point-right { - &::before { - content: "👉"; - } -} - -.k-icon--hand-point-up { - &::before { - content: "👆"; - } -} - -.k-icon--hand-point-down { - &::before { - content: "👇"; - } -} - -.k-icon--hand-holding { - &::before { - content: "🤲"; - } -} - -.k-icon--hand-holding-heart { - &::before { - content: "🫶"; - } -} - -.k-icon--hand-holding-usd { - &::before { - content: "💵"; - } -} - -.k-icon--hand-holding-water { - &::before { - content: "💧"; - } -} - -.k-icon--hands { - &::before { - content: "🤝"; - } -} - -.k-icon--hands-helping { - &::before { - content: "🤝"; - } -} - -.k-icon--handshake { - &::before { - content: "🤝"; - } -} - -.k-icon--handshake-alt { - &::before { - content: "🤝"; - } -} - -.k-icon--handshake-simple { - &::before { - content: "🤝"; - } -} - -.k-icon--handshake-simple-slash { - &::before { - content: "🤝"; - } -} - -.k-icon--handshake-slash { - &::before { - content: "🤝"; - } -} - -.k-icon--hamsa { - &::before { - content: "🤚"; - } -} - -.k-icon--pray { - &::before { - content: "🙏"; - } -} - -.k-icon--pray-hands { - &::before { - content: "🙏"; - } -} - -.k-icon--sign { - &::before { - content: "📜"; - } -} - -.k-icon--sign-language { - &::before { - content: "🤟"; - } -} - -.k-icon--asl-interpreting { - &::before { - content: "🤟"; - } -} - -.k-icon--deaf { - &::before { - content: "🧏"; - } -} - -.k-icon--deafness { - &::before { - content: "🧏"; - } -} - -.k-icon--hard-of-hearing { - &::before { - content: "🧏"; - } -} - -.k-icon--assistive-listening-systems { - &::before { - content: "🦻"; - } -} - -.k-icon--american-sign-language-interpreting { - &::before { - content: "🤟"; - } -} - -.k-icon--audio-description { - &::before { - content: "🔊"; - } -} - -.k-icon--braille { - &::before { - content: "🧱"; - } -} - -.k-icon--closed-captioning { - &::before { - content: "🔇"; - } -} - -.k-icon--closed-captioning-sign { - &::before { - content: "🔇"; - } -} - -.k-icon--low-vision { - &::before { - content: "👁️"; - } -} - -.k-icon--sign-language { - &::before { - content: "🤟"; - } -} - -.k-icon--universal-access { - &::before { - content: "♿"; - } -} - -.k-icon--wheelchair { - &::before { - content: "♿"; - } -} - -.k-icon--wheelchair-alt { - &::before { - content: "♿"; - } -} - -.k-icon--blind { - &::before { - content: "👁️"; - } -} - -.k-icon--tty { - &::before { - content: "📞"; - } -} - -.k-icon--volume-low { - &::before { - content: "🔉"; - } -} - -.k-icon--volume-high { - &::before { - content: "🔊"; - } -} - -.k-icon--volume-mute { - &::before { - content: "🔇"; - } -} - -.k-icon--volume-off { - &::before { - content: "🔇"; - } -} - -.k-icon--volume-up { - &::before { - content: "🔊"; - } -} - -.k-icon--volume-down { - &::before { - content: "🔉"; - } -} - -.k-icon--bell-slash { - &::before { - content: "🔕"; - } -} - -.k-icon--comment { - &::before { - content: "💬"; - } -} - -.k-icon--comment-alt { - &::before { - content: "💬"; - } -} - -.k-icon--comment-dots { - &::before { - content: "💬"; - } -} - -.k-icon--comment-slash { - &::before { - content: "💬"; - } -} - -.k-icon--comments { - &::before { - content: "💬"; - } -} - -.k-icon--comments-alt { - &::before { - content: "💬"; - } -} - -.k-icon--envelope { - &::before { - content: "✉️"; - } -} - -.k-icon--envelope-open { - &::before { - content: "📧"; - } -} - -.k-icon--envelope-open-text { - &::before { - content: "📧"; - } -} - -.k-icon--envelope-square { - &::before { - content: "📧"; - } -} - -.k-icon--paper-plane { - &::before { - content: "✈️"; - } -} - -.k-icon--paper-plane-alt { - &::before { - content: "✈️"; - } -} - -.k-icon--reply { - &::before { - content: "↩️"; - } -} - -.k-icon--reply-all { - &::before { - content: "↩️"; - } -} - -.k-icon--share-alt { - &::before { - content: "🔗"; - } -} - -.k-icon--share-alt-square { - &::before { - content: "🔗"; - } -} - -.k-icon--share-square { - &::before { - content: "🔗"; - } -} - -.k-icon--share { - &::before { - content: "🔗"; - } -} - -.k-icon--bookmark { - &::before { - content: "🔖"; - } -} - -.k-icon--bookmark-alt { - &::before { - content: "🔖"; - } -} - -.k-icon--flag { - &::before { - content: "🚩"; - } -} - -.k-icon--flag-usa { - &::before { - content: "🇺🇸"; - } -} - -.k-icon--flag-checkered { - &::before { - content: "🏁"; - } -} - -.k-icon--tag { - &::before { - content: "🏷️"; - } -} - -.k-icon--tags { - &::before { - content: "🏷️"; - } -} - -.k-icon--certificate { - &::before { - content: "🏆"; - } -} - -.k-icon--award { - &::before { - content: "🏆"; - } -} - -.k-icon--medal { - &::before { - content: "🏅"; - } -} - -.k-icon--trophy { - &::before { - content: "🏆"; - } -} - -.k-icon--gift { - &::before { - content: "🎁"; - } -} - -.k-icon--birthday-cake { - &::before { - content: "🎂"; - } -} - -.k-icon--glass-cheers { - &::before { - content: "🥂"; - } -} - -.k-icon--guitar { - &::before { - content: "🎸"; - } -} - -.k-icon--headphones { - &::before { - content: "🎧"; - } -} - -.k-icon--music { - &::before { - content: "🎵"; - } -} - -.k-icon--record-vinyl { - &::before { - content: "💿"; - } -} - -.k-icon--compact-disc { - &::before { - content: "💿"; - } -} - -.k-icon--drum { - &::before { - content: "🥁"; - } -} - -.k-icon--drum-steelpan { - &::before { - content: "🥁"; - } -} - -.k-icon--microphone { - &::before { - content: "🎤"; - } -} - -.k-icon--microphone-alt { - &::before { - content: "🎤"; - } -} - -.k-icon--microphone-alt-slash { - &::before { - content: "🎤"; - } -} - -.k-icon--microphone-slash { - &::before { - content: "🎤"; - } -} - -.k-icon--video { - &::before { - content: "🎥"; - } -} - -.k-icon--video-slash { - &::before { - content: "🎥"; - } -} - -.k-icon--camera { - &::before { - content: "📷"; - } -} - -.k-icon--camera-alt { - &::before { - content: "📷"; - } -} - -.k-icon--camera-retro { - &::before { - content: "📷"; - } -} - -.k-icon--film { - &::before { - content: "🎬"; - } -} - -.k-icon--video-camera { - &::before { - content: "🎥"; - } -} - -.k-icon--binoculars { - &::before { - content: "🔭"; - } -} - -.k-icon--telescope { - &::before { - content: "🔭"; - } -} - -.k-icon--microscope { - &::before { - content: "🔬"; - } -} - -.k-icon--dna { - &::before { - content: "🧬"; - } -} - -.k-icon--atom { - &::before { - content: "⚛️"; - } -} - -.k-icon--flask { - &::before { - content: "🧪"; - } -} - -.k-icon--magnet { - &::before { - content: "🧲"; - } -} - -.k-icon--vial { - &::before { - content: "🧪"; - } -} - -.k-icon--vials { - &::before { - content: "🧪"; - } -} - -.k-icon--bacteria { - &::before { - content: "🦠"; - } -} - -.k-icon--virus { - &::before { - content: "🦠"; - } -} - -.k-icon--virus-slash { - &::before { - content: "🦠"; - } -} - -.k-icon--syringe { - &::before { - content: "💉"; - } -} - -.k-icon--pills { - &::before { - content: "💊"; - } -} - -.k-icon--prescription-bottle { - &::before { - content: "💊"; - } -} - -.k-icon--prescription-bottle-alt { - &::before { - content: "💊"; - } -} - -.k-icon--stethoscope { - &::before { - content: "🩺"; - } -} - -.k-icon--tooth { - &::before { - content: "🦷"; - } -} - -.k-icon--teeth { - &::before { - content: "🦷"; - } -} - -.k-icon--teeth-open { - &::before { - content: "🦷"; - } -} - -.k-icon--user-md { - &::before { - content: "👨‍⚕️"; - } -} - -.k-icon--user-nurse { - &::before { - content: "👩‍⚕️"; - } -} - -.k-icon--crutch { - &::before { - content: "🦯"; - } -} - -.k-icon--wheelchair { - &::before { - content: "♿"; - } -} - -.k-icon--procedures { - &::before { - content: "🏥"; - } -} - -.k-icon--hospital { - &::before { - content: "🏥"; - } -} - -.k-icon--hospital-alt { - &::before { - content: "🏥"; - } -} - -.k-icon--hospital-symbol { - &::before { - content: "🏥"; - } -} - -.k-icon--ambulance { - &::before { - content: "🚑"; - } -} - -.k-icon--helicopter { - &::before { - content: "🚁"; - } -} - -.k-icon--plane { - &::before { - content: "✈️"; - } -} - -.k-icon--plane-alt { - &::before { - content: "✈️"; - } -} - -.k-icon--fighter-jet { - &::before { - content: "✈️"; - } -} - -.k-icon--rocket { - &::before { - content: "🚀"; - } -} - -.k-icon--space-shuttle { - &::before { - content: "🚀"; - } -} - -.k-icon--satellite { - &::before { - content: "🛰️"; - } -} - -.k-icon--satellite-dish { - &::before { - content: "📡"; - } -} - -.k-icon--space-station { - &::before { - content: "🛰️"; - } -} - -.k-icon--moon { - &::before { - content: "🌙"; - } -} - -.k-icon--planet-ringed { - &::before { - content: "🪐"; - } -} - -.k-icon--globe { - &::before { - content: "🌍"; - } -} - -.k-icon--globe-africa { - &::before { - content: "🌍"; - } -} - -.k-icon--globe-americas { - &::before { - content: "🌎"; - } -} - -.k-icon--globe-asia { - &::before { - content: "🌏"; - } -} - -.k-icon--globe-europe { - &::before { - content: "🌍"; - } -} - -.k-icon--earth { - &::before { - content: "🌍"; - } -} - -.k-icon--earth-africa { - &::before { - content: "🌍"; - } -} - -.k-icon--earth-americas { - &::before { - content: "🌎"; - } -} - -.k-icon--earth-asia { - &::before { - content: "🌏"; - } -} - -.k-icon--earth-europe { - &::before { - content: "🌍"; - } -} - -.k-icon--map { - &::before { - content: "🗺️"; - } -} - -.k-icon--map-marked { - &::before { - content: "🗺️"; - } -} - -.k-icon--map-marked-alt { - &::before { - content: "🗺️"; - } -} - -.k-icon--map-pin { - &::before { - content: "📍"; - } -} - -.k-icon--map-marker { - &::before { - content: "📍"; - } -} - -.k-icon--map-marker-alt { - &::before { - content: "📍"; - } -} - -.k-icon--location-arrow { - &::before { - content: "➡️"; - } -} - -.k-icon--compass { - &::before { - content: "🧭"; - } -} - -.k-icon--route { - &::before { - content: "🛣️"; - } -} - -.k-icon--directions { - &::before { - content: "🛣️"; - } -} - -.k-icon--street-view { - &::before { - content: "🗺️"; - } -} - -.k-icon--traffic-light { - &::before { - content: "🚦"; - } -} - -.k-icon--road { - &::before { - content: "🛣️"; - } -} - -.k-icon--bridge { - &::before { - content: "🌉"; - } -} - -.k-icon--train { - &::before { - content: "🚂"; - } -} - -.k-icon--subway { - &::before { - content: "🚇"; - } -} - -.k-icon--bus { - &::before { - content: "🚌"; - } -} - -.k-icon--bus-alt { - &::before { - content: "🚌"; - } -} - -.k-icon--tram { - &::before { - content: "🚊"; - } -} - -.k-icon--car { - &::before { - content: "🚗"; - } -} - -.k-icon--car-alt { - &::before { - content: "🚗"; - } -} - -.k-icon--taxi { - &::before { - content: "🚕"; - } -} - -.k-icon--truck { - &::before { - content: "🚚"; - } -} - -.k-icon--truck-monster { - &::before { - content: "🚚"; - } -} - -.k-icon--truck-pickup { - &::before { - content: "🚚"; - } -} - -.k-icon--shipping-fast { - &::before { - content: "🚚"; - } -} - -.k-icon--bicycle { - &::before { - content: "🚲"; - } -} - -.k-icon--motorcycle { - &::before { - content: "🏍️"; - } -} - -.k-icon--ship { - &::before { - content: "🚢"; - } -} - -.k-icon--anchor { - &::before { - content: "⚓"; - } -} - -.k-icon--life-ring { - &::before { - content: "⛑️"; - } -} - -.k-icon--life-buoy { - &::before { - content: "⛑️"; - } -} - -.k-icon--life-preserver { - &::before { - content: "⛑️"; - } -} - -.k-icon--buoy { - &::before { - content: "⛑️"; - } -} - -.k-icon--swimmer { - &::before { - content: "🏊"; - } -} - -.k-icon--swimming-pool { - &::before { - content: "🏊"; - } -} - -.k-icon--hot-tub { - &::before { - content: "🛁"; - } -} - -.k-icon--bath { - &::before { - content: "🛁"; - } -} - -.k-icon--bathtub { - &::before { - content: "🛁"; - } -} - -.k-icon--shower { - &::before { - content: "🚿"; - } -} - -.k-icon--sink { - &::before { - content: "🚿"; - } -} - -.k-icon--toilet { - &::before { - content: "🚽"; - } -} - -.k-icon--toilet-paper { - &::before { - content: "🧻"; - } -} - -.k-icon--toilet-paper-alt { - &::before { - content: "🧻"; - } -} - -.k-icon--restroom { - &::before { - content: "🚻"; - } -} - -.k-icon--men { - &::before { - content: "🚹"; - } -} - -.k-icon--women { - &::before { - content: "🚺"; - } -} - -.k-icon--baby { - &::before { - content: "👶"; - } -} - -.k-icon--baby-carriage { - &::before { - content: "🍼"; - } -} - -.k-icon--bed { - &::before { - content: "🛏️"; - } -} - -.k-icon--couch { - &::before { - content: "🛋️"; - } -} - -.k-icon--chair { - &::before { - content: "🪑"; - } -} - -.k-icon--tv { - &::before { - content: "📺"; - } -} - -.k-icon--tv-alt { - &::before { - content: "📺"; - } -} - -.k-icon--desktop { - &::before { - content: "🖥️"; - } -} - -.k-icon--desktop-alt { - &::before { - content: "🖥️"; - } -} - -.k-icon--laptop { - &::before { - content: "💻"; - } -} - -.k-icon--laptop-code { - &::before { - content: "💻"; - } -} - -.k-icon--laptop-medical { - &::before { - content: "💻"; - } -} - -.k-icon--tablet { - &::before { - content: "📱"; - } -} - -.k-icon--tablet-alt { - &::before { - content: "📱"; - } -} - -.k-icon--mobile { - &::before { - content: "📱"; - } -} - -.k-icon--mobile-alt { - &::before { - content: "📱"; - } -} - -.k-icon--phone { - &::before { - content: "📞"; - } -} - -.k-icon--phone-alt { - &::before { - content: "📞"; - } -} - -.k-icon--phone-slash { - &::before { - content: "📞"; - } -} - -.k-icon--phone-volume { - &::before { - content: "📞"; - } -} - -.k-icon--fax { - &::before { - content: "📠"; - } -} - -.k-icon--bell { - &::before { - content: "🔔"; - } -} - -.k-icon--bell-slash { - &::before { - content: "🔕"; - } -} - -.k-icon--door-open { - &::before { - content: "🚪"; - } -} - -.k-icon--door-closed { - &::before { - content: "🚪"; - } -} - -.k-icon--window-maximize { - &::before { - content: "🔳"; - } -} - -.k-icon--window-minimize { - &::before { - content: "🔳"; - } -} - -.k-icon--window-restore { - &::before { - content: "🔳"; - } -} - -.k-icon--window-close { - &::before { - content: "🔳"; - } -} - -.k-icon--window-alt { - &::before { - content: "🔳"; - } -} - -.k-icon--archway { - &::before { - content: "🏛️"; - } -} - -.k-icon--church { - &::before { - content: "⛪"; - } -} - -.k-icon--mosque { - &::before { - content: "🕌"; - } -} - -.k-icon--synagogue { - &::before { - content: "🕍"; - } -} - -.k-icon--place-of-worship { - &::before { - content: "🛐"; - } -} - -.k-icon--home { - &::before { - content: "🏠"; - } -} - -.k-icon--home-alt { - &::before { - content: "🏠"; - } -} - -.k-icon--home-lg { - &::before { - content: "🏠"; - } -} - -.k-icon--home-lg-alt { - &::before { - content: "🏠"; - } -} - -.k-icon--building { - &::before { - content: "🏢"; - } -} - -.k-icon--warehouse { - &::before { - content: "🏭"; - } -} - -.k-icon--industry { - &::before { - content: "🏭"; - } -} - -.k-icon--store { - &::before { - content: "🏪"; - } -} - -.k-icon--store-alt { - &::before { - content: "🏪"; - } -} - -.k-icon--shopping-bag { - &::before { - content: "🛍️"; - } -} - -.k-icon--shopping-basket { - &::before { - content: "🛒"; - } -} - -.k-icon--shopping-cart { - &::before { - content: "🛒"; - } -} - -.k-icon--shopping-cart-arrow-down { - &::before { - content: "🛒"; - } -} - -.k-icon--shopping-cart-plus { - &::before { - content: "🛒"; - } -} - -.k-icon--box { - &::before { - content: "📦"; - } -} - -.k-icon--box-open { - &::before { - content: "📦"; - } -} - -.k-icon--box-tissue { - &::before { - content: "📦"; - } -} - -.k-icon--boxes { - &::before { - content: "📦"; - } -} - -.k-icon--archive { - &::before { - content: "🗄️"; - } -} - -.k-icon--file { - &::before { - content: "📄"; - } -} - -.k-icon--file-alt { - &::before { - content: "📄"; - } -} - -.k-icon--file-archive { - &::before { - content: "📦"; - } -} - -.k-icon--file-audio { - &::before { - content: "🎵"; - } -} - -.k-icon--file-code { - &::before { - content: ""; - } -} - -.k-icon--file-contract { - &::before { - content: "📄"; - } -} - -.k-icon--file-csv { - &::before { - content: "📊"; - } -} - -.k-icon--file-download { - &::before { - content: "📥"; - } -} - -.k-icon--file-excel { - &::before { - content: "📊"; - } -} - -.k-icon--file-export { - &::before { - content: "📤"; - } -} - -.k-icon--file-image { - &::before { - content: "🖼️"; - } -} - -.k-icon--file-import { - &::before { - content: "📥"; - } -} - -.k-icon--file-invoice { - &::before { - content: "📄"; - } -} - -.k-icon--file-invoice-dollar { - &::before { - content: "💵"; - } -} - -.k-icon--file-medical { - &::before { - content: "📄"; - } -} - -.k-icon--file-medical-alt { - &::before { - content: "📄"; - } -} - -.k-icon--file-pdf { - &::before { - content: "📄"; - } -} - -.k-icon--file-powerpoint { - &::before { - content: "📊"; - } -} - -.k-icon--file-prescription { - &::before { - content: "📄"; - } -} - -.k-icon--file-signature { - &::before { - content: "📄"; - } -} - -.k-icon--file-upload { - &::before { - content: "📤"; - } -} - -.k-icon--file-video { - &::before { - content: "🎥"; - } -} - -.k-icon--file-word { - &::before { - content: "📄"; - } -} - -.k-icon--folder { - &::before { - content: "📁"; - } -} - -.k-icon--folder-minus { - &::before { - content: "📁"; - } -} - -.k-icon--folder-open { - &::before { - content: "📂"; - } -} - -.k-icon--folder-plus { - &::before { - content: "📁"; - } -} - -.k-icon--folder-tree { - &::before { - content: "📁"; - } -} - -.k-icon--newspaper { - &::before { - content: "📰"; - } -} - -.k-icon--address-book { - &::before { - content: "📇"; - } -} - -.k-icon--address-card { - &::before { - content: "🪪"; - } -} - -.k-icon--id-badge { - &::before { - content: "🪪"; - } -} - -.k-icon--id-card { - &::before { - content: "🪪"; - } -} - -.k-icon--id-card-alt { - &::before { - content: "🪪"; - } -} - -.k-icon--passport { - &::before { - content: "🪪"; - } -} - -.k-icon--portrait { - &::before { - content: "🖼️"; - } -} - -.k-icon--user { - &::before { - content: "👤"; - } -} - -.k-icon--user-alt { - &::before { - content: "👤"; - } -} - -.k-icon--user-astronaut { - &::before { - content: "👨‍🚀"; - } -} - -.k-icon--user-check { - &::before { - content: "👤"; - } -} - -.k-icon--user-circle { - &::before { - content: "👤"; - } -} - -.k-icon--user-clock { - &::before { - content: "👤"; - } -} - -.k-icon--user-cog { - &::before { - content: "👤"; - } -} - -.k-icon--user-edit { - &::before { - content: "👤"; - } -} - -.k-icon--user-friends { - &::before { - content: "👥"; - } -} - -.k-icon--user-graduate { - &::before { - content: "👨‍🎓"; - } -} - -.k-icon--user-injured { - &::before { - content: "👤"; - } -} - -.k-icon--user-lock { - &::before { - content: "👤"; - } -} - -.k-icon--user-md { - &::before { - content: "👨‍⚕️"; - } -} - -.k-icon--user-minus { - &::before { - content: "👤"; - } -} - -.k-icon--user-ninja { - &::before { - content: "🥷"; - } -} - -.k-icon--user-nurse { - &::before { - content: "👩‍⚕️"; - } -} - -.k-icon--user-plus { - &::before { - content: "👤"; - } -} - -.k-icon--user-secret { - &::before { - content: "🕵️"; - } -} - -.k-icon--user-shield { - &::before { - content: "👤"; - } -} - -.k-icon--user-slash { - &::before { - content: "👤"; - } -} - -.k-icon--user-tag { - &::before { - content: "👤"; - } -} - -.k-icon--user-tie { - &::before { - content: "👔"; - } -} - -.k-icon--user-times { - &::before { - content: "👤"; - } -} - -.k-icon--users { - &::before { - content: "👥"; - } -} - -.k-icon--users-cog { - &::before { - content: "👥"; - } -} - -.k-icon--users-slash { - &::before { - content: "👥"; - } -} - -.k-icon--hdd { - &::before { - content: "💾"; - } -} - -.k-icon--hdd-alt { - &::before { - content: "💾"; - } -} - -.k-icon--memory { - &::before { - content: "💾"; - } -} - -.k-icon--microchip { - &::before { - content: "🔲"; - } -} - -.k-icon--microchip-alt { - &::before { - content: "🔲"; - } -} - -.k-icon--sd-card { - &::before { - content: "💾"; - } -} - -.k-icon--sim-card { - &::before { - content: "📱"; - } -} - -.k-icon--usb { - &::before { - content: "🔌"; - } -} - -.k-icon--bluetooth { - &::before { - content: "📶"; - } -} - -.k-icon--bluetooth-b { - &::before { - content: "📶"; - } -} - -.k-icon--wifi { - &::before { - content: "📶"; - } -} - -.k-icon--broadcast-tower { - &::before { - content: "📡"; - } -} - -.k-icon--satellite { - &::before { - content: "🛰️"; - } -} - -.k-icon--satellite-dish { - &::before { - content: "📡"; - } -} - -.k-icon--signal { - &::before { - content: "📶"; - } -} - -.k-icon--signal-alt { - &::before { - content: "📶"; - } -} - -.k-icon--signal-alt-slash { - &::before { - content: "📶"; - } -} - -.k-icon--signal-slash { - &::before { - content: "📶"; - } -} - -.k-icon--battery-full { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-three-quarters { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-half { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-quarter { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-empty { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-alt { - &::before { - content: "🔋"; - } -} - -.k-icon--battery-slash { - &::before { - content: "🔋"; - } -} - -.k-icon--plug { - &::before { - content: "🔌"; - } -} - -.k-icon--power-off { - &::before { - content: "🔌"; - } -} - -.k-icon--cog { - &::before { - content: "⚙️"; - } -} - -.k-icon--cogs { - &::before { - content: "⚙️"; - } -} - -.k-icon--gear { - &::before { - content: "⚙️"; - } -} - -.k-icon--wrench { - &::before { - content: "🔧"; - } -} - -.k-icon--tools { - &::before { - content: "🔧"; - } -} - -.k-icon--hammer { - &::before { - content: "🔨"; - } -} - -.k-icon--screwdriver { - &::before { - content: "🔧"; - } -} - -.k-icon--pencil-alt { - &::before { - content: "✏️"; - } -} - -.k-icon--pencil-ruler { - &::before { - content: "📏"; - } -} - -.k-icon--ruler { - &::before { - content: "📏"; - } -} - -.k-icon--ruler-combined { - &::before { - content: "📏"; - } -} - -.k-icon--ruler-horizontal { - &::before { - content: "📏"; - } -} - -.k-icon--ruler-vertical { - &::before { - content: "📏"; - } -} - -.k-icon--eraser { - &::before { - content: "🧹"; - } -} - -.k-icon--pen { - &::before { - content: "🖊️"; - } -} - -.k-icon--pen-alt { - &::before { - content: "🖊️"; - } -} - -.k-icon--pen-fancy { - &::before { - content: "🖊️"; - } -} - -.k-icon--pen-nib { - &::before { - content: "🖊️"; - } -} - -.k-icon--pen-square { - &::before { - content: "📝"; - } -} - -.k-icon--pencil-square { - &::before { - content: "📝"; - } -} - -.k-icon--paint-brush { - &::before { - content: "🖌️"; - } -} - -.k-icon--paint-roller { - &::before { - content: "🖌️"; - } -} - -.k-icon--palette { - &::before { - content: "🎨"; - } -} - -.k-icon--eye { - &::before { - content: "👁️"; - } -} - -.k-icon--eye-dropper { - &::before { - content: "💧"; - } -} - -.k-icon--eye-slash { - &::before { - content: "👁️‍🗨️"; - } -} - -.k-icon--glasses { - &::before { - content: "👓"; - } -} - -.k-icon--binoculars { - &::before { - content: "🔭"; - } -} - -.k-icon--microscope { - &::before { - content: "🔬"; - } -} - -.k-icon--search { - &::before { - content: "🔍"; - } -} - -.k-icon--search-dollar { - &::before { - content: "🔍"; - } -} - -.k-icon--search-location { - &::before { - content: "🔍"; - } -} - -.k-icon--search-minus { - &::before { - content: "🔍"; - } -} - -.k-icon--search-plus { - &::before { - content: "🔍"; - } -} - -.k-icon--filter { - &::before { - content: "🔍"; - } -} - -.k-icon--sort { - &::before { - content: "↕️"; - } -} - -.k-icon--sort-alpha-down { - &::before { - content: "🔤"; - } -} - -.k-icon--sort-alpha-down-alt { - &::before { - content: "🔤"; - } -} - -.k-icon--sort-alpha-up { - &::before { - content: "🔤"; - } -} - -.k-icon--sort-alpha-up-alt { - &::before { - content: "🔤"; - } -} - -.k-icon--sort-amount-down { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-amount-down-alt { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-amount-up { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-amount-up-alt { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-down { - &::before { - content: "⬇️"; - } -} - -.k-icon--sort-numeric-down { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-numeric-down-alt { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-numeric-up { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-numeric-up-alt { - &::before { - content: "🔢"; - } -} - -.k-icon--sort-up { - &::before { - content: "⬆️"; - } -} - -.k-icon--tint { - &::before { - content: "💧"; - } -} - -.k-icon--tint-slash { - &::before { - content: "💧"; - } -} - -.k-icon--thermometer { - &::before { - content: "🌡️"; - } -} - -.k-icon--thermometer-empty { - &::before { - content: "🌡️"; - } -} - -.k-icon--thermometer-full { - &::before { - content: "🌡️"; - } -} - -.k-icon--thermometer-half { - &::before { - content: "🌡️"; - } -} - -.k-icon--thermometer-quarter { - &::before { - content: "🌡️"; - } -} - -.k-icon--thermometer-three-quarters { - &::before { - content: "🌡️"; - } -} - -.k-icon--cloud { - &::before { - content: "☁️"; - } -} - -.k-icon--cloud-download-alt { - &::before { - content: "☁️"; - } -} - -.k-icon--cloud-upload-alt { - &::before { - content: "☁️"; - } -} - -.k-icon--cloud-sun { - &::before { - content: "⛅"; - } -} - -.k-icon--cloud-moon { - &::before { - content: "☁️"; - } -} - -.k-icon--cloud-rain { - &::before { - content: "🌧️"; - } -} - -.k-icon--cloud-showers-heavy { - &::before { - content: "🌧️"; - } -} - -.k-icon--cloud-sun-rain { - &::before { - content: "🌦️"; - } -} - -.k-icon--cloud-moon-rain { - &::before { - content: "🌧️"; - } -} - -.k-icon--cloud-bolt { - &::before { - content: "⛈️"; - } -} - -.k-icon--cloud-meatball { - &::before { - content: "☁️"; - } -} - -.k-icon--cloud-music { - &::before { - content: "☁️"; - } -} - -.k-icon--smog { - &::before { - content: "🌫️"; - } -} - -.k-icon--sun { - &::before { - content: "☀️"; - } -} - -.k-icon--moon { - &::before { - content: "🌙"; - } -} - -.k-icon--star { - &::before { - content: "⭐"; - } -} - -.k-icon--star-half { - &::before { - content: "⭐"; - } -} - -.k-icon--star-half-alt { - &::before { - content: "⭐"; - } -} - -.k-icon--meteor { - &::before { - content: "☄️"; - } -} - -.k-icon--snowflake { - &::before { - content: "❄️"; - } -} - -.k-icon--icicles { - &::before { - content: "🧊"; - } -} - -.k-icon--fire { - &::before { - content: "🔥"; - } -} - -.k-icon--fire-alt { - &::before { - content: "🔥"; - } -} - -.k-icon--bolt { - &::before { - content: "⚡"; - } -} - -.k-icon--water { - &::before { - content: "💧"; - } -} - -.k-icon--leaf { - &::before { - content: "🍃"; - } -} - -.k-icon--seedling { - &::before { - content: "🌱"; - } -} - -.k-icon--tree { - &::before { - content: "🌳"; - } -} - -.k-icon--palm-tree { - &::before { - content: "🌴"; - } -} - -.k-icon--mountain { - &::before { - content: "⛰️"; - } -} - -.k-icon--umbrella { - &::before { - content: "☂️"; - } -} - -.k-icon--umbrella-beach { - &::before { - content: "🏖️"; - } -} - -.k-icon--umbrella-alt { - &::before { - content: "☂️"; - } -} - -.k-icon--wind { - &::before { - content: "💨"; - } -} - -.k-icon--temperature-high { - &::before { - content: "🌡️"; - } -} - -.k-icon--temperature-low { - &::before { - content: "🌡️"; - } } \ No newline at end of file diff --git a/src/components/Icon/index.vue b/src/components/Icon/index.vue index 2bb258b..028e501 100644 --- a/src/components/Icon/index.vue +++ b/src/components/Icon/index.vue @@ -182,23 +182,5 @@ export default defineComponent({ diff --git a/src/components/Image/index.scss b/src/components/Image/index.scss index a2dea36..2d4bf83 100644 --- a/src/components/Image/index.scss +++ b/src/components/Image/index.scss @@ -1,5 +1,5 @@ // Image组件样式 - +@use "@/styles/index.scss" as *; .k-image { position: relative; @@ -11,7 +11,7 @@ width: 100%; height: 100%; object-fit: cover; - transition: transform $transition-duration $transition-timing-function; + transition: transform $transition-normal; &--loading { opacity: 0; @@ -29,8 +29,8 @@ flex-direction: column; justify-content: center; align-items: center; - background-color: $color-bg-container; - color: $color-text-tertiary; + background-color: $white; + color: $gray-400; } &__placeholder-icon, @@ -55,7 +55,7 @@ background-color: rgba(0, 0, 0, 0.5); color: white; opacity: 0; - transition: opacity $transition-duration $transition-timing-function; + transition: opacity $transition-normal; cursor: pointer; &:hover { diff --git a/src/components/Image/index.test.ts b/src/components/Image/index.test.ts deleted file mode 100644 index 53a21ad..0000000 --- a/src/components/Image/index.test.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { mount } from '@vue/test-utils'; -import { describe, it, expect, vi } from 'vitest'; -import KImage from './index.vue'; - -// 模拟Icon组件 -vi.mock('../Icon/index.vue', () => ({ - default: { - name: 'KIcon', - props: ['name', 'class:iconClass'], - template: '' - } -})); - -describe('KImage Component', () => { - // 测试基础渲染 - it('should render correctly with basic props', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - alt: 'Test Image' - } - }); - - expect(wrapper.exists()).toBe(true); - expect(wrapper.classes()).toContain('k-image'); - expect(wrapper.find('img').exists()).toBe(true); - expect(wrapper.find('img').attributes('src')).toBe('https://example.com/image.jpg'); - expect(wrapper.find('img').attributes('alt')).toBe('Test Image'); - }); - - // 测试图片加载状态 - it('should show loading state initially', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - } - }); - - expect(wrapper.vm.loading).toBe(true); - expect(wrapper.find('.k-image__img--loading').exists()).toBe(true); - expect(wrapper.find('.k-image__placeholder').exists()).toBe(true); - }); - - // 测试图片加载成功 - it('should handle image load success', async () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - } - }); - - // 触发图片加载成功事件 - await wrapper.find('img').trigger('load'); - - expect(wrapper.vm.loading).toBe(false); - expect(wrapper.vm.error).toBe(false); - expect(wrapper.find('.k-image__img--loading').exists()).toBe(false); - expect(wrapper.find('.k-image__placeholder').exists()).toBe(false); - }); - - // 测试图片加载失败 - it('should handle image load error', async () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/non-existent.jpg' - } - }); - - // 触发图片加载失败事件 - await wrapper.find('img').trigger('error'); - - expect(wrapper.vm.loading).toBe(false); - expect(wrapper.vm.error).toBe(true); - expect(wrapper.find('.k-image__placeholder').exists()).toBe(false); - expect(wrapper.find('.k-image__error').exists()).toBe(true); - }); - - // 测试预览功能 - it('should show preview button when preview prop is true', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - preview: true - } - }); - - expect(wrapper.classes()).toContain('k-image--preview'); - expect(wrapper.find('.k-image__preview').exists()).toBe(true); - }); - - // 测试预览点击事件 - it('should trigger preview event when preview button is clicked', async () => { - const previewSpy = vi.fn(); - - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - preview: true - }, - onPreview: previewSpy - }); - - await wrapper.find('.k-image__preview').trigger('click'); - - expect(previewSpy).toHaveBeenCalledWith({ - url: 'https://example.com/image.jpg', - index: 0, - srcList: ['https://example.com/image.jpg'] - }); - }); - - // 测试fit属性 - it('should apply correct object-fit style based on fit prop', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - fit: 'contain' - } - }); - - expect(wrapper.find('img').attributes('style')).toContain('object-fit: contain'); - }); - - // 测试默认fit值为cover - it('should use cover as default fit value', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - } - }); - - // 由于组件内部设置了默认值为cover,所以应该看到这个值 - expect(wrapper.vm.imgStyle.objectFit).toBe('cover'); - }); - - // 测试width和height属性 - it('should apply correct width and height styles', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - width: 200, - height: 150 - } - }); - - const imageStyle = wrapper.vm.imageStyle; - expect(imageStyle.width).toBe('200px'); - expect(imageStyle.height).toBe('150px'); - }); - - // 测试width和height为字符串的情况 - it('should handle string width and height correctly', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - width: '300px', - height: '200px' - } - }); - - const imageStyle = wrapper.vm.imageStyle; - expect(imageStyle.width).toBe('300px'); - expect(imageStyle.height).toBe('200px'); - }); - - // 测试borderRadius属性 - it('should apply correct border-radius style', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - borderRadius: 8 - } - }); - - const imgStyle = wrapper.vm.imgStyle; - expect(imgStyle.borderRadius).toBe('8px'); - }); - - // 测试borderRadius为字符串的情况 - it('should handle string border-radius correctly', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - borderRadius: '12px' - } - }); - - const imgStyle = wrapper.vm.imgStyle; - expect(imgStyle.borderRadius).toBe('12px'); - }); - - // 测试placeholder插槽 - it('should render custom placeholder content', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - }, - slots: { - placeholder: '
自定义加载中...
' - } - }); - - expect(wrapper.find('.custom-placeholder').exists()).toBe(true); - expect(wrapper.find('.custom-placeholder').text()).toBe('自定义加载中...'); - }); - - // 测试error插槽 - it('should render custom error content', async () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - }, - slots: { - error: '
自定义错误信息
' - } - }); - - // 触发错误状态 - await wrapper.find('img').trigger('error'); - - expect(wrapper.find('.custom-error').exists()).toBe(true); - expect(wrapper.find('.custom-error').text()).toBe('自定义错误信息'); - }); - - // 测试组合属性 - it('should handle all props together correctly', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - alt: 'Test Image', - fit: 'contain', - width: 400, - height: 300, - borderRadius: 16, - preview: true - } - }); - - expect(wrapper.classes()).toContain('k-image--preview'); - expect(wrapper.find('img').attributes('alt')).toBe('Test Image'); - expect(wrapper.vm.imageStyle.width).toBe('400px'); - expect(wrapper.vm.imageStyle.height).toBe('300px'); - expect(wrapper.vm.imgStyle.objectFit).toBe('contain'); - expect(wrapper.vm.imgStyle.borderRadius).toBe('16px'); - }); - - // 快照测试 - it('should match snapshot with default props', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg' - } - }); - - expect(wrapper.html()).toMatchSnapshot(); - }); - - it('should match snapshot with all props', () => { - const wrapper = mount(KImage, { - props: { - src: 'https://example.com/image.jpg', - alt: 'Test Image', - fit: 'cover', - width: 200, - height: 150, - borderRadius: 8, - preview: true - } - }); - - expect(wrapper.html()).toMatchSnapshot(); - }); -}); \ No newline at end of file diff --git a/src/components/Image/index.vue b/src/components/Image/index.vue index 579c426..4f5360e 100644 --- a/src/components/Image/index.vue +++ b/src/components/Image/index.vue @@ -199,3 +199,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Loading/index.scss b/src/components/Loading/index.scss index 2adae40..0b4062e 100644 --- a/src/components/Loading/index.scss +++ b/src/components/Loading/index.scss @@ -1,11 +1,12 @@ // Loading组件样式 +@use "@/styles/index.scss" as *; .k-loading { display: flex; align-items: center; justify-content: center; - color: $color-primary; + color: $primary-color; // 尺寸样式 &--size-small { @@ -54,7 +55,7 @@ &__text { margin-left: 8px; - color: $color-text-secondary; + color: $gray-400; } // 垂直布局下的文本样式 diff --git a/src/components/Loading/index.test.ts b/src/components/Loading/index.test.ts deleted file mode 100644 index 5dcd115..0000000 --- a/src/components/Loading/index.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { mount } from '@vue/test-utils'; -import { describe, it, expect, vi } from 'vitest'; -import KLoading from './index.vue'; -import type { LoadingProps } from './types'; - -// 模拟Icon组件 -vi.mock('../Icon/index.vue', () => ({ - default: { - name: 'KIcon', - props: ['name', 'class:iconClass'], - template: '' - } -})); - -describe('KLoading Component', () => { - // 测试基础渲染 - it('should render correctly with default props', () => { - const wrapper = mount(KLoading); - - expect(wrapper.exists()).toBe(true); - expect(wrapper.classes()).toContain('k-loading'); - expect(wrapper.classes()).toContain('k-loading--size-medium'); - expect(wrapper.find('.k-loading__spinner').exists()).toBe(true); - expect(wrapper.find('.k-loading__icon').exists()).toBe(true); - expect(wrapper.findComponent({ name: 'KIcon' }).props('name')).toBe('loading'); - }); - - // 测试loading状态控制 - it('should show loading content when loading is true', () => { - const wrapper = mount(KLoading, { - props: { - loading: true - }, - slots: { - default: '
Default content
' - } - }); - - expect(wrapper.find('.k-loading__spinner').exists()).toBe(true); - expect(wrapper.find('.default-content').exists()).toBe(false); - }); - - it('should show default slot when loading is false', () => { - const wrapper = mount(KLoading, { - props: { - loading: false - }, - slots: { - default: '
Default content
' - } - }); - - expect(wrapper.find('.k-loading__spinner').exists()).toBe(false); - expect(wrapper.find('.default-content').exists()).toBe(true); - expect(wrapper.find('.default-content').text()).toBe('Default content'); - }); - - // 测试尺寸属性 - it('should apply correct size class', () => { - const sizeCases = [ - { size: 'small', expectedClass: 'k-loading--size-small' }, - { size: 'medium', expectedClass: 'k-loading--size-medium' }, - { size: 'large', expectedClass: 'k-loading--size-large' } - ]; - - sizeCases.forEach(({ size, expectedClass }) => { - const wrapper = mount(KLoading, { - props: { size } as LoadingProps - }); - - expect(wrapper.classes()).toContain(expectedClass); - expect(wrapper.find('.k-loading__icon').classes()).toContain(`k-loading__icon--${size}`); - }); - }); - - // 测试文字提示 - it('should display loading text when provided', () => { - const wrapper = mount(KLoading, { - props: { - text: 'Loading...' - } - }); - - expect(wrapper.find('.k-loading__text').exists()).toBe(true); - expect(wrapper.find('.k-loading__text').text()).toBe('Loading...'); - }); - - it('should not display text element when text is empty', () => { - const wrapper = mount(KLoading, { - props: { - text: '' - } - }); - - expect(wrapper.find('.k-loading__text').exists()).toBe(false); - }); - - // 测试垂直排列 - it('should apply vertical class when vertical is true', () => { - const wrapper = mount(KLoading, { - props: { - vertical: true, - text: 'Loading...' - } - }); - - expect(wrapper.classes()).toContain('k-loading--vertical'); - }); - - // 测试全屏模式 - it('should apply fullscreen class when fullscreen is true', () => { - const wrapper = mount(KLoading, { - props: { - fullscreen: true - } - }); - - expect(wrapper.classes()).toContain('k-loading--fullscreen'); - }); - - // 测试背景色 - it('should apply background color when provided', () => { - const wrapper = mount(KLoading, { - props: { - background: 'rgba(255, 255, 255, 0.8)' - } - }); - - expect(wrapper.attributes('style')).toContain('background-color: rgba(255, 255, 255, 0.8)'); - }); - - // 测试自定义图标 - it('should use custom spinner icon when provided', () => { - const wrapper = mount(KLoading, { - props: { - spinner: 'loading-ring' - } - }); - - expect(wrapper.findComponent({ name: 'KIcon' }).props('name')).toBe('loading-ring'); - }); - - // 测试spinner插槽 - it('should render custom spinner from slot', () => { - const wrapper = mount(KLoading, { - slots: { - spinner: '
Custom Spinner
' - } - }); - - expect(wrapper.find('.custom-spinner').exists()).toBe(true); - expect(wrapper.find('.custom-spinner').text()).toBe('Custom Spinner'); - expect(wrapper.findComponent({ name: 'KIcon' }).exists()).toBe(false); - }); - - // 测试text插槽 - it('should render custom text from slot', () => { - const wrapper = mount(KLoading, { - slots: { - text: 'Custom Text' - } - }); - - expect(wrapper.find('.k-loading__text').exists()).toBe(true); - expect(wrapper.find('.custom-text').exists()).toBe(true); - expect(wrapper.find('.custom-text').text()).toBe('Custom Text'); - }); - - // 测试组合属性 - it('should handle all props together correctly', () => { - const wrapper = mount(KLoading, { - props: { - size: 'large', - text: 'Processing...', - vertical: true, - background: '#f0f0f0', - spinner: 'refresh' - } - }); - - expect(wrapper.classes()).toContain('k-loading--size-large'); - expect(wrapper.classes()).toContain('k-loading--vertical'); - expect(wrapper.find('.k-loading__text').text()).toBe('Processing...'); - expect(wrapper.attributes('style')).toContain('background-color: #f0f0f0'); - expect(wrapper.findComponent({ name: 'KIcon' }).props('name')).toBe('refresh'); - }); - - // 快照测试 - it('should match snapshot with default props', () => { - const wrapper = mount(KLoading); - - expect(wrapper.html()).toMatchSnapshot(); - }); - - it('should match snapshot with all props', () => { - const wrapper = mount(KLoading, { - props: { - size: 'small', - text: 'Loading...', - vertical: true, - background: '#fff', - spinner: 'loading-dots' - } - }); - - expect(wrapper.html()).toMatchSnapshot(); - }); - - // 测试类型定义中存在但组件未直接使用的属性 - it('should accept lock and customClass props (from type definition)', () => { - const wrapper = mount(KLoading, { - props: { - lock: true, - customClass: 'test-custom-class' - } - }); - - // 验证组件不会因为这些属性而报错 - expect(wrapper.exists()).toBe(true); - }); - - // 测试delay属性(虽然组件中未直接实现延迟逻辑) - it('should accept delay prop', () => { - const wrapper = mount(KLoading, { - props: { - delay: 300 - } - }); - - // 验证组件不会因为delay属性而报错 - expect(wrapper.exists()).toBe(true); - }); - - // 测试color属性(虽然组件中未直接实现颜色逻辑) - it('should accept color prop', () => { - const wrapper = mount(KLoading, { - props: { - color: '#ff0000' - } - }); - - // 验证组件不会因为color属性而报错 - expect(wrapper.exists()).toBe(true); - }); -}); \ No newline at end of file diff --git a/src/components/Loading/index.vue b/src/components/Loading/index.vue index 5e23ec3..cb12edc 100644 --- a/src/components/Loading/index.vue +++ b/src/components/Loading/index.vue @@ -107,3 +107,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Message/index.scss b/src/components/Message/index.scss index d93cd9a..f6b7625 100644 --- a/src/components/Message/index.scss +++ b/src/components/Message/index.scss @@ -1,4 +1,5 @@ // Message组件样式 +@use "@/styles/index.scss" as *; .k-message { @@ -11,7 +12,7 @@ align-items: center; padding: 10px 16px; background-color: #fff; - border-radius: $border-radius-md; + border-radius: $rounded-md; box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); transition: all 0.3s; pointer-events: auto; @@ -19,31 +20,31 @@ &__icon { margin-right: 8px; - font-size: $font-size-md; + font-size: $text-base; flex-shrink: 0; } &__content { - color: $color-text-primary; - font-size: $font-size-md; + color: $gray-700; + font-size: $text-base; line-height: 1.5715; word-wrap: break-word; } &__close { margin-left: 8px; - color: $color-text-secondary; + color: $gray-400; background: transparent; border: none; outline: none; cursor: pointer; - font-size: $font-size-md; + font-size: $text-base; padding: 0; line-height: 1; transition: color 0.2s; &:hover { - color: $color-text-primary; + color: $gray-700; } } @@ -53,7 +54,7 @@ border: 1px solid #b7eb8f; .k-message__icon { - color: $color-success; + color: $success-color; } .k-message__content { @@ -66,7 +67,7 @@ border: 1px solid #91d5ff; .k-message__icon { - color: $color-info; + color: $info-color; } .k-message__content { @@ -79,7 +80,7 @@ border: 1px solid #ffe58f; .k-message__icon { - color: $color-warning; + color: $warning-color; } .k-message__content { @@ -92,7 +93,7 @@ border: 1px solid #ffccc7; .k-message__icon { - color: $color-danger; + color: $danger-color; } .k-message__content { @@ -105,7 +106,7 @@ border: 1px solid #91d5ff; .k-message__icon { - color: $color-info; + color: $info-color; animation: spin 1s linear infinite; } diff --git a/src/components/Message/index.vue b/src/components/Message/index.vue index 6657624..cbded1f 100644 --- a/src/components/Message/index.vue +++ b/src/components/Message/index.vue @@ -188,3 +188,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Notification/index.scss b/src/components/Notification/index.scss index aab853d..b695b5e 100644 --- a/src/components/Notification/index.scss +++ b/src/components/Notification/index.scss @@ -1,4 +1,5 @@ // Notification组件样式 +@use "@/styles/index.scss" as *; .k-notification { @@ -10,7 +11,7 @@ margin-right: 24px; padding: 16px; background: #fff; - border-radius: $border-radius-md; + border-radius: $rounded-md; box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); line-height: 1.5715; position: relative; @@ -22,7 +23,7 @@ } &__icon { - font-size: $font-size-lg; + font-size: $text-lg; line-height: 22px; margin-right: 12px; flex-shrink: 0; @@ -34,52 +35,52 @@ } &__title { - color: $color-text-primary; + color: $gray-700; font-weight: 500; - font-size: $font-size-md; + font-size: $text-base; margin-bottom: 4px; line-height: 22px; } &__description { - color: $color-text-secondary; - font-size: $font-size-sm; + color: $gray-400; + font-size: $text-sm; } &__close { position: absolute; top: 16px; right: 16px; - color: $color-text-secondary; + color: $gray-400; outline: none; border: none; background: transparent; cursor: pointer; - font-size: $font-size-md; + font-size: $text-base; padding: 0; line-height: 1; transition: color 0.2s; &:hover { - color: $color-text-primary; + color: $gray-700; } } // 类型样式 &--type-success &__icon { - color: $color-success; + color: $success-color; } &--type-info &__icon { - color: $color-info; + color: $info-color; } &--type-warning &__icon { - color: $color-warning; + color: $warning-color; } &--type-error &__icon { - color: $color-danger; + color: $danger-color; } // 位置样式 diff --git a/src/components/Notification/index.vue b/src/components/Notification/index.vue index c9e18e5..d5bffe0 100644 --- a/src/components/Notification/index.vue +++ b/src/components/Notification/index.vue @@ -224,3 +224,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Result/index.scss b/src/components/Result/index.scss index 7de3d6b..98ba2a3 100644 --- a/src/components/Result/index.scss +++ b/src/components/Result/index.scss @@ -1,37 +1,38 @@ // Result组件样式 +@use "@/styles/index.scss" as *; .k-result { box-sizing: border-box; margin: 0; padding: 0; - color: $color-text-primary; - font-size: $font-size-md; + color: $gray-700; + font-size: $text-base; line-height: 1.5715; text-align: center; // 状态样式 &--status-success { .k-result__icon-image { - color: $color-success; + color: $success-color; } } &--status-error { .k-result__icon-image { - color: $color-danger; + color: $danger-color; } } &--status-info { .k-result__icon-image { - color: $color-info; + color: $info-color; } } &--status-warning { .k-result__icon-image { - color: $color-warning; + color: $warning-color; } } @@ -39,7 +40,7 @@ &--status-403, &--status-500 { .k-result__icon-image { - color: $color-text-disabled; + color: $gray-300; } } @@ -53,14 +54,14 @@ &__title { margin-bottom: 16px; - color: $color-text-primary; + color: $gray-700; font-size: 24px; font-weight: 500; } &__subtitle { margin-bottom: 24px; - color: $color-text-secondary; + color: $gray-400; } &__extra { diff --git a/src/components/Result/index.vue b/src/components/Result/index.vue index a36540d..a4b7777 100644 --- a/src/components/Result/index.vue +++ b/src/components/Result/index.vue @@ -124,3 +124,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Space/index.scss b/src/components/Space/index.scss index ff902c4..ced2d03 100644 --- a/src/components/Space/index.scss +++ b/src/components/Space/index.scss @@ -1,4 +1,5 @@ // Space组件样式 +@use "@/styles/index.scss" as *; .k-space { diff --git a/src/components/Space/index.vue b/src/components/Space/index.vue index da4e5c5..a327bee 100644 --- a/src/components/Space/index.vue +++ b/src/components/Space/index.vue @@ -89,3 +89,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Tag/index.scss b/src/components/Tag/index.scss index 7d44050..cdfe33b 100644 --- a/src/components/Tag/index.scss +++ b/src/components/Tag/index.scss @@ -1,4 +1,5 @@ // Tag组件样式 +@use "@/styles/index.scss" as *; .k-tag { @@ -9,10 +10,10 @@ padding: 0 8px; font-size: 12px; line-height: 1; - border-radius: $border-radius-base; + border-radius: $rounded-md; white-space: nowrap; box-sizing: border-box; - transition: all $transition-duration $transition-timing-function; + transition: all $transition-normal; // 类型样式 &--default { @@ -22,33 +23,33 @@ } &--primary { - color: $color-primary; - background-color: rgba($color-primary, 0.1); - border: 1px solid rgba($color-primary, 0.2); + color: $primary-color; + background-color: rgba($primary-color, 0.1); + border: 1px solid rgba($primary-color, 0.2); } &--success { - color: $color-success; - background-color: rgba($color-success, 0.1); - border: 1px solid rgba($color-success, 0.2); + color: $success-color; + background-color: rgba($success-color, 0.1); + border: 1px solid rgba($success-color, 0.2); } &--warning { - color: $color-warning; - background-color: rgba($color-warning, 0.1); - border: 1px solid rgba($color-warning, 0.2); + color: $warning-color; + background-color: rgba($warning-color, 0.1); + border: 1px solid rgba($warning-color, 0.2); } &--danger { - color: $color-danger; - background-color: rgba($color-danger, 0.1); - border: 1px solid rgba($color-danger, 0.2); + color: $danger-color; + background-color: rgba($danger-color, 0.1); + border: 1px solid rgba($danger-color, 0.2); } &--info { - color: $color-info; - background-color: rgba($color-info, 0.1); - border: 1px solid rgba($color-info, 0.2); + color: $info-color; + background-color: rgba($info-color, 0.1); + border: 1px solid rgba($info-color, 0.2); } // 效果样式 @@ -62,23 +63,23 @@ } &--dark.k-tag--primary { - background-color: $color-primary; + background-color: $primary-color; } &--dark.k-tag--success { - background-color: $color-success; + background-color: $success-color; } &--dark.k-tag--warning { - background-color: $color-warning; + background-color: $warning-color; } &--dark.k-tag--danger { - background-color: $color-danger; + background-color: $danger-color; } &--dark.k-tag--info { - background-color: $color-info; + background-color: $info-color; } &--plain { @@ -129,7 +130,7 @@ font-size: 12px; cursor: pointer; border-radius: 50%; - transition: all $transition-duration $transition-timing-function; + transition: all $transition-normal; &:hover { background-color: rgba(0, 0, 0, 0.1); diff --git a/src/components/Tag/index.vue b/src/components/Tag/index.vue index 70926f2..99c6464 100644 --- a/src/components/Tag/index.vue +++ b/src/components/Tag/index.vue @@ -117,3 +117,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/Text/index.scss b/src/components/Text/index.scss index f7ed8b2..7574a98 100644 --- a/src/components/Text/index.scss +++ b/src/components/Text/index.scss @@ -1,61 +1,62 @@ // Text组件样式 +@use "@/styles/index.scss" as *; .k-text { display: inline; word-wrap: break-word; user-select: text; - transition: color $transition-duration $transition-timing-function; + transition: color $transition-normal; // 类型样式 &--type-default { - color: $color-text-primary; + color: $gray-700; } &--type-primary { - color: $color-primary; + color: $primary-color; } &--type-secondary { - color: $color-text-secondary; + color: $gray-400; } &--type-success { - color: $color-success; + color: $success-color; } &--type-warning { - color: $color-warning; + color: $warning-color; } &--type-danger { - color: $color-danger; + color: $danger-color; } &--type-info { - color: $color-info; + color: $info-color; } // 尺寸样式 &--size-small { - font-size: $font-size-sm; + font-size: $text-sm; } &--size-medium { - font-size: $font-size-md; + font-size: $text-base; } &--size-large { - font-size: $font-size-lg; + font-size: $text-lg; } // 自定义尺寸 &--size-xs { - font-size: $font-size-xs; + font-size: $text-xs; } &--size-xl { - font-size: $font-size-xl; + font-size: $text-xl; } // 字重样式 @@ -109,15 +110,15 @@ margin: 0 2px; font-family: 'Courier New', monospace; font-size: 0.9em; - background-color: $color-bg-container; - border: 1px solid $color-border; - border-radius: $border-radius-sm; + background-color: $white; + border: 1px solid $gray-200; + border-radius: $rounded-sm; } &--mark { padding: 0 2px; background-color: #fffbe6; - border-radius: $border-radius-sm; + border-radius: $rounded-sm; } &--strong { @@ -125,7 +126,7 @@ } &--disabled { - color: $color-text-disabled; + color: $gray-300; cursor: not-allowed; } @@ -134,7 +135,7 @@ position: relative; &:hover { - color: $color-primary; + color: $primary-color; } } diff --git a/src/components/Text/index.vue b/src/components/Text/index.vue index b06ae8b..f5641de 100644 --- a/src/components/Text/index.vue +++ b/src/components/Text/index.vue @@ -115,3 +115,7 @@ export default defineComponent({ } }); + + diff --git a/src/components/index.ts b/src/components/index.ts index f2ce505..91ae219 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,44 +1,44 @@ // 基础视觉系统组件 -export { default as Button } from './Button'; -export { default as Icon } from './Icon'; -export { default as Text } from './Text'; -export { default as Divider } from './Divider'; -export { default as Avatar} from './Avatar'; -export { default as Tag } from './Tag'; -export { default as Image } from './Image'; +export { default as KButton } from './Button'; +export { default as KIcon } from './Icon'; +export { default as KText } from './Text'; +export { default as KDivider } from './Divider'; +export { default as KAvatar } from './Avatar'; +export { default as KTag } from './Tag'; +export { default as KImage } from './Image'; // 布局容器组件 -export { default as Container } from './Container'; -export { default as Grid } from './Grid'; -export { default as Space } from './Space'; +export { default as KContainer } from './Container'; +export { default as KGrid } from './Grid'; +export { default as KSpace } from './Space'; // 通用反馈类组件 -export { default as ChatBubble } from './ChatBubble'; -export { default as Message } from './Message'; -export { default as Notification } from './Notification'; -export { default as Loading } from './Loading'; -export { default as Result } from './Result'; -export { default as Empty } from './Empty'; +export { default as KChatBubble } from './ChatBubble'; +export { default as KMessage } from './Message'; +export { default as KNotification } from './Notification'; +export { default as KLoading } from './Loading'; +export { default as KResult } from './Result'; +export { default as KEmpty } from './Empty'; // 以下组件后续将从 Element Plus 中引入,暂时注释 -// export { default as Alert } from './Alert'; -// export { default as Card } from './Card'; -// export { default as Collapse } from './Collapse'; -// export { default as Dialog } from './Dialog'; -// export { default as Drawer } from './Drawer'; -// export { default as Tooltip } from './Tooltip'; -// export { default as Switch } from './Switch'; -// export { default as Table } from './Table'; -// export { default as Tabs } from './Tabs'; -// export { default as Upload } from './Upload'; -// export { default as Badge } from './Badge'; -// export { default as Progress } from './Progress'; -// export { default as Checkbox } from './Checkbox'; -// export { default as Radio } from './Radio'; -// export { default as Slider } from './Slider'; -// export { default as Rate } from './Rate'; -// export { default as Select } from './Select'; -// export { default as Input } from './Input'; -// export { default as Popconfirm } from './Popconfirm'; -// export { default as Dropdown } from './Dropdown'; -// export { default as Pagination } from './Pagination'; +// export { default as KAlert } from './Alert'; +// export { default as KCard } from './Card'; +// export { default as KCollapse } from './Collapse'; +// export { default as KDialog } from './Dialog'; +// export { default as KDrawer } from './Drawer'; +// export { default as KTooltip } from './Tooltip'; +// export { default as KSwitch } from './Switch'; +// export { default as KTable } from './Table'; +// export { default asKTabs } from './Tabs'; +// export { default as KUpload } from './Upload'; +// export { default as KBadge } from './Badge'; +// export { default as KProgress } from './Progress'; +// export { default as KCheckbox } from './Checkbox'; +// export { default as KRadio } from './Radio'; +// export { default as KSlider } from './Slider'; +// export { default as KRate } from './Rate'; +// export { default as KSelect } from './Select'; +// export { default as KInput } from './Input'; +// export { default as KPopconfirm } from './Popconfirm'; +// export { default as KDropdown } from './Dropdown'; +// export { default as KPagination } from './Pagination'; diff --git a/src/index.ts b/src/index.ts index fd708a8..467122f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,26 +4,26 @@ import * as Components from './components/index'; // 组件列表 const components = [ // 基础视觉系统组件(保留) - Components.Button, - Components.Icon, - Components.Text, - Components.Divider, - Components.Avatar, - Components.Tag, - Components.Image, + Components.KButton, + Components.KIcon, + Components.KText, + Components.KDivider, + Components.KAvatar, + Components.KTag, + Components.KImage, // 布局容器组件(保留) - Components.Container, - Components.Grid, - Components.Space, + Components.KContainer, + Components.KGrid, + Components.KSpace, // 通用反馈类组件(保留) - Components.ChatBubble, - Components.Message, - Components.Notification, - Components.Loading, - Components.Result, - Components.Empty + Components.KChatBubble, + Components.KMessage, + Components.KNotification, + Components.KLoading, + Components.KResult, + Components.KEmpty ]; // 安装函数 diff --git a/src/styles/index.scss b/src/styles/index.scss index 3695a1c..980b7d1 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -1,5 +1,9 @@ // KnowAI UI组件库基础样式 +// 引入SCSS变量系统 +@forward './variables.scss'; +@use './variables.scss' as *; + // 重置样式 *, *::before, diff --git a/tsconfig.json b/tsconfig.json index 4dbde0b..3537619 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,10 @@ "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, - "noEmit": true, + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "declarationDir": "dist/types", "jsx": "preserve", "strict": true, "noUnusedLocals": true, diff --git a/vite.config.ts b/vite.config.ts index 9b935e4..96fa794 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,21 +12,16 @@ export default defineConfig({ '~': fileURLToPath(new URL('./src', import.meta.url)) } }, - css: { - preprocessorOptions: { - // 全局引入variable.scss - scss: { - additionalData: `@import "@/styles/variables.scss";` - } - } - }, build: { // 构建为库模式 lib: { entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)), - name: 'KnowAIUI', + name: 'knowaiUi', fileName: (format) => `knowai-ui.${format}.js` }, + // 输出目录 + outDir: 'dist/client', + emptyOutDir: false, rollupOptions: { // 不打包进库 external: ['vue'],