doc: add site

pull/4606/head
tangjinzhou 2021-09-01 16:12:07 +08:00
parent c4902235ce
commit 58e5107cf9
167 changed files with 13416 additions and 85 deletions

View File

@ -1,82 +0,0 @@
{
"root": true,
"env": {
"browser": true,
"node": true,
"jasmine": true,
"jest": true,
"es6": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"parser": "babel-eslint"
},
"extends": ["plugin:vue/vue3-recommended", "prettier"],
"plugins": ["markdown", "jest", "@typescript-eslint", "eslint-plugin-no-explicit-type-exports"],
"overrides": [
{
"files": ["**/demo/*.md"],
"processor": "markdown/markdown",
"rules": {
"no-console": "off"
}
},
{
"files": ["*.ts", "*.tsx"],
"extends": [
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
],
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"no-explicit-type-exports/no-explicit-type-exports": 2,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-imports": 1,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": [
"error",
{ "vars": "all", "args": "after-used", "ignoreRestSiblings": true }
],
"@typescript-eslint/ban-ts-comment": 0
}
}
],
"rules": {
"comma-dangle": [2, "always-multiline"],
"no-var": "error",
"no-console": [2, { "allow": ["warn", "error"] }],
"object-shorthand": 2,
"no-unused-vars": [2, { "ignoreRestSiblings": true, "argsIgnorePattern": "^h$" }],
"no-undef": 2,
"camelcase": "off",
"no-extra-boolean-cast": "off",
"semi": ["error", "always"],
"vue/require-explicit-emits": "off",
"vue/require-prop-types": "off",
"vue/require-default-prop": "off",
"vue/no-reserved-keys": "off",
"vue/comment-directive": "off",
"vue/prop-name-casing": "off",
"vue/one-component-per-file": "off",
"vue/custom-event-name-casing": "off",
"vue/max-attributes-per-line": [
2,
{
"singleline": 20,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}
]
},
"globals": {
"h": true
}
}

78
.eslintrc.js Normal file
View File

@ -0,0 +1,78 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
jasmine: true,
jest: true,
es6: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
parser: 'babel-eslint',
},
extends: ['plugin:vue/vue3-recommended', 'prettier'],
plugins: ['markdown', 'jest', '@typescript-eslint', 'eslint-plugin-no-explicit-type-exports'],
overrides: [
{
files: ['**/demo/*.md'],
processor: 'markdown/markdown',
rules: {
'no-console': 'off',
},
},
{
files: ['*.ts', '*.tsx'],
extends: ['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'],
parserOptions: {
project: './tsconfig.json',
},
rules: {
'no-explicit-type-exports/no-explicit-type-exports': 2,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/consistent-type-imports': 1,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
],
'@typescript-eslint/ban-ts-comment': 0,
},
},
],
rules: {
'comma-dangle': [2, 'always-multiline'],
'no-var': 'error',
'no-console': [2, { allow: ['warn', 'error'] }],
'object-shorthand': 2,
'no-unused-vars': [2, { ignoreRestSiblings: true, argsIgnorePattern: '^h$' }],
'no-undef': 2,
camelcase: 'off',
'no-extra-boolean-cast': 'off',
semi: ['error', 'always'],
'vue/require-explicit-emits': 'off',
'vue/require-prop-types': 'off',
'vue/require-default-prop': 'off',
'vue/no-reserved-keys': 'off',
'vue/comment-directive': 'off',
'vue/prop-name-casing': 'off',
'vue/one-component-per-file': 'off',
'vue/custom-event-name-casing': 'off',
'vue/max-attributes-per-line': [
2,
{
singleline: 20,
multiline: {
max: 1,
allowFirstLine: false,
},
},
],
},
globals: {
h: true,
},
};

View File

@ -28,7 +28,8 @@
"vetur"
],
"scripts": {
"dev": "vite",
"debugger": "vite",
"dev": "vite serve site",
"test": "cross-env NODE_ENV=test WORKFLOW=true jest --config .jest.js",
"test:dev": "cross-env NODE_ENV=test jest --config .jest.js",
"compile": "node antd-tools/cli/run.js compile",

View File

@ -1,8 +1,10 @@
import { transformSync } from '@babel/core';
import { CLIEngine } from 'eslint';
import path from 'path';
const engine = new CLIEngine({
fix: true,
useEslintrc: false,
baseConfig: require(path.join(process.cwd(), '.eslintrc.js')),
});
const tsToJs = (content: string): string => {
if (!content) {

97
site/404.html Normal file
View File

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta
name="description"
content="An enterprise-class UI components based on Ant Design and Vue"
/>
<title>Ant Design Vue</title>
<link rel="icon" type="image/x-icon" href="https://qn.antdv.com/favicon.ico" />
<style id="nprogress-style">
#page-404 {
background-image: url('https://os.alipayobjects.com/rmsportal/NOAjOBbnYCrNzrW.jpg');
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
background-size: 100%;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
}
section {
position: absolute;
top: 48%;
left: 55%;
margin: -103px 0 0 -120px;
text-align: center;
}
h1 {
color: #1890ff;
font-size: 120px;
font-weight: 500;
}
p {
color: #314659;
font-size: 18px;
}
</style>
<script>
var _hmt = _hmt || [];
var srcMap = {
'ant-design-vue.gitee.io': 'https://hm.baidu.com/hm.js?1e30265f06f76fabfcdb7ed272017441',
'vue.ant.design': 'https://hm.baidu.com/hm.js?f0ba868f114e674b816b4880f7525811',
'www.antdv.com': 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22',
};
var src =
srcMap[location.host] || 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22';
(function() {
var hm = document.createElement('script');
hm.src = src;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="app">
<div id="page-404" data-reactroot="">
<section>
<h1>404</h1>
<p>你要找的页面不存在<a href="/">返回首页</a></p>
</section>
<style>
#app {
height: 100%;
background-color: #fff;
}
</style>
</div>
</div>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-151755889-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-151755889-1');
</script>
</body>
</html>

83
site/index.html Normal file
View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta
name="description"
content="An enterprise-class UI components based on Ant Design and Vue"
/>
<title>Ant Design Vue</title>
<meta
name="keywords"
content="ant design vue,ant-design-vue,ant-design-vue admin,ant design pro,vue ant design,vue ant design pro,vue ant design admin,ant design vue官网,ant design vue中文文档,ant design vue文档"
/>
<link rel="shortcut icon" type="image/x-icon" href="https://qn.antdv.com/favicon.ico" />
<style id="nprogress-style">
#nprogress {
display: none;
}
</style>
<script>
if (location.host === 'ant-design-vue.gitee.io' || location.host === 'vue.ant.design') {
location.replace(location.href.replace(location.host, 'www.antdv.com'));
}
var _hmt = _hmt || [];
var srcMap = {
'ant-design-vue.gitee.io': 'https://hm.baidu.com/hm.js?1e30265f06f76fabfcdb7ed272017441',
'vue.ant.design': 'https://hm.baidu.com/hm.js?f0ba868f114e674b816b4880f7525811',
'www.antdv.com': 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22',
};
var src =
srcMap[location.host] || 'https://hm.baidu.com/hm.js?4ad38a0c8f0960d731b654425317da22';
(function () {
var hm = document.createElement('script');
hm.src = src;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="app"></div>
<script src="https://aliyuncdn.antdv.com/common/docsearch.min_2.6.3.js"></script>
<script type="module" src="/src/main.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-151755889-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-151755889-1');
</script>
<!-- Hotjar Tracking Code for http://vue.ant.design -->
<script>
(function (h, o, t, j, a, r) {
if (location.href.indexOf('iframe') === -1) {
h.hj =
h.hj ||
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = {
hjid: 1359441,
hjsv: 6,
};
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
}
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
</script>
</body>
</html>

2
site/public/docsearch.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
site/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,42 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const globby = require('globby');
const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const { CLIEngine } = require('eslint');
(async () => {
const paths = await globby('src/docs/*/index.*.md');
const components = {};
paths.forEach(path => {
const content = fs.readFileSync(path).toString();
const componentName = path.split('/')[2];
if (componentName !== 'color-picker') {
const { data } = matter(content);
components[componentName] = { ...components[componentName], ...data };
}
});
const TEMPLATE = `
export default [
${Object.keys(components).map(
component => `
{
path: '${component}:lang(-cn)?',
meta: ${JSON.stringify(components[component])},
component: () => import('../docs/${component}/demo/index.vue'),
}`,
)}
];`;
const engine = new CLIEngine({
fix: true,
useEslintrc: false,
baseConfig: require(path.join(process.cwd(), '.eslintrc.js')),
});
const report = engine.executeOnText(TEMPLATE);
fs.writeFileSync('src/router/demoRoutes.js', report.results[0].output);
})();

59
site/scripts/pushToOSS.js Normal file
View File

@ -0,0 +1,59 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const OSS = require('ali-oss');
const path = require('path');
const fs = require('fs');
const accessKeyId = process.env.ALI_OSS_ACCESSKEY;
const accessKeySecret = process.env.ALI_OSS_SECRETKEY;
const client = new OSS({
bucket: 'antdv-beijing',
cname: 'true',
endpoint: 'aliyuncdn.antdv.com',
// region以杭州为例oss-cn-hangzhou其他region按实际情况填写。
region: 'oss-cn-beijing',
// 阿里云主账号AccessKey拥有所有API的访问权限风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维请登录RAM控制台创建RAM账号。
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret,
});
const assetsPath = path.join(process.cwd(), 'dist', 'assets');
const put = file => {
return new Promise((reslove, reject) => {
client
.put(`v2/assets/${file}`, path.join(assetsPath, file))
.then(res => {
if (res.res.status !== 200) {
console.log(`${res.name} upload failed!`);
reject();
process.exit(500);
} else {
console.log(`${res.name} upload success!`);
reslove();
}
})
.catch(err => {
if (err) {
err && console.log(err);
process.exit(500);
}
});
});
};
async function upload() {
try {
const files = await fs.promises.readdir(assetsPath, {
withFileTypes: true,
});
for (const file of files) {
if (file.isFile()) {
await put(file.name);
}
}
} catch (err) {
console.error(err);
}
}
upload();

101
site/src/App.vue Normal file
View File

@ -0,0 +1,101 @@
<template>
<a-config-provider :locale="locale">
<router-view />
</a-config-provider>
</template>
<script lang="ts">
import { computed, defineComponent, provide, Ref, watch, ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import useMediaQuery from './hooks/useMediaQuery';
import { GLOBAL_CONFIG } from './SymbolKey';
import enUS from 'ant-design-vue/es/locale/en_US';
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
function isZhCN(name: string) {
return /-cn\/?$/.test(name);
}
export interface GlobalConfig {
isMobile: Ref<boolean>;
lang: Ref<'zh-CN' | 'en-US'>;
isZhCN: Ref<boolean>;
responsive: Ref<null | 'narrow' | 'crowded'>;
blocked: Ref<boolean>;
}
export default defineComponent({
setup() {
const route = useRoute();
const i18n = useI18n();
const colSize = useMediaQuery();
const isMobile = computed(() => colSize.value === 'sm' || colSize.value === 'xs');
const theme = ref(localStorage.getItem('theme') || 'default');
const responsive = computed(() => {
if (colSize.value === 'xs') {
return 'crowded';
} else if (colSize.value === 'sm') {
return 'narrow';
}
return null;
});
const globalConfig: GlobalConfig = {
isMobile,
responsive,
lang: computed(() => i18n.locale.value as any),
isZhCN: computed(() => i18n.locale.value === 'zh-CN'),
blocked: ref(false),
};
const changeTheme = (t: string) => {
theme.value = t;
localStorage.setItem('theme', t);
};
provide('themeMode', {
theme,
changeTheme,
});
provide(GLOBAL_CONFIG, globalConfig);
watch(
() => route.path,
val => {
i18n.locale.value = isZhCN(val) ? 'zh-CN' : 'en-US';
},
{ immediate: true },
);
watch(
globalConfig.isZhCN,
val => {
if (val) {
dayjs.locale(zhCN.locale);
} else {
dayjs.locale(enUS.locale);
}
},
{ immediate: true },
);
const locale = computed(() => {
return globalConfig.isZhCN.value ? zhCN : enUS;
});
setTimeout(() => {
const div = document.createElement('div');
div.className = 'adsbox';
document.body.appendChild(div);
globalConfig.blocked.value = 'none' === getComputedStyle(div).display;
}, 300);
watch(
theme,
() => {
if (theme.value === 'dark') {
document.getElementsByTagName('html')[0].setAttribute('data-doc-theme', 'dark');
document.getElementsByTagName('body')[0].setAttribute('data-theme', 'dark');
} else {
document.getElementsByTagName('html')[0].setAttribute('data-doc-theme', 'light');
document.getElementsByTagName('body')[0].setAttribute('data-theme', 'light');
}
},
{ immediate: true },
);
return { globalConfig, locale };
},
});
</script>

1
site/src/SymbolKey.ts Normal file
View File

@ -0,0 +1 @@
export const GLOBAL_CONFIG = Symbol('globalConfig');

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
site/src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

29
site/src/assets/logo.svg Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->
<title>Vue</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="69.644116%" y1="0%" x2="69.644116%" y2="100%" id="linearGradient-1">
<stop stop-color="#29CDFF" offset="0%"></stop>
<stop stop-color="#148EFF" offset="37.8600687%"></stop>
<stop stop-color="#0A60FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-19.8191553%" y1="-36.7931464%" x2="138.57919%" y2="157.637507%" id="linearGradient-2">
<stop stop-color="#29CDFF" offset="0%"></stop>
<stop stop-color="#0F78FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-3">
<stop stop-color="#FA8E7D" offset="0%"></stop>
<stop stop-color="#F74A5C" offset="51.2635191%"></stop>
<stop stop-color="#F51D2C" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Vue" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" transform="translate(19.000000, 9.000000)">
<path d="M89.96,90.48 C78.58,93.48 68.33,83.36 67.62,82.48 L46.6604487,62.2292258 C45.5023849,61.1103236 44.8426845,59.5728835 44.8296987,57.9626396 L44.5035564,17.5209948 C44.4948861,16.4458744 44.0537714,15.4195095 43.2796864,14.6733517 L29.6459999,1.53153737 C28.055475,-0.00160504005 25.5232423,0.0449126588 23.9900999,1.63543756 C23.2715121,2.38092066 22.87,3.37600834 22.87,4.41143746 L22.87,64.3864751 C22.87,67.0807891 23.9572233,69.6611067 25.885409,71.5429748 L63.6004615,108.352061 C65.9466323,110.641873 69.6963584,110.624605 72.0213403,108.313281" id="Path-Copy" fill="url(#linearGradient-1)" fill-rule="nonzero" transform="translate(56.415000, 54.831157) scale(-1, 1) translate(-56.415000, -54.831157) "></path>
<path d="M68,90.1163122 C56.62,93.1163122 45.46,83.36 44.75,82.48 L23.7904487,62.2292258 C22.6323849,61.1103236 21.9726845,59.5728835 21.9596987,57.9626396 L21.6335564,17.5209948 C21.6248861,16.4458744 21.1837714,15.4195095 20.4096864,14.6733517 L6.7759999,1.53153737 C5.185475,-0.00160504005 2.65324232,0.0449126588 1.12009991,1.63543756 C0.401512125,2.38092066 3.90211878e-13,3.37600834 3.90798505e-13,4.41143746 L3.94351218e-13,64.3864751 C3.94681177e-13,67.0807891 1.08722326,69.6611067 3.01540903,71.5429748 L40.7807092,108.401101 C43.1069304,110.671444 46.8180151,110.676525 49.1504445,108.412561" id="Path" fill="url(#linearGradient-2)" fill-rule="nonzero"></path>
<path d="M43.2983488,19.0991931 L27.5566079,3.88246244 C26.7624281,3.11476967 26.7409561,1.84862177 27.5086488,1.05444194 C27.8854826,0.664606611 28.4044438,0.444472651 28.9466386,0.444472651 L60.3925021,0.444472651 C61.4970716,0.444472651 62.3925021,1.33990315 62.3925021,2.44447265 C62.3925021,2.9858375 62.1730396,3.50407742 61.7842512,3.88079942 L46.0801285,19.0975301 C45.3051579,19.8484488 44.0742167,19.8491847 43.2983488,19.0991931 Z" id="Path" fill="url(#linearGradient-3)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,214 @@
<template>
<template v-if="inIframe">
<div :id="sectionId"><slot /></div>
</template>
<section v-else class="code-box" :id="sectionId">
<section class="code-box-demo">
<template v-if="iframeDemo[iframeDemoKey]">
<div class="browser-mockup with-url">
<iframe :src="iframeDemo[iframeDemoKey]" :height="iframeHeight" />
</div>
</template>
<template v-else>
<slot />
</template>
</section>
<section class="code-box-meta markdown">
<div class="code-box-title">
<a :href="`#${sectionId}`">{{ title }}</a>
</div>
<div class="code-box-description" v-html="docHtml"></div>
<div class="code-box-actions">
<a-tooltip :title="$t(`app.demo.type.${type === 'JS' ? 'js' : 'ts'}`)">
<span
class="code-expand-icon code-box-code-action"
style="width: auto"
@click="handleChangeType"
>
{{ type }}
</span>
</a-tooltip>
<a-tooltip
v-if="!blocked"
:title="$t(`app.demo.${copied ? 'copied' : 'copy'}`)"
:visible="copyTooltipVisible"
@visibleChange="onCopyTooltipVisibleChange"
>
<component
key="copy"
v-clipboard:copy="type === 'TS' ? sourceCode : jsSourceCode"
v-clipboard:success="handleCodeCopied"
:is="copied && copyTooltipVisible ? 'CheckOutlined' : 'SnippetsOutlined'"
class="code-box-code-copy code-box-code-action"
/>
</a-tooltip>
<a-tooltip v-else :title="$t('app.demo.copy')">
<SnippetsOutlined class="code-box-code-copy code-box-code-action" @click="warning" />
</a-tooltip>
<a-tooltip :title="$t(`app.demo.code.${codeExpand ? 'hide' : 'show'}`)">
<span class="code-expand-icon code-box-code-action">
<img
alt="expand code"
:src="
theme === 'dark'
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
"
:class="codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'"
@click="handleCodeExpand"
/>
<img
alt="expand code"
:src="
theme === 'dark'
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
"
:class="codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'"
@click="handleCodeExpand"
/>
</span>
</a-tooltip>
</div>
</section>
<section :class="highlightClass">
<div class="highlight">
<slot v-if="type === 'TS'" name="htmlCode" />
<slot v-else name="jsVersionHtml" />
</div>
</section>
</section>
</template>
<script lang="ts">
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { computed, defineComponent, inject, onMounted, ref } from 'vue';
import { CheckOutlined, SnippetsOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
export default defineComponent({
name: 'DemoBox',
props: {
jsfiddle: Object,
},
setup(props) {
const codeExpand = ref(false);
const type = ref('TS');
const copyTooltipVisible = ref(false);
const copied = ref(false);
const sectionId = computed(() => {
const relativePath = props.jsfiddle?.relativePath || '';
return `components-${relativePath
.split('/docs/')[1]
.split('/')
.join('-')
.replace('.vue', '')}`;
});
const inIframe = inject('inIframe', false);
const iframeHeight = computed(() => props.jsfiddle?.iframe);
// eslint-disable-next-line @typescript-eslint/no-empty-function
const addDemosInfo: any = inject('addDemosInfo', () => {});
const globalConfig = inject<GlobalConfig>(GLOBAL_CONFIG)!;
const title = computed(
() =>
props.jsfiddle &&
props.jsfiddle.title &&
props.jsfiddle?.title[globalConfig.isZhCN.value ? 'zh-CN' : 'en-US'],
);
const warning = () => {
Modal.warning({
content: globalConfig.isZhCN
? '我们检测到你可能使用了 AdBlock 或 Adblock Plus它会影响到复制、展开代码等功能。 你可以将 Ant Design Vue 加入白名单,以便我们更好地提供服务。'
: 'We have detected that you may have used AdBlock or Adblock Plus, which will affect functions such as copying and expanding code. You can add Ant Design Vue to the whitelist so that we can provide better services.',
});
};
const iframeDemoKey = computed(() => {
return (
props.jsfiddle &&
props.jsfiddle.title &&
props.jsfiddle?.title['en-US'] &&
String(props.jsfiddle?.title['en-US']).split(' ').join('-').toLowerCase()
);
});
const onCopyTooltipVisibleChange = (visible: boolean) => {
if (visible) {
copyTooltipVisible.value = visible;
copied.value = false;
} else {
copyTooltipVisible.value = visible;
}
};
const docHtml = computed(() =>
props.jsfiddle && props.jsfiddle.docHtml
? (
props.jsfiddle.docHtml
.replace('<h2 id="zh-cn">zh-CN</h2>', '')
.split('<h2 id="en-us">en-US</h2>')[globalConfig.isZhCN.value ? 0 : 1] || ''
).trim()
: '',
);
const handleCodeExpand = () => {
if (globalConfig.blocked.value) {
warning();
return;
}
codeExpand.value = !codeExpand.value;
};
const handleCodeCopied = () => {
copied.value = true;
};
const handleChangeType = () => {
if (globalConfig.blocked.value) {
warning();
return;
}
type.value = type.value === 'TS' ? 'JS' : 'TS';
};
const highlightClass = computed(() => {
return {
'highlight-wrapper': true,
'highlight-wrapper-expand': codeExpand.value,
};
});
const iframeDemo = inject('iframeDemo', {});
onMounted(() => {
addDemosInfo({
href: `#${sectionId.value}`,
title,
});
});
const theme = computed(() => inject('themeMode', { theme: ref('default') }).theme.value);
return {
docHtml,
iframeDemo,
iframeDemoKey,
iframeHeight,
inIframe,
theme,
type,
warning,
blocked: globalConfig.blocked,
isZhCN: globalConfig.isZhCN,
sectionId,
title,
codeExpand,
copyTooltipVisible,
copied,
onCopyTooltipVisibleChange,
handleCodeExpand,
handleCodeCopied,
handleChangeType,
highlightClass,
sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))),
jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))),
};
},
components: {
CheckOutlined,
SnippetsOutlined,
},
});
</script>
<style></style>

View File

@ -0,0 +1,5 @@
<template>
<div>
<router-view></router-view>
</div>
</template>

View File

@ -0,0 +1,31 @@
<template>
<div class="markdown api-container">
<google-ads v-if="showAd" />
<slot v-if="isZhCN" name="cn" />
<slot v-else />
</div>
</template>
<script lang="ts">
import { isZhCN } from '../utils/util';
import GoogleAds from './GoogleAds.vue';
import { inject } from 'vue';
const showAd = location.host.indexOf('antdv.com') > -1;
export default {
name: 'Api',
components: {
GoogleAds,
},
setup() {
return {
demoContext: inject('demoContext', {}),
};
},
data() {
return {
showAd,
isZhCN: isZhCN(this.demoContext.name),
};
},
};
</script>

View File

@ -0,0 +1,79 @@
<template>
<div>
<demo-box :jsfiddle="jsfiddle">
<template #component>
<slot />
</template>
<template #description>
<div class="demo-description" v-html="cnHtml" />
</template>
<template #us-description>
<div class="demo-description" v-html="usHtml" />
</template>
<template #code>
{{ codeStr }}
</template>
</demo-box>
</div>
</template>
<script>
import marked from 'marked';
import Prism from 'prismjs';
// import 'prismjs/components/prism-jsx.min.js';
// import 'prismjs/components/prism-bash.min.js';
const replaceDelimiters = function (str) {
return str.replace(/({{|}})/g, '<span>$1</span>');
};
const renderHighlight = function (str, lang) {
if (!(lang && Prism.languages[lang])) {
return '';
}
try {
return replaceDelimiters(Prism.highlight(str, Prism.languages[lang], lang));
} catch (err) {}
};
const renderer = new marked.Renderer();
renderer.heading = function (text, level) {
return (
'<h' + level + ' id="' + text.replace(/[^\w]+/g, '-') + '">' + text + '</h' + level + '>\n'
);
};
marked.setOptions({
renderer,
gfm: true,
tables: true,
breaks: true,
pedantic: true,
sanitize: true,
smartLists: true,
smartypants: true,
html: true,
highlight: renderHighlight,
});
const cnReg = /<cn>([\S\s\t]*?)<\/cn>/;
const usReg = /<us>([\S\s\t]*?)<\/us>/;
export default {
name: 'DemoContainer',
props: ['code'],
data() {
const cn = this.code.match(cnReg) || [];
const us = this.code.match(usReg) || [];
const cnHtml = marked(cn[1].trim());
const usHtml = marked(us[1].trim());
const sourceCode = this.code.replace(cn[0], '').replace(us[0], '').trim();
const codeHtml = marked('```html\n' + sourceCode + '```');
return {
codeStr: window.btoa(unescape(encodeURIComponent(codeHtml))),
cnHtml,
usHtml,
jsfiddle: {
sourceCode: window.btoa(unescape(encodeURIComponent(sourceCode))),
cn: cn[1].trim(),
us: us[1].trim(),
},
};
},
};
</script>

View File

@ -0,0 +1,47 @@
import { defineComponent, inject } from 'vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
export default defineComponent({
props: {
cols: {
type: [Number, String],
default: 2,
},
},
setup() {
return {
demoContext: inject('demoContext', {}),
globalConfig: inject(GLOBAL_CONFIG),
};
},
render() {
const { cols, globalConfig, $slots } = this;
// 访 demo
const isSingleCol = cols === 1 || globalConfig.isMobile.value;
const leftChildren = [];
const rightChildren = [];
const children = $slots.default?.() || [];
children.forEach((demo, index) => {
if (index % 2 === 0 || isSingleCol) {
leftChildren.push(demo);
} else {
rightChildren.push(demo);
}
});
return (
<a-row gutter={16}>
<a-col
span={isSingleCol ? 24 : 12}
class={isSingleCol ? 'code-boxes-col-1-1' : 'code-boxes-col-2-1'}
>
{leftChildren}
</a-col>
{isSingleCol ? null : (
<a-col class="code-boxes-col-2-1" span={12}>
{rightChildren}
</a-col>
)}
</a-row>
);
},
});

View File

@ -0,0 +1,204 @@
import { isZhCN } from '../utils/util';
import packageInfo from '../../package.json';
import logo from '../assets/logo.svg';
import antDesignVue from '../assets/ant-design-vue.svg';
import { SearchOutlined } from '@ant-design/icons-vue';
export default {
props: {
name: String,
searchData: Array,
},
data() {
return {
value: null,
};
},
mounted() {
this.initDocSearch(this.$i18n.locale);
},
methods: {
handleClose(key) {
localStorage.removeItem('jobs-notification-key');
localStorage.setItem('jobs-notification-key', key);
},
initDocSearch(locale) {
window.docsearch({
apiKey: '92003c1d1d07beef165b08446f4224a3',
indexName: 'antdv',
inputSelector: '#search-box input',
algoliaOptions: { facetFilters: [isZhCN(locale) ? 'cn' : 'en'] },
transformData(hits) {
hits.forEach(hit => {
hit.url = hit.url.replace('www.antdv.com', window.location.host);
hit.url = hit.url.replace('https:', window.location.protocol);
});
return hits;
},
debug: false, // Set debug to true if you want to inspect the dropdown
});
},
handleClick() {
const name = this.name;
const path = this.$route.path;
const newName = isZhCN(name) ? name.replace(/-cn\/?$/, '') : `${name}-cn`;
this.$router.push({
path: path.replace(name, newName),
});
this.$i18n.locale = isZhCN(name) ? 'en-US' : 'zh-CN';
},
onSelect(val) {
this.$router.push(val);
this.value = val;
},
},
render() {
const name = this.name;
const isCN = isZhCN(name);
const path = this.$route.path;
const selectedKeys = path === '/jobs/list-cn' ? ['jobs'] : ['components'];
return (
<header id="header">
<a-row>
<a-col class="header-left" xxl={4} xl={5} lg={5} md={6} sm={24} xs={24}>
<router-link to={{ path: '/' }} id="logo">
<img alt="logo" height="32" src={logo} />
<img alt="logo" height="16" src={antDesignVue} />
</router-link>
<a-button
ghost
size="small"
onClick={this.handleClick}
class="header-lang-button"
key="lang-button"
>
{isCN ? 'English' : '中文'}
</a-button>
</a-col>
<a-col xxl={20} xl={19} lg={19} md={18} sm={0} xs={0}>
<div id="search-box">
<SearchOutlined />
<a-input
placeholder={isCN ? '搜索组件...' : 'input search text'}
style="width: 200px"
/>
</div>
<span id="github-btn" class="github-btn">
<a class="gh-btn" href="//github.com/vueComponent/ant-design-vue/" target="_blank">
<span class="gh-ico" aria-hidden="true"></span>
<span class="gh-text">Star</span>
</a>
</span>
<a-button
ghost
size="small"
onClick={this.handleClick}
class="header-lang-button"
key="lang-button"
>
{isCN ? 'English' : '中文'}
</a-button>
<a-select
style="width: 100px"
size="small"
defaultValue={packageInfo.version}
class="version"
>
<a-select-option value={packageInfo.version}>{packageInfo.version}</a-select-option>
<a-select-option value="1.x" onClick={() => (location.href = 'https://1x.antdv.com')}>
1.x
</a-select-option>
</a-select>
<a-menu selectedKeys={selectedKeys} mode="horizontal" class="menu-site" id="nav">
<a-menu-item key="components">
<router-link to="/docs/vue/introduce">{isCN ? '组件' : 'Components'}</router-link>
</a-menu-item>
{isCN ? (
<a-menu-item key="store">
<a
href="https://store.antdv.com/pro/"
target="_blank"
style="position: relative;"
>
商店
<a-badge color="red" style="position: absolute;top: -10px;right: -10px;" />
</a>
</a-menu-item>
) : null}
{isCN ? (
<a-menu-item key="geektime">
<a
href="https://time.geekbang.org/course/intro/100024601?code=KHKYcoBU6vZa8nMglg7AWfDxxi3BWrz9INAzAY3umPk%3D"
target="_blank"
style="position: relative;"
>
Vue 实战教程
<a-badge color="red" style="position: absolute;top: -10px;right: -10px;" />
</a>
</a-menu-item>
) : null}
<a-menu-item key="sponsor">
<router-link
to={{
path: isCN ? '/docs/vue/sponsor-cn/' : '/docs/vue/sponsor/',
}}
>
{isCN ? '支持我们' : 'Support us'}
</router-link>
</a-menu-item>
<a-sub-menu key="Ecosystem" title={isCN ? '更多' : 'More'}>
<a-menu-item key="pro">
<a target="_blank" href="https://pro.antdv.com">
Pro (Admin)
</a>
</a-menu-item>
<a-menu-item key="design">
<router-link
to={{
path: isCN ? '/docs/vue/download-cn/' : '/docs/vue/download/',
}}
>
{isCN ? '设计资源' : 'Design Resources'}
</router-link>
</a-menu-item>
<a-menu-item key="vscode">
<a
target="_blank"
href="https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper"
>
VS Code Extension
</a>
</a-menu-item>
<a-menu-item key="awesome">
<a target="_blank" href="https://github.com/vueComponent/ant-design-vue-awesome">
Awesome
</a>
</a-menu-item>
<a-menu-item key="wechat">
<a-popover
placement="right"
content={
<img
width="160"
height="160"
alt="wechat"
src="https://qn.antdv.com/wechat.jpeg"
/>
}
>
<a>{isCN ? '微信' : 'WeChat'}</a>
</a-popover>
</a-menu-item>
<a-menu-item key="qq">
<a>QQ 群12174900933000人已满</a>
<a>QQ 群2809774695</a>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-col>
</a-row>
</header>
);
},
};

View File

@ -0,0 +1,124 @@
<template>
<div id="carbon-ads" :class="isMobile ? 'carbon-mobile' : ''" />
</template>
<script>
const carbonUrls = {
'www.antdv.com': '//cdn.carbonads.com/carbon.js?serve=CK7DL2JW&placement=antdvcom',
// 'tangjinzhou.gitee.io':
// '//cdn.carbonads.com/carbon.js?serve=CK7DL2JN&placement=tangjinzhougiteeio',
// 'ant-design-vue.gitee.io':
// '//cdn.carbonads.com/carbon.js?serve=CK7DL2JN&placement=antdesignvuegiteeio',
'vue.ant.design': '//cdn.carbonads.com/carbon.js?serve=CK7DL2JW&placement=vueantdesign',
};
const carbonUrl =
carbonUrls[location.host] ||
'//cdn.carbonads.com/carbon.js?serve=CK7DL2JW&placement=vueantdesign';
export default {
props: {
isMobile: Boolean,
},
watch: {
$route(e, t) {
let adId = '#carbonads';
// if(isGitee) {
// adId = '#cf';
// }
if (e.path !== t.path && this.$el.querySelector(adId)) {
this.$el.innerHTML = '';
this.load();
}
this.adInterval && clearInterval(this.adInterval);
this.adInterval = setInterval(() => {
if (!this.$el.querySelector(adId)) {
this.$el.innerHTML = '';
this.load();
}
}, 20000);
},
},
mounted() {
this.load();
},
methods: {
load() {
// if(isGitee) {
// axios.get('https://api.codefund.app/properties/162/funder.html?template=horizontal')
// .then(function (response) {
// document.getElementById("codefund-ads").innerHTML = response.data;
// });
// } else
if (carbonUrl) {
const e = document.createElement('script');
e.id = '_carbonads_js';
e.src = carbonUrl;
this.$el.appendChild(e);
}
},
},
};
</script>
<style lang="less">
#carbon-ads {
width: 280px;
float: right;
margin-top: 75px;
position: relative;
right: 0;
bottom: 0;
padding: 0;
overflow: hidden;
z-index: 9;
background-color: #fff;
border-radius: 3px;
font-size: 13px;
background: #f5f5f5;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
#carbonads {
overflow: hidden;
}
#carbon-ads a {
display: inline-block;
color: #7f8c8d;
font-weight: normal;
}
#carbon-ads span {
color: #7f8c8d;
}
#carbon-ads img {
float: left;
padding-right: 10px;
}
#carbon-ads .carbon-img,
#carbon-ads .carbon-text {
display: block;
font-weight: normal;
color: #34495e;
}
#carbon-ads .carbon-text {
padding-top: 6px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
#carbon-ads .carbon-poweredby {
color: #aaa;
font-weight: normal;
line-height: 1.2;
margin-top: 6px;
}
#carbon-ads.carbon-mobile {
width: 100%;
position: relative;
right: 0;
bottom: 0;
padding: 0;
margin-bottom: 15px;
margin-top: 5px;
.carbon-img {
float: left;
margin-right: 10px;
}
}
</style>

