feat: add iconSelect component

This commit is contained in:
xiaoxian521
2022-03-05 13:47:24 +08:00
parent a35dc9d7b6
commit 0a7d22248f
23 changed files with 6684 additions and 101 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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
};

View File

@@ -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";

View 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>

View File

@@ -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"
};

View File

@@ -42,5 +42,9 @@ export default {
hsPureDocument: "平台文档(内嵌)",
externalLink: "平台文档(外链)",
hsEpDocument: "Element Plus文档(内嵌)",
hsAbout: "关于"
hsAbout: "关于",
hsResult: "结果页面",
hsSuccess: "成功页面",
hsFail: "失败页面",
hsIconSelect: "图标选择器"
};

View File

@@ -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
}
}
]
};

View File

@@ -10,7 +10,7 @@ const aboutRouter = {
icon: "question-line",
title: $t("menus.hsAbout"),
i18n: true,
rank: 12
rank: 14
},
children: [
{

View File

@@ -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

View File

@@ -10,7 +10,7 @@ const guideRouter = {
icon: "guide",
title: $t("menus.hsguide"),
i18n: true,
rank: 11
rank: 13
},
children: [
{

View File

@@ -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,

View File

@@ -10,7 +10,7 @@ const nestedRouter = {
title: $t("menus.hsmenus"),
icon: "histogram",
i18n: true,
rank: 8
rank: 11
},
children: [
{

View 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;

View File

@@ -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;

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>

View File

@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>