mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2026-01-20 16:53:37 +08:00
feat: add iconSelect component
This commit is contained in:
6139
src/components/ReIcon/data.ts
Normal file
6139
src/components/ReIcon/data.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,16 @@
|
||||
import iconifyIconOffline from "./src/iconifyIconOffline";
|
||||
import iconifyIconOnline from "./src/iconifyIconOnline";
|
||||
import fontIcon from "./src/iconfont";
|
||||
import iconSelect from "./src/select.vue";
|
||||
|
||||
export const IconifyIconOffline = iconifyIconOffline;
|
||||
export const IconifyIconOnline = iconifyIconOnline;
|
||||
export const FontIcon = fontIcon;
|
||||
export const IconSelect = iconSelect;
|
||||
|
||||
export default {
|
||||
IconifyIconOffline,
|
||||
IconifyIconOnline,
|
||||
FontIcon
|
||||
FontIcon,
|
||||
IconSelect
|
||||
};
|
||||
|
||||
@@ -60,12 +60,16 @@ import logoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
|
||||
import nodeTree from "@iconify-icons/ri/node-tree";
|
||||
import ubuntuFill from "@iconify-icons/ri/ubuntu-fill";
|
||||
import questionLine from "@iconify-icons/ri/question-line";
|
||||
import checkboxCircleLine from "@iconify-icons/ri/checkbox-circle-line";
|
||||
import informationLine from "@iconify-icons/ri/information-line";
|
||||
addIcon("arrow-right-s-line", arrowRightSLine);
|
||||
addIcon("arrow-left-s-line", arrowLeftSLine);
|
||||
addIcon("logout-circle-r-line", logoutCircleRLine);
|
||||
addIcon("node-tree", nodeTree);
|
||||
addIcon("ubuntu-fill", ubuntuFill);
|
||||
addIcon("question-line", questionLine);
|
||||
addIcon("checkbox-circle-line", checkboxCircleLine);
|
||||
addIcon("information-line", informationLine);
|
||||
|
||||
// Font Awesome 4
|
||||
import faUser from "@iconify-icons/fa/user";
|
||||
|
||||
200
src/components/ReIcon/src/select.vue
Normal file
200
src/components/ReIcon/src/select.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<script setup lang="ts">
|
||||
import { cloneDeep } from "lodash-unified";
|
||||
import { ref, computed, CSSProperties } from "vue";
|
||||
import { IconJson } from "/@/components/ReIcon/data";
|
||||
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
|
||||
|
||||
let inputValue = ref("ep:add-location");
|
||||
let iconList = ref(IconJson);
|
||||
let icon = ref("add-location");
|
||||
let currentActiveType = ref("ep:");
|
||||
// 深拷贝图标数据,前端做搜索
|
||||
let copyIconList = cloneDeep(iconList.value);
|
||||
|
||||
let pageSize = ref(96);
|
||||
let currentPage = ref(1);
|
||||
|
||||
// 搜索条件
|
||||
let filterValue = ref("");
|
||||
|
||||
let tabsList = [
|
||||
{
|
||||
label: "Element Plus",
|
||||
name: "ep:"
|
||||
},
|
||||
{
|
||||
label: "Remix Icon",
|
||||
name: "ri:"
|
||||
},
|
||||
{
|
||||
label: "Font Awesome 4",
|
||||
name: "fa:"
|
||||
},
|
||||
{
|
||||
label: "Font Awesome 5 Solid",
|
||||
name: "fa-solid:"
|
||||
},
|
||||
{
|
||||
label: "Ant Design Icons",
|
||||
name: "ant-design:"
|
||||
},
|
||||
{
|
||||
label: "VSCode Icons",
|
||||
name: "vscode-icons:"
|
||||
}
|
||||
];
|
||||
|
||||
let pageList = computed(() => {
|
||||
if (currentPage.value === 1) {
|
||||
return copyIconList[currentActiveType.value]
|
||||
.slice(currentPage.value - 1, pageSize.value)
|
||||
.filter(v => v.includes(filterValue.value));
|
||||
} else {
|
||||
return copyIconList[currentActiveType.value]
|
||||
.slice(
|
||||
pageSize.value * (currentPage.value - 1),
|
||||
pageSize.value * (currentPage.value - 1) + pageSize.value
|
||||
)
|
||||
.filter(v => v.includes(filterValue.value));
|
||||
}
|
||||
});
|
||||
|
||||
const iconItemStyle = computed((): ParameterCSSProperties => {
|
||||
return item => {
|
||||
if (inputValue.value === currentActiveType.value + item) {
|
||||
return {
|
||||
borderColor: "var(--el-color-primary)"
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function handleClick({ props }) {
|
||||
currentPage.value = 1;
|
||||
currentActiveType.value = props.name;
|
||||
inputValue.value =
|
||||
currentActiveType.value + iconList.value[currentActiveType.value][0];
|
||||
icon.value = iconList.value[currentActiveType.value][0];
|
||||
}
|
||||
|
||||
function onChangeIcon(item) {
|
||||
inputValue.value = currentActiveType.value + item;
|
||||
icon.value = item;
|
||||
}
|
||||
|
||||
function onCurrentChange(page) {
|
||||
currentPage.value = page;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="selector w-350px">
|
||||
<el-input v-model="inputValue" disabled>
|
||||
<template #append>
|
||||
<el-popover :width="350" trigger="click" popper-class="pure-popper">
|
||||
<template #reference>
|
||||
<div
|
||||
class="w-40px h-32px cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<IconifyIconOnline :icon="icon" :type="currentActiveType" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-input
|
||||
class="p-2"
|
||||
v-model="filterValue"
|
||||
placeholder="搜索图标"
|
||||
clearable
|
||||
/>
|
||||
<el-divider border-style="dashed"></el-divider>
|
||||
|
||||
<el-tabs v-model="currentActiveType" @tab-click="handleClick">
|
||||
<el-tab-pane
|
||||
v-for="(pane, index) in tabsList"
|
||||
:key="index"
|
||||
:label="pane.label"
|
||||
:name="pane.name"
|
||||
>
|
||||
<el-divider
|
||||
class="tab-divider"
|
||||
border-style="dashed"
|
||||
></el-divider>
|
||||
<el-scrollbar height="220px">
|
||||
<ul class="flex flex-wrap px-2 ml-2">
|
||||
<li
|
||||
v-for="(item, key) in pageList"
|
||||
:key="key"
|
||||
:title="item"
|
||||
class="icon-item p-2 w-1/10 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-solid"
|
||||
:style="iconItemStyle(item)"
|
||||
@click="onChangeIcon(item)"
|
||||
>
|
||||
<IconifyIconOnline :icon="item" :type="currentActiveType" />
|
||||
</li>
|
||||
</ul>
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-divider border-style="dashed"></el-divider>
|
||||
|
||||
<el-pagination
|
||||
small
|
||||
:total="copyIconList[currentActiveType].length"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
class="flex items-center justify-center h-10"
|
||||
@current-change="onCurrentChange"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-divider--horizontal {
|
||||
margin: 1px auto !important;
|
||||
}
|
||||
|
||||
.tab-divider.el-divider--horizontal {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-next) {
|
||||
font-size: 15px;
|
||||
line-height: 32px;
|
||||
box-shadow: -5px 0 5px -6px #ccc;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-prev) {
|
||||
font-size: 15px;
|
||||
line-height: 32px;
|
||||
box-shadow: 5px 0 5px -6px #ccc;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__header),
|
||||
:deep(.el-tabs__nav-wrap) {
|
||||
margin: 0;
|
||||
position: static;
|
||||
}
|
||||
</style>
|
||||
@@ -42,5 +42,9 @@ export default {
|
||||
hsPureDocument: "Pure Doc(Embedded)",
|
||||
externalLink: "Pure Doc(External)",
|
||||
hsEpDocument: "Element Plus Doc(Embedded)",
|
||||
hsAbout: "About"
|
||||
hsAbout: "About",
|
||||
hsResult: "Result Page",
|
||||
hsSuccess: "Success Page",
|
||||
hsFail: "Fail Page",
|
||||
hsIconSelect: "Icon Select"
|
||||
};
|
||||
|
||||
@@ -42,5 +42,9 @@ export default {
|
||||
hsPureDocument: "平台文档(内嵌)",
|
||||
externalLink: "平台文档(外链)",
|
||||
hsEpDocument: "Element Plus文档(内嵌)",
|
||||
hsAbout: "关于"
|
||||
hsAbout: "关于",
|
||||
hsResult: "结果页面",
|
||||
hsSuccess: "成功页面",
|
||||
hsFail: "失败页面",
|
||||
hsIconSelect: "图标选择器"
|
||||
};
|
||||
|
||||
@@ -39,6 +39,15 @@ const ableRouter = {
|
||||
title: $t("menus.hsPrint"),
|
||||
i18n: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/able/iconSelect",
|
||||
name: "reIconSelect",
|
||||
component: () => import("/@/views/able/icon-select.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsIconSelect"),
|
||||
i18n: true
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ const aboutRouter = {
|
||||
icon: "question-line",
|
||||
title: $t("menus.hsAbout"),
|
||||
i18n: true,
|
||||
rank: 12
|
||||
rank: 14
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ const errorRouter = {
|
||||
component: Layout,
|
||||
redirect: "/error/403",
|
||||
meta: {
|
||||
icon: "position",
|
||||
icon: "information-line",
|
||||
title: $t("menus.hserror"),
|
||||
i18n: true,
|
||||
rank: 9
|
||||
|
||||
@@ -10,7 +10,7 @@ const guideRouter = {
|
||||
icon: "guide",
|
||||
title: $t("menus.hsguide"),
|
||||
i18n: true,
|
||||
rank: 11
|
||||
rank: 13
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ import homeRouter from "./home";
|
||||
import ableRouter from "./able";
|
||||
import errorRouter from "./error";
|
||||
import guideRouter from "./guide";
|
||||
import resultRouter from "./result";
|
||||
import editorRouter from "./editor";
|
||||
import nestedRouter from "./nested";
|
||||
import flowChartRouter from "./flowchart";
|
||||
@@ -25,6 +26,7 @@ const routes = [
|
||||
ableRouter,
|
||||
errorRouter,
|
||||
guideRouter,
|
||||
resultRouter,
|
||||
nestedRouter,
|
||||
editorRouter,
|
||||
flowChartRouter,
|
||||
|
||||
@@ -10,7 +10,7 @@ const nestedRouter = {
|
||||
title: $t("menus.hsmenus"),
|
||||
icon: "histogram",
|
||||
i18n: true,
|
||||
rank: 8
|
||||
rank: 11
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
37
src/router/modules/result.ts
Normal file
37
src/router/modules/result.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { $t } from "/@/plugins/i18n";
|
||||
const Layout = () => import("/@/layout/index.vue");
|
||||
|
||||
const resultRouter = {
|
||||
path: "/result",
|
||||
name: "reResult",
|
||||
component: Layout,
|
||||
redirect: "/result/success",
|
||||
meta: {
|
||||
icon: "checkbox-circle-line",
|
||||
title: $t("menus.hsResult"),
|
||||
i18n: true,
|
||||
rank: 8
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/result/success",
|
||||
name: "reSuccess",
|
||||
component: () => import("/@/views/result/success.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsSuccess"),
|
||||
i18n: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/result/fail",
|
||||
name: "reFail",
|
||||
component: () => import("/@/views/result/fail.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsFail"),
|
||||
i18n: true
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default resultRouter;
|
||||
@@ -36,6 +36,11 @@
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
// 自定义popover的类名
|
||||
.pure-popper {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 动态改变cssvar 用于主题切换 https://github.com/element-plus/element-plus/issues/4856#issuecomment-1000174357 */
|
||||
.el-button--primary {
|
||||
--el-button-active-bg-color: var(--el-color-primary-active) !important;
|
||||
|
||||
14
src/views/able/icon-select.vue
Normal file
14
src/views/able/icon-select.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { IconSelect } from "/@/components/ReIcon";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="font-medium">图标选择器</span>
|
||||
</div>
|
||||
</template>
|
||||
<IconSelect />
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -6,9 +6,57 @@ import noAccess from "/@/assets/status/403.svg?component";
|
||||
<div class="flex justify-center items-center h-screen-sm">
|
||||
<noAccess />
|
||||
<div class="ml-12">
|
||||
<p class="font-medium text-4xl mb-4">403</p>
|
||||
<p class="mb-4 text-gray-500">抱歉,你无权访问该页面</p>
|
||||
<el-button type="primary" @click="$router.push('/')">返回首页</el-button>
|
||||
<p
|
||||
class="font-medium text-4xl mb-4"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 100
|
||||
}
|
||||
}"
|
||||
>
|
||||
403
|
||||
</p>
|
||||
<p
|
||||
class="mb-4 text-gray-500"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 300
|
||||
}
|
||||
}"
|
||||
>
|
||||
抱歉,你无权访问该页面
|
||||
</p>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="$router.push('/')"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 500
|
||||
}
|
||||
}"
|
||||
>返回首页</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,9 +6,57 @@ import noExist from "/@/assets/status/404.svg?component";
|
||||
<div class="flex justify-center items-center h-screen-sm">
|
||||
<noExist />
|
||||
<div class="ml-12">
|
||||
<p class="font-medium text-4xl mb-4">404</p>
|
||||
<p class="mb-4 text-gray-500">抱歉,你访问的页面不存在</p>
|
||||
<el-button type="primary" @click="$router.push('/')">返回首页</el-button>
|
||||
<p
|
||||
class="font-medium text-4xl mb-4"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 100
|
||||
}
|
||||
}"
|
||||
>
|
||||
404
|
||||
</p>
|
||||
<p
|
||||
class="mb-4 text-gray-500"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 300
|
||||
}
|
||||
}"
|
||||
>
|
||||
抱歉,你访问的页面不存在
|
||||
</p>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="$router.push('/')"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 500
|
||||
}
|
||||
}"
|
||||
>返回首页</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,9 +6,57 @@ import noServer from "/@/assets/status/500.svg?component";
|
||||
<div class="flex justify-center items-center h-screen-sm">
|
||||
<noServer />
|
||||
<div class="ml-12">
|
||||
<p class="font-medium text-4xl mb-4">403</p>
|
||||
<p class="mb-4 text-gray-500">抱歉,服务器出错了</p>
|
||||
<el-button type="primary" @click="$router.push('/')">返回首页</el-button>
|
||||
<p
|
||||
class="font-medium text-4xl mb-4"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 100
|
||||
}
|
||||
}"
|
||||
>
|
||||
403
|
||||
</p>
|
||||
<p
|
||||
class="mb-4 text-gray-500"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 300
|
||||
}
|
||||
}"
|
||||
>
|
||||
抱歉,服务器出错了
|
||||
</p>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="$router.push('/')"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 500
|
||||
}
|
||||
}"
|
||||
>返回首页</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
7
src/views/result/fail.vue
Normal file
7
src/views/result/fail.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
7
src/views/result/success.vue
Normal file
7
src/views/result/success.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user