From b180cd8900bc9e5c50c4713670f0208610622c40 Mon Sep 17 00:00:00 2001 From: Kirk Lin Date: Mon, 8 Jan 2024 01:10:54 +0800 Subject: [PATCH] feat: add search anywhere --- apps/admin/autoResolver/auto-imports.d.ts | 3 + apps/admin/autoResolver/components.d.ts | 5 +- apps/admin/package.json | 1 + .../admin/src/component/SearchDialog/index.ts | 4 + .../SearchDialog/src/SearchDialog.vue | 304 ++++++++++++++++++ .../src/component/SearchDialog/src/types.ts | 15 + apps/admin/src/composables/useSearchDialog.ts | 16 + .../header/components/SearchAnyWhere.vue | 70 ++++ apps/admin/src/layouts/header/index.vue | 24 +- apps/admin/src/layouts/index.vue | 2 + apps/admin/src/locales/en.json | 11 + apps/admin/src/locales/zh.json | 11 + apps/admin/src/store/modules/design/index.ts | 6 +- .../src/store/modules/design/themeUtils.ts | 3 + packages/web/styles/src/index.css | 2 + packages/web/styles/src/mark.css | 6 + packages/web/styles/src/naive-override.css | 21 ++ packages/web/utils/src/color/utils.ts | 5 + pnpm-lock.yaml | 16 + 19 files changed, 508 insertions(+), 17 deletions(-) create mode 100644 apps/admin/src/component/SearchDialog/index.ts create mode 100644 apps/admin/src/component/SearchDialog/src/SearchDialog.vue create mode 100644 apps/admin/src/component/SearchDialog/src/types.ts create mode 100644 apps/admin/src/composables/useSearchDialog.ts create mode 100644 apps/admin/src/layouts/header/components/SearchAnyWhere.vue create mode 100644 packages/web/styles/src/mark.css create mode 100644 packages/web/styles/src/naive-override.css diff --git a/apps/admin/autoResolver/auto-imports.d.ts b/apps/admin/autoResolver/auto-imports.d.ts index b4a9edf..116de8c 100644 --- a/apps/admin/autoResolver/auto-imports.d.ts +++ b/apps/admin/autoResolver/auto-imports.d.ts @@ -248,6 +248,7 @@ declare global { const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] const useScroll: typeof import('@vueuse/core')['useScroll'] const useScrollLock: typeof import('@vueuse/core')['useScrollLock'] + const useSearchDialog: typeof import('../src/composables/useSearchDialog')['useSearchDialog'] const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] const useShare: typeof import('@vueuse/core')['useShare'] const useSlots: typeof import('vue')['useSlots'] @@ -558,6 +559,7 @@ declare module 'vue' { readonly useScriptTag: UnwrapRef readonly useScroll: UnwrapRef readonly useScrollLock: UnwrapRef + readonly useSearchDialog: UnwrapRef readonly useSessionStorage: UnwrapRef readonly useShare: UnwrapRef readonly useSlots: UnwrapRef @@ -861,6 +863,7 @@ declare module '@vue/runtime-core' { readonly useScriptTag: UnwrapRef readonly useScroll: UnwrapRef readonly useScrollLock: UnwrapRef + readonly useSearchDialog: UnwrapRef readonly useSessionStorage: UnwrapRef readonly useShare: UnwrapRef readonly useSlots: UnwrapRef diff --git a/apps/admin/autoResolver/components.d.ts b/apps/admin/autoResolver/components.d.ts index 8d0550f..3ddcc28 100644 --- a/apps/admin/autoResolver/components.d.ts +++ b/apps/admin/autoResolver/components.d.ts @@ -31,26 +31,25 @@ declare module 'vue' { NGrid: typeof import('@celeris/ca-components')['NGrid'] NGridItem: typeof import('@celeris/ca-components')['NGridItem'] NInput: typeof import('@celeris/ca-components')['NInput'] - NInputGroup: typeof import('@celeris/ca-components')['NInputGroup'] NLayout: typeof import('@celeris/ca-components')['NLayout'] NLayoutContent: typeof import('@celeris/ca-components')['NLayoutContent'] NLayoutSider: typeof import('@celeris/ca-components')['NLayoutSider'] NLoadingBarProvider: typeof import('@celeris/ca-components')['NLoadingBarProvider'] NMenu: typeof import('@celeris/ca-components')['NMenu'] NMessageProvider: typeof import('@celeris/ca-components')['NMessageProvider'] + NModal: typeof import('@celeris/ca-components')['NModal'] NNotificationProvider: typeof import('@celeris/ca-components')['NNotificationProvider'] - NPopconfirm: typeof import('@celeris/ca-components')['NPopconfirm'] NPopover: typeof import('@celeris/ca-components')['NPopover'] NResult: typeof import('@celeris/ca-components')['NResult'] NScrollbar: typeof import('@celeris/ca-components')['NScrollbar'] NSelect: typeof import('@celeris/ca-components')['NSelect'] NSpace: typeof import('@celeris/ca-components')['NSpace'] - NSpin: typeof import('@celeris/ca-components')['NSpin'] NSplit: typeof import('@celeris/ca-components')['NSplit'] NStep: typeof import('@celeris/ca-components')['NStep'] NSteps: typeof import('@celeris/ca-components')['NSteps'] NSwitch: typeof import('@celeris/ca-components')['NSwitch'] NTable: typeof import('@celeris/ca-components')['NTable'] + NText: typeof import('@celeris/ca-components')['NText'] NTooltip: typeof import('@celeris/ca-components')['NTooltip'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/apps/admin/package.json b/apps/admin/package.json index 29a24c1..c40a8d5 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -44,6 +44,7 @@ "pinia-plugin-persistedstate": "^3.2.1", "pkg-types": "^1.0.3", "vue": "^3.4.5", + "vue-highlight-words": "^3.0.1", "vue-i18n": "^9.8.0", "vue-router": "^4.2.5" }, diff --git a/apps/admin/src/component/SearchDialog/index.ts b/apps/admin/src/component/SearchDialog/index.ts new file mode 100644 index 0000000..765e943 --- /dev/null +++ b/apps/admin/src/component/SearchDialog/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from "@celeris/utils"; +import searchDialog from "./src/SearchDialog.vue"; + +export const SearchDialog = withInstall(searchDialog); diff --git a/apps/admin/src/component/SearchDialog/src/SearchDialog.vue b/apps/admin/src/component/SearchDialog/src/SearchDialog.vue new file mode 100644 index 0000000..07e3e36 --- /dev/null +++ b/apps/admin/src/component/SearchDialog/src/SearchDialog.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/apps/admin/src/component/SearchDialog/src/types.ts b/apps/admin/src/component/SearchDialog/src/types.ts new file mode 100644 index 0000000..77014ae --- /dev/null +++ b/apps/admin/src/component/SearchDialog/src/types.ts @@ -0,0 +1,15 @@ +export interface SearchGroupItem { + iconName: string | null; + iconImage: string | null; + key: number | string; + title: string; + label: string; + tags?: string; + action: () => void; +} + +export interface SearchGroup { + name: string; + items: SearchGroupItem[]; +} +export type SearchGroups = SearchGroup[]; diff --git a/apps/admin/src/composables/useSearchDialog.ts b/apps/admin/src/composables/useSearchDialog.ts new file mode 100644 index 0000000..8548148 --- /dev/null +++ b/apps/admin/src/composables/useSearchDialog.ts @@ -0,0 +1,16 @@ +import { ref } from "vue"; +import { isWindows } from "@celeris/utils"; + +const listener = ref(); +export function useSearchDialog() { + const commandIcon = ref(isWindows() ? "CTRL" : "⌘"); + return { + commandIcon, + trigger: (cb: () => void): void => { + listener.value = cb; + }, + open: (): void => { + listener.value && listener.value(); + }, + }; +} diff --git a/apps/admin/src/layouts/header/components/SearchAnyWhere.vue b/apps/admin/src/layouts/header/components/SearchAnyWhere.vue new file mode 100644 index 0000000..2ce05b3 --- /dev/null +++ b/apps/admin/src/layouts/header/components/SearchAnyWhere.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/apps/admin/src/layouts/header/index.vue b/apps/admin/src/layouts/header/index.vue index 2411a15..95fae0e 100644 --- a/apps/admin/src/layouts/header/index.vue +++ b/apps/admin/src/layouts/header/index.vue @@ -5,6 +5,7 @@ import LocaleSwitcher from "~/layouts/header/components/LocaleSwitcher.vue"; import UserInfoButton from "~/layouts/header/components/UserInfoButton.vue"; import SettingButton from "~/layouts/setting/index.vue"; import Breadcrumb from "~/layouts/header/components/Breadcrumb.vue"; +import SearchAnyWhere from "~/layouts/header/components/SearchAnyWhere.vue"; defineOptions({ name: "HeaderLayout", @@ -13,24 +14,25 @@ defineOptions({ diff --git a/apps/admin/src/locales/en.json b/apps/admin/src/locales/en.json index c003fa3..f94c02d 100644 --- a/apps/admin/src/locales/en.json +++ b/apps/admin/src/locales/en.json @@ -89,6 +89,17 @@ "onPositiveClickMessage": "Logout successful" } }, + "searchDialog": { + "searchPlaceholder": "Search", + "noResultsFound": "Sorry, no results found for { search }", + "toSelectTooltip": "to select", + "toNavigateTooltip": "to navigate", + "applications": "Applications", + "chatBot": "ChatBot", + "action": "Action", + "actions": "Actions", + "shortcut": "Shortcut" + }, "page": { "login": { "title": "Login", diff --git a/apps/admin/src/locales/zh.json b/apps/admin/src/locales/zh.json index faad357..0472c45 100644 --- a/apps/admin/src/locales/zh.json +++ b/apps/admin/src/locales/zh.json @@ -89,6 +89,17 @@ "onPositiveClickMessage": "退出登录成功" } }, + "searchDialog": { + "searchPlaceholder": "搜索", + "noResultsFound": "抱歉,未找到符合 { search } 的结果", + "toSelectTooltip": "选择", + "toNavigateTooltip": "导航", + "applications": "应用程序", + "chatBot": "ChatBot", + "actions": "操作列表", + "action": "操作", + "shortcut": "快捷方式" + }, "page": { "login": { "title": "登录", diff --git a/apps/admin/src/store/modules/design/index.ts b/apps/admin/src/store/modules/design/index.ts index 4526ed1..112f166 100644 --- a/apps/admin/src/store/modules/design/index.ts +++ b/apps/admin/src/store/modules/design/index.ts @@ -3,7 +3,7 @@ import { deepMerge } from "@celeris/utils"; import { defineStore } from "pinia"; import { APP_DESIGN_STORE_ID } from "@celeris/constants"; import type { GlobalTheme, GlobalThemeOverrides } from "naive-ui"; -import { darkTheme } from "naive-ui"; +import { darkTheme, lightTheme } from "naive-ui"; import { getNaiveUICustomTheme } from "./themeUtils"; import { DEFAULT_THEME_SETTING } from "~/setting/themeSetting"; @@ -28,8 +28,8 @@ export const useDesignStore = defineStore({ return state.themeSetting; }, // 获取Naive UI 预设主题 - getNaiveUIPresetTheme(): GlobalTheme | null { - return this.getDarkMode ? darkTheme : null; + getNaiveUIPresetTheme(): GlobalTheme { + return this.getDarkMode ? darkTheme : lightTheme; }, // 获取Naive UI 自定义主题 getNaiveUICustomTheme(state): GlobalThemeOverrides | null { diff --git a/apps/admin/src/store/modules/design/themeUtils.ts b/apps/admin/src/store/modules/design/themeUtils.ts index 2c18bc7..21c1514 100644 --- a/apps/admin/src/store/modules/design/themeUtils.ts +++ b/apps/admin/src/store/modules/design/themeUtils.ts @@ -117,12 +117,15 @@ function getTextColor(darkMode: boolean): string { return darkMode ? commonDark.textColor2 : commonLight.baseColor; } function getOtherTheme(_darkMode: boolean): GlobalThemeOverrides { + const naiveTheme = useThemeSetting().getNaiveUIPresetTheme.value; return { common: { borderRadius: "0.5rem", + borderRadiusSmall: "0.25rem", cubicBezierEaseInOut: "cubic-bezier(0.65, 0, 0.35, 1)", cubicBezierEaseOut: "cubic-bezier(0.33, 1, 0.68, 1)", cubicBezierEaseIn: "cubic-bezier(0.32, 0, 0.67, 0)", + modalColor: naiveTheme?.common?.modalColor, }, Card: { borderRadius: "1rem", diff --git a/packages/web/styles/src/index.css b/packages/web/styles/src/index.css index db423d4..cc82006 100644 --- a/packages/web/styles/src/index.css +++ b/packages/web/styles/src/index.css @@ -1,3 +1,5 @@ +@import "naive-override.css"; +@import "mark.css"; @import "transition.css"; html{ diff --git a/packages/web/styles/src/mark.css b/packages/web/styles/src/mark.css new file mode 100644 index 0000000..8c25b43 --- /dev/null +++ b/packages/web/styles/src/mark.css @@ -0,0 +1,6 @@ +mark { + padding: 2px 0px; + border-radius: var(--border-radius-small); + background-color: var(--primary-color); + color: var(--text-color-base); +} diff --git a/packages/web/styles/src/naive-override.css b/packages/web/styles/src/naive-override.css new file mode 100644 index 0000000..b678ad9 --- /dev/null +++ b/packages/web/styles/src/naive-override.css @@ -0,0 +1,21 @@ +.ca-modal-mask { + backdrop-filter: blur(5px); +} +.ca-modal, +.ca-card.ca-modal[role] { + background-color: rgba(var(--modal-color), 0.6); + backdrop-filter: blur(20px); + max-width: 90%; + margin: 10vh auto; +} + +.ca-image-preview-overlay { + backdrop-filter: blur(5px); +} + +.ca-slider { + box-sizing: content-box; +} +.ca-calendar * { + box-sizing: content-box; +} diff --git a/packages/web/utils/src/color/utils.ts b/packages/web/utils/src/color/utils.ts index cab5235..47e7176 100644 --- a/packages/web/utils/src/color/utils.ts +++ b/packages/web/utils/src/color/utils.ts @@ -12,3 +12,8 @@ export function isBlackColor(color: string) { export function colorToRgb(color: string): RgbaColor { return colord(color).toRgb(); } + +export function colorToRgbString(color: string) { + const rgba = colord(color).toRgb(); + return [rgba.r, rgba.g, rgba.b].join(", "); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05cbc33..b6fbbf7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: vue: specifier: ^3.4.5 version: 3.4.5(typescript@5.3.3) + vue-highlight-words: + specifier: ^3.0.1 + version: 3.0.1(vue@3.4.5) vue-i18n: specifier: ^9.8.0 version: 9.8.0(vue@3.4.5) @@ -8059,6 +8062,10 @@ packages: hasBin: true dev: true + /highlight-words-core@1.2.2: + resolution: {integrity: sha512-BXUKIkUuh6cmmxzi5OIbUJxrG8OAk2MqoL1DtO3Wo9D2faJg2ph5ntyuQeLqaHJmzER6H5tllCDA9ZnNe9BVGg==} + dev: false + /highlight.js@11.8.0: resolution: {integrity: sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==} engines: {node: '>=12.0.0'} @@ -12794,6 +12801,15 @@ packages: vue: 3.4.5(typescript@5.3.3) dev: false + /vue-highlight-words@3.0.1(vue@3.4.5): + resolution: {integrity: sha512-t6L0+KRaMzX5RVubWl6Sog+Aa+U0kHsbUlDIrln1VfajR2SEg+zQYfXov8UmX3MLNOfd6cv7MCM6LclqNlW4ww==} + peerDependencies: + vue: ^3.0.0 + dependencies: + highlight-words-core: 1.2.2 + vue: 3.4.5(typescript@5.3.3) + dev: false + /vue-i18n@9.8.0(vue@3.4.5): resolution: {integrity: sha512-Izho+6PYjejsTq2mzjcRdBZ5VLRQoSuuexvR8029h5CpN03FYqiqBrShMyf2I1DKkN6kw/xmujcbvC+4QybpsQ==} engines: {node: '>= 16'}