Skip to content

Commit

Permalink
feat: add search page
Browse files Browse the repository at this point in the history
  • Loading branch information
anncwb committed Dec 10, 2020
1 parent 596e706 commit dddda5b
Show file tree
Hide file tree
Showing 45 changed files with 1,399 additions and 1,004 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.zh_CN.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Wip

### ✨ Features

- 移除左侧菜单搜索,新增顶部菜单搜索功能

## 2.0.0-rc.13 (2020-12-10)

## (破坏性更新) Breaking changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dependencies": {
"@iconify/iconify": "^2.0.0-rc.2",
"@vueuse/core": "^4.0.0-rc.7",
"ant-design-vue": "^2.0.0-rc.3",
"ant-design-vue": "^2.0.0-rc.4",
"apexcharts": "^3.22.3",
"axios": "^0.21.0",
"crypto-es": "^1.2.6",
Expand Down
13 changes: 7 additions & 6 deletions src/components/Application/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import AppLocalePicker from './src/AppLocalePicker.vue';
import AppLogo from './src/AppLogo.vue';
import AppProvider from './src/AppProvider.vue';
import { withInstall } from '../util';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';

withInstall(AppLocalePicker, AppLogo, AppProvider);
export const AppLocalePicker = createAsyncComponent(() => import('./src/AppLocalePicker.vue'));
export const AppProvider = createAsyncComponent(() => import('./src/AppProvider.vue'));
export const AppSearch = createAsyncComponent(() => import('./src/search/AppSearch.vue'));
export const AppLogo = createAsyncComponent(() => import('./src/AppLogo.vue'));

export { useAppProviderContext } from './src/useAppContext';
withInstall(AppLocalePicker, AppLogo, AppProvider, AppSearch);

export { AppLocalePicker, AppLogo, AppProvider };
export { useAppProviderContext } from './src/useAppContext';
55 changes: 55 additions & 0 deletions src/components/Application/src/search/AppSearch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<div :class="prefixCls" v-if="getShowSearch" @click="handleSearch">
<Tooltip>
<template #title> {{ t('component.app.search') }} </template>
<SearchOutlined />
</Tooltip>