View File

@ -0,0 +1,36 @@
<template>
<div v-if="false" class="google-ads" id="API">
<ins
ref="ins"
class="adsbygoogle"
style="display: block"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="7647023136"
data-ad-format="auto"
data-full-width-responsive="true"
></ins>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
mounted() {
// this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
});
</script>

View File

@ -0,0 +1,43 @@
<template>
<div
style="
width: 300px;
float: right;
margin-top: 75px;
position: relative;
right: 0;
bottom: 0;
padding: 0;
z-index: 9;
"
>
<ins
ref="ins"
class="adsbygoogle"
style="display: inline-block; width: 300px; height: 100px"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="2774992529"
></ins>
</div>
</template>
<script>
export default {
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
};
</script>

View File

@ -0,0 +1,34 @@
<template>
<div class="google-ads">
<ins
ref="ins"
class="adsbygoogle"
data-ad-client="ca-pub-4801326429087140"
data-ad-slot="2425414214"
style="display: inline-block; width: 728px; height: 90px"
></ins>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.ins.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
(window.adsbygoogle = window.adsbygoogle || []).push({});
},
},
});
</script>

View File

@ -0,0 +1,27 @@
<template>
<div>
<div ref="inner" class="wwads-cn wwads-horizontal" data-id="62" style="max-width: 350px"></div>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
mounted() {
this.load();
},
methods: {
load() {
if (this.scriptDom) {
this.$el.removeChild(this.scriptDom);
}
this.$refs.inner.innerHTML = '';
const e = document.createElement('script');
e.src = 'https://wwads.cn/js/makemoney.js';
e.async = true;
this.$el.appendChild(e);
this.scriptDom = e;
},
},
});
</script>

View File

@ -0,0 +1,45 @@
<template>
<div v-show="visible" id="geektime">
<a
href="https://time.geekbang.org/course/intro/100024601?code=KHKYcoBU6vZa8nMglg7AWfDxxi3BWrz9INAzAY3umPk%3D"
target="_blank"
>
<img width="150" alt="Vue 实战教程" src="https://qn.antdv.com/geektime-vue.jpeg" />
</a>
<div class="close" @click="visible = false">
<close-outlined />
</div>
</div>
</template>
<script>
import { CloseOutlined } from '@ant-design/icons-vue';
export default {
components: {
CloseOutlined,
},
props: ['isMobile'],
data() {
return {
visible: true,
};
},
};
</script>
<style lang="less" scoped>
#geektime {
position: fixed;
bottom: 10px;
right: 10px;
.close {
position: absolute;
text-align: center;
top: -8px;
right: -8px;
font-size: 16px;
padding: 15px;
color: #6e3041;
}
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<div
v-if="isEffective(effectiveTime)"
id="geektime-ads"
:class="isMobile ? 'geektime-ads-mobile' : ''"
>
<a
href="https://time.geekbang.org/column/intro/154?utm_term=zeusGZFFE&utm_source=app&utm_medium=tangjinzhou"
target="_blank"
>
<img height="100" alt="重学前端" src="https://qn.antdv.com/chongxueqianduan.jpg" />
</a>
</div>
</template>
<script lang="ts">
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
export default {
props: ['isMobile'],
data() {
return {
visible: true,
effectiveTime: {
start: '2019-08-05 17:00:00',
end: '2019-09-05 17:00:00',
},
};
},
methods: {
isEffective({ start, end }) {
return dayjs().isBetween(start, end);
},
},
};
</script>
<style lang="less" scoped>
#geektime-ads {
width: 266px;
position: fixed;
left: 0;
bottom: 0px;
padding: 0;
overflow: hidden;
z-index: 9;
background-color: #fff;
border-radius: 3px;
font-size: 13px;
background: #f5f5f5;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
#geektime-ads.geektime-ads-mobile {
width: 100%;
position: relative;
right: 0;
bottom: 0;
padding: 0;
margin-bottom: 15px;
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<div id="right-bottom">
<img v-if="isCN" width="150" alt="官方公众号" src="https://qn.antdv.com/wechat.jpeg" />
<div v-if="isMobile" class="close" @click="visible = false">
<close-outlined />
</div>
<!-- <span v-if="isCN">广</span> -->
</div>
</template>
<script>
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
import { CloseOutlined } from '@ant-design/icons-vue';
const isEffective = (start, end) => {
return dayjs().isBetween(start, end);
};
export default {
components: {
CloseOutlined,
},
props: ['isCN', 'isMobile'],
data() {
return {
visible: true,
ads: [
{
alt: 'geektime',
img: 'https://qn.antdv.com/geektime-web-small.jpg',
href: 'http://gk.link/a/10l8O',
visible: isEffective('2020-09-03 10:00:00', '2020-10-04 10:00:00'),
},
{
alt: 'powerproject',
img: 'https://qn.antdv.com/powerproject.jpeg?v=20200327',
href: 'http://www.powerproject.com.cn',
visible: isEffective('2020-03-27 17:00:00', '2020-09-28 17:00:00'),
},
],
};
},
};
</script>
<style lang="less" scoped>
#right-bottom {
position: fixed;
bottom: 10px;
right: 10px;
width: 150px;
.close {
position: absolute;
text-align: center;
top: -8px;
right: -8px;
font-size: 16px;
padding: 15px;
color: #6e3041;
}
}
</style>

View File

@ -0,0 +1,71 @@
<template>
<div class="snd-ad" style="padding-left: 40px">
<div class="sponsorsWrap">
<span v-if="!isCN" class="sponsorsTitle">
{{ isCN ? '赞助商' : 'Sponsors' }}
</span>
<ul>
<!-- <li class="sponsorsItem">
<a href="https://tipe.io/?ref=ant-design-vue" target="_blank">
<img height="51" src="https://cdn.tipe.io/tipe/tipe-cat-no-text.svg" alt="tipe" />
</a>
</li> -->
<li v-if="isCN && isEffective(effectiveTime.kkb)" class="sponsorsItem">
<a href="https://datayi.cn/w/Y9J3M2vR" target="_blank">
<img height="66" src="https://qn.antdv.com/kaikeba_ssr.jpeg" alt="kaikeba" />
</a>
</li>
<li class="sponsorsItem" style="padding: 10px 0">
<a-button type="primary" ghost style="font-size: 12px" @click="handleClick">
{{ isCN ? '成为赞助商' : 'Become a Sponsor' }}
</a-button>
</li>
</ul>
</div>
<a-modal v-model:visible="visible" title="成为赞助商" @ok="visible = false">
如果您有品牌推广活动推广招聘推广社区合作等需求欢迎联系我们成为赞助商
<br />
您的广告将出现在 And Design Vue 文档所有子页面及 GitHub Readme 等页面
<br />
咨询邮箱
<a href="mailto:antdv@foxmail.com">antdv@foxmail.com</a>
<br />
</a-modal>
</div>
</template>
<script>
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
export default {
props: ['isCN'],
data() {
return {
top: 50,
effectiveTime: {
bmatch: {
start: '2019-03-11',
end: '2019-06-11',
},
kkb: {
start: '2020-11-16 22:00:00',
end: '2021-05-17 22:00:00',
},
},
visible: false,
};
},
methods: {
isEffective({ start, end }) {
return dayjs().isBetween(start, end);
},
handleClick() {
if (this.isCN) {
this.visible = true;
} else {
window.open('https://opencollective.com/ant-design-vue#sponsor');
}
},
},
};
</script>

View File

@ -0,0 +1,63 @@
<template>
<div>
<template v-if="ads.length">
<a-carousel autoplay>
<template v-for="ad in ads" :key="ad.href">
<a :href="ad.href" target="_blank">
<img style="width: 100%; max-width: 1200px" :alt="ad.alt || ''" :src="ad.img" />
</a>
</template>
</a-carousel>
</template>
<template v-else-if="showGoogleAd">
<template v-if="isCN">
<WWAds :key="`WWAds_${$route.path}`" />
</template>
<google-ads-top v-else :key="`GoogleAdsTop_${$route.path}`" />
</template>
</div>
</template>
<script>
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
import GoogleAdsTop from './GoogleAdsTop.vue';
import WWAds from './WWAds.vue';
const isEffective = (start, end) => {
return dayjs().isBetween(start, end);
};
export default {
components: {
GoogleAdsTop,
WWAds,
},
props: ['isCN', 'isMobile'],
data() {
return {
showGoogleAd: location.host.indexOf('antdv.com') > -1,
cnAds: [
{
img: `https://yidengfe.com/launches/01/yd.png?v=${Date.now()}`,
href: 'https://yidengfe.com/launches/01/yd.html',
visible: isEffective('2020-09-11 17:00:00', '2021-03-11 17:00:00'),
},
].filter(ad => ad.visible),
enAds: [
{
img: 'https://qn.antdv.com/TheBigRichGroup.png',
href: 'https://thebigrichgroup.com/',
visible: isEffective('2020-09-18 17:00:00', '2021-07-09 17:00:00'),
},
].filter(ad => ad.visible),
};
},
computed: {
ads() {
return this.isCN ? this.cnAds : this.enAds;
},
},
};
</script>
<style lang="less" scoped></style>

398
site/src/demo.js Normal file
View File

