diff --git a/locales/en.yaml b/locales/en.yaml index e21ed9769..ce91b53cc 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -45,6 +45,7 @@ menus: hsmap: Map hsdraggable: Draggable hssplitPane: Split Pane + hsText: Text Ellipsis hsElButton: Button hsbutton: Button Animation hsCheckButton: Check Button diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index 0343f084d..2875bb638 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -45,6 +45,7 @@ menus: hsmap: 地图 hsdraggable: 拖拽 hssplitPane: 切割面板 + hsText: 文本省略 hsElButton: 按钮 hsCheckButton: 可选按钮 hsbutton: 按钮动效 diff --git a/src/components/ReCropper/src/circled.css b/src/components/ReCropper/src/circled.css index d9216c4f1..54c77d23f 100644 --- a/src/components/ReCropper/src/circled.css +++ b/src/components/ReCropper/src/circled.css @@ -1,4 +1,3 @@ -@import "tippy.js/themes/light.css"; @import "cropperjs/dist/cropper.css"; .re-circled { diff --git a/src/components/ReText/index.ts b/src/components/ReText/index.ts new file mode 100644 index 000000000..621356605 --- /dev/null +++ b/src/components/ReText/index.ts @@ -0,0 +1,7 @@ +import reText from "./src/index.vue"; +import { withInstall } from "@pureadmin/utils"; + +/** 支持`Tooltip`提示的文本省略组件 */ +export const ReText = withInstall(reText); + +export default ReText; diff --git a/src/components/ReText/src/index.vue b/src/components/ReText/src/index.vue new file mode 100644 index 000000000..1b34178f4 --- /dev/null +++ b/src/components/ReText/src/index.vue @@ -0,0 +1,62 @@ + + + diff --git a/src/components/ReTypeit/index.ts b/src/components/ReTypeit/index.ts index 4c34bae62..dd6f2ca49 100644 --- a/src/components/ReTypeit/index.ts +++ b/src/components/ReTypeit/index.ts @@ -1,44 +1,8 @@ -import { h, defineComponent } from "vue"; -import TypeIt from "typeit"; +import typeIt from "./src/index"; +import type { TypeItOptions } from "typeit"; -// 打字机效果组件(只是简单的封装下,更多配置项参考 https://www.typeitjs.com/docs/vanilla/usage#options) -export default defineComponent({ - name: "TypeIt", - props: { - /** 打字速度,以每一步之间的毫秒数为单位,默认`200` */ - speed: { - type: Number, - default: 200 - }, - values: { - type: Array, - defalut: [] - }, - className: { - type: String, - default: "type-it" - }, - cursor: { - type: Boolean, - default: true - } - }, - render() { - return h( - "span", - { - class: this.className - }, - { - default: () => [] - } - ); - }, - mounted() { - new TypeIt(`.${this.className}`, { - strings: this.values, - speed: this.speed, - cursor: this.cursor - }).go(); - } -}); +const TypeIt = typeIt; + +export { TypeIt, TypeItOptions }; + +export default TypeIt; diff --git a/src/components/ReTypeit/src/index.tsx b/src/components/ReTypeit/src/index.tsx new file mode 100644 index 000000000..9e61b85ca --- /dev/null +++ b/src/components/ReTypeit/src/index.tsx @@ -0,0 +1,56 @@ +import type { El } from "typeit/dist/types"; +import TypeIt, { type TypeItOptions } from "typeit"; +import { ref, defineComponent, onMounted, type PropType } from "vue"; + +// 打字机效果组件(配置项详情请查阅 https://www.typeitjs.com/docs/vanilla/usage#options) +export default defineComponent({ + name: "TypeIt", + props: { + options: { + type: Object as PropType, + default: () => ({}) as TypeItOptions + } + }, + setup(props, { slots, expose }) { + /** + * 输出错误信息 + * @param message 错误信息 + */ + function throwError(message: string) { + throw new TypeError(message); + } + + /** + * 获取浏览器默认语言 + */ + function getBrowserLanguage() { + return navigator.language; + } + + const typedItRef = ref(null); + + onMounted(() => { + const $typed = typedItRef.value!.querySelector(".type-it") as El; + + if (!$typed) { + const errorMsg = + getBrowserLanguage() === "zh-CN" + ? "请确保有且只有一个具有class属性为 'type-it' 的元素" + : "Please make sure that there is only one element with a Class attribute with 'type-it'"; + throwError(errorMsg); + } + + const typeIt = new TypeIt($typed, props.options).go(); + + expose({ + typeIt + }); + }); + + return () => ( +
+ {slots.default?.() ?? } +
+ ); + } +}); diff --git a/src/layout/components/sidebar/sidebarItem.vue b/src/layout/components/sidebar/sidebarItem.vue index dd40645c1..be0b9c01f 100644 --- a/src/layout/components/sidebar/sidebarItem.vue +++ b/src/layout/components/sidebar/sidebarItem.vue @@ -3,10 +3,12 @@ import path from "path"; import { getConfig } from "@/config"; import { menuType } from "../../types"; import extraIcon from "./extraIcon.vue"; +import { useDark } from "@pureadmin/utils"; +import { ReText } from "@/components/ReText"; import { useNav } from "@/layout/hooks/useNav"; import { transformI18n } from "@/plugins/i18n"; import { useRenderIcon } from "@/components/ReIcon/src/hooks"; -import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue"; +import { type CSSProperties, type PropType, computed, ref, toRaw } from "vue"; import ArrowUp from "@iconify-icons/ep/arrow-up-bold"; import EpArrowDown from "@iconify-icons/ep/arrow-down-bold"; @@ -14,6 +16,7 @@ import ArrowLeft from "@iconify-icons/ep/arrow-left-bold"; import ArrowRight from "@iconify-icons/ep/arrow-right-bold"; const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav(); +const { isDark } = useDark(); const props = defineProps({ item: { @@ -29,13 +32,6 @@ const props = defineProps({ } }); -const getSpanStyle = computed((): CSSProperties => { - return { - width: "100%", - textAlign: "center" - }; -}); - const getNoDropdownStyle = computed((): CSSProperties => { return { display: "flex", @@ -43,15 +39,7 @@ const getNoDropdownStyle = computed((): CSSProperties => { }; }); -const getMenuTextStyle = computed(() => { - return { - overflow: "hidden", - textOverflow: "ellipsis", - outline: "none" - }; -}); - -const getsubMenuIconStyle = computed((): CSSProperties => { +const getSubMenuIconStyle = computed((): CSSProperties => { return { display: "flex", justifyContent: "center", @@ -65,43 +53,6 @@ const getsubMenuIconStyle = computed((): CSSProperties => { }; }); -const getSubTextStyle = computed((): CSSProperties => { - if (!isCollapse.value) { - return { - width: "210px", - display: "inline-block", - overflow: "hidden", - textOverflow: "ellipsis" - }; - } else { - return { - width: "" - }; - } -}); - -const getSubMenuDivStyle = computed((): any => { - return item => { - return !isCollapse.value - ? { - width: "100%", - display: "flex", - alignItems: "center", - justifyContent: "space-between", - overflow: "hidden" - } - : { - width: "100%", - textAlign: - item?.parentId === null - ? "center" - : layout.value === "mix" && item?.pathList?.length === 2 - ? "center" - : "" - }; - }; -}); - const expandCloseIcon = computed(() => { if (!getConfig()?.MenuArrowIconNoTransition) return ""; return { @@ -113,41 +64,6 @@ const expandCloseIcon = computed(() => { }); const onlyOneChild: menuType = ref(null); -// 存放菜单是否存在showTooltip属性标识 -const hoverMenuMap = new WeakMap(); -// 存储菜单文本dom元素 -const menuTextRef = ref(null); - -function hoverMenu(key) { - // 如果当前菜单showTooltip属性已存在,退出计算 - if (hoverMenuMap.get(key)) return; - - nextTick(() => { - // 如果文本内容的整体宽度大于其可视宽度,则文本溢出 - menuTextRef.value?.scrollWidth > menuTextRef.value?.clientWidth - ? Object.assign(key, { - showTooltip: true - }) - : Object.assign(key, { - showTooltip: false - }); - hoverMenuMap.set(key, true); - }); -} - -// 左侧菜单折叠后,当菜单没有图标时只显示第一个文字并加上省略号 -function overflowSlice(text, item?: any) { - const newText = - (text?.length > 1 ? text.toString().slice(0, 1) : text) + "..."; - if (item && !(isCollapse.value && item?.parentId === null)) { - return layout.value === "mix" && - item?.pathList?.length === 2 && - isCollapse.value - ? newText - : text; - } - return newText; -} function hasOneShowingChild(children: menuType[] = [], parent: menuType) { const showingChildren = children.filter((item: any) => { @@ -194,7 +110,7 @@ function resolvePath(routePath) { - - {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }} - - - {{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }} - + {{ transformI18n(onlyOneChild.meta.title) }} + + @@ -264,48 +163,38 @@ function resolvePath(routePath) { { app.directive(key, (directives as { [key: string]: Directive })[key]); }); -// 全局注册`@iconify/vue`图标库 +// 全局注册@iconify/vue图标库 import { IconifyIconOffline, IconifyIconOnline, @@ -45,13 +45,11 @@ app.component("FontIcon", FontIcon); import { Auth } from "@/components/ReAuth"; app.component("Auth", Auth); -// 全局注册`vue-tippy` +// 全局注册vue-tippy import "tippy.js/dist/tippy.css"; -import "tippy.js/animations/perspective.css"; +import "tippy.js/themes/light.css"; import VueTippy from "vue-tippy"; -app.use(VueTippy, { - defaultProps: { animation: "perspective" } -}); +app.use(VueTippy); getPlatformConfig(app).then(async config => { setupStore(app); diff --git a/src/router/modules/components.ts b/src/router/modules/components.ts index 485d0432a..a73d3517a 100644 --- a/src/router/modules/components.ts +++ b/src/router/modules/components.ts @@ -91,6 +91,15 @@ export default { title: $t("menus.hssegmented") } }, + { + path: "/components/text", + name: "PureText", + component: () => import("@/views/components/text.vue"), + meta: { + title: $t("menus.hsText"), + extraIcon: "IF-pure-iconfont-new svg" + } + }, { path: "/components/el-button", name: "PureButton", diff --git a/src/views/able/typeit.vue b/src/views/able/typeit.vue index c79820755..3c0d24f70 100644 --- a/src/views/able/typeit.vue +++ b/src/views/able/typeit.vue @@ -1,9 +1,13 @@ - + diff --git a/src/views/components/text.vue b/src/views/components/text.vue new file mode 100644 index 000000000..f988620ed --- /dev/null +++ b/src/views/components/text.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 0be17a3e5..20ff66fe3 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -166,7 +166,9 @@ watch(loginDay, value => {

- +