ant-design-vue/site/src/layouts/index.vue

285 lines
8.5 KiB
Vue

<template>
<Header />
<div class="main-wrapper">
<a-row>
<template v-if="isMobile">
<a-drawer
key="mobile-menu"
:closable="false"
placement="left"
class="drawer drawer-left"
:visible="visible"
wrapper-class-name="drawer-wrapper"
width="60%"
>
<surelyVueVue />
<Menu :menus="dataSource" :active-menu-item="activeMenuItem" :is-zh-c-n="isZhCN" />
<template #handle>
<div class="drawer-handle" @click="handleClickShowButton">
<close-outlined v-if="visible" :style="iconStyle" />
<MenuOutlined v-else :style="iconStyle" />
</div>
</template>
</a-drawer>
</template>
<template v-else>
<a-col :xxxl="4" :xxl="4" :xl="5" :lg="6" :md="6" :sm="24" :xs="24" class="main-menu">
<a-affix>
<section class="main-menu-inner">
<!-- <Sponsors :is-c-n="isZhCN" /> -->
<div>
<surelyVueVue />
</div>
<Menu :menus="dataSource" :active-menu-item="activeMenuItem" :is-zh-c-n="isZhCN" />
</section>
</a-affix>
</a-col>
</template>
<a-col :xxxl="20" :xxl="20" :xl="19" :lg="18" :md="18" :sm="24" :xs="24">
<section :class="mainContainerClass">
<WWAdsVue v-if="isZhCN" />
<TopAd v-else />
<Demo v-if="isDemo" :page-data="pageData" :is-zh-c-n="isZhCN">
<component :is="matchCom" />
</Demo>
<router-view v-else />
<a-affix v-if="headers.length" class="toc-affix" :offset-top="20">
<a-anchor>
<a-anchor-link
v-for="h in headers"
:key="h.title"
:href="h.href || `#${slugifyTitle(h.title)}`"
:target="h.target"
>
<template #title>
<LinkOutlined v-if="h.target" />
{{ isZhCN ? h.title : h.enTitle || h.title }}
</template>
</a-anchor-link>
</a-anchor>
</a-affix>
</section>
<a-back-top />
<div class="fixed-widgets" :style="isZhCN ? { bottom: '175px' } : {}">
<a-dropdown placement="top">
<template #overlay>
<a-menu
:selected-keys="[themeMode.theme.value]"
@click="({ key }) => themeMode.changeTheme(key)"
>
<a-menu-item key="default">{{ $t('app.theme.switch.default') }}</a-menu-item>
<a-menu-item key="dark">{{ $t('app.theme.switch.dark') }}</a-menu-item>
</a-menu>
</template>
<a-avatar class="fixed-widgets-avatar" :size="44">
<template #icon><ThemeIcon /></template>
</a-avatar>
</a-dropdown>
</div>
<PrevAndNext :menus="menus" :current-menu-index="currentMenuIndex" :is-zh-c-n="isZhCN" />
<Footer />
</a-col>
</a-row>
</div>
</template>
<script lang="ts">
import type { GlobalConfig } from '../App.vue';
import { GLOBAL_CONFIG } from '../SymbolKey';
import { defineComponent, inject, computed, ref, provide, watch } from 'vue';
import { useRoute } from 'vue-router';
import Header from './header/index.vue';
import Footer from './Footer.vue';
import Menu from './Menu.vue';
import PrevAndNext from './PrevAndNext.vue';
import Demo from './Demo.vue';
import useMenus from '../hooks/useMenus';
import TopAd from '../components/rice/top_rice.vue';
import Sponsors from '../components/rice/sponsors.vue';
import RightBottomAd from '../components/rice/right_bottom_rice.vue';
import { CloseOutlined, MenuOutlined, LinkOutlined } from '@ant-design/icons-vue';
import ThemeIcon from './ThemeIcon.vue';
import surelyVueVue from '../components/surelyVue.vue';
import WWAdsVue from '../components/rice/WWAds.vue';
const rControl = /[\u0000-\u001f]/g;
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.?/]+/g;
export default defineComponent({
name: 'Layout',
components: {
TopAd,
Sponsors,
RightBottomAd,
Demo,
Header,
Footer,
Menu,
PrevAndNext,
CloseOutlined,
MenuOutlined,
ThemeIcon,
surelyVueVue,
WWAdsVue,
LinkOutlined,
},
setup() {
const visible = ref(false);
const route = useRoute();
const globalConfig = inject<GlobalConfig>(GLOBAL_CONFIG);
const { menus, activeMenuItem, currentMenuIndex, dataSource } = useMenus();
const demos = ref<any[]>([]);
provide('addDemosInfo', (info: any) => {
if (!demos.value.find(d => d.href === info.href)) {
demos.value.push(info);
}
});
const themeMode = inject('themeMode', {
theme: ref('default'),
// eslint-disable-next-line @typescript-eslint/no-unused-vars
changeTheme: (_key: any) => void 0,
});
watch(
() => route.path,
() => {
demos.value.length = 0;
},
);
const isDemo = computed(() => {
return (
route.path.indexOf('/components') === 0 && route.path.indexOf('/components/overview') !== 0
);
});
const isTablePage = computed(() => {
return route.path.indexOf('/components/table') === 0;
});
const matchCom = computed(() => {
return route.matched[route.matched.length - 1]?.components?.default;
});
const isZhCN = globalConfig.isZhCN;
const pageData = computed(() =>
isDemo.value
? matchCom.value[isZhCN.value ? 'CN' : 'US']?.pageData
: (matchCom.value as any)?.pageData,
);
const headers = computed(() => {
let tempHeaders = (pageData.value?.headers || []).filter((h: Header) => h.level === 2);
if (isDemo.value) {
tempHeaders = [...demos.value];
if (isTablePage.value) {
tempHeaders.push(
...[
{
title: '大数据渲染',
enTitle: 'Virtualized Table',
href: 'https://surely.cool/doc/performance',
target: '_blank',
},
{
title: '行拖拽排序',
enTitle: 'Row Drag Sort',
href: 'https://surely.cool/doc/dragable#drag-row',
target: '_blank',
},
{
title: '列拖拽排序',
enTitle: 'Column Drag Sort',
href: 'https://surely.cool/doc/dragable#drag-column',
target: '_blank',
},
{
title: '更多高性能示例',
enTitle: 'More high-performance examples ',
href: 'https://surely.cool',
target: '_blank',
},
],
);
}
tempHeaders.push({ title: 'API', href: '#API' });
}
return tempHeaders;
});
const mainContainerClass = computed(() => {
return {
'main-container': true,
'main-container-component': isDemo.value,
};
});
const handleClickShowButton = () => {
visible.value = !visible.value;
};
return {
slugifyTitle: (str: string) => {
return (
str
// Remove control characters
.replace(rControl, '')
// Replace special characters
.replace(rSpecial, '-')
// Remove continuos separators
.replace(/\-{2,}/g, '-')
// Remove prefixing and trailing separtors
.replace(/^\-+|\-+$/g, '')
// ensure it doesn't start with a number (#121)
.replace(/^(\d)/, '_$1')
);
},
themeMode,
visible,
isMobile: globalConfig.isMobile,
isZhCN,
mainContainerClass,
menus,
currentMenuIndex,
activeMenuItem,
headers,
isDemo,
matchCom,
pageData,
dataSource,
handleClickShowButton,
iconStyle: {
// color: '#fff',
fontSize: '20px',
},
};
},
});
</script>
<style lang="less" scoped>
.toc-affix :deep(.ant-anchor) {
font-size: 12px;
max-width: 110px;
.ant-anchor-link {
border-left: 2px solid #f0f0f0;
padding: 4px 0 4px 16px;
}
.ant-anchor-link-active {
border-left: 2px solid #1890ff;
}
.ant-anchor-ink::before {
display: none;
}
.ant-anchor-ink-ball {
display: none;
}
}
[data-theme='dark'] .toc-affix :deep(.ant-anchor) {
.ant-anchor-link {
border-left: 2px solid #303030;
}
.ant-anchor-link-active {
border-left: 2px solid #177ddc;
}
}
</style>