@ -0,0 +1,398 @@
export default {
avatar: {
category: 'Components',
subtitle: '头像',
type: 'Data Display',
title: 'Avatar',
},
badge: {
category: 'Components',
subtitle: '徽标数',
type: 'Data Display',
title: 'Badge',
},
comment: {
category: 'Components',
subtitle: '评论',
type: 'Data Display',
title: 'Comment',
},
configProvider: {
category: 'Components',
subtitle: '全局化配置',
type: 'Other',
title: 'ConfigProvider',
},
empty: {
category: 'Components',
subtitle: '空状态',
type: 'Data Display',
title: 'Empty',
},
breadcrumb: {
category: 'Components',
subtitle: '面包屑',
type: 'Navigation',
title: 'Breadcrumb',
},
button: {
category: 'Components',
subtitle: '按钮',
type: 'General',
title: 'Button',
},
card: {
category: 'Components',
subtitle: '卡片',
type: 'Data Display',
title: 'Card',
cols: 1,
},
checkbox: {
category: 'Components',
subtitle: '多选框',
type: 'Data Entry',
title: 'Checkbox',
},
grid: {
category: 'Components',
subtitle: '栅格',
type: 'Layout',
title: 'Grid',
cols: 1,
},
icon: {
category: 'Components',
subtitle: '图标',
type: 'General',
title: 'Icon',
},
input: {
category: 'Components',
subtitle: '输入框',
type: 'Data Entry',
title: 'Input',
},
mentions: {
category: 'Components',
subtitle: '提及',
type: 'Data Entry',
title: 'Mentions',
},
select: {
category: 'Components',
subtitle: '选择器',
type: 'Data Entry',
title: 'Select',
},
menu: {
category: 'Components',
subtitle: '导航菜单',
type: 'Navigation',
title: 'Menu',
cols: 1,
},
pagination: {
category: 'Components',
subtitle: '分页',
type: 'Navigation',
title: 'Pagination',
cols: 1,
},
pageHeader: {
category: 'Components',
subtitle: '页头',
type: 'Navigation',
title: 'PageHeader',
cols: 1,
},
popconfirm: {
category: 'Components',
subtitle: '气泡确认框',
type: 'Feedback',
title: 'Popconfirm',
},
popover: {
category: 'Components',
subtitle: '气泡卡片',
type: 'Data Display',
title: 'Popover',
},
radio: {
category: 'Components',
subtitle: '单选框',
type: 'Data Entry',
title: 'Radio',
},
rate: {
category: 'Components',
subtitle: '评分',
type: 'Data Entry',
title: 'Rate',
cols: 1,
},
tabs: {
category: 'Components',
subtitle: '标签页',
type: 'Data Display',
title: 'Tabs',
cols: 1,
},
tag: {
category: 'Components',
subtitle: '标签',
type: 'Data Display',
title: 'Tag',
},
tooltip: {
category: 'Components',
subtitle: '文字提示',
type: 'Data Display',
title: 'Tooltip',
},
dropdown: {
category: 'Components',
subtitle: '下拉菜单',
type: 'Navigation',
title: 'Dropdown',
},
divider: {
category: 'Components',
subtitle: '分割线',
type: 'Other',
title: 'Divider',
},
collapse: {
category: 'Components',
subtitle: '折叠面板',
type: 'Data Display',
title: 'Collapse',
cols: 1,
},
notification: {
category: 'Components',
subtitle: '通知提醒框',
type: 'Feedback',
title: 'Notification',
},
message: {
category: 'Components',
subtitle: '全局提示',
type: 'Feedback',
title: 'Message',
},
spin: {
category: 'Components',
subtitle: '加载中',
type: 'Feedback',
title: 'Spin',
},
result: {
category: 'Components',
subtitle: '结果',
type: 'Feedback',
title: 'Result',
},
switch: {
category: 'Components',
subtitle: '开关',
type: 'Data Entry',
title: 'Switch',
},
autoComplete: {
category: 'Components',
subtitle: '自动完成',
type: 'Data Entry',
title: 'AutoComplete',
cols: 2,
},
affix: {
category: 'Components',
subtitle: '固钉',
type: 'Navigation',
title: 'Affix',
},
cascader: {
category: 'Components',
subtitle: '级联选择',
type: 'Data Entry',
title: 'Cascader',
},
backTop: {
category: 'Components',
subtitle: '回到顶部',
type: 'Other',
title: 'BackTop',
},
modal: {
category: 'Components',
subtitle: '对话框',
type: 'Feedback',
title: 'Modal',
},
alert: {
category: 'Components',
subtitle: '警告提示',
type: 'Feedback',
title: 'Alert',
},
timePicker: {
category: 'Components',
subtitle: '时间选择框',
type: 'Data Entry',
title: 'TimePicker',
},
steps: {
category: 'Components',
subtitle: '步骤条',
type: 'Navigation',
title: 'Steps',
cols: 1,
},
calendar: {
category: 'Components',
subtitle: '日历',
type: 'Data Display',
title: 'Calendar',
cols: 1,
},
datePicker: {
category: 'Components',
subtitle: '日期选择框',
type: 'Data Entry',
title: 'DatePicker',
},
slider: {
category: 'Components',
subtitle: '滑动输入条',
type: 'Data Entry',
title: 'Slider',
},
progress: {
category: 'Components',
subtitle: '进度条',
type: 'Feedback',
title: 'Progress',
},
timeline: {
category: 'Components',
subtitle: '时间轴',
type: 'Data Display',
title: 'Timeline',
},
table: {
category: 'Components',
subtitle: '表格',
type: 'Data Display',
title: 'Table',
cols: 1,
},
inputNumber: {
category: 'Components',
subtitle: '数字输入框',
type: 'Data Entry',
title: 'InputNumber',
},
transfer: {
category: 'Components',
subtitle: '穿梭框',
type: 'Data Entry',
title: 'Transfer',
cols: '1',
},
upload: {
category: 'Components',
subtitle: '上传',
type: 'Data Entry',
title: 'Upload',
},
carousel: {
category: 'Components',
type: 'Data Display',
title: 'Carousel',
subtitle: '走马灯',
},
tree: {
category: 'Components',
subtitle: '树形控件',
type: 'Data Display',
title: 'Tree',
},
treeSelect: {
category: 'Components',
subtitle: '树选择',
type: 'Data Entry',
title: 'TreeSelect',
},
layout: {
category: 'Components',
subtitle: '布局',
type: 'Layout',
title: 'Layout',
cols: 1,
},
form: {
category: 'Components',
subtitle: '表单',
type: 'Data Entry',
title: 'Form',
cols: 1,
},
anchor: {
category: 'Components',
subtitle: '锚点',
type: 'Other',
title: 'Anchor',
cols: 2,
},
image: {
category: 'Components',
subtitle: '图片',
type: 'Data Display',
title: 'Image',
cols: 2,
},
list: {
category: 'Components',
subtitle: '列表',
type: 'Data Display',
title: 'List',
cols: 1,
},
drawer: {
category: 'Components',
type: 'Feedback',
title: 'Drawer',
subtitle: '抽屉',
},
skeleton: {
category: 'Components',
type: 'Feedback',
title: 'Skeleton',
subtitle: '骨架屏',
},
statistic: {
category: 'Components',
subtitle: '统计数值',
type: 'Data Display',
title: 'Statistic',
},
descriptions: {
category: 'Components',
subtitle: '描述列表',
type: 'Data Display',
title: 'Descriptions',
},
space: {
category: 'Components',
subtitle: '间距',
type: 'Layout',
title: 'Space',
},
// colorPicker: {
// category: 'Components',
// subtitle: '取色器',
// type: 'Data Entry',
// title: 'ColorPicker (Beta)',
// },
};

View File

@ -0,0 +1,208 @@
import select from './select';
/**
* Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations.
*/
class ClipboardAction {
/**
* @param {Object} options
*/
constructor(options) {
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options
*/
resolveOptions(options = {}) {
this.action = options.action;
this.container = options.container;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
}
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
initSelection() {
if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
}
}
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
selectFake() {
const isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake();
this.fakeHandlerCallback = () => this.removeFake();
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
this.fakeElem = document.createElement('textarea');
// Prevent zooming on iOS
this.fakeElem.style.fontSize = '12pt';
// Reset box model
this.fakeElem.style.border = '0';
this.fakeElem.style.padding = '0';
this.fakeElem.style.margin = '0';
// Move element out of screen horizontally
this.fakeElem.style.position = 'absolute';
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
// Move element to the same position vertically
let yPosition = window.pageYOffset || document.documentElement.scrollTop;
this.fakeElem.style.top = `${yPosition}px`;
this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text;
this.container.appendChild(this.fakeElem);
this.selectedText = select(this.fakeElem);
this.copyText();
}
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
removeFake() {
if (this.fakeHandler) {
this.container.removeEventListener('click', this.fakeHandlerCallback);
this.fakeHandler = null;
this.fakeHandlerCallback = null;
}
if (this.fakeElem) {
this.container.removeChild(this.fakeElem);
this.fakeElem = null;
}
}
/**
* Selects the content from element passed on `target` property.
*/
selectTarget() {
this.selectedText = select(this.target);
this.copyText();
}
/**
* Executes the copy operation based on the current selection.
*/
copyText() {
let succeeded;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
handleResult(succeeded) {
this.emitter.emit(succeeded ? 'success' : 'error', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this),
});
}
/**
* Moves focus away from `target` and back to the trigger, removes current selection.
*/
clearSelection() {
if (this.trigger) {
this.trigger.focus();
}
document.activeElement.blur();
window.getSelection().removeAllRanges();
}
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
set action(action = 'copy') {
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"');
}
}
/**
* Gets the `action` property.
* @return {String}
*/
get action() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
set target(target) {
if (target !== undefined) {
if (target && typeof target === 'object' && target.nodeType === 1) {
if (this.action === 'copy' && target.hasAttribute('disabled')) {
throw new Error(
'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute',
);
}
if (
this.action === 'cut' &&
(target.hasAttribute('readonly') || target.hasAttribute('disabled'))
) {
throw new Error(
'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes',
);
}
this._target = target;
} else {
throw new Error('Invalid "target" value, use a valid Element');
}
}
}
/**
* Gets the `target` property.
* @return {String|HTMLElement}
*/
get target() {
return this._target;
}
/**
* Destroy lifecycle.
*/
destroy() {
this.removeFake();
}
}
export default ClipboardAction;

View File

@ -0,0 +1,134 @@
import ClipboardAction from './clipboard-action';
import Emitter from './tiny-emitter';
import listen from './listen';
/**
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
class Clipboard extends Emitter {
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
constructor(trigger, options) {
super();
this.resolveOptions(options);
this.listenClick(trigger);
}
/**
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor.
* @param {Object} options
*/
resolveOptions(options = {}) {
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
this.container = typeof options.container === 'object' ? options.container : document.body;
}
/**
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
listenClick(trigger) {
this.listener = listen(trigger, 'click', e => this.onClick(e));
}
/**
* Defines a new `ClipboardAction` on each click event.
* @param {Event} e
*/
onClick(e) {
const trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new ClipboardAction({
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
container: this.container,
trigger: trigger,
emitter: this,
});
}
/**
* Default `action` lookup function.
* @param {Element} trigger
*/
defaultAction(trigger) {
return getAttributeValue('action', trigger);
}
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
defaultTarget(trigger) {
const selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
}
/**
* Returns the support of the given action, or all actions if no action is
* given.
* @param {String} [action]
*/
static isSupported(action = ['copy', 'cut']) {
const actions = typeof action === 'string' ? [action] : action;
let support = !!document.queryCommandSupported;
actions.forEach(action => {
support = support && !!document.queryCommandSupported(action);
});
return support;
}
/**
* Default `text` lookup function.
* @param {Element} trigger
*/
defaultText(trigger) {
return getAttributeValue('text', trigger);
}
/**
* Destroy lifecycle.
*/
destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
}
}
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
function getAttributeValue(suffix, element) {
const attribute = `data-clipboard-${suffix}`;
if (!element.hasAttribute(attribute)) {
return;
}
return element.getAttribute(attribute);
}
export default Clipboard;

View File

@ -0,0 +1,33 @@
var DOCUMENT_NODE_TYPE = 9;
/**
* A polyfill for Element.matches()
*/
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
var proto = Element.prototype;
proto.matches =
proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector;
}
/**
* Finds the closest parent that matches a selector.
*
* @param {Element} element
* @param {String} selector
* @return {Function}
*/
function closest(element, selector) {
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
if (typeof element.matches === 'function' && element.matches(selector)) {
return element;
}
element = element.parentNode;
}
}
export default closest;

View File