<transition name="zoom-fade" mode="out-in">
<AppSearchModal @close="handleClose" v-if="showModal" />
</transition>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { Tooltip } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import AppSearchModal from './AppSearchModal.vue';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { SearchOutlined } from '@ant-design/icons-vue';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'AppSearch',
components: { AppSearchModal, Tooltip, SearchOutlined },
setup() {
const showModal = ref(false);
const { prefixCls } = useDesign('app-search');
const { getShowSearch } = useHeaderSetting();
const { t } = useI18n();
function handleSearch() {
showModal.value = true;
}
return {
t,
prefixCls,
showModal,
getShowSearch,
handleClose: () => {
showModal.value = false;
},
handleSearch,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-app-search';
.@{prefix-cls} {
padding: 0 10px;
}
</style>
76 changes: 76 additions & 0 deletions src/components/Application/src/search/AppSearchFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<template>
<div :class="`${prefixCls}`">
<span :class="`${prefixCls}__item`">
<g-icon icon="ant-design:enter-outlined" />
</span>
<span>{{ t('component.app.toSearch') }}</span>

<span :class="`${prefixCls}__item`">
<g-icon icon="bi:arrow-up" />
</span>
<span :class="`${prefixCls}__item`">
<g-icon icon="bi:arrow-down" />
</span>
<span>{{ t('component.app.toNavigate') }}</span>
<span :class="`${prefixCls}__item`">
<g-icon icon="mdi:keyboard-esc" />
</span>
<span>{{ t('component.app.toClose') }}</span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'AppSearchFooter',
components: {},
setup() {
const { prefixCls } = useDesign('app-search-footer');
const { t } = useI18n();
return {
prefixCls,
t,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-app-search-footer';
.@{prefix-cls} {
position: relative;
display: flex;
height: 44px;
padding: 0 16px;
font-size: 12px;
color: #666;
background: rgb(255 255 255);
border-radius: 0 0 8px 8px;
box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgba(69, 98, 155, 0.12);
align-items: center;
flex-shrink: 0;
&__item {
display: flex;
width: 20px;
height: 18px;
padding-bottom: 2px;
margin-right: 0.4em;
background: linear-gradient(-225deg, #d5dbe4, #f8f8f8);
border-radius: 2px;
box-shadow: inset 0 -2px 0 0 #cdcde6, inset 0 0 1px 1px #fff,
0 1px 2px 1px rgba(30, 35, 90, 0.4);
align-items: center;
justify-content: center;
&:nth-child(2),
&:nth-child(3),
&:nth-child(6) {
margin-left: 14px;
}
}
}
</style>
198 changes: 198 additions & 0 deletions src/components/Application/src/search/AppSearchModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<template>
<div :class="prefixCls" @click.stop>
<ClickOutSide @clickOutside="handleClose">
<div :class="`${prefixCls}-content`">
<a-input
:class="`${prefixCls}-input`"
:placeholder="t('component.app.search')"
allow-clear
@change="handleSearch"
>
<template #prefix>
<SearchOutlined />
</template>
</a-input>
<div :class="`${prefixCls}-not-data`" v-show="getIsNotData">
{{ t('component.app.searchNotData') }}
</div>
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
<li
:ref="setRefs(index)"
v-for="(item, index) in searchResult"
:key="item.path"
:data-index="index"
@mouseenter="handleMouseenter"
@click="handleEnter"
:class="[
`${prefixCls}-list__item`,
{
[`${prefixCls}-list__item--active`]: activeIndex === index,
},
]"
>
<div :class="`${prefixCls}-list__item-icon`">
<g-icon :icon="item.icon || 'mdi:form-select'" :size="20" />
</div>
<div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div>
<div :class="`${prefixCls}-list__item-enter`">
<g-icon icon="ant-design:enter-outlined" :size="20" />
</div>
</li>
</ul>
<AppSearchFooter />
</div>
</ClickOutSide>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, unref, ref } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useRefs } from '/@/hooks/core/useRefs';
import { useMenuSearch } from './useMenuSearch';
import { SearchOutlined } from '@ant-design/icons-vue';
import AppSearchFooter from './AppSearchFooter.vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { ClickOutSide } from '/@/components/ClickOutSide';
export default defineComponent({
name: 'AppSearchModal',
components: { SearchOutlined, ClickOutSide, AppSearchFooter },
emits: ['close'],
setup(_, { emit }) {
const scrollWrap = ref<ElRef>(null);
const { prefixCls } = useDesign('app-search-modal');
const { t } = useI18n();
const [refs, setRefs] = useRefs();
const {
handleSearch,
searchResult,
keyword,
activeIndex,
handleEnter,
handleMouseenter,
} = useMenuSearch(refs, scrollWrap, emit);
const getIsNotData = computed(() => {
return !keyword || unref(searchResult).length === 0;
});
return {
t,
prefixCls,
handleSearch,
searchResult,
activeIndex,
getIsNotData,
handleEnter,
setRefs,
scrollWrap,
handleMouseenter,
handleClose: () => {
emit('close');
},
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-app-search-modal';
.@{prefix-cls} {
position: fixed;
top: 0;
left: 0;
z-index: 100;
display: flex;
width: 100%;
height: 100%;
padding-top: 50px;
// background: #656c85cc;
background: rgba(0, 0, 0, 0.8);
justify-content: center;
// backdrop-filter: blur(2px);
&-content {
position: relative;
width: 532px;
// padding: 14px;
margin: 0 auto auto auto;
background: #f5f6f7;
border-radius: 6px;
box-shadow: inset 1px 1px 0 0 hsla(0, 0%, 100%, 0.5), 0 3px 8px 0 #555a64;
flex-direction: column;
}
&-input {
width: calc(100% - 28px);
height: 56px;
margin: 14px 14px 0 14px;
font-size: 1.5em;
color: #1c1e21;
span[role='img'] {
color: #999;
}
}
&-not-data {
display: flex;
width: 100%;
height: 100px;
font-size: 0.9;
color: rgb(150 159 175);
align-items: center;
justify-content: center;
}
&-list {
max-height: 472px;
padding: 0 14px;
padding-bottom: 20px;
margin: 0 auto;
margin-top: 14px;
overflow: auto;
&__item {
position: relative;
display: flex;
width: 100%;
height: 56px;
padding-bottom: 4px;
padding-left: 14px;
margin-top: 8px;
font-size: 14px;
color: @text-color-base;
cursor: pointer;
// background: @primary-color;
background: #fff;
border-radius: 4px;
box-shadow: 0 1px 3px 0 #d4d9e1;
align-items: center;
&--active {
color: #fff;
background: @primary-color;
.@{prefix-cls}-list__item-enter {
opacity: 1;
}
}
&-icon {
width: 30px;
}
&-text {
flex: 1;
}
&-enter {
width: 30px;
opacity: 0;
}
}
}
}
</style>
Loading

0 comments on commit dddda5b

Please sign in to comment.