@ -0,0 +1,78 @@
import closest from './closest';
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function _delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn, useCapture);
return {
destroy: function () {
element.removeEventListener(type, listenerFn, useCapture);
},
};
}
/**
* Delegates event to a selector.
*
* @param {Element|String|Array} [elements]
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(elements, selector, type, callback, useCapture) {
// Handle the regular Element usage
if (typeof elements.addEventListener === 'function') {
return _delegate.apply(null, arguments);
}
// Handle Element-less usage, it defaults to global delegation
if (typeof type === 'function') {
// Use `document` as the first parameter, then apply arguments
// This is a short way to .unshift `arguments` without running into deoptimizations
return _delegate.bind(null, document).apply(null, arguments);
}
// Handle Selector-based usage
if (typeof elements === 'string') {
elements = document.querySelectorAll(elements);
}
// Handle Array-like based usage
return Array.prototype.map.call(elements, function (element) {
return _delegate(element, selector, type, callback, useCapture);
});
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function (e) {
e.delegateTarget = closest(e.target, selector);
if (e.delegateTarget) {
callback.call(element, e);
}
};
}
export default delegate;

View File

@ -0,0 +1,92 @@
import Clipboard from './clipboard'; // FIXME: workaround for browserify
const VueClipboardConfig = {
autoSetContainer: false,
appendToBody: true, // This fixes IE, see #50
};
const VueClipboard = {
install(app) {
// Vue.prototype.$clipboardConfig = VueClipboardConfig;
// Vue.prototype.$copyText = function(text, container) {
// return new Promise(function(resolve, reject) {
// const fakeElement = document.createElement('button');
// const clipboard = new Clipboard(fakeElement, {
// text() {
// return text;
// },
// action() {
// return 'copy';
// },
// container: typeof container === 'object' ? container : document.body,
// });
// clipboard.on('success', function(e) {
// clipboard.destroy();
// resolve(e);
// });
// clipboard.on('error', function(e) {
// clipboard.destroy();
// reject(e);
// });
// if (VueClipboardConfig.appendToBody) document.body.appendChild(fakeElement);
// fakeElement.click();
// if (VueClipboardConfig.appendToBody) document.body.removeChild(fakeElement);
// });
// };
app.directive('clipboard', {
mounted(el, binding) {
if (binding.arg === 'success') {
el._vClipboard_success = binding.value;
} else if (binding.arg === 'error') {
el._vClipboard_error = binding.value;
} else {
const clipboard = new Clipboard(el, {
text() {
return binding.value;
},
action() {
return binding.arg === 'cut' ? 'cut' : 'copy';
},
container: VueClipboardConfig.autoSetContainer ? el : undefined,
});
clipboard.on('success', function (e) {
const callback = el._vClipboard_success;
callback && callback(e);
});
clipboard.on('error', function (e) {
const callback = el._vClipboard_error;
callback && callback(e);
});
el._vClipboard = clipboard;
}
},
updated(el, binding) {
if (binding.arg === 'success') {
el._vClipboard_success = binding.value;
} else if (binding.arg === 'error') {
el._vClipboard_error = binding.value;
} else {
el._vClipboard.text = function () {
return binding.value;
};
el._vClipboard.action = function () {
return binding.arg === 'cut' ? 'cut' : 'copy';
};
}
},
unmounted(el, binding) {
if (binding.arg === 'success') {
delete el._vClipboard_success;
} else if (binding.arg === 'error') {
delete el._vClipboard_error;
} else {
el._vClipboard.destroy();
delete el._vClipboard;
}
},
});
},
};
export default VueClipboard;

View File

@ -0,0 +1,55 @@
/**
* Check if argument is a HTML element.
*
* @param {Object} value
* @return {Boolean}
*/
export const node = function (value) {
return value !== undefined && value instanceof HTMLElement && value.nodeType === 1;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
export const nodeList = function (value) {
var type = Object.prototype.toString.call(value);
return (
value !== undefined &&
(type === '[object NodeList]' || type === '[object HTMLCollection]') &&
'length' in value &&
(value.length === 0 || node(value[0]))
);
};
/**
* Check if argument is a string.
*
* @param {Object} value
* @return {Boolean}
*/
export const string = function (value) {
return typeof value === 'string' || value instanceof String;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
export const fn = function (value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
export default {
node,
nodeList,
string,
fn,
};

View File

@ -0,0 +1,94 @@
import is from './is';
import delegate from './delegate';
/**
* Validates all params and calls the right
* listener function based on its target type.
*
* @param {String|HTMLElement|HTMLCollection|NodeList} target
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listen(target, type, callback) {
if (!target && !type && !callback) {
throw new Error('Missing required arguments');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.fn(callback)) {
throw new TypeError('Third argument must be a Function');
}
if (is.node(target)) {
return listenNode(target, type, callback);
} else if (is.nodeList(target)) {
return listenNodeList(target, type, callback);
} else if (is.string(target)) {
return listenSelector(target, type, callback);
} else {
throw new TypeError(
'First argument must be a String, HTMLElement, HTMLCollection, or NodeList',
);
}
}
/**
* Adds an event listener to a HTML element
* and returns a remove listener function.
*
* @param {HTMLElement} node
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNode(node, type, callback) {
node.addEventListener(type, callback);
return {
destroy: function () {
node.removeEventListener(type, callback);
},
};
}
/**
* Add an event listener to a list of HTML elements
* and returns a remove listener function.
*
* @param {NodeList|HTMLCollection} nodeList
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNodeList(nodeList, type, callback) {
Array.prototype.forEach.call(nodeList, function (node) {
node.addEventListener(type, callback);
});
return {
destroy: function () {
Array.prototype.forEach.call(nodeList, function (node) {
node.removeEventListener(type, callback);
});
},
};
}
/**
* Add an event listener to a selector
* and returns a remove listener function.
*
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenSelector(selector, type, callback) {
return delegate(document.body, selector, type, callback);
}
export default listen;

View File

@ -0,0 +1,40 @@
function select(element) {
var selectedText;
if (element.nodeName === 'SELECT') {
element.focus();
selectedText = element.value;
} else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
var isReadOnly = element.hasAttribute('readonly');
if (!isReadOnly) {
element.setAttribute('readonly', '');
}
element.select();
element.setSelectionRange(0, element.value.length);
if (!isReadOnly) {
element.removeAttribute('readonly');
}
selectedText = element.value;
} else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selectedText;
}
export default select;

View File

@ -0,0 +1,63 @@
function E() {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
export default E;

View File

@ -0,0 +1,76 @@
import { ref } from 'vue';
export const MediaQueryEnum = {
xs: {
maxWidth: 575,
matchMedia: '(max-width: 575px)',
},
sm: {
minWidth: 576,
maxWidth: 767,
matchMedia: '(min-width: 576px) and (max-width: 767px)',
},
md: {
minWidth: 768,
maxWidth: 991,
matchMedia: '(min-width: 768px) and (max-width: 991px)',
},
lg: {
minWidth: 992,
maxWidth: 1199,
matchMedia: '(min-width: 992px) and (max-width: 1199px)',
},
xl: {
minWidth: 1200,
maxWidth: 1599,
matchMedia: '(min-width: 1200px) and (max-width: 1599px)',
},
xxl: {
minWidth: 1600,
matchMedia: '(min-width: 1600px)',
},
};
export type MediaQueryKey = keyof typeof MediaQueryEnum;
/**
* loop query screen className
* Array.find will throw a error
* `Rendered more hooks than during the previous render.`
* So should use Array.forEach
*/
export const getScreenClassName = () => {
let className: MediaQueryKey = 'md';
// support ssr
if (typeof window === 'undefined') {
return className;
}
const mediaQueryKey = (Object.keys(MediaQueryEnum) as MediaQueryKey[]).find(key => {
const { matchMedia } = MediaQueryEnum[key];
if (window.matchMedia(matchMedia).matches) {
return true;
}
return false;
});
className = (mediaQueryKey as unknown) as MediaQueryKey;
return className;
};
const useMedia = () => {
const colSpan = ref(getScreenClassName());
(Object.keys(MediaQueryEnum) as MediaQueryKey[]).forEach(key => {
const { matchMedia } = MediaQueryEnum[key];
const mediaQuery = window.matchMedia(matchMedia);
if (mediaQuery.matches) {
colSpan.value = key;
}
mediaQuery.onchange = e => {
if (e.matches) {
colSpan.value = key;
}
};
});
return colSpan;
};
export default useMedia;

View File

@ -0,0 +1,86 @@
import { groupBy, sortBy } from 'lodash-es';
import { computed, ComputedRef, inject } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { GLOBAL_CONFIG } from '../SymbolKey';
const typeOrder: any = {
: { order: -1, en: 'Overview' },
: { order: 0, en: 'General' },
: { order: 1, en: 'Layout' },
: { order: 2, en: 'Navigation' },
: { order: 3, en: 'Data Entry' },
: { order: 4, en: 'Data Display' },
: { order: 5, en: 'Feedback' },
: { order: 6, en: 'Other' },
: { order: 7, en: 'Deprecated' },
};
const useMenus = (): {
menus: ComputedRef<any[]>;
dataSource: ComputedRef<any[]>;
currentMenuIndex: ComputedRef<number>;
activeMenuItem: ComputedRef<string>;
} => {
const route = useRoute();
const router = useRouter();
const routes = router.getRoutes();
const globalConfig = inject<any>(GLOBAL_CONFIG);
const menus = computed(() => {
const path = route.path;
const category = path.split('/')[1];
const pattern = /^\/iframe/;
const isZhCN = globalConfig.isZhCN.value;
const ms = routes
.filter(r => {
const inCategory =
r.meta &&
r.meta.category &&
r.meta.category.toLowerCase() === category &&
!pattern.test(r.path);
if (inCategory && category === 'docs') {
if (isZhCN) {
return r.path.indexOf('-cn') >= 0;
} else {
return r.path.indexOf('-cn') === -1;
}
} else {
return inCategory;
}
})
.map(r => ({ ...r.meta, path: r.path.split(':lang')[0].replace('-cn', '') }));
if (category === 'docs') {
ms.push({
enTitle: 'Change Log',
title: '更新日志',
category: 'docs',
target: '_blank',
path: globalConfig.isZhCN.value
? 'https://github.com/vueComponent/ant-design-vue/blob/next/CHANGELOG.zh-CN.md'
: 'https://github.com/vueComponent/ant-design-vue/blob/next/CHANGELOG.en-US.md',
} as any);
}
return ms;
});
const activeMenuItem = computed(() => {
return route.path.split('-cn')[0];
});
const currentMenuIndex = computed(() => {
return menus.value.findIndex(m => m.path === activeMenuItem.value);
});
const dataSource = computed(() => {
const group = groupBy(menus.value, (m: any) => m.type || m.category);
const keys: string[] = Object.keys(group);
const newMenus = keys
.map(key => {
return {
title: key,
order: typeOrder[key] && typeOrder[key].order,
enTitle: typeOrder[key] && typeOrder[key].en,
children: sortBy(group[key], 'title'),
};
})
.sort((a, b) => a.order - b.order);
return keys.length === 1 ? menus.value : newMenus;
});
return { menus, dataSource, activeMenuItem, currentMenuIndex };
};
export default useMenus;

16
site/src/i18n.js Normal file
View File

@ -0,0 +1,16 @@
import { createI18n } from 'vue-i18n';
import enUS from './locale/en-US';
import zhCN from './locale/zh-CN';
import { isZhCN } from './utils/util';
const i18n = createI18n({
legacy: true,
locale: isZhCN(location.pathname) ? 'zh-CN' : 'en-US',
fallbackLocale: 'en-US',
messages: {
'zh-CN': zhCN,
'en-US': enUS,
},
});
export default i18n;

159
site/src/index.less Normal file
View File

@ -0,0 +1,159 @@
@import './theme/static/index.less';
.drawer {
position: fixed;
z-index: 9999;
-webkit-transition: width 0s ease 0.3s, height 0s ease 0.3s,
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: width 0s ease 0.3s, height 0s ease 0.3s,
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: width 0s ease 0.3s, height 0s ease 0.3s,
transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: width 0s ease 0.3s, height 0s ease 0.3s,
transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
}
.drawer > * {
-webkit-transition: opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-box-shadow 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
}
.drawer.drawer-open {
-webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
}
.drawer .drawer-mask {
background: #000;
opacity: 0;
width: 100%;
height: 0;
position: absolute;
top: 0;
left: 0;
-webkit-transition: opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), height 0s ease 0.3s;
transition: opacity 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), height 0s ease 0.3s;
}
.drawer-content-wrapper {
position: absolute;
background: #fff;
}
.drawer-content {
overflow: auto;
z-index: 1;
position: relative;
}
.drawer-handle {
position: absolute;
top: 72px;
width: 41px;
height: 40px;
cursor: pointer;
z-index: 0;
text-align: center;
line-height: 40px;
font-size: 16px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background: #fff;
}
.drawer-handle-icon {
width: 14px;
height: 2px;
background: #333;
position: relative;
-webkit-transition: background 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: background 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
}
.drawer-handle-icon:after,
.drawer-handle-icon:before {
content: '';
display: block;
position: absolute;
background: #333;
width: 100%;
height: 2px;
-webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
}
.drawer-handle-icon:before {
top: -5px;
}
.drawer-handle-icon:after {
top: 5px;
}
.drawer-left,
.drawer-right {
width: 0;
height: 100%;
}
.drawer-left .drawer-content,
.drawer-left .drawer-content-wrapper,
.drawer-right .drawer-content,
.drawer-right .drawer-content-wrapper {
height: 100%;
}
.drawer-left.drawer-open,
.drawer-right.drawer-open {
width: 100%;
}
.drawer-left.drawer-open.no-mask,
.drawer-right.drawer-open.no-mask {
width: 0;
}
.drawer-left {
top: 0;
left: 0;
}
.drawer-left .ant-drawer-body {
padding: 0;
}
.drawer-left .drawer-handle {
right: -40px;
border-radius: 0 4px 4px 0;
}
.drawer-left .drawer-handle,
.drawer-left.drawer-open .drawer-content-wrapper {
-webkit-box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
}

View File

@ -0,0 +1,29 @@
<template>
<div>
<header :name="name" />
<div style="padding: 20px; margin: 0 auto; width: 960px">
<router-view />
</div>
<footer />
</div>
</template>
<script>
import Header from '../components/header';
import Footer from '../components/footer';
import NProgress from 'nprogress';
export default {
components: {
Header,
Footer,
},
props: ['name'],
beforeCreate() {},
methods: {
mountedCallback() {
NProgress.done();
document.documentElement.scrollTop = 0;
},
},
};
</script>

49
site/src/layouts/Demo.vue Normal file
View File

@ -0,0 +1,49 @@
<template>
<article>
<section class="markdown">
<h1>
{{ frontmatter.title }}
<span v-if="isZhCN" class="subtitle">{{ frontmatter.subtitle }}</span>
</h1>
<section class="markdown" v-html="description"></section>
</section>
<section class="markdown">
<h2>{{ $t('app.component.examples') }}</h2>
</section>
<slot />
<GoogleAds v-if="showAd" :key="`goo-${route.path}`" />
<section class="markdown api-container" v-html="api"></section>
</article>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { useRoute } from 'vue-router';
import GoogleAds from '../components/rice/GoogleAds.vue';
const showAd = location.host.indexOf('antdv.com') > -1;
export default defineComponent({
name: 'Demo',
props: ['pageData', 'isZhCN'],
components: {
GoogleAds,
},
setup(props) {
const route = useRoute();
const frontmatter = computed(() => props?.pageData?.frontmatter || {});
const docHtml = computed(() => {
return props?.pageData?.html || '';
});
const description = computed(() => {
return docHtml.value.split('<h2 id="api">API</h2>')[0];
});
const api = computed(() => {
return `
<h2 id="API"><span>API</span><a href="#API" class="anchor">#</a></h2>
${docHtml.value.split('<h2 id="api">API</h2>')[1]}
`;
});
return { frontmatter, description, api, route, showAd };
},
});
</script>
<style lang="less" scoped></style>

126
site/src/layouts/Footer.vue Normal file
View File

@ -0,0 +1,126 @@
<template>
<footer id="footer">
<div class="footer-wrap">
<a-row>
<a-col :md="6" :sm="24" :xs="24">
<div class="footer-center">
<h2>Ant Design</h2>
<div>
<a href="https://github.com/vueComponent/ant-design-vue" target="_blank ">
<span>GitHub</span>
</a>
<span></span>
<span>
<i class="anticon anticon-github"></i>
</span>
</div>
<div>
<a href="https://ant.design/docs/react/introduce-cn" target="_blank">Ant Design</a>
<span>-</span>
<span>React</span>
</div>
<div>
<a href="https://github.com/NG-ZORRO/ng-zorro-antd" target="_blank">Ant Design</a>
<span>-</span>
<span>Angular</span>
</div>
<div>
<a href="https://github.com/websemantics/awesome-ant-design" target="_blank ">
<span>Awesome Ant Design</span>
</a>
</div>
<div>
<a href="http://library.ant.design/" rel="noopener noreferrer" target="_blank">
AntD Library
</a>
</div>
</div>
</a-col>
<a-col :md="6" :sm="24" :xs="24">
<div class="footer-center">
<h2>{{ isCN ? '社区' : 'Community' }}</h2>
<div v-if="isCN">
<a href="https://zhuanlan.zhihu.com/ant-design-vue" target="_blank">
<span>知乎专栏</span>
</a>
</div>
<div>
<a href="https://github.com/vueComponent/ant-design-vue/releases" target="_blank">
<span>{{ isCN ? '更新记录' : 'Change Log' }}</span>
</a>
</div>
<div>
<a
rel="noopener noreferrer"
target="_blank"
:href="`https://vuecomponent.github.io/issue-helper/${isCN ? '?lang=zh' : ''}`"
>
<span>{{ isCN ? '报告 Bug' : 'Bug Report' }}</span>
</a>
</div>
</div>
</a-col>
<a-col :md="6" :sm="24" :xs="24">
<div class="footer-center">
<h2>{{ isCN ? '友情链接' : 'Links' }}</h2>
<div>
<a href="https://cn.vuejs.org/" target="_blank">Vue</a>
</div>
<div>
<a href="https://cli.vuejs.org/" target="_blank">Vue CLI</a>
</div>
<div>
<a href="https://vitejs.dev/" target="_blank">Vite</a>
</div>
<div v-if="showPpy()">
<a href="https://www.pengpengyu.com/" target="_blank">砰砰鱼</a>
</div>
</div>
</a-col>
<a-col :md="6" :sm="24" :xs="24">
<div class="footer-center">
<h2>
<img
alt=""
class="title-icon"
src="https://gw.alipayobjects.com/zos/rmsportal/nBVXkrFdWHxbZlmMbsaH.svg"
/>
<span>{{ isCN ? '更多产品' : 'More Products' }}</span>
</h2>
<div>
<a href="https://antv.alipay.com/" rel="noopener noreferrer" target="_blank">AntV</a>
<span>-</span>
<span>{{ isCN ? '数据可视化' : 'Data Visualization' }}</span>
</div>
<div>
<a href="https://eggjs.org/" rel="noopener noreferrer" target="_blank">Egg</a>
<span>-</span>
<span>{{ isCN ? '企业级 Node 开发框架' : 'Enterprise Node Framework' }}</span>
</div>
</div>
</a-col>
</a-row>
</div>
<div style="padding: 10px 144px">
备案号
<a href="http://www.beian.miit.gov.cn/" target="_blank">浙ICP备19034671号</a>
</div>
</footer>
</template>
<script>
import dayjs from 'dayjs';
export default {
props: {
isCN: Boolean,
},
setup() {
const showPpy = () => {
return dayjs().isBefore(dayjs('2021-06-15'));
};
return {
dayjs,
showPpy,
};
},
};
</script>

View File

@ -0,0 +1,14 @@
<template>
<router-view></router-view>
</template>
<script lang="ts">
import { defineComponent, provide } from 'vue';
export default defineComponent({
name: 'IframeLayout',
setup() {
provide('inIframe', true);
return {};
},
});
</script>
<style lang="less" scoped></style>

62
site/src/layouts/Menu.vue Normal file
View File

@ -0,0 +1,62 @@
<template>
<a-menu
:inlineIndent="30"
class="aside-container menu-site"
mode="inline"
:selectedKeys="[activeMenuItem]"
>
<a-menu-item v-if="showOverview" key="/components/overview">
<router-link :to="getLocalizedPathname('/components/overview', isZhCN)">
{{ isZhCN ? '组件总览' : 'Components Overview' }}
</router-link>
</a-menu-item>
<template v-for="m in menus">
<template v-if="m.children">
<a-menu-item-group :key="m.order" :title="isZhCN ? m.title : m.enTitle">
<template v-for="n in m.children">
<a-menu-item v-if="n.path" :key="n.path">
<a v-if="n.target" :target="n.target" :href="n.path">
<span>{{ isZhCN ? n.title : n.enTitle || n.title }}</span>
<span v-if="isZhCN" class="chinese">{{ n.subtitle }}</span>
</a>
<router-link v-else :to="getLocalizedPathname(n.path, isZhCN)">
<span>{{ isZhCN ? n.title : n.enTitle || n.title }}</span>
<span v-if="isZhCN" class="chinese">{{ n.subtitle }}</span>
</router-link>
</a-menu-item>
</template>
</a-menu-item-group>
</template>
<template v-else>
<a-menu-item :key="m.path">
<a v-if="m.target" :target="m.target" :href="m.path">
{{ isZhCN ? `${m.title} ${m.subtitle || ''}` : m.enTitle || m.title }}
</a>
<router-link v-else :to="getLocalizedPathname(m.path, isZhCN)">
{{ isZhCN ? `${m.title} ${m.subtitle || ''}` : m.enTitle || m.title }}
</router-link>
</a-menu-item>
</template>
</template>
</a-menu>
</template>
<script lang="ts">
import { getLocalizedPathname } from '@/utils/util';
import { computed, defineComponent } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'Menu',
props: ['menus', 'isZhCN', 'activeMenuItem'],
setup() {
const route = useRoute();
const showOverview = computed(() => {
return route.path.indexOf('/components') === 0;
});
return {
getLocalizedPathname,
showOverview,
};
},
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,68 @@
<template>
<section class="prev-next-nav">
<router-link
key="prev"
v-if="prev"
class="prev-page"
:to="getLocalizedPathname(prev.path, isZhCN)"
>
<span role="img" aria-label="left" class="anticon anticon-left footer-nav-icon-before">
<svg
viewBox="64 64 896 896"
focusable="false"
data-icon="left"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
></path>
</svg>
</span>
<span>{{ prev.title }}</span>
<span v-if="isZhCN" class="chinese">{{ prev.subtitle }}</span>
</router-link>
<router-link
key="next"
v-if="next"
class="next-page"
:to="getLocalizedPathname(next.path, isZhCN)"
>
<span>{{ next.title }}</span>
<span v-if="isZhCN" class="chinese">{{ next.subtitle }}</span>
<span role="img" aria-label="right" class="anticon anticon-right footer-nav-icon-after">
<svg
viewBox="64 64 896 896"
focusable="false"
data-icon="right"
width="1em"
height="1em"
fill="currentColor"
aria-hidden="true"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
></path>
</svg>
</span>
</router-link>
</section>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { getLocalizedPathname } from '@/utils/util';
export default defineComponent({
name: 'PrevAndNext',
props: ['menus', 'isZhCN', 'currentMenuIndex'],
setup(props) {
return {
getLocalizedPathname,
prev: computed(() => props.menus[props.currentMenuIndex - 1]),
next: computed(() => props.menus[props.currentMenuIndex + 1]),
};
},
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,29 @@
<template>
<Icon v-bind="$attrs">
<template #component>
<svg :width="21" :height="21" viewBox="0 0 21 21" fill="currentColor" v-bind="$attrs">
<g fillRule="evenodd">
<g fillRule="nonzero">
<path
d="M7.02 3.635l12.518 12.518a1.863 1.863 0 010 2.635l-1.317 1.318a1.863 1.863 0 01-2.635 0L3.068 7.588A2.795 2.795 0 117.02 3.635zm2.09 14.428a.932.932 0 110 1.864.932.932 0 010-1.864zm-.043-9.747L7.75 9.635l9.154 9.153 1.318-1.317-9.154-9.155zM3.52 12.473c.514 0 .931.417.931.931v.932h.932a.932.932 0 110 1.864h-.932v.931a.932.932 0 01-1.863 0l-.001-.931h-.93a.932.932 0 010-1.864h.93v-.932c0-.514.418-.931.933-.931zm15.374-3.727a1.398 1.398 0 110 2.795 1.398 1.398 0 010-2.795zM4.385 4.953a.932.932 0 000 1.317l2.046 2.047L7.75 7 5.703 4.953a.932.932 0 00-1.318 0zM14.701.36a.932.932 0 01.931.932v.931h.932a.932.932 0 010 1.864h-.933l.001.932a.932.932 0 11-1.863 0l-.001-.932h-.93a.932.932 0 110-1.864h.93v-.931a.932.932 0 01.933-.932z"
/>
</g>
</g>
</svg>
</template>
</Icon>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Icon from '@ant-design/icons-vue';
export default defineComponent({
name: 'ThemeIcon',
setup() {
return {};
},
components: {
Icon,
},
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,71 @@
@import '../../components/style/themes/default.less';
.container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: auto;
background: @layout-body-background;
}
.lang {
width: 100%;
height: 40px;
line-height: 44px;
text-align: right;
:global(.ant-dropdown-trigger) {
margin-right: 24px;
}
}
.content {
flex: 1;
padding: 32px 0;
}
@media (min-width: @screen-md-min) {
.container {
background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
background-repeat: no-repeat;
background-position: center 110px;
background-size: 100%;
}
.content {
padding: 32px 0 24px 0;
}
}
.top {
text-align: center;
}
.header {
height: 44px;
line-height: 44px;
a {
text-decoration: none;
}
}
.logo {
height: 44px;
margin-right: 16px;
vertical-align: top;
}
.title {
position: relative;
top: 2px;
color: @heading-color;
font-weight: 600;
font-size: 33px;
font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
}
.desc {
margin-top: 12px;
margin-bottom: 40px;
color: @text-color-secondary;
font-size: @font-size-base;
}

View File

@ -0,0 +1,27 @@
<template>
<div :class="$style.container">
<div :class="$style.lang">中文</div>
<div :class="$style.content">
<div :class="$style.top">
<div :class="$style.header">
<a to="/">
<img alt="logo" :class="$style.logo" :src="logo" />
<span :class="$style.title">Ant Design Vue</span>
</a>
</div>
</div>
<router-view />
</div>
</div>
</template>
<script>
import logo from '../public/logo.svg';
export default {
components: {},
beforeCreate() {
this.logo = logo;
},
};
</script>
<style lang="less" src="./UserLayout.less" module />

View File

@ -0,0 +1,70 @@
<template>
<a-menu class="ecosystem">
<a-menu-item-group key="ecosystem" :title="$t('app.header.menu.ecosystem')">
<a-menu-item key="pro">
<a target="_blank" href="https://pro.antdv.com">Pro For Vue2(Free)</a>
</a-menu-item>
<a-menu-item key="vip">
<a target="_blank" href="https://store.antdv.com/pro">Pro For Vue3(VIP)</a>
</a-menu-item>
<a-menu-item key="design">
<router-link :to="getLocalizedPathname('/docs/vue/download/', isZhCN)">
{{ isZhCN ? '设计资源' : 'Design Resources' }}
</router-link>
</a-menu-item>
<a-menu-item key="vscode">
<a
target="_blank"
href="https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper"
>
VS Code Extension
</a>
</a-menu-item>
<a-menu-item key="awesome">
<a target="_blank" href="https://github.com/vueComponent/ant-design-vue-awesome">Awesome</a>
</a-menu-item>
<a-menu-item key="wechat">
<a-popover placement="right">
<a>{{ isZhCN ? '微信' : 'WeChat' }}</a>
<template v-slot:content>
<img width="160" height="160" alt="wechat" src="https://qn.antdv.com/wechat.jpeg" />
</template>
</a-popover>
</a-menu-item>
<a-menu-item key="qq1">
<a>QQ 1(217490093)</a>
</a-menu-item>
<a-menu-item key="qq2">
<a>QQ 2(809774695)</a>
</a-menu-item>
</a-menu-item-group>
</a-menu>
</template>
<script lang="ts">
import { computed, defineComponent, inject } from 'vue';
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { getLocalizedPathname } from '@/utils/util';
export default defineComponent({
props: {
isRTL: {
type: Boolean,
default: false,
},
},
setup(props) {
const downstyle = computed(() => (props.isRTL ? '-1px 2px 0 0' : '-1px 0 0 2px'));
return {
downstyle,
isZhCN: inject<GlobalConfig>(GLOBAL_CONFIG)!.isZhCN.value,
getLocalizedPathname,
};
},
});
</script>
<style scoped>
.ecosystem a {
color: rgba(0, 0, 0, 0.65);
}
</style>

View File

@ -0,0 +1,133 @@
.github-btn {
font: bold 11px/14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 20px;
overflow: hidden;
}
.gh-btn,
.gh-count,
.gh-ico {
float: left;
}
.gh-btn,
.gh-count {
padding: 2px 5px 2px 4px;
color: #333;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
border-radius: 3px;
}
.gh-btn {
background-color: #eee;
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0, #fcfcfc),
color-stop(100%, #eee)
);
background-image: -webkit-linear-gradient(top, #fcfcfc 0, #eee 100%);
background-image: -moz-linear-gradient(top, #fcfcfc 0, #eee 100%);
background-image: -ms-linear-gradient(top, #fcfcfc 0, #eee 100%);
background-image: -o-linear-gradient(top, #fcfcfc 0, #eee 100%);
background-image: linear-gradient(to bottom, #fcfcfc 0, #eee 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#eeeeee', GradientType=0);
background-repeat: no-repeat;
border: 1px solid #d5d5d5;
}
.gh-btn:hover,
.gh-btn:focus {
text-decoration: none;
background-color: #ddd;
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0, #eee),
color-stop(100%, #ddd)
);
background-image: -webkit-linear-gradient(top, #eee 0, #ddd 100%);
background-image: -moz-linear-gradient(top, #eee 0, #ddd 100%);
background-image: -ms-linear-gradient(top, #eee 0, #ddd 100%);
background-image: -o-linear-gradient(top, #eee 0, #ddd 100%);
background-image: linear-gradient(to bottom, #eee 0, #ddd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);
border-color: #ccc;
}
.gh-btn:active {
background-image: none;
background-color: #dcdcdc;
border-color: #b5b5b5;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
}
.gh-ico {
width: 14px;
height: 14px;
margin-right: 4px;
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjQwcHgiIGhlaWdodD0iNDBweCIgdmlld0JveD0iMTIgMTIgNDAgNDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMTIgMTIgNDAgNDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiAxMy40Yy0xMC41IDAtMTkgOC41LTE5IDE5YzAgOC40IDUuNSAxNS41IDEzIDE4YzEgMC4yIDEuMy0wLjQgMS4zLTAuOWMwLTAuNSAwLTEuNyAwLTMuMiBjLTUuMyAxLjEtNi40LTIuNi02LjQtMi42QzIwIDQxLjYgMTguOCA0MSAxOC44IDQxYy0xLjctMS4yIDAuMS0xLjEgMC4xLTEuMWMxLjkgMC4xIDIuOSAyIDIuOSAyYzEuNyAyLjkgNC41IDIuMSA1LjUgMS42IGMwLjItMS4yIDAuNy0yLjEgMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEgMC43LTMuNyAyLTUuMWMtMC4yLTAuNS0wLjgtMi40IDAuMi01YzAgMCAxLjYtMC41IDUuMiAyIGMxLjUtMC40IDMuMS0wLjcgNC44LTAuN2MxLjYgMCAzLjMgMC4yIDQuNyAwLjdjMy42LTIuNCA1LjItMiA1LjItMmMxIDIuNiAwLjQgNC42IDAuMiA1YzEuMiAxLjMgMiAzIDIgNS4xYzAgNy4zLTQuNSA4LjktOC43IDkuNCBjMC43IDAuNiAxLjMgMS43IDEuMyAzLjVjMCAyLjYgMCA0LjYgMCA1LjJjMCAwLjUgMC40IDEuMSAxLjMgMC45YzcuNS0yLjYgMTMtOS43IDEzLTE4LjFDNTEgMjEuOSA0Mi41IDEzLjQgMzIgMTMuNHoiLz48L3N2Zz4=');
background-size: 100% 100%;
background-repeat: no-repeat;
}
.gh-count {
position: relative;
display: none; /* hidden to start */
margin-left: 4px;
background-color: #fafafa;
border: 1px solid #d4d4d4;
}
.gh-count:hover,
.gh-count:focus {
color: #4183c4;
}
.gh-count:before,
.gh-count:after {
content: '';
position: absolute;
display: inline-block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.gh-count:before {
top: 50%;
left: -3px;
margin-top: -4px;
border-width: 4px 4px 4px 0;
border-right-color: #fafafa;
}
.gh-count:after {
top: 50%;
left: -4px;
z-index: -1;
margin-top: -5px;
border-width: 5px 5px 5px 0;
border-right-color: #d4d4d4;
}
.github-btn-large {
height: 30px;
}
.github-btn-large .gh-btn,
.github-btn-large .gh-count {
padding: 3px 10px 3px 8px;
font-size: 16px;
line-height: 22px;
border-radius: 4px;
}
.github-btn-large .gh-ico {
width: 20px;
height: 20px;
}
.github-btn-large .gh-count {
margin-left: 6px;
}
.github-btn-large .gh-count:before {
left: -5px;
margin-top: -6px;
border-width: 6px 6px 6px 0;
}
.github-btn-large .gh-count:after {
left: -6px;
margin-top: -7px;
border-width: 7px 7px 7px 0;
}

View File

@ -0,0 +1,59 @@
<template>
<span id="github-btn" class="github-btn">
<a class="gh-btn" href="https://github.com/vueComponent/ant-design-vue" target="_blank">
<span class="gh-ico" aria-hidden="true"></span>
<span class="gh-text">Star</span>
</a>
</span>
</template>
<style lang="less" scoped>
@import '../../theme/static/theme.less';
@import './Github.less';
#github-btn {
display: flex;
flex-flow: nowrap;
height: auto;
.gh-btn {
height: auto;
padding: 1px 4px;
background: transparent;
border: 0;
.gh-ico {
width: 20px;
height: 20px;
margin: 0;
}
.gh-text {
display: none;
}
}
.gh-count {
height: auto;
padding: 4px 8px;
font-weight: normal;
background: #fff;
&:hover {
color: @primary-color;
}
}
&.responsive-mode {
.gh-count {
display: none !important;
}
}
}
.ant-row-rtl {
#github-btn {
.gh-count {
display: none !important;
}
}
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<h1>
<a id="logo" :href="isZhCN ? '/index-cn' : '/index'">
<img alt="logo" :src="logo" />
Ant Design Vue
</a>
</h1>
</template>
<script lang="ts">
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { defineComponent, inject } from 'vue';
import logo from '../../assets/logo.svg';
export default defineComponent({
setup() {
return { logo, isZhCN: inject<GlobalConfig>(GLOBAL_CONFIG)!.isZhCN.value };
},
});
</script>
<style lang="less" scoped>
@import '../../theme/static/theme.less';
@import './index.less';
#logo {
height: @header-height;
padding-left: 40px;
overflow: hidden;
color: @site-heading-color;
font-size: 18px;
font-family: Avenir, @font-family, sans-serif;
line-height: @header-height;
white-space: nowrap;
text-decoration: none;
.ant-row-rtl & {
float: right;
padding-right: 40px;
padding-left: 0;
}
img {
position: relative;
top: -1.5px;
height: 32px;
margin-right: 16px;
.ant-row-rtl & {
margin-right: 0;
margin-left: 16px;
}
}
}
@media only screen and (max-width: @mobile-max-width) {
#logo {
padding-right: 0;
padding-left: 0;
}
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<Navigation @langChange="onLangChange" />
<template v-if="isMobile">
<Ecosystem />
</template>
<template v-else>
<a-select
key="version"
class="version"
size="small"
:defaultValue="antdVersion"
:getPopupContainer="trigger => trigger.parentNode"
>
<a-select-option :value="antdVersion">{{ antdVersion }}</a-select-option>
<a-select-option value="1.x" @click="changeVersion">1.x</a-select-option>
</a-select>
<a-button
size="small"
@click="onLangChange"
class="header-button header-lang-button"
key="lang-button"
>
{{ $t('app.header.lang') }}
</a-button>
<More />
<Github />
</template>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import Github from './Github.vue';
import More from './More.vue';
import Navigation from './Navigation.vue';
import Ecosystem from './Ecosystem.vue';
import { version } from 'ant-design-vue';
import { isZhCN, isLocalStorageNameSupported, getLocalizedPathname } from '@/utils/util';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'HeaderMenu',
props: ['isMobile'],
setup() {
const antdVersion = ref(version);
const route = useRoute();
const onLangChange = () => {
const {
location: { pathname },
} = window;
const currentProtocol = `${window.location.protocol}//`;
const currentHref = window.location.href.substr(currentProtocol.length);
if (isLocalStorageNameSupported()) {
localStorage.setItem('locale', isZhCN(pathname) ? 'en-US' : 'zh-CN');
}
window.location.href =
currentProtocol +
currentHref.replace(
window.location.pathname,
getLocalizedPathname(pathname, !isZhCN(pathname)).path,
);
};
const changeVersion = () => {
location.href = `https://1x.antdv.com${route.fullPath}`;
};
return {
onLangChange,
antdVersion,
changeVersion,
};
},
components: {
Navigation,
Github,
More,
Ecosystem,
},
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,46 @@
<template>
<a-dropdown>
<a-button size="small" class="header-button">
{{ $t('app.header.menu.more') }}
<DownOutlined
:style="{
fontSize: '9px',
margin: downstyle,
verticalAlign: 'middle',
}"
/>
</a-button>
<template v-slot:overlay>
<Ecosystem />
</template>
</a-dropdown>
</template>
<script lang="ts">
import { computed, defineComponent, inject } from 'vue';
import { DownOutlined } from '@ant-design/icons-vue';
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { getLocalizedPathname } from '@/utils/util';
import Ecosystem from './Ecosystem.vue';
export default defineComponent({
props: {
isRTL: {
type: Boolean,
default: false,
},
},
setup(props) {
const downstyle = computed(() => (props.isRTL ? '-1px 2px 0 0' : '-1px 0 0 2px'));
return {
downstyle,
isZhCN: inject<GlobalConfig>(GLOBAL_CONFIG)!.isZhCN.value,
getLocalizedPathname,
};
},
components: {
DownOutlined,
Ecosystem,
},
});
</script>

View File

@ -0,0 +1,177 @@
<template>
<a-menu class="menu-site" :mode="menuMode" :selectedKeys="[activeMenuItem]" id="nav">
<a-menu-item key="docs/vue">
<router-link :to="getLocalizedPathname('/docs/vue/introduce', isZhCN)">
{{ $t('app.header.menu.documentation') }}
</router-link>
</a-menu-item>
<a-menu-item key="components">
<router-link :to="getLocalizedPathname('/components/overview/', isZhCN)">
{{ $t('app.header.menu.components') }}
</router-link>
</a-menu-item>
<a-menu-item key="store">
<a
href="https://store.antdv.com/pro/"
target="_blank"
rel="noopener noreferrer"
style="position: relative"
>
{{ $t('app.header.menu.store') }}
<a-badge color="red" style="position: absolute; top: -35px; right: -15px" />
</a>
</a-menu-item>
<a-menu-item v-if="isZhCN" key="geektime">
<a
href="https://time.geekbang.org/course/intro/100024601?code=KHKYcoBU6vZa8nMglg7AWfDxxi3BWrz9INAzAY3umPk%3D"
target="_blank"
rel="noopener noreferrer"
style="position: relative"
>
实战课程
<a-badge color="red" style="position: absolute; top: -35px; right: -15px" />
</a>
</a-menu-item>
<template v-if="isMobile">
<a-menu-item key="switch-lang" @click="$emit('langChange')">
{{ $t('app.header.lang') }}
</a-menu-item>
<a-menu-item key="github">
<a
href="https://github.com/vueComponent/ant-design-vue"
target="_blank"
rel="noopener noreferrer"
>
Github
</a>
</a-menu-item>
</template>
</a-menu>
</template>
<script lang="ts">
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { getLocalizedPathname } from '@/utils/util';
import { computed, defineComponent, inject, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
emits: ['langChange'],
setup() {
const globalConfig = inject<GlobalConfig>(GLOBAL_CONFIG);
const menuMode = computed(() => {
return globalConfig!.isMobile.value ? 'inline' : 'horizontal';
});
const route = useRoute();
const activeMenuItem = ref('home');
watch(
() => route.path,
pathname => {
const modules = pathname.split('/');
if (pathname === 'changelog' || pathname === 'changelog-cn') {
activeMenuItem.value = 'docs/vue';
} else if (pathname === '/docs/resources' || pathname === '/docs/resources-cn') {
activeMenuItem.value = 'docs/resources';
} else if (modules[1] === 'components') {
activeMenuItem.value = 'components';
} else if (modules[1] === 'docs') {
activeMenuItem.value = `${modules[1]}/${modules[2]}`;
} else {
activeMenuItem.value = 'home';
}
},
{ immediate: true },
);
return {
isMobile: globalConfig!.isMobile,
isZhCN: globalConfig!.isZhCN,
getLocalizedPathname,
menuMode,
activeMenuItem,
};
},
});
</script>
<style lang="less">
@import '../../theme/static/theme.less';
@import './index.less';
#nav {
height: 100%;
font-size: 14px;
font-family: Avenir, @font-family, sans-serif;
border: 0;
&.ant-menu-horizontal {
border-bottom: none;
& > .ant-menu-item,
& > .ant-menu-submenu {
min-width: (40px + 12px * 2);
height: @header-height;
padding-right: 12px;
padding-left: 12px;
line-height: @header-height;
&::after {
top: 0;
right: 12px;
bottom: auto;
left: 12px;
border-width: @menu-item-border;
}
}
& .ant-menu-submenu-title .anticon {
margin: 0;
}
& > .ant-menu-item-selected {
a {
color: @primary-color;
}
}
}
& > .ant-menu-item,
& > .ant-menu-submenu {
text-align: center;
}
}
.header-link {
color: @site-text-color;
}
.ant-menu-item-active .header-link {
color: @primary-color;
}
// Popover menu is only used for mobile
.popover-menu {
width: 300px;
.ant-popover-inner-content {
padding: 0;
#nav {
.ant-menu-item,
.ant-menu-submenu {
text-align: left;
}
.ant-menu-item-group-title {
padding-left: 24px;
}
.ant-menu-item-group-list {
padding: 0 16px;
}
.ant-menu-item,
a {
color: #333;
}
}
}
}
</style>

View File

@ -0,0 +1,136 @@
@import '../../theme/static/theme.less';
@search-icon-color: #ced4d9;
#search-box {
position: relative;
display: flex;
flex: auto !important;
align-items: center;
height: 22px;
margin: 0 auto 0 0 !important;
padding-left: 16px;
line-height: 22px;
white-space: nowrap;
border-left: 1px solid @site-border-color-split;
transition: width 0.5s;
.ant-row-rtl & {
margin: 0 0 0 auto !important;
padding-right: 16px;
padding-left: 0;
border-right: 1px solid @site-border-color-split;
border-left: none;
}
> * {
flex: auto;
}
.anticon {
position: absolute;
top: 50%;
z-index: 1;
flex: none;
color: @search-icon-color;
transform: translateY(-50%);
pointer-events: none;
}
input {
width: 100%;
max-width: 200px;
padding-left: 20px;
font-size: 14px;
background: transparent;
border: 0;
box-shadow: none;
.ant-row-rtl & {
padding-right: 20px;
padding-left: 11px;
}
&::placeholder {
color: #a3b1bf;
}
}
// ================ Narrow ================
&.narrow-mode {
flex: none !important;
width: 30px;
&:hover {
.anticon {
color: #a3b1bf;
}
}
.anticon {
right: 0;
left: auto;
.ant-row-rtl & {
right: auto;
left: 0;
}
}
input {
max-width: none;
padding-right: 20px;
padding-left: 11px;
cursor: pointer;
.ant-row-rtl & {
padding-right: 11px;
padding-left: 20px;
}
}
&.focused {
width: 500px;
.anticon {
color: @search-icon-color;
}
input {
cursor: text;
}
}
}
}
.component-select {
&.ant-select-dropdown {
font-size: 14px;
border: 0;
border-radius: 0;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.25);
}
.ant-select-dropdown-menu {
max-height: 200px;
}
.ant-select-dropdown-menu-item {
border-radius: 0 !important;
}
.ant-component-decs {
position: absolute;
right: 16px;
color: #aaa;
font-size: 12px;
.ant-row-rtl & {
right: auto;
left: 16px;
}
}
}
@media only screen and (max-width: @mobile-max-width) {
#search-box {
display: none;
}
}

View File

@ -0,0 +1,37 @@
<template>
<div id="search-box" :class="{ 'narrow-mode': responsive, focused: !!focused }">
<SearchOutlined />
<a-input
:placeholder="searchPlaceholder"
ref="inputRef"
@focus="triggerFocus(true)"
@blue="triggerFocus(false)"
></a-input>
</div>
</template>
<script lang="ts">
import { ref, defineComponent } from 'vue';
import { SearchOutlined } from '@ant-design/icons-vue';
export default defineComponent({
name: 'SearchBox',
props: ['isZhCN', 'responsive'],
emits: ['triggerFocus'],
setup(props, { emit }) {
const inputRef = ref();
const focused = ref(false);
function triggerFocus(focus: boolean) {
focused.value = focus;
emit('triggerFocus', focus);
}
return {
inputRef,
focused,
triggerFocus,
searchPlaceholder: props.isZhCN ? '搜索文档' : 'Search Docs',
};
},
components: {
SearchOutlined,
},
});
</script>

View File

@ -0,0 +1,83 @@
@import '../../theme/static/theme.less';
@import './SearchBox.less';
@header-height: 64px;
@menu-item-border: 2px;
@mobile-max-width: 767.99px;
#header {
position: relative;
z-index: 10;
max-width: 100%;
background: @component-background;
box-shadow: 0 2px 8px rgba(240, 241, 242, 65);
.menu-row {
display: flex;
align-items: center;
margin: 0;
> * {
flex: none;
margin: 0 16px 0 0;
&:last-child {
margin-right: 40px;
}
}
}
// Adjust github button style
.ant-row-rtl {
.menu-row {
> * {
&:last-child {
margin-right: 16px;
margin-left: 40px;
}
}
}
}
// Buttons
.header-button {
color: @text-color;
border-color: @border-color-base;
}
}
@media only screen and (max-width: @mobile-max-width) {
#header {
text-align: center;
}
}
// Popover menu is only used for mobile
.popover-menu {
width: 300px;
.ant-popover-inner-content {
padding: 0;
#nav {
.ant-menu-item,
.ant-menu-submenu {
text-align: left;
}
.ant-menu-item-group-title {
padding-left: 24px;
}
.ant-menu-item-group-list {
padding: 0 16px;
}
.ant-menu-item,
a {
color: #333;
}
}
}
}

View File

@ -0,0 +1,156 @@
<template>
<header id="header" :class="headerClassName">
<div class="adblock-banner" v-if="visibleAdblockBanner">
<template v-if="isZhCN">
我们检测到你可能使用了 AdBlock Adblock
Plus它会影响到正常功能的使用如复制展开代码等
<br />
你可以将 Ant Design Vue 加入白名单以便我们更好地提供服务
</template>
<template v-else>
We have detected that you may use AdBlock or Adblock Plus, which will affect the use of
normal functions (such as copying, expanding code, etc.)
<br />
You can add Ant Design Vue to the whitelist so that we can provide better services.
</template>
<CloseOutlined class="close-icon" @click="visibleAdblockBanner = false" />
</div>
<a-popover
overlayClassName="popover-menu"
placement="bottomRight"
trigger="click"
arrowPointAtCenter
v-model:visible="menuVisible"
>
<UnorderedListOutlined class="nav-phone-icon" />
<template v-slot:content>
<Menu :isMobile="isMobile" />
</template>
</a-popover>
<a-row :style="{ flexFlow: 'nowrap', height: 64 }">
<a-col v-bind="colProps[0]">
<Logo />
</a-col>
<a-col v-bind="colProps[1]" class="menu-row">
<SearchBox
key="search"
:isZhCN="isZhCN"
:responsive="responsive"
@triggerFocus="onTriggerSearching"
/>
<Menu v-if="!isMobile" />
</a-col>
</a-row>
</header>
</template>
<script lang="ts">
import { GlobalConfig } from '@/App.vue';
import { GLOBAL_CONFIG } from '@/SymbolKey';
import { getLocalizedPathname } from '@/utils/util';
import { computed, defineComponent, inject, onMounted, Ref, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import Logo from './Logo.vue';
import Menu from './Menu.vue';
import { UnorderedListOutlined, CloseOutlined } from '@ant-design/icons-vue';
import SearchBox from './SearchBox.vue';
export default defineComponent({
setup() {
const route = useRoute();
const globalConfig = inject<GlobalConfig>(GLOBAL_CONFIG);
const isHome = computed(() => {
return ['', 'index', 'index-cn'].includes(route.path);
});
const menuVisible = ref(false);
const colProps = isHome.value
? [{ flex: 'none' }, { flex: 'auto' }]
: [
{
xxl: 4,
xl: 5,
lg: 6,
md: 6,
sm: 24,
xs: 24,
},
{
xxl: 20,
xl: 19,
lg: 18,
md: 18,
sm: 0,
xs: 0,
},
];
const searching = ref(false);
const onTriggerSearching = (value: boolean) => {
searching.value = value;
};
const initDocSearch = () => {
window.docsearch({
apiKey: '92003c1d1d07beef165b08446f4224a3',
indexName: 'antdv',
inputSelector: '#search-box input',
algoliaOptions: { facetFilters: [`tags:${globalConfig!.isZhCN.value ? 'cn' : 'en'}`] },
transformData(hits: any[]) {
hits.forEach(hit => {
hit.url = hit.url.replace('www.antdv.com', window.location.host);
hit.url = hit.url.replace('https:', window.location.protocol);
});
return hits;
},
debug: false, // Set debug to true if you want to inspect the dropdown
});
};
onMounted(() => {
setTimeout(() => {
initDocSearch();
});
});
const visibleAdblockBanner = ref(false);
watch(globalConfig?.blocked as Ref<boolean>, val => {
visibleAdblockBanner.value = val;
});
return {
isZhCN: globalConfig!.isZhCN,
isMobile: globalConfig!.isMobile,
responsive: globalConfig!.responsive,
getLocalizedPathname,
visibleAdblockBanner,
headerClassName: {
clearfix: true,
'home-header': isHome.value,
},
colProps,
menuVisible,
onTriggerSearching,
};
},
components: {
Logo,
Menu,
UnorderedListOutlined,
SearchBox,
CloseOutlined,
},
});
</script>
<style lang="less" src="./index.less"></style>
<style scope>
.adblock-banner {
position: relative;
z-index: 100;
min-width: 1000px;
padding: 16px;
line-height: 28px;
color: #8590a6;
text-align: center;
background-color: #ebebeb;
}
.close-icon {
position: absolute;
top: 15px;
right: 15px;
}
</style>

214
site/src/layouts/index.vue Normal file
View File

@ -0,0 +1,214 @@
<template>
<Header />
<div class="main-wrapper">
<a-row>
<template v-if="isMobile">
<a-drawer
:closable="false"
placement="left"
class="drawer drawer-left"
:visible="visible"
key="mobile-menu"
wrapperClassName="drawer-wrapper"
>
<Menu :menus="dataSource" :activeMenuItem="activeMenuItem" :isZhCN="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 :xxl="4" :xl="5" :lg="6" :md="6" :sm="24" :xs="24" class="main-menu">
<a-affix>
<section class="main-menu-inner">
<Sponsors :isCN="isZhCN" />
<Menu :menus="dataSource" :activeMenuItem="activeMenuItem" :isZhCN="isZhCN" />
</section>
</a-affix>
</a-col>
</template>
<a-col :xxl="20" :xl="19" :lg="18" :md="18" :sm="24" :xs="24">
<section :class="mainContainerClass">
<TopAd :isCN="isZhCN" />
<Demo v-if="isDemo" :pageData="pageData" :isZhCN="isZhCN">
<component :is="matchCom" />
</Demo>
<router-view v-else />
<a-affix v-if="headers.length" class="toc-affix" :offsetTop="20">
<a-anchor>
<a-anchor-link
v-for="h in headers"
:key="h.title"
:href="h.href || `#${h.title}`"
:title="h.title"
></a-anchor-link>
</a-anchor>
</a-affix>
</section>
<div class="fixed-widgets" :style="isZhCN ? { bottom: '175px' } : {}">
<a-dropdown placement="topCenter">
<template #overlay>
<a-menu
@click="({ key }) => themeMode.changeTheme(key)"
:selectedKeys="[themeMode.theme.value]"
>
<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" :currentMenuIndex="currentMenuIndex" />
<Footer />
</a-col>
</a-row>
<RightBottomAd :isCN="isZhCN" :isMobile="isMobile" />
</div>
</template>
<script lang="ts">
import { 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 } from '@ant-design/icons-vue';
import ThemeIcon from './ThemeIcon.vue';
export default defineComponent({
name: 'Layout',
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'),
changeTheme: () => 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 matchCom = computed(() => {
return route.matched[route.matched.length - 1]?.components?.default as any;
});
const isZhCN = globalConfig!.isZhCN;
const pageData = computed(() =>
isDemo.value
? matchCom.value[isZhCN.value ? 'CN' : 'US']?.pageData
: matchCom.value?.pageData,
);
const headers = computed(() => {
if (isDemo.value) {
return [...demos.value, { title: 'API', href: '#API' }];
} else {
return (pageData.value?.headers || []).filter((h: Header) => h.level === 2);
}
});
const mainContainerClass = computed(() => {
return {
'main-container': true,
'main-container-component': isDemo.value,
};
});
const handleClickShowButton = () => {
visible.value = !visible.value;
};
return {
themeMode,
visible,
isMobile: globalConfig!.isMobile,
isZhCN,
mainContainerClass,
menus,
currentMenuIndex,
activeMenuItem,
headers,
isDemo,
matchCom,
pageData,
dataSource,
handleClickShowButton,
iconStyle: {
// color: '#fff',
fontSize: '20px',
},
};
},
components: {
TopAd,
Sponsors,
RightBottomAd,
Demo,
Header,
Footer,
Menu,
PrevAndNext,
CloseOutlined,
MenuOutlined,
ThemeIcon,
},
});
</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>

29
site/src/locale/en-US.js Normal file
View File

@ -0,0 +1,29 @@
import login from '../views/user/login/locales/en-US';
import register from '../views/user/register/locales/en-US';
import registerResult from '../views/user/register-result/locales/en-US';
import theme from '../theme/en-US';
export default {
...theme,
'navBar.lang': 'Languages',
'layout.user.link.help': 'Help',
'layout.user.link.privacy': 'Privacy',
'layout.user.link.terms': 'Terms',
'app.preview.down.block': 'Download this page to your local project',
'app.welcome.link.fetch-blocks': 'Get all block',
'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development',
'app.docs.components.icon.search.placeholder': 'Search icon here, click icon to copy code',
'app.docs.components.icon.pick-theme': 'Select the Icon Theme',
'app.docs.components.icon.outlined': 'Outlined',
'app.docs.components.icon.filled': 'Filled',
'app.docs.components.icon.two-tone': 'Two Tone',
'app.docs.components.icon.category.direction': 'Directional Icons',
'app.docs.components.icon.category.suggestion': 'Suggested Icons',
'app.docs.components.icon.category.editor': 'Editor Icons',
'app.docs.components.icon.category.data': 'Data Icons',
'app.docs.components.icon.category.other': 'Application Icons',
'app.docs.components.icon.category.logo': 'Brand and Logos',
'app.docs.components.icon.pic-searcher.intro': 'AI Search by image is online, welcome to use! 🎉',
...login,
...register,
...registerResult,
};

34
site/src/locale/zh-CN.js Normal file
View File

@ -0,0 +1,34 @@
import login from '../views/user/login/locales/zh-CN';
import register from '../views/user/register/locales/zh-CN';
import registerResult from '../views/user/register-result/locales/zh-CN';
import theme from '../theme/zh-CN';
export default {
...theme,
'navBar.lang': '语言',
'layout.user.link.help': '帮助',
'layout.user.link.privacy': '隐私',
'layout.user.link.terms': '条款',
'app.preview.down.block': '下载此页面到本地项目',
'app.welcome.link.fetch-blocks': '获取全部区块',
'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面',
'app.docs.components.icon.search.placeholder': '在此搜索图标,点击图标可复制代码',
'app.docs.components.icon.pick-theme': '选择图标主题风格',
'app.docs.components.icon.outlined': '线框风格',
'app.docs.components.icon.filled': '实底风格',
'app.docs.components.icon.two-tone': '双色风格',
'app.docs.components.icon.category.direction': '方向性图标',
'app.docs.components.icon.category.suggestion': '提示建议性图标',
'app.docs.components.icon.category.editor': '编辑类图标',
'app.docs.components.icon.category.data': '数据类图标',
'app.docs.components.icon.category.other': '网站通用图标',
'app.docs.components.icon.category.logo': '品牌和标识',
'app.docs.components.icon.pic-searcher.intro': 'AI 截图搜索上线了,快来体验吧!🎉',
'app.docs.components.icon.pic-searcher.title': '上传图片搜索图标',
'app.docs.components.icon.pic-searcher.upload-text': '点击/拖拽/粘贴上传图片',
'app.docs.components.icon.pic-searcher.upload-hint':
'我们会通过上传的图片进行匹配,得到最相似的图标',
...login,
...register,
...registerResult,
};

57
site/src/main.js Normal file
View File

@ -0,0 +1,57 @@
import 'ant-design-vue/dist/antd.less';
import 'docsearch.js/dist/cdn/docsearch.css';
import './index.less';
import 'nprogress/nprogress.css';
import { createApp, Transition, TransitionGroup } from 'vue';
import i18n from './i18n';
import NProgress from 'nprogress';
import router from './router';
import Antd from 'ant-design-vue';
import demoBox from './components/DemoBox.vue';
import demoContainer from './components/demoContainer.vue';
import demoSort from './components/demoSort.jsx';
import store from './store/index.js';
import clipboard from './directives/clipboard';
import App from './App.vue';
const app = createApp(App);
app.use(Antd);
app.use(clipboard);
app.component('transition', Transition);
app.component('transition-group', TransitionGroup);
app.component('demo-box', demoBox);
app.component('demo-container', demoContainer);
app.component('demo-sort', demoSort);
app.component('VNodes', function (_, { attrs: { value } }) {
return value;
});
// app.component('tempVar', {
// functional: true,
// render: (h, ctx) => {
// return ctx.scopedSlots && ctx.scopedSlots.default && ctx.scopedSlots.default(ctx.props);
// },
// });
router.beforeEach((to, from, next) => {
if (to.path !== from.path) {
NProgress.start();
}
next();
});
router.afterEach((to, from) => {
if (to.path !== from.path) {
NProgress.done();
document.documentElement.scrollTop = 0;
}
});
app.use(store);
app.use(router);
app.use(i18n);
app.config.globalProperties.$i18n = i18n;
app.mount('#app');

52
site/src/mock/user.js Normal file
View File

@ -0,0 +1,52 @@
// 代码中会兼容本地 service mock 以及部署站点的静态数据
module.exports = {
// 支持值为 Object 和 Array
'GET /api/currentUser': {
name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: '00000001',
email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大',
title: '交互专家',
group: '蚂蚁金服某某某事业群某某平台部某某技术部UED',
},
// GET POST 可省略
'GET /api/users': [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
],
'POST /api/login/account': (req, res) => {
const { password, userName, type } = req.body;
if (password === 'antdv' && userName === 'admin') {
res.send({ status: 'ok', type });
return;
}
if (password === 'antdv' && userName === 'user') {
res.send({ status: 'ok', type });
return;
}
res.send({ status: 'error', type });
},
'GET /api/login/captcha': (req, res) => {
return res.json('captcha-xxx');
},
'POST /api/register': (req, res) => {
res.send({ status: 'ok' });
},
};

155
site/src/router/index.js Normal file
View File

@ -0,0 +1,155 @@
import Layout from '../layouts/index.vue';
import Iframe from '../layouts/Iframe.vue';
// import Iframe from '../components/iframe.jsx';
import demoRoutes from './demoRoutes';
// import otherRoutes from './otherRoutes';
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
// ...otherRoutes,
{
path: '/components',
component: Layout,
children: [
{
path: 'overview:lang(.*)',
component: () => import('../views/ComponentOverview.vue'),
},
...demoRoutes,
],
},
{
path: '/iframe',
component: Iframe,
children: [
{
path: 'layout:lang(.*)',
meta: {
category: 'Components',
subtitle: '布局',
type: '布局',
cols: 1,
title: 'Layout',
cover: 'https://gw.alipayobjects.com/zos/alicdn/hzEndUVEx/Layout.svg',
},
props: route => {
const hash = route.hash.replace('#', '');
return { iframeName: hash };
},
component: () => import('../docs/layout/demo/index.vue'),
},
],
},
{
path: '/docs',
component: Layout,
// props: route => {
// const name = route.path.split('/docs/vue/')[1].split('/')[0];
// return { name, showApi: true };
// },
children: [
{
path: 'vue/introduce-cn',
meta: { enTitle: 'Ant Design of Vue', title: 'Ant Design of Vue', category: 'docs' },
component: () => import('../vueDocs/introduce.zh-CN.md'),
},
{
path: 'vue/introduce',
meta: { enTitle: 'Ant Design of Vue', title: 'Ant Design of Vue', category: 'docs' },
component: () => import('../vueDocs/introduce.en-US.md'),
},
{
path: 'vue/getting-started-cn',
meta: { enTitle: 'Getting Started', title: '快速上手', category: 'docs' },
component: () => import('../vueDocs/getting-started.zh-CN.md'),
},
{
path: 'vue/getting-started',
meta: { enTitle: 'Getting Started', title: '快速上手', category: 'docs' },
component: () => import('../vueDocs/getting-started.en-US.md'),
},
{
path: 'vue/customize-theme-cn',
meta: { enTitle: 'Customize Theme', title: '定制主题', category: 'docs' },
component: () => import('../vueDocs/customize-theme.zh-CN.md'),
},
{
path: 'vue/customize-theme',
meta: { enTitle: 'Customize Theme', title: '定制主题', category: 'docs' },
component: () => import('../vueDocs/customize-theme.en-US.md'),
},
{
path: 'vue/migration-v2-cn',
meta: { enTitle: 'V1 to V2', title: '从 v1 到 v2', category: 'docs' },
component: () => import('../vueDocs/migration-v2.zh-CN.md'),
},
{
path: 'vue/migration-v2',
meta: { enTitle: 'V1 to V2', title: '从 v1 到 v2', category: 'docs' },
component: () => import('../vueDocs/migration-v2.en-US.md'),
},
{
path: 'vue/replace-date-cn',
meta: { enTitle: 'Custom Date Library', title: '自定义时间库', category: 'docs' },
component: () => import('../vueDocs/replace-date.zh-CN.md'),
},
{
path: 'vue/replace-date',
meta: { enTitle: 'Custom Date Library', title: '自定义时间库', category: 'docs' },
component: () => import('../vueDocs/replace-date.en-US.md'),
},
{
path: 'vue/i18n-cn',
meta: { enTitle: 'Internationalization', title: '国际化', category: 'docs' },
component: () => import('../vueDocs/i18n.zh-CN.md'),
},
{
path: 'vue/i18n',
meta: { enTitle: 'Internationalization', title: '国际化', category: 'docs' },
component: () => import('../vueDocs/i18n.en-US.md'),
},
{
path: 'vue/faq-cn',
meta: { enTitle: 'FAQ', title: '常见问题', category: 'docs' },
component: () => import('../vueDocs/faq.zh-CN.md'),
},
{
path: 'vue/faq',
meta: { enTitle: 'FAQ', title: '常见问题', category: 'docs' },
component: () => import('../vueDocs/faq.en-US.md'),
},
{
path: 'vue/download-cn',
meta: { enTitle: 'Download Design Resources', title: '下载设计资源', category: 'docs' },
component: () => import('../vueDocs/download.zh-CN.md'),
},
{
path: 'vue/download',
meta: { enTitle: 'Download Design Resources', title: '下载设计资源', category: 'docs' },
component: () => import('../vueDocs/download.en-US.md'),
},
{
path: 'vue/sponsor-cn',
meta: { enTitle: 'Sponsor', title: '支持我们', category: 'docs' },
component: () => import('../vueDocs/sponsor.zh-CN.md'),
},
{
path: 'vue/sponsor',
meta: { enTitle: 'Sponsor', title: '支持我们', category: 'docs' },
component: () => import('../vueDocs/sponsor.en-US.md'),
},
{ path: '', redirect: '/docs/vue/introduce/' },
],
},
{ path: '/:lang(.*)', redirect: '/components/overview/' },
];
export default createRouter({
history: createWebHistory(),
fallback: false,
routes,
scrollBehavior: to => {
if (to.hash) {
return { el: to.hash, top: 80, behavior: 'auto' };
}
},
});

View File

@ -0,0 +1,56 @@
import UserLayout from '../layouts/UserLayout';
import BaseLayout from '../layouts/BaseLayout';
export default [
{
path: '/vip',
component: () => import('../views/vip.vue'),
},
{
path: '/jobs',
component: BaseLayout,
props: () => {
return { name: 'list-cn' };
},
children: [
{
path: '/jobs',
redirect: '/jobs/list-cn',
},
{
path: '/jobs/list-cn',
name: 'list-cn',
component: () => import(/* webpackChunkName: "jobs" */ '../views/jobs.vue'),
},
],
},
{
path: '/user',
component: UserLayout,
children: [
{
path: '/user',
redirect: '/user/login',
},
{
path: '/user/login',
name: 'login',
component: () =>
import(
/* webpackChunkName: "user" */
'../views/user/login'
),
},
{
path: '/user/register',
name: 'register',
component: () => import(/* webpackChunkName: "user" */ '../views/user/register'),
},
{
path: '/user/register-result',
name: 'register.result',
component: () => import(/* webpackChunkName: "user" */ '../views/user/register-result'),
},
],
},
];

View File

@ -0,0 +1,12 @@
import request from '../utils/request';
export async function fakeAccountLogin(params) {
return request('/api/login/account', {
method: 'POST',
data: params,
});
}
export async function getFakeCaptcha(mobile) {
return request(`/api/login/captcha?mobile=${mobile}`);
}

13
site/src/services/user.js Normal file
View File

@ -0,0 +1,13 @@
import request from '../utils/request';
export async function query() {
return request('/api/users');
}
export async function queryCurrent() {
return request('/api/currentUser');
}
export async function queryNotices() {
return request('/api/notices');
}

60
site/src/store/index.js Normal file
View File

@ -0,0 +1,60 @@
import { createStore } from 'vuex';
import user from './user';
import userAndLogin from '../views/user/login/model';
import userAndregister from '../views/user/register/model';
const createLoadingPlugin = ({ namespace: NAMESPACE = 'loading' } = {}) => {
const SHOW = '@@ANTDV_LOADING/SHOW';
const HIDE = '@@ANTDV_LOADING/HIDE';
return store => {
if (store.state[NAMESPACE]) {
throw new Error(`createLoadingPlugin: ${NAMESPACE} exited in current store`);
}
store.registerModule(NAMESPACE, {
namespaced: true,
state: {
global: false,
models: {},
effects: {},
},
mutations: {
[SHOW]: (state, { payload: { actionType } }) => {
state.global = true;
const _namespace = actionType.split('/')[0];
state.models = { ...state.models, [_namespace]: true };
state.effects = { ...state.effects, [actionType]: true };
},
[HIDE]: (state, { payload: { actionType } }) => {
state.global = false;
const _namespace = actionType.split('/')[0];
state.models = { ...state.models, [_namespace]: false };
state.effects = { ...state.effects, [actionType]: false };
},
},
});
store.subscribeAction({
before: action => {
store.commit(
{ type: `${NAMESPACE}/${SHOW}`, payload: { actionType: action.type } },
{ root: true },
);
},
after: action => {
store.commit(
{ type: `${NAMESPACE}/${HIDE}`, payload: { actionType: action.type } },
{ root: true },
);
},
});
};
};
export default createStore({
state: {},
plugins: [createLoadingPlugin()],
modules: {
userAndLogin,
userAndregister,
user,
},
});

41
site/src/store/user.js Normal file
View File

@ -0,0 +1,41 @@
/* eslint-disable no-unused-vars */
import { queryCurrent, query as queryUsers } from '../services/user';
export default {
namespaced: true,
state: {
currentUser: {},
},
actions: {
async login({ commit }, payload) {
const response = await queryUsers(payload);
commit({
type: 'save',
payload: response,
});
},
async fetchCurrent({ commit }, payload) {
const response = await queryCurrent(payload);
commit({
type: 'saveCurrentUser',
payload: response,
});
},
},
mutations: {
saveCurrentUser(state, { payload }) {
Object.assign(state, {
currentUser: payload || {},
});
},
changeNotifyCount(state, { payload }) {
Object.assign(state, {
currentUser: {
...state.currentUser,
notifyCount: payload.totalCount,
unreadCount: payload.unreadCount,
},
});
},
},
};

149
site/src/theme/en-US.js Normal file
View File

@ -0,0 +1,149 @@
export default {
'app.theme.switch.default': 'Default theme',
'app.theme.switch.dark': 'Dark theme',
'app.theme.switch.compact': 'Compact theme',
'app.header.search': 'Search...',
'app.header.menu.documentation': 'Docs',
'app.header.menu.components': 'Components',
'app.header.menu.spec': 'Design',
'app.header.menu.resource': 'Resources',
'app.header.menu.more': 'More',
'app.header.menu.mobile': 'Mobile',
'app.header.menu.pro.v4': 'Ant Design Pro',
'app.header.menu.charts': 'Ant Design Charts',
'app.header.menu.ecosystem': 'Ecosystem',
'app.header.menu.store': 'Store',
'app.header.lang': '中文',
'app.content.edit-page': 'Edit this page on GitHub!',
'app.content.edit-demo': 'Edit this demo on GitHub!',
'app.content.contributors': 'contributors',
'app.component.examples': 'Examples',
'app.component.examples.expand': 'Expand all code',
'app.component.examples.collapse': 'Collapse all code',
'app.component.examples.visible': 'Expand debug examples',
'app.component.examples.hide': 'Collapse debug examples',
'app.demo.debug': "Debug only, won't display at online",
'app.demo.type.js': 'Switch to TypeScript',
'app.demo.type.ts': 'Switch to JavaScript',
'app.demo.copy': 'Copy code',
'app.demo.copied': 'Copied!',
'app.demo.code.show': 'Show code',
'app.demo.code.hide': 'Hide code',
'app.demo.codepen': 'Open in CodePen',
'app.demo.codesandbox': 'Open in CodeSandbox',
'app.demo.stackblitz': 'Open in Stackblitz',
'app.demo.riddle': 'Open in Riddle',
'app.home.introduce':
'A design system for enterprise-level products. Create an efficient and enjoyable work experience.',
'app.home.recommend': 'Recommended',
'app.home.popularize': 'Popular',
'app.home.design-and-framework': 'Design language and framework',
'app.home.design-values': 'Design values',
'app.home.design-values-description':
'This is Ant Design\'s internal standard for evaluating design quality. Based on the assumption that "everyone is pursuing happiness at work", we have added the two values of "Meaningfulness" and "Growth" on the basis of "Certainty" and "Naturalness" to guide each designer towards better judgment and decision-making.',
'app.home.certainty': 'Certainty',
'app.home.meaningful': 'Meaningfulness',
'app.home.growth': 'Growth',
'app.home.natural': 'Naturalness',
'app.home.design-guide': 'Guidelines',
'app.home.components': 'Components',
'app.home.detail': 'More details',
'app.home.global-style': 'Global style',
'app.home.design-patterns': 'Design patterns',
'app.home.more': 'Learn More',
'app.home.play-video': 'Play video',
'app.home.qr': '4.0 is out',
'app.home.qr.desc': '4.0 is out',
'app.home.getting-started': 'Getting Started',
'app.home.design-language': 'Design Language',
'app.home.product-antv-slogan': 'A new way to do data visualization',
'app.home.product-pro-slogan': 'Out-of-the-box UI solution for enterprise applications',
'app.home.product-mobile-slogan': 'Mobile UI components with Ant Design',
'app.home.product-hitu': 'HiTu',
'app.home.product-hitu-slogan': 'A new generation of graphical solutions',
'app.home.product-kitchen-slogan': 'A Sketch plugin to enhance designers',
'app.home.product-icons-slogan': 'A set of premium icons',
'app.home.view-more': 'More',
'app.footer.repo': 'GitHub Repository',
'app.footer.awesome': 'Awesome Ant Design',
'app.footer.course': 'Ant Design Practical Tutorial',
'app.footer.chinamirror': 'China Mirror 🇨🇳',
'app.footer.primary-color-changing': 'Changing primary color...',
'app.footer.primary-color-changed': 'Changed primary color successfully!',
'app.footer.scaffold': 'Scaffold',
'app.footer.kitchen': 'Sketch Toolkit',
'app.footer.landing': 'Landing Templates',
'app.footer.scaffolds': 'Scaffold Market',
'app.footer.dev-tools': 'Developer Tools',
'app.footer.umi': 'React Application Framework',
'app.footer.dumi': 'Component doc generator',
'app.footer.remax': 'Mini Program Framework',
'app.footer.hooks': 'React Hooks Library',
'app.footer.resources': 'Resources',
'app.footer.data-vis': 'Data Visualization',
'app.footer.eggjs': 'Enterprise Node Framework',
'app.footer.motion': 'Motion Solution',
'app.footer.design-resources': 'Design Resources',
'app.footer.antd-library': 'Axure library',
'app.footer.antux': 'Sitemap Template',
'app.footer.community': 'Community',
'app.footer.help': 'Help',
'app.footer.change-log': 'Change Log',
'app.footer.faq': 'FAQ',
'app.footer.feedback': 'Feedback',
'app.footer.stackoverflow': 'StackOverflow',
'app.footer.segmentfault': 'SegmentFault',
'app.footer.discussions': 'Discussions',
'app.footer.bug-report': 'Bug Report',
'app.footer.issues': 'Issues',
'app.footer.version': 'Version: ',
'app.footer.author': 'Created by XTech',
'app.footer.work_with_us': 'Work with Us',
'app.footer.more-product': 'More Products',
'app.footer.company': 'XTech',
'app.footer.ant-design': 'UI Design Language',
'app.footer.yuque': 'YuQue',
'app.footer.yuque.slogan': 'Write your document as a team',
'app.footer.fengdie': 'FengDie',
'app.footer.fengdie.slogan': 'Console Applications Builder',
'app.footer.antv.slogan': 'Data Visualization',
'app.footer.egg.slogan': 'Enterprise Node.js Framework',
'app.footer.zhihu': 'Ant Design Blog',
'app.footer.zhihu.xtech': 'Experience Cloud Blog',
'app.footer.seeconf': 'Experience Tech Conference',
'app.footer.xtech': 'Ant Financial Experience Tech',
'app.footer.xtech.slogan': 'Experience The Beauty',
'app.publish.title': 'antd@3.0.0 has been released! 🎉 🎉 🎉',
'app.publish.greeting': 'Hello, ',
'app.publish.intro': ' has been released, so please upgrade. ',
'app.publish.old-version-guide': 'If you need documentation for an older version, please visit ',
'app.publish.old-version-tips': ', or switch the version via the dropdown in the header nav bar.',
'app.docs.color.pick-primary': 'Pick your primary color',
'app.docs.color.pick-background': 'Pick your background color',
'app.docs.components.icon.search.placeholder': 'Search icons here, click icon to copy code',
'app.docs.components.icon.pick-theme': 'Select the Icon Theme',
'app.docs.components.icon.outlined': 'Outlined',
'app.docs.components.icon.filled': 'Filled',
'app.docs.components.icon.two-tone': 'Two Tone',
'app.docs.components.icon.category.direction': 'Directional Icons',
'app.docs.components.icon.category.suggestion': 'Suggested Icons',
'app.docs.components.icon.category.editor': 'Editor Icons',
'app.docs.components.icon.category.data': 'Data Icons',
'app.docs.components.icon.category.other': 'Application Icons',
'app.docs.components.icon.category.logo': 'Brand and Logos',
'app.docs.components.icon.pic-searcher.intro':
'AI Search by image is online, you are welcome to use it! 🎉',
'app.docs.components.icon.pic-searcher.title': 'Search by image',
'app.docs.components.icon.pic-searcher.upload-text':
'Click, drag, or paste file to this area to upload',
'app.docs.components.icon.pic-searcher.upload-hint':
'We will find the best matching icon based on the image provided',
'app.docs.components.icon.pic-searcher.server-error':
'Predict service is temporarily unavailable',
'app.docs.components.icon.pic-searcher.matching': 'Matching...',
'app.docs.components.icon.pic-searcher.modelloading': 'Model is loading...',
'app.docs.components.icon.pic-searcher.result-tip': 'Matched the following icons for you:',
'app.docs.components.icon.pic-searcher.th-icon': 'Icon',
'app.docs.components.icon.pic-searcher.th-score': 'Probability',
'app.components.overview.search': 'Search in components',
};

View File

@ -0,0 +1,242 @@
.make-palette(@color, @index: 1) when (@index <= 10) {
.palette-@{color}-@{index} {
@background: '@{color}-@{index}';
background: @@background;
}
.make-palette(@color, (@index + 1)); // next iteration
}
@gray-1: #fff;
@gray-2: #fafafa;
@gray-3: #f5f5f5;
@gray-4: #f0f0f0;
@gray-5: #d9d9d9;
@gray-6: #bfbfbf;
@gray-7: #8c8c8c;
@gray-8: #595959;
@gray-9: #434343;
@gray-10: #262626;
@gray-11: #1f1f1f;
@gray-12: #141414;
@gray-13: #000;
@border-color: rgba(229, 231, 235, 100);
.color-palettes {
margin: 0 1%;
&-dark {
margin: 0;
padding: 0 28px;
background-color: #141414;
.color-title {
color: fade(@white, 85);
}
.color-description {
color: fade(@white, 45);
}
.color-palette {
margin: 45px 3.5% 45px 0;
&:nth-of-type(3n) {
margin-right: 0;
}
.main-color-item {
margin-right: 0;
&:hover {
margin-right: -8px;
}
}
}
}
}
.color-palette {
display: inline-block;
width: 31%;
margin: 45px 1%;
&-pick {
margin: 0 0 20px;
font-size: 20px;
text-align: center;
}
&-picker {
margin: 24px 0;
&-value {
position: relative;
top: -3px;
margin-left: 16px;
font-size: 14px;
font-family: Consolas, sans-serif;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
}
&-validation {
position: relative;
top: -3px;
margin-left: 16px;
color: @error-color;
font-size: 13px;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
&-dark {
margin-left: 0;
}
}
}
}
.main-color {
.make-palette(blue);
.make-palette(purple);
.make-palette(cyan);
.make-palette(green);
.make-palette(magenta);
.make-palette(red);
.make-palette(volcano);
.make-palette(orange);
.make-palette(gold);
.make-palette(yellow);
.make-palette(lime);
.make-palette(geekblue);
.make-palette(gray);
.palette-gray-11 {
background: @gray-11;
}
.palette-gray-12 {
background: @gray-12;
}
.palette-gray-13 {
background: @gray-13;
}
text-align: left;
&-item {
position: relative;
height: 44px;
margin-right: 4px;
padding: 0 12px;
font-size: 14px;
font-family: Consolas, sans-serif;
line-height: 44px;
cursor: pointer;
transition: all 0.2s;
&:first-child {
border-radius: 4px 4px 0 0;
}
&:last-child {
border-radius: 0 0 4px 4px;
}
&:hover {
margin-right: -8px;
border-radius: 0 4px 4px 0;
}
}
&-item &-text {
float: left;
transition: all 0.3s;
}
&-item &-value {
position: relative;
left: 3px;
float: right;
transform: scale(0.85);
transform-origin: 100% 50%;
opacity: 0;
transition: all 0.3s;
}
}
.color-title {
margin: 0 0 24px;
color: #5c6b77;
font-weight: 500;
font-size: 22px;
text-align: center;
text-transform: capitalize;
}
.color-description {
display: block;
color: #777;
font-weight: lighter;
font-size: 14px;
}
.main-color:hover {
.main-color-value {
left: 0;
opacity: 0.7;
}
}
.color-palette-horizontal {
width: 100%;
&-dark {
height: 303px;
padding: 32px 28px;
background-color: #141414;
.color-palette-picker {
margin-bottom: 0;
}
.color-palette-pick {
color: fade(@white, 65);
text-align: left;
&-hex {
color: fade(@white, 65);
}
.ant-row-rtl & {
direction: rtl;
text-align: right;
}
}
}
.main-color {
display: flex;
&-item {
position: relative;
flex: 1;
height: 86px;
margin-right: 0;
padding: 37px 0 0;
line-height: normal;
text-align: center;
border-radius: 0;
.main-color-text {
float: none;
}
&:hover {
height: 96px;
margin-top: -10px;
border-radius: 4px 4px 0 0;
}
}
&-value {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
transform-origin: unset;
}
&:hover {
.main-color-item {
padding-top: 8px;
}
.main-color-value {
bottom: 8px;
opacity: 0.7;
}
}
}
}

View File

@ -0,0 +1,263 @@
html {
&.rtl {
direction: rtl;
}
}
body {
overflow-x: hidden;
color: @site-text-color;
font-size: @font-size-base;
font-family: @font-family;
background: @body-background;
transition: background 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
a {
transition: color 0.3s ease;
}
.main-wrapper {
position: relative;
padding: 40px 0 0;
background: @component-background;
}
.main-container {
position: relative;
min-height: 500px;
padding: 0 170px 32px 64px;
background: @component-background;
.ant-row-rtl & {
padding: 0 64px 144px 170px;
}
}
.main-menu {
z-index: 1;
&-inner {
height: 100%;
max-height: 100vh;
overflow: hidden;
}
&:hover &-inner {
overflow-y: auto;
}
> div,
> div > div {
height: 100%;
}
}
.aside-container {
min-height: 100%;
padding-bottom: 48px;
font-family: Avenir, @font-family, sans-serif;
&.ant-menu-inline {
.ant-menu-submenu-title h4,
> .ant-menu-item,
.ant-menu-item a {
overflow: hidden;
font-size: 14px;
text-overflow: ellipsis;
}
> .ant-menu-item-group > .ant-menu-item-group-title {
margin-top: 16px;
margin-bottom: 16px;
font-size: 13px;
&::after {
position: relative;
top: 12px;
display: block;
width: calc(100% - 20px);
height: 1px;
background: @border-color-split;
content: '';
}
}
> .ant-menu-item,
> .ant-menu-submenu > .ant-menu-submenu-title,
> .ant-menu-item-group > .ant-menu-item-group-title,
> .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
&.ant-menu-inline > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item {
padding-left: 40px !important;
.ant-row-rtl & {
padding-right: 40px !important;
padding-left: 16px !important;
}
}
// Nest Category > Type > Article
&.ant-menu-inline {
.ant-menu-item-group-title {
padding-left: 60px;
.ant-row-rtl & {
padding-right: 60px;
padding-left: 16px;
}
}
.ant-menu-item-group-list > .ant-menu-item {
padding-left: 80px !important;
.ant-row-rtl & {
padding-right: 80px !important;
padding-left: 16px !important;
}
}
}
.ant-menu-item-group:first-child {
.ant-menu-item-group-title {
margin-top: 0;
}
}
}
a[disabled] {
color: #ccc;
}
.menu-item-link-outside {
position: relative;
.anticon {
position: absolute;
top: 16px;
right: -10px;
color: @primary-color;
font-size: 12px;
opacity: 0;
transition: all 0.3s;
}
&:hover .anticon {
opacity: 1;
}
}
}
.aside-container .chinese {
margin-left: 6px;
font-weight: normal;
font-size: 12px;
opacity: 0.67;
}
.outside-link {
display: inline-block;
}
.outside-link-icon {
margin-left: 5px;
color: #aaa;
font-size: 12px;
.ant-row-rtl & {
margin-right: 5px;
margin-left: 0;
transform: rotate(180deg);
}
}
// reset menu text color
.menu-site {
.ant-menu-item > a {
color: @site-text-color;
}
.ant-menu-item-selected > a,
.ant-menu-item > a:hover {
color: @primary-color;
}
}
#app {
height: 100%;
transition: transform 0.3s @ease-in-out-circ;
}
.drawer-content {
padding: 40px 0;
&-wrapper {
background-color: @component-background;
}
}
.drawer {
z-index: 1029;
}
#_hj_feedback_container {
[class$='icon_emotion_path1']::before {
color: @primary-color !important;
}
}
.fixed-widgets {
position: fixed;
right: 32px;
bottom: 102px;
z-index: 2147483640;
display: flex;
flex-direction: column;
cursor: pointer;
&-tooltip {
.ant-tooltip-inner {
min-width: 100px;
}
}
& > div {
display: block;
}
&-active {
color: @primary-color;
}
& &-avatar {
color: #000;
background-color: #fff;
box-shadow: @shadow-2;
transition: color 0.3s;
&:hover {
color: @primary-color;
}
}
}
// keep transition consistent to make mode toggle animation be more smooth, include:
// nav bar background
// nav search border
// nav menu background
// wrapper content
// sidemenu background
// sidemenu active background
// content background
// affix toc
#header,
#header #search-box,
#header #nav.ant-menu,
.main-wrapper,
.main-wrapper > .ant-row > .main-menu .main-menu-inner > .ant-menu,
.main-wrapper
> .ant-row
> .main-menu
.main-menu-inner
> .ant-menu.aside-container.ant-menu-inline
> .ant-menu-item-group
> .ant-menu-item-group-title::after,
.main-wrapper .main-container,
#demo-toc.toc {
transition: all 0.3s @ease-in-out-circ;
}
// remove margin-bottom from dark theme (why need margin-bottom in dark theme?)
#header > .ant-row > .ant-col h1 {
margin-bottom: 0;
}

View File

@ -0,0 +1,11 @@
.contributors-list {
display: flex;
flex-wrap: wrap;
margin-top: 120px !important;
a,
.ant-avatar + .ant-avatar {
margin-right: 8px;
margin-bottom: 8px;
}
}

View File

@ -0,0 +1,369 @@
[data-theme='dark'] {
/* Change autocomplete styles in WebKit */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
border: 1px solid @border-color-base;
-webkit-text-fill-color: @text-color;
box-shadow: none;
transition: background-color 5000s ease-in-out 0s;
}
#header {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.65);
}
#search-box input {
&::placeholder {
color: fade(@white, 30%);
}
}
.toc-affix {
.ant-affix {
background: @component-background;
}
}
:not(pre) > code[class*='language-'],
pre[class*='language-'] {
color: rgba(255, 255, 255, 0.65);
background: #262626;
}
.code-box {
border: 1px solid @border-color-split;
.markdown {
pre {
margin: 0.5em 0;
padding: 6px 12px;
}
pre code {
margin: 0;
background: #262626;
}
}
&-debug {
border-color: @purple-3;
}
&-expand-trigger {
position: relative;
margin-left: 12px;
color: #fff;
font-size: 20px;
cursor: pointer;
opacity: 0.45;
transition: all 0.3s;
&:hover {
opacity: 0.65;
}
}
&-demo {
border-bottom: 1px solid @border-color-split;
}
&-actions > &-code-action {
color: @site-text-color-secondary;
&:hover {
color: @site-text-color;
}
}
}
ul.anticons-list {
li {
color: #acacac;
&.TwoTone:hover {
background-color: #15395b;
}
&:hover {
.anticon {
color: #fff;
}
}
}
}
a[disabled] {
color: rgba(255, 255, 255, 0.25);
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: @heading-color;
}
.markdown {
code,
pre,
pre code {
background: #262626;
}
}
.markdown.api-container {
table {
tbody tr {
&:hover {
background: #262626;
}
}
}
}
.markdown code {
background: fade(@white, 8%);
}
.prev-next-nav {
> a.prev-page {
.footer-nav-icon-before {
color: fade(@white, 45%);
}
&:hover .footer-nav-icon-before {
color: @primary-color;
}
}
> .next-page {
.footer-nav-icon-after {
color: fade(@white, 45%);
}
&:hover .footer-nav-icon-after {
color: @primary-color;
}
}
}
.grid-demo,
[id^='components-grid-demo-'] {
.demo-row,
.code-box-demo .demo-row {
background-image: linear-gradient(
90deg,
#1d1d1d 4.16666667%,
transparent 4.16666667%,
transparent 8.33333333%,
#1d1d1d 8.33333333%,
#1d1d1d 12.5%,
transparent 12.5%,
transparent 16.66666667%,
#1d1d1d 16.66666667%,
#1d1d1d 20.83333333%,
transparent 20.83333333%,
transparent 25%,
#1d1d1d 25%,
#1d1d1d 29.16666667%,
transparent 29.16666667%,
transparent 33.33333333%,
#1d1d1d 33.33333333%,
#1d1d1d 37.5%,
transparent 37.5%,
transparent 41.66666667%,
#1d1d1d 41.66666667%,
#1d1d1d 45.83333333%,
transparent 45.83333333%,
transparent 50%,
#1d1d1d 50%,
#1d1d1d 54.16666667%,
transparent 54.16666667%,
transparent 58.33333333%,
#1d1d1d 58.33333333%,
#1d1d1d 62.5%,
transparent 62.5%,
transparent 66.66666667%,
#1d1d1d 66.66666667%,
#1d1d1d 70.83333333%,
transparent 70.83333333%,
transparent 75%,
#1d1d1d 75%,
#1d1d1d 79.16666667%,
transparent 79.16666667%,
transparent 83.33333333%,
#1d1d1d 83.33333333%,
#1d1d1d 87.5%,
transparent 87.5%,
transparent 91.66666667%,
#1d1d1d 91.66666667%,
#1d1d1d 95.83333333%,
transparent 95.83333333%
);
}
.code-box-demo .ant-row > div:not(.gutter-row) {
padding: 16px 0;
background: #028ac8;
&:nth-child(2n + 1) {
background: fade(#0088c6, 70%);
}
}
.ant-row .demo-col,
.code-box-demo .ant-row .demo-col {
margin-top: 0;
margin-bottom: 0;
padding: 30px 0;
color: @black;
font-size: 18px;
text-align: center;
border: none;
}
.ant-row .demo-col-1 {
background: fade(#0088c6, 70%);
}
.ant-row .demo-col-3,
.code-box-demo .ant-row .demo-col-3 {
color: @site-text-color-secondary;
background: unset;
}
.ant-row .demo-col-5,
.code-box-demo .ant-row .demo-col-5 {
color: @site-text-color-secondary;
background: unset;
}
}
.markdown > table th {
color: fade(@white, 65%);
background: #1d1d1d;
}
.copied-code {
background: fade(@white, 8%);
}
.browser-mockup.with-url::after {
background-color: @component-background;
}
.browser-mockup {
border-top: 2em solid #262626;
}
.browser-mockup::before {
background-color: #fb4742;
box-shadow: 0 0 0 2px #fb4742, 1.5em 0 0 2px #99bc2e, 3em 0 0 2px #ffba5a;
}
.browser-mockup.with-tab::after {
border-bottom: 2em solid @component-background;
}
.algolia-autocomplete {
.ds-dropdown-menu {
[class^='ds-dataset-'] {
background: @popover-background;
.algolia-docsearch-suggestion {
background: @popover-background;
}
}
.ds-suggestion.ds-cursor {
.algolia-docsearch-suggestion:not(.suggestion-layout-simple) {
.algolia-docsearch-suggestion--content {
background-color: fade(@white, 8%);
}
}
}
}
.algolia-docsearch-suggestion--category-header {
color: rgba(255, 255, 255, 0.65);
border-bottom: 1px solid @border-color-split;
}
.algolia-docsearch-suggestion--subcategory-column::before {
background: @border-color-split;
}
.algolia-docsearch-suggestion--content {
&::before {
background: @border-color-split;
}
}
}
.token.comment,
.token.quote {
color: #b6b18b;
}
.token.property,
.token.variable,
.token.template-variable,
.token.tag,
.token.number,
.token.name,
.token.selector-id,
.token.selector-class,
.token.regexp,
.token.deletion {
color: #eb3c54;
}
.token.built_in,
.token.builtin-name,
.token.literal,
.token.type,
.token.params,
.token.meta,
.token.link {
color: #e7ce56;
}
.token.attribute {
color: #ee7c2b;
}
.token.string,
.token.symbol,
.token.bullet,
.token.addition {
color: @primary-color;
}
.token.title,
.token.section {
color: #78bb65;
}
.token.function,
.token.keyword,
.token.selector-tag {
color: #b45ea4;
}
.hljs {
display: block;
padding: 0.5em;
overflow-x: auto;
color: #c0c5ce;
background: #1c1d21;
}
.token.emphasis {
font-style: italic;
}
.token.strong {
font-weight: bold;
}
.components-overview {
&-img {
background-color: rgba(255, 255, 255, 0.1);
}
&-search input {
color: rgba(255, 255, 255, 0.65);
}
}
}

View File

@ -0,0 +1,359 @@
.code-boxes-col-1-1 {
width: 100%;
}
.code-boxes-col-2-1 {
display: inline-block;
vertical-align: top;
}
.code-box {
position: relative;
display: inline-block;
width: 100%;
margin: 0 0 16px;
border: 1px solid @site-border-color-split;
border-radius: @border-radius-base;
transition: all 0.2s;
.code-box-title {
&,
a {
color: @site-text-color;
background: @component-background;
}
}
&,
.code-box-demo {
background-color: @component-background;
}
.markdown {
pre {
margin: 0.5em 0;
padding: 6px 12px;
}
pre code {
margin: 0;
background: #f5f5f5;
}
}
&:target {
border: 1px solid @primary-color;
}
&-expand-trigger {
position: relative;
margin-left: 12px;
color: #3b4357;
font-size: 20px;
cursor: pointer;
opacity: 0.75;
transition: all 0.3s;
&:hover {
opacity: 1;
}
.ant-row-rtl & {
margin-right: 8px;
margin-left: 0;
}
}
&-title {
position: absolute;
top: -14px;
margin-left: 16px;
padding: 1px 8px;
color: #777;
background: @body-background;
border-radius: @border-radius-base @border-radius-base 0 0;
transition: background-color 0.4s;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
border-radius: @border-radius-base 0 0 @border-radius-base;
}
a,
a:hover {
color: @site-text-color;
font-weight: 500;
font-size: @font-size-base;
}
}
&-description {
padding: 18px 24px 12px;
}
a.edit-button {
position: absolute;
top: 7px;
right: -16px;
padding-right: 6px;
font-size: 12px;
text-decoration: none;
background: inherit;
transform: scale(0.9);
.anticon {
color: @site-text-color-secondary;
transition: all 0.3s;
&:hover {
color: @site-text-color;
}
}
.ant-row.ant-row-rtl & {
right: auto;
left: -22px;
margin-right: 0;
padding-right: 8px;
padding-left: 6px;
}
}
&-demo {
padding: 42px 24px 50px;
color: @site-text-color;
border-bottom: 1px solid @site-border-color-split;
}
iframe {
width: 100%;
border: 0;
}
&-meta {
&.markdown {
position: relative;
width: 100%;
font-size: @font-size-base;
border-radius: 0 0 @border-radius-base @border-radius-base;
transition: background-color 0.4s;
}
blockquote {
line-height: 1.5;
}
h4,
section& p {
margin: 0;
}
> p {
width: 100%;
margin: 0.5em 0;
padding-right: 25px;
font-size: 12px;
word-break: break-word;
.ant-row-rtl & {
padding-right: 0;
padding-left: 25px;
}
}
}
&.expand &-meta {
border-bottom: 1px dashed @site-border-color-split;
border-radius: 0;
}
.code-expand-icon {
cursor: pointer;
}
.code-expand-icon-show,
.code-expand-icon-hide {
position: absolute;
top: 0;
left: 0;
width: 100%;
max-width: 100%;
margin: 0;
box-shadow: none;
transition: all 0.4s;
user-select: none;
.ant-row-rtl & {
right: 0;
left: auto;
}
}
.code-expand-icon-show {
opacity: 0.55;
pointer-events: auto;
&:hover {
opacity: 1;
}
}
.code-expand-icon.ant-tooltip-open .code-expand-icon-show {
opacity: 1;
}
.code-expand-icon-hide {
opacity: 0;
pointer-events: none;
}
.highlight-wrapper {
display: none;
overflow: auto;
border-radius: 0 0 @border-radius-base @border-radius-base;
&-expand {
display: block;
}
}
.highlight {
position: relative;
.ant-tabs-nav-list {
margin: 0 auto;
}
pre {
margin: 0;
padding: 0;
background: @component-background;
}
&:not(:first-child) {
border-top: 1px dashed @site-border-color-split;
}
}
&-actions {
display: flex;
justify-content: center;
padding: 12px 0;
border-top: 1px dashed @site-border-color-split;
opacity: 0.7;
transition: opacity 0.3s;
&:hover {
opacity: 1;
}
}
&-actions > &-code-action {
position: relative;
display: flex;
align-items: center;
width: 16px;
height: 16px;
margin-left: 16px;
color: @site-text-color-secondary;
cursor: pointer;
transition: all 0.24s;
.ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
&:first-child {
margin-left: 0;
.ant-row-rtl & {
margin-right: 0;
}
}
&:hover {
color: @site-text-color;
}
}
&-code-copy {
width: 14px;
height: 14px;
font-size: 14px;
text-align: center;
background: @component-background;
cursor: pointer;
transition: transform 0.24s;
&:hover {
transform: scale(1.2);
}
&.anticon-check {
color: @green-6 !important;
font-weight: bold;
}
}
&-codepen {
width: 14px;
height: 14px;
overflow: hidden;
border: 0;
cursor: pointer;
}
&-riddle {
width: 14px;
height: 14px;
overflow: hidden;
border: 0;
cursor: pointer;
}
&-codesandbox {
width: 16px;
height: 16px;
overflow: hidden;
border: 0;
cursor: pointer;
&:hover {
opacity: 1;
}
}
.highlight-wrapper:hover &-code-copy,
.highlight-wrapper:hover &-codepen,
.highlight-wrapper:hover &-codesandbox,
.highlight-wrapper:hover &-riddle {
opacity: 1;
}
pre {
width: auto;
margin: 0;
code {
background: @component-background;
border: none;
}
}
&-debug {
border-color: @purple-3;
}
&-debug &-title a {
color: @purple-6;
}
}
.all-code-box-controls {
float: right;
.ant-row-rtl & {
float: left;
}
}
.ant-row-rtl {
#components-tooltip-demo-placement,
#components-popover-demo-placement,
#components-popconfirm-demo-placement {
.code-box-demo {
direction: ltr;
}
}
}

View File

@ -0,0 +1,18 @@
.design-inline-cards {
display: flex;
margin: 0 -20px;
> * {
flex: 10%;
margin: 0 20px;
}
img {
width: 100%;
max-width: 100%;
}
h4 {
margin-bottom: 0;
}
}

View File

@ -0,0 +1,26 @@
.algolia-autocomplete {
.ds-dropdown-menu {
border: none;
box-shadow: @box-shadow-base;
[class^='ds-dataset-'] {
background: @component-background;
border: none;
.algolia-docsearch-suggestion {
background: @component-background;
}
}
&::before {
display: none;
}
}
.algolia-docsearch-suggestion--title {
color: @site-text-color;
}
.algolia-docsearch-suggestion--highlight {
color: @primary-color;
}
}

View File

@ -0,0 +1,80 @@
@import './colors';
@padding-space: 144px;
#footer {
clear: both;
font-size: 14px;
background-color: #000;
position: relative;
z-index: 100;
margin-left: -1px;
color: rgba(255, 255, 255, 0.65);
.ant-row {
text-align: center;
.footer-center {
display: inline-block;
text-align: left;
> h2 {
font-size: 16px;
margin: 0 auto 24px;
font-weight: 500;
position: relative;
> .title-icon {
width: 27px;
margin-right: 16px;
}
> .anticon {
font-size: 16px;
position: absolute;
left: -22px;
top: 3px;
color: #aaa;
}
}
> div {
margin: 12px 0;
}
}
}
.footer-wrap {
position: relative;
padding: 86px @padding-space 93px @padding-space;
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}
.bottom-bar {
text-align: center;
padding: 16px @padding-space;
margin: 0;
line-height: 32px;
overflow: hidden;
font-family: Avenir, @font-family;
font-size: 16px;
font-variant: tabular-nums;
a {
color: rgba(255, 255, 255, 0.65);
margin-left: 4px;
&:hover {
color: #fff;
}
}
.translate-button {
text-align: left;
}
.heart {
color: #f73f51;
font-size: 22px;
}
}
a {
color: rgba(255, 255, 255, 0.9);
}
h2 {
color: rgba(255, 255, 255, 1);
& > span {
color: rgba(255, 255, 255, 1);
}
}
}

View File

@ -0,0 +1,49 @@
@import '../../../node_modules/ant-design-vue/es/style/themes/default.less';
#header {
// ===================== Home Page =====================
&.home-header {
position: absolute;
top: 0;
right: 0;
left: 0;
max-width: 1280px;
margin-right: auto;
margin-left: auto;
background: transparent;
box-shadow: none;
#logo {
padding-right: 16px;
padding-left: 40px;
html.rtl & {
padding-right: 40px;
padding-left: 16px;
}
}
.ant-menu {
background: transparent;
}
}
}
@media (max-width: @screen-sm-min) {
#header.home-header {
.ant-row {
.ant-col {
margin: 0 auto;
a {
padding-right: 0;
padding-left: 0;
}
&:last-child {
display: none;
}
}
}
}
}

View File

@ -0,0 +1,155 @@
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
pre code {
display: block;
padding: 16px 32px;
color: @site-text-color;
font-size: @font-size-base;
font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
line-height: 2;
white-space: pre;
background: white;
border: 1px solid #e9e9e9;
border-radius: @border-radius-base;
}
code[class*='language-'],
pre[class*='language-'] {
color: black;
font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
line-height: 1.5;
direction: ltr;
white-space: pre;
text-align: left;
word-wrap: normal;
word-break: normal;
word-spacing: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
background: none;
}
code[class*='css'] {
direction: ltr;
}
pre[class*='language-']::-moz-selection,
pre[class*='language-'] ::-moz-selection,
code[class*='language-']::-moz-selection,
code[class*='language-'] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*='language-']::selection,
pre[class*='language-'] ::selection,
code[class*='language-']::selection,
code[class*='language-'] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*='language-'],
pre[class*='language-'] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*='language-'] {
margin: 16px 0;
padding: 12px 20px;
overflow: auto;
}
:not(pre) > code[class*='language-'],
pre[class*='language-'] {
background: #f5f5f5;
}
/* Inline code */
:not(pre) > code[class*='language-'] {
padding: 0.1em;
white-space: normal;
border-radius: 0.3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #f81d22;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #0b8235;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #0b8235;
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #008dff;
}
.token.function {
color: #f81d22;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,2 @@
@home-bg-color: #2f54eb;
@home-text-color: #314659;

View File

@ -0,0 +1,51 @@
.icon-pic-searcher {
display: inline-block;
margin: 0 8px;
.icon-pic-btn {
color: @text-color-secondary;
cursor: pointer;
transition: all 0.3s;
&:hover {
color: @input-icon-hover-color;
}
}
}
.icon-pic-preview {
width: 66px;
height: 66px;
margin-top: 10px;
padding: 8px;
text-align: center;
border: 1px solid @border-color-base;
border-radius: 4px;
> img {
max-width: 50px;
max-height: 50px;
}
}
.icon-pic-search-result {
min-height: 50px;
padding: 0 10px;
> .result-tip {
padding: 10px 0;
color: @text-color-secondary;
}
> table {
width: 100%;
.col-icon {
width: 80px;
padding: 10px 0;
> .anticon {
font-size: 30px;
:hover {
color: @link-hover-color;
}
}
}
}
}

View File

@ -0,0 +1,88 @@
ul.anticons-list {
margin: 10px 0;
overflow: hidden;
direction: ltr;
list-style: none;
li {
position: relative;
float: left;
width: 16.66%;
height: 100px;
margin: 3px 0;
padding: 10px 0 0;
overflow: hidden;
color: #555;
text-align: center;
list-style: none;
background-color: inherit;
border-radius: 4px;
cursor: pointer;
transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;
.rtl & {
margin: 3px 0;
padding: 10px 0 0;
}
.anticon {
margin: 12px 0 8px;
font-size: 36px;
transition: transform 0.3s ease-in-out;
will-change: transform;
}
.anticon-class {
display: block;
font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
white-space: nowrap;
text-align: center;
transform: scale(0.83);
.ant-badge {
transition: color 0.3s ease-in-out;
}
}
&:hover {
color: #fff;
background-color: @primary-color;
.anticon {
transform: scale(1.4);
}
.ant-badge {
color: #fff;
}
}
&.TwoTone:hover {
background-color: #8ecafe;
}
&.copied:hover {
color: rgba(255, 255, 255, 0.2);
}
&::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
color: #fff;
line-height: 110px;
text-align: center;
opacity: 0;
transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
content: 'Copied!';
}
&.copied::after {
top: -10px;
opacity: 1;
}
}
}
.copied-code {
padding: 2px 4px 2px;
font-size: 12px;
background: #f5f5f5;
border-radius: 2px;
}

View File

@ -0,0 +1,28 @@
@import './reset.less';
@import '../../../node_modules/ant-design-vue/es/style/themes/default.less';
@import './theme';
@import './common';
@import './header';
@import './footer';
@import './home';
@import './page-nav';
@import './markdown';
@import './design-doc';
@import './preview-img';
@import './toc';
@import './not-found';
@import './highlight';
@import './demo';
@import './colors';
@import './icons';
@import './icon-pic-searcher';
@import './mock-browser';
@import './new-version-info-modal';
@import './motion';
@import './responsive';
@import './resource';
@import './docsearch';
@import './nprogress';
@import './contributors';
@import './dark.less';
@import './rtl.less';

View File

@ -0,0 +1,490 @@
.markdown {
color: @site-text-color;
font-size: 14px;
line-height: 2;
}
.highlight {
line-height: 1.5;
}
.markdown img {
max-width: ~'calc(100% - 32px)';
}
.markdown p > img {
margin: 34px 0;
box-shadow: 0 8px 20px rgba(143, 168, 191, 0.35);
}
.markdown p > img.markdown-inline-image {
margin: 0;
box-shadow: none;
}
.markdown h1 {
margin-top: 8px;
margin-bottom: 20px;
color: @site-heading-color;
font-weight: 500;
font-size: 30px;
font-family: Avenir, @font-family, sans-serif;
line-height: 38px;
.subtitle {
margin-left: 12px;
}
}
.markdown h2 {
font-size: 24px;
line-height: 32px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
clear: both;
margin: 1.6em 0 0.6em;
color: @site-heading-color;
font-weight: 500;
font-family: Avenir, @font-family, sans-serif;
}
.markdown h3 {
font-size: 18px;
}
.markdown h4 {
font-size: 16px;
}
.markdown h5 {
font-size: 14px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
clear: both;
height: 1px;
margin: 56px 0;
background: @site-border-color-split;
border: 0;
}
.markdown p,
.markdown pre {
margin: 1em 0;
.ant-row-rtl & {
direction: rtl;
text-align: right;
}
}
.markdown ul > li {
margin-left: 20px;
padding-left: 4px;
list-style-type: circle;
.rtl & {
margin-right: 20px;
margin-left: 0;
padding-right: 4px;
padding-left: 0;
}
&:empty {
display: none;
}
}
.markdown ol > li {
margin-left: 20px;
padding-left: 4px;
list-style-type: decimal;
.ant-row-rtl & {
margin-right: 20px;
margin-left: 0;
padding-right: 4px;
padding-left: 0;
}
}
.markdown ul > li > p,
.markdown ol > li > p {
margin: 0.2em 0;
}
.markdown code {
margin: 0 1px;
padding: 0.2em 0.4em;
font-size: 0.9em;
background: @site-markdown-code-bg;
border: 1px solid @border-color-split;
border-radius: 3px;
}
.markdown pre {
font-family: @code-family;
background: @site-markdown-code-bg;
border-radius: @border-radius-base;
}
.markdown pre code {
margin: 0;
padding: 0;
overflow: auto;
color: @site-text-color;
font-size: max(@font-size-base - 1px, 12px);
direction: ltr;
text-align: left;
background: #f5f5f5;
border: none;
}
.markdown strong,
.markdown b {
font-weight: 500;
}
.markdown > table {
width: 100%;
margin: 8px 0 16px;
direction: ltr;
empty-cells: show;
border: 1px solid @site-border-color-split;
border-collapse: collapse;
border-spacing: 0;
}
.markdown > table th {
color: #5c6b77;
font-weight: 500;
white-space: nowrap;
background: rgba(0, 0, 0, 0.02);
}
.markdown > table th,
.markdown > table td {
padding: 16px 24px;
text-align: left;
border: 1px solid @site-border-color-split;
}
.markdown table td > a:not(:last-child) {
margin-right: 0 !important;
&::after {
position: relative !important;
}
}
.markdown blockquote {
margin: 1em 0;
padding-left: 0.8em;
color: @site-text-color-secondary;
font-size: 90%;
border-left: 4px solid @site-border-color-split;
.rtl & {
padding-right: 0.8em;
padding-left: 0;
border-right: 4px solid @site-border-color-split;
border-left: none;
}
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
margin-left: 8px;
opacity: 0;
transition: opacity 0.3s;
.rtl & {
margin-right: 8px;
margin-left: 0;
}
}
.markdown .waiting {
color: #ccc;
cursor: not-allowed;
}
.markdown a.edit-button {
display: inline-block;
margin-left: 8px;
text-decoration: none;
.rtl & {
margin-right: 8px;
margin-left: 0;
transform: rotateY(180deg);
}
.anticon {
display: block;
color: @site-text-color-secondary;
font-size: 16px;
transition: all 0.3s;
&:hover {
color: @site-text-color;
}
}
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
display: inline-block;
opacity: 1;
}
.markdown > br,
.markdown > p > br {
clear: both;
}
.markdown.api-container {
table {
display: block;
margin: 2em 0;
overflow-x: auto;
overflow-y: hidden;
font-size: max(@font-size-base - 1px, 12px);
font-family: @code-family;
line-height: @line-height-base;
border: 0;
-webkit-overflow-scrolling: touch;
th,
td {
padding: 12px;
border-color: @border-color-split;
border-width: 1px 0;
&:first-child {
border-left: 1px solid @border-color-split;
}
&:last-child {
border-right: 1px solid @border-color-split;
}
}
th {
padding-top: 14px;
border-width: 1px 0 2px 0;
}
tbody tr {
transition: all 0.3s;
&:hover {
background: rgba(60, 90, 100, 0.04);
}
}
td {
&:first-child {
width: 18%;
color: @gray-8;
font-weight: 600;
white-space: nowrap;
}
&:nth-child(2) {
width: 55%;
}
&:nth-child(3) {
width: 22%;
color: @magenta-7;
font-size: max(@font-size-base - 1px, 12px);
}
&:nth-child(4) {
width: 15%;
font-size: max(@font-size-base - 1px, 12px);
}
&:nth-child(5) {
width: 8%;
font-size: max(@font-size-base - 1px, 12px);
}
&:nth-last-child(3):first-child {
width: 38%;
}
&:nth-last-child(3):first-child ~ td:nth-last-child(2) {
width: 70%;
}
}
}
hr {
margin: 12px 0;
}
}
@demo-grid-color: #0092ff;
.grid-demo,
[id^='components-grid-demo-'] {
.demo-row,
.code-box-demo .demo-row {
margin-bottom: 8px;
overflow: hidden;
background-image: linear-gradient(
90deg,
#f5f5f5 4.16666667%,
transparent 4.16666667%,
transparent 8.33333333%,
#f5f5f5 8.33333333%,
#f5f5f5 12.5%,
transparent 12.5%,
transparent 16.66666667%,
#f5f5f5 16.66666667%,
#f5f5f5 20.83333333%,
transparent 20.83333333%,
transparent 25%,
#f5f5f5 25%,
#f5f5f5 29.16666667%,
transparent 29.16666667%,
transparent 33.33333333%,
#f5f5f5 33.33333333%,
#f5f5f5 37.5%,
transparent 37.5%,
transparent 41.66666667%,
#f5f5f5 41.66666667%,
#f5f5f5 45.83333333%,
transparent 45.83333333%,
transparent 50%,
#f5f5f5 50%,
#f5f5f5 54.16666667%,
transparent 54.16666667%,
transparent 58.33333333%,
#f5f5f5 58.33333333%,
#f5f5f5 62.5%,
transparent 62.5%,
transparent 66.66666667%,
#f5f5f5 66.66666667%,
#f5f5f5 70.83333333%,
transparent 70.83333333%,
transparent 75%,
#f5f5f5 75%,
#f5f5f5 79.16666667%,
transparent 79.16666667%,
transparent 83.33333333%,
#f5f5f5 83.33333333%,
#f5f5f5 87.5%,
transparent 87.5%,
transparent 91.66666667%,
#f5f5f5 91.66666667%,
#f5f5f5 95.83333333%,
transparent 95.83333333%
);
}
.ant-row > div,
.code-box-demo .ant-row > div {
min-height: 30px;
margin-top: 8px;
margin-bottom: 8px;
color: #fff;
text-align: center;
border-radius: 0;
}
.code-box-demo .ant-row > div:not(.gutter-row) {
padding: 16px 0;
background: @demo-grid-color;
&:nth-child(2n + 1) {
background: fade(@demo-grid-color, 75%);
}
}
.ant-row .demo-col,
.code-box-demo .ant-row .demo-col {
margin-top: 0;
margin-bottom: 0;
padding: 30px 0;
color: @white;
font-size: 18px;
text-align: center;
border: none;
}
.ant-row .demo-col-1 {
background: fade(@demo-grid-color, 75%);
}
.ant-row .demo-col-2,
.code-box-demo .ant-row .demo-col-2 {
background: fade(@demo-grid-color, 50%);
}
.ant-row .demo-col-3,
.code-box-demo .ant-row .demo-col-3 {
color: #999;
background: rgba(255, 255, 255, 0.2);
}
.ant-row .demo-col-4,
.code-box-demo .ant-row .demo-col-4 {
background: fade(@demo-grid-color, 60%);
}
.ant-row .demo-col-5,
.code-box-demo .ant-row .demo-col-5 {
color: #999;
background: rgba(255, 255, 255, 0.2);
}
.code-box-demo .height-100 {
height: 100px;
line-height: 100px;
}
.code-box-demo .height-50 {
height: 50px;
line-height: 50px;
}
.code-box-demo .height-120 {
height: 120px;
line-height: 120px;
}
.code-box-demo .height-80 {
height: 80px;
line-height: 80px;
}
}
[id='components-grid-demo-playground'],
[id='components-grid-demo-gutter'] {
> .code-box-demo .ant-row > div {
margin-top: 0;
margin-bottom: 0;
}
}
// For Changelog
.markdown ul.ant-timeline {
line-height: 2;
li.ant-timeline-item {
margin: 0;
padding: 0 0 30px;
list-style: none;
.ant-timeline-item-content {
position: relative;
top: -14px;
padding-left: 32px;
font-size: 14px;
> h2 {
margin-top: 0;
padding-top: 4px;
direction: ltr;
span {
.ant-row-rtl & {
float: right;
}
}
}
}
}
li.ant-timeline-item:first-child {
margin-top: 40px;
}
}

View File

@ -0,0 +1,53 @@
/* Browser mockup code
* Contribute: https://gist.github.com/jarthod/8719db9fef8deb937f4f
* Live example: https://updown.io
*/
.browser-mockup {
position: relative;
border-top: 2em solid rgba(230, 230, 230, 0.7);
border-radius: 3px 3px 0 0;
box-shadow: 0 0.1em 0.5em 0 rgba(0, 0, 0, 0.28);
}
.browser-mockup::before {
position: absolute;
top: -1.25em;
left: 1em;
display: block;
width: 0.5em;
height: 0.5em;
background-color: #f44;
border-radius: 50%;
box-shadow: 0 0 0 2px #f44, 1.5em 0 0 2px #9b3, 3em 0 0 2px #fb5;
content: '';
}
.browser-mockup.with-tab::after {
position: absolute;
top: -2em;
left: 5.5em;
display: block;
width: 20%;
height: 0;
border-right: 0.8em solid transparent;
border-bottom: 2em solid white;
border-left: 0.8em solid transparent;
content: '';
}
.browser-mockup.with-url::after {
position: absolute;
top: -1.6em;
left: 5.5em;
display: block;
width: ~'calc(100% - 6em)';
height: 1.2em;
background-color: white;
border-radius: 2px;
content: '';
}
.browser-mockup > * {
display: block;
}

View File

@ -0,0 +1,39 @@
.motion-container {
height: 190px;
margin: 40px 0 20px;
line-height: 190px;
text-align: center;
}
.motion-example {
display: inline-block !important;
width: 180px;
height: 180px;
color: #fff;
font-weight: bold;
font-size: 18px;
line-height: 180px;
text-align: center;
background: url(https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg) center/180px;
border-radius: 8px;
animation-duration: 0.5s !important;
}
.motion-select-wrapper {
margin-bottom: 40px;
text-align: center;
}
.motion-select {
width: 180px;
text-align: left;
}
.video-player {
position: relative;
max-width: 800px;
&-right {
float: right;
width: 616px;
}
}

View File

@ -0,0 +1,24 @@
.new-version-info-modal {
img {
position: absolute;
top: 36px;
left: 34px;
width: 100px;
}
p {
margin-top: 1em;
}
.anticon {
display: none;
}
.ant-confirm-body {
.ant-confirm-title {
font-size: 18px;
}
margin-left: 120px;
.ant-confirm-content {
margin-left: 0;
}
}
}

View File

@ -0,0 +1,34 @@
#page-404 {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
width: 100%;
height: 100%;
background-color: #fff;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
background-attachment: fixed;
section {
position: absolute;
top: 50%;
left: 50%;
text-align: center;
transform: translate(-50%, -50%);
}
h1 {
color: @primary-color;
font-weight: 500;
font-size: 120px;
}
p {
color: @site-text-color;
font-size: 18px;
}
}

View File

@ -0,0 +1,14 @@
#nprogress {
.bar {
background: @primary-color;
}
.peg {
box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color;
}
.spinner-icon {
border-top-color: @primary-color;
border-left-color: @primary-color;
}
}

View File

@ -0,0 +1,102 @@
.prev-next-nav {
width: ~'calc(100% - 128px)';
margin-right: 64px;
margin-left: 64px;
overflow: hidden;
font-size: 14px;
border-top: 1px solid @site-border-color-split;
> .prev-page,
> .next-page {
float: left;
width: 50%;
height: 72px;
line-height: 72px;
text-decoration: none;
.ant-row-rtl & {
float: right;
.footer-nav-icon-before,
.footer-nav-icon-after {
transform: rotate(180deg);
}
}
}
> a.prev-page {
.footer-nav-icon-before {
position: relative;
left: 0;
margin-right: 1em;
color: @site-text-color-secondary;
font-size: 12px;
transition: all 0.3s;
.ant-row-rtl & {
right: 0;
left: auto;
margin-right: 0;
margin-left: 1em;
}
}
.footer-nav-icon-after {
display: none;
}
&:hover .footer-nav-icon-before {
left: -3px;
color: @primary-color;
.ant-row-rtl & {
right: -3px;
left: auto;
}
}
}
> .next-page {
float: right;
text-align: right;
.ant-row-rtl & {
float: left;
text-align: left;
}
.footer-nav-icon-after {
position: relative;
right: 0;
margin-left: 1em;
color: @site-text-color-secondary;
font-size: 12px;
transition: all 0.3s;
.ant-row-rtl & {
right: auto;
left: 0;
margin-right: 1em;
margin-left: 0;
}
}
.footer-nav-icon-before {
display: none;
}
&:hover .footer-nav-icon-after {
right: -3px;
color: @primary-color;
.ant-row-rtl & {
right: auto;
left: -3px;
}
}
}
.chinese {
margin-left: 0.5em;
}
}

View File

@ -0,0 +1,214 @@
.preview-image-boxes {
display: flex;
float: right;
clear: both;
width: 496px;
margin: 0 0 70px 64px;
&-with-carousel {
width: 420px;
.preview-image-box img {
padding: 0;
}
}
.ant-row-rtl & {
float: left;
margin: 0 64px 70px 0;
}
}
.preview-image-boxes + .preview-image-boxes {
margin-top: -35px;
}
.preview-image-box {
float: left;
width: 100%;
}
.preview-image-box + .preview-image-box {
margin-left: 24px;
.ant-row-rtl & {
margin-right: 24px;
margin-left: 0;
}
}
.preview-image-wrapper {
position: relative;
display: inline-block;
width: 100%;
padding: 16px;
text-align: center;
background: #f2f4f5;
}
.preview-image-wrapper.video {
display: block;
padding: 0;
background: 0;
}
.preview-image-wrapper video {
display: block;
width: 100%;
+ svg {
position: absolute;
top: 0;
left: 0;
}
}
.preview-image-wrapper.good::after {
position: absolute;
bottom: 0;
left: 0;
display: block;
width: 100%;
height: 3px;
background: @primary-color;
content: '';
}
.preview-image-wrapper.bad::after {
position: absolute;
bottom: 0;
left: 0;
display: block;
width: 100%;
height: 3px;
background: @error-color;
content: '';
}
.preview-image-title {
margin-top: 20px;
color: @site-text-color;
font-size: 12px;
}
.preview-image-description {
margin-top: 2px;
color: @site-text-color-secondary;
font-size: 12px;
line-height: 1.5;
}
.preview-image-description hr {
margin: 2px 0;
background: none;
border: 0;
}
.preview-image-box img {
max-width: 100%;
padding: 12px;
background: @body-background;
border-radius: @border-radius-base;
cursor: pointer;
transition: all 0.3s;
&.no-padding {
padding: 0;
background: none;
}
}
.preview-image-boxes.preview-image-boxes-with-carousel img {
padding: 0;
box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 @body-background, 0 4px 0 0 #ddd, 0 6px 0 0 @body-background,
0 7px 0 0 #ddd;
}
.preview-image-box img:hover {
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);
}
.image-modal {
text-align: center;
&-container {
position: relative;
text-align: center;
}
.ant-carousel {
.slick-slider {
padding-bottom: 24px;
img {
display: inline;
max-width: 100%;
}
}
.slick-dots {
bottom: 4px;
li button {
background: #888;
}
}
}
.image-modal-single.slick-slider {
padding-bottom: 0;
}
.image-modal-single .slick-dots {
display: none !important;
}
}
.transition-video-player,
.motion-video-min {
float: right;
width: 600px;
padding: 0 0 70px 20px;
.preview-image-wrapper {
padding: 0;
}
.ant-row-rtl & {
float: left;
}
}
.motion-video-min {
width: 390px;
}
.motion-principle-wrapper {
width: 100%;
max-width: 900px;
margin: 48px 0 24px;
}
.principle-wrapper {
width: 100%;
.principle {
display: inline-block;
width: 100%;
min-height: 180px;
margin-right: 12.5%;
margin-bottom: 24px;
padding: 24px;
font-size: 24px;
text-align: center;
border: 1px solid #e8e8e8;
border-radius: 4px;
&:last-child {
margin-right: 0;
}
h4 {
margin: 16px 0 8px;
}
p {
font-size: 12px;
line-height: 24px;
}
}
}

View File

@ -0,0 +1,46 @@
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
code,
form,
fieldset,
legend,
input,
textarea,
p,
blockquote,
th,
td,
hr,
button,
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
margin: 0;
padding: 0;
}
ul,
ol {
list-style: none;
}

Some files were not shown because too many files have changed in this diff Show More