未验证 提交 737bd60f 编写于 作者: X xrk 提交者: GitHub

docs: add direction & theme to url (#26567)

* docs: add direction to localStorage

* wip

* wip

* wip

* wip

* browserHistory push

* add slider menu click query

* expand getLocalizedPathname

* add logo footer query

* fix lint

* wip pathname

* wip: fix pathname

* add hash & theme

* remove only component theme

* fix theme component change

* change var

* remove static

* change color

* chore: optimize code style

* fix: exchange theme when router is change

* fix: pathname

* fix: location pathname

* change dark

* fix theme

* fix router listen theme

* remove console
Co-authored-by: NKermit <kermitlx@outlook.com>
上级 58a69bc0
......@@ -353,4 +353,13 @@
.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);
}
}
}
......@@ -34,6 +34,7 @@ const ComponentOverview = ({
meta: { title },
content,
},
location,
utils: { toReactComponent },
}) => {
const { locale, formatMessage } = useIntl();
......@@ -103,7 +104,7 @@ const ComponentOverview = ({
const url = `${component.filename
.replace(/(\/index)?((\.zh-cn)|(\.en-us))?\.md$/i, '')
.toLowerCase()}/`;
const href = getLocalizedPathname(url, locale === 'zh-CN');
const href = getLocalizedPathname(url, locale === 'zh-CN', location.query);
return (
<Col xs={24} sm={12} lg={8} xl={6} key={component.title}>
<Link to={href} onClick={() => onClickCard(href)}>
......
import React, { Component } from 'react';
import { Link } from 'bisheng/router';
import { Link, browserHistory } from 'bisheng/router';
import { Row, Col, Menu, Affix, Tooltip, Avatar, Dropdown } from 'antd';
import { injectIntl } from 'react-intl';
import { LeftOutlined, RightOutlined, ExportOutlined } from '@ant-design/icons';
......@@ -230,6 +230,7 @@ class MainContent extends Component {
generateMenuItem(isTop, item, { before = null, after = null }) {
const {
intl: { locale },
location,
} = this.props;
const key = fileNameToPath(item.filename);
if (!item.title) {
......@@ -246,11 +247,13 @@ class MainContent extends Component {
];
const { disabled } = item;
const url = item.filename.replace(/(\/index)?((\.zh-cn)|(\.en-us))?\.md$/i, '').toLowerCase();
const child = !item.link ? (
<Link
to={utils.getLocalizedPathname(
/^components/.test(url) ? `${url}/` : url,
locale === 'zh-CN',
location.query,
)}
disabled={disabled}
>
......@@ -312,8 +315,19 @@ class MainContent extends Component {
changeThemeMode = theme => {
const { setTheme, theme: selectedTheme } = this.context;
const { pathname, hash, query } = this.props.location;
if (selectedTheme !== theme) {
setTheme(theme);
if (theme === 'default') {
delete query.theme;
} else {
query.theme = theme;
}
browserHistory.push({
pathname: `/${pathname}`,
query,
hash,
});
}
};
......@@ -438,7 +452,7 @@ class MainContent extends Component {
</div>
)}
<PrevAndNext prev={prev} next={next} />
<Footer />
<Footer location={location} />
</Col>
</Row>
</div>
......
......@@ -10,7 +10,8 @@ import Logo from './Logo';
import './index.less';
import SiteContext from '../../Layout/SiteContext';
export default function Banner() {
const Banner = (props: { location: any }) => {
const { location } = props;
const { isMobile } = React.useContext(SiteContext);
const { locale } = useIntl();
const isZhCN = locale === 'zh-CN';
......@@ -74,12 +75,12 @@ export default function Banner() {
{isZhCN && <div className="banner-qr">{qrNode}</div>}
<div className="home-banner-content-operations">
<Link to={getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Link to={getLocalizedPathname('/docs/react/introduce', isZhCN, location.query)}>
<Button type="primary" shape="round">
<FormattedMessage id="app.home.getting-started" />
</Button>
</Link>
<Link to={getLocalizedPathname('/docs/spec/introduce', isZhCN)}>
<Link to={getLocalizedPathname('/docs/spec/introduce', isZhCN, location.query)}>
<Button shape="round" ghost>
<FormattedMessage id="app.home.design-language" />
</Button>
......@@ -89,4 +90,6 @@ export default function Banner() {
</div>
</div>
);
}
};
export default Banner;
......@@ -68,7 +68,8 @@ const MiniPanel = ({
href,
link,
isZhCN,
}: PanelProps & { isZhCN: boolean }) => {
query,
}: PanelProps & { isZhCN: boolean } & { query: object }) => {
let content = (
<Card
hoverable
......@@ -86,7 +87,7 @@ const MiniPanel = ({
</a>
);
} else if (link) {
content = <Link to={getLocalizedPathname(link, isZhCN)}>{content}</Link>;
content = <Link to={getLocalizedPathname(link, isZhCN, query)}>{content}</Link>;
}
return (
......@@ -96,7 +97,8 @@ const MiniPanel = ({
);
};
export default function DesignPage() {
const DesignPage = (props: { location: any }) => {
const { location } = props;
const { locale } = useIntl();
const isZhCN = locale === 'zh-CN';
const { direction } = React.useContext(SiteContext);
......@@ -123,7 +125,7 @@ export default function DesignPage() {
<Link
className="design-card-detail"
to={getLocalizedPathname('/docs/spec/values', isZhCN)}
to={getLocalizedPathname('/docs/spec/values', isZhCN, location.query)}
>
<FormattedMessage id="app.home.detail" />
{IconComponent}
......@@ -195,13 +197,13 @@ export default function DesignPage() {
<ul>
<li>
<Link to={getLocalizedPathname('/docs/spec/colors', isZhCN)}>
<Link to={getLocalizedPathname('/docs/spec/colors', isZhCN, location.query)}>
<FormattedMessage id="app.home.global-style" />
{IconComponent}
</Link>
</li>
<li>
<Link to={getLocalizedPathname('/docs/spec/overview', isZhCN)}>
<Link to={getLocalizedPathname('/docs/spec/overview', isZhCN, location.query)}>
<FormattedMessage id="app.home.design-patterns" />
{IconComponent}
</Link>
......@@ -242,7 +244,9 @@ export default function DesignPage() {
<ul>
<li>
<Link to={getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Link
to={getLocalizedPathname('/docs/react/introduce', isZhCN, location.query)}
>
Ant Design of React
{IconComponent}
</Link>
......@@ -284,9 +288,11 @@ export default function DesignPage() {
className="design-mini-panels"
>
{MINI_LIST.map(panel => (
<MiniPanel key={panel.description} {...panel} isZhCN={isZhCN} />
<MiniPanel key={panel.description} {...panel} isZhCN={isZhCN} query={location.query} />
))}
</Row>
</div>
);
}
};
export default DesignPage;
......@@ -42,33 +42,42 @@ const BlockContent: React.FC<BlockContentProps> = ({ title, children, extra }) =
</div>
);
export default function Home() {
const Home = (props: { location: any }) => {
const { location } = props;
const { locale } = useIntl();
const isZhCN = locale === 'zh-CN';
const getLink = () => {
const path = getLocalizedPathname('/docs/resources', isZhCN, location.query, {
zhCN: '文章',
enUS: 'Articles',
});
const { pathname, query } = path;
const pathnames = pathname.split('#');
if ('direction' in query) {
return `${pathnames[0]}?direction=rtl#${pathnames[1]}`;
}
return path;
};
return (
<div className="home-container">
<style dangerouslySetInnerHTML={{ __html: getStyle() }} />
<Banner />
<Banner location={location} />
<div style={{ maxWidth: 1256, margin: '0 auto' }}>
<BlockContent title={<FormattedMessage id="app.home.recommend" />}>
<RecommendPage />
</BlockContent>
<BlockContent title={<FormattedMessage id="app.home.design-and-framework" />}>
<DesignPage />
<DesignPage location={location} />
</BlockContent>
{isZhCN ? (
<BlockContent
title={<FormattedMessage id="app.home.more" />}
extra={
<Link
to={getLocalizedPathname('/docs/resources', isZhCN, {
zhCN: '文章',
enUS: 'Articles',
})}
>
<Link to={getLink()}>
<FormattedMessage id="app.home.view-more" />
</Link>
}
......@@ -77,7 +86,9 @@ export default function Home() {
</BlockContent>
) : null}
</div>
<Footer />
<Footer location={location} />
</div>
);
}
};
export default Home;
......@@ -22,7 +22,7 @@ import {
import { isLocalStorageNameSupported, loadScript, getLocalizedPathname } from '../utils';
import ColorPicker from '../Color/ColorPicker';
class Footer extends React.Component<WrappedComponentProps> {
class Footer extends React.Component<WrappedComponentProps & { location: any }> {
lessLoaded = false;
state = {
......@@ -47,9 +47,29 @@ class Footer extends React.Component<WrappedComponentProps> {
}
getColumns() {
const { intl } = this.props;
const { intl, location } = this.props;
const isZhCN = intl.locale === 'zh-CN';
const getLinkHash = (path: string, hash: { zhCN: string; enUS: string }) => {
const pathName = getLocalizedPathname(path, isZhCN, location.query, hash);
const { pathname, query } = pathName;
const pathnames = pathname.split('#');
if ('direction' in query) {
return `${pathnames[0]}?direction=rtl#${pathnames[1]}`;
}
return pathname;
};
const getLink = (path: string) => {
const pathName = getLocalizedPathname(path, isZhCN, location.query);
const { pathname, query } = pathName;
if ('direction' in query) {
return `${pathname}?direction=rtl}`;
}
return pathname;
};
const col1 = {
title: <FormattedMessage id="app.footer.resources" />,
items: [
......@@ -128,7 +148,7 @@ class Footer extends React.Component<WrappedComponentProps> {
},
{
title: <FormattedMessage id="app.footer.design-resources" />,
url: getLocalizedPathname('/docs/resources', isZhCN, {
url: getLinkHash('/docs/resources', {
zhCN: '设计资源',
enUS: 'Design-Resources',
}),
......@@ -193,7 +213,7 @@ class Footer extends React.Component<WrappedComponentProps> {
col2.items.push({
icon: <UsergroupAddOutlined />,
title: <FormattedMessage id="app.footer.work_with_us" />,
url: getLocalizedPathname('/docs/resources', isZhCN, {
url: getLinkHash('/docs/resources', {
zhCN: '加入我们',
enUS: 'JoinUs',
}),
......@@ -213,13 +233,13 @@ class Footer extends React.Component<WrappedComponentProps> {
{
icon: <HistoryOutlined />,
title: <FormattedMessage id="app.footer.change-log" />,
url: getLocalizedPathname('/changelog', isZhCN),
url: getLink('/changelog'),
LinkComponent: Link,
},
{
icon: <ProfileOutlined />,
title: <FormattedMessage id="app.footer.faq" />,
url: getLocalizedPathname('/docs/react/faq', isZhCN),
url: getLink('/docs/react/faq'),
LinkComponent: Link,
},
{
......
import * as React from 'react';
import { Link } from 'bisheng/router';
import * as utils from '../../utils';
import { SharedProps } from './interface';
import './Logo.less';
export default ({ isZhCN }: SharedProps) => (
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN)} id="logo">
<img alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
Ant Design
</Link>
</h1>
);
export interface LogoProps {
isZhCN: boolean;
location: any;
}
const Logo = ({ isZhCN, location }: LogoProps) => {
return (
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN, location.query)} id="logo">
<img alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
Ant Design
</Link>
</h1>
);
};
export default Logo;
......@@ -15,7 +15,7 @@ export interface NavigationProps extends SharedProps {
isRTL: boolean;
pathname: string;
responsive: null | 'narrow' | 'crowded';
location: { pathname: string };
location: { pathname: string; query: any };
directionText: string;
onLangChange: () => void;
onDirectionChange: () => void;
......@@ -81,22 +81,22 @@ export default ({
id="nav"
>
<Menu.Item key="docs/spec">
<Link to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN)}>
<Link to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN, location.query)}>
<FormattedMessage id="app.header.menu.spec" />
</Link>
</Menu.Item>
<Menu.Item key="docs/react">
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN, location.query)}>
<FormattedMessage id="app.header.menu.documentation" />
</Link>
</Menu.Item>
<Menu.Item key="components">
<Link to={utils.getLocalizedPathname('/components/overview/', isZhCN)}>
<Link to={utils.getLocalizedPathname('/components/overview/', isZhCN, location.query)}>
<FormattedMessage id="app.header.menu.components" />
</Link>
</Menu.Item>
<Menu.Item key="docs/resources">
<Link to={utils.getLocalizedPathname('/docs/resources', isZhCN)}>
<Link to={utils.getLocalizedPathname('/docs/resources', isZhCN, location.query)}>
<FormattedMessage id="app.header.menu.resource" />
</Link>
</Menu.Item>
......
......@@ -51,7 +51,7 @@ export interface HeaderProps {
intl: {
locale: string;
};
location: { pathname: string };
location: { pathname: string; query: any };
router: any;
themeConfig: { docVersions: Record<string, string> };
changeDirection: (direction: string) => void;
......@@ -158,7 +158,7 @@ class Header extends React.Component<HeaderProps, HeaderState> {
onLangChange = () => {
const {
location: { pathname },
location: { pathname, query },
} = this.props;
const currentProtocol = `${window.location.protocol}//`;
const currentHref = window.location.href.substr(currentProtocol.length);
......@@ -171,7 +171,7 @@ class Header extends React.Component<HeaderProps, HeaderState> {
currentProtocol +
currentHref.replace(
window.location.pathname,
utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname)),
utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname), query).pathname,
);
};
......@@ -316,7 +316,7 @@ class Header extends React.Component<HeaderProps, HeaderState> {
)}
<Row style={{ flexFlow: 'nowrap', height: 64 }}>
<Col {...colProps[0]}>
<Logo {...sharedProps} />
<Logo {...sharedProps} location={location} />
</Col>
<Col {...colProps[1]} className="menu-row">
{searchBox}
......
......@@ -10,6 +10,7 @@ import 'moment/locale/zh-cn';
import { ConfigProvider } from 'antd';
import LogRocket from 'logrocket';
import setupLogRocketReact from 'logrocket-react';
import { browserHistory } from 'bisheng/router';
// eslint-disable-next-line import/no-unresolved
import zhCN from 'antd/es/locale/zh_CN';
import Header from './Header';
......@@ -57,7 +58,6 @@ if (typeof window !== 'undefined') {
}
const RESPONSIVE_MOBILE = 768;
const SITE_THEME_STORE_KEY = 'site-theme';
// for dark.css timestamp to remove cache
const timestamp = new Date().getTime();
......@@ -73,6 +73,8 @@ const { switcher } = themeSwitcher(themeConfig);
export default class Layout extends React.Component {
static contextType = SiteContext;
isBeforeComponent = false;
constructor(props) {
super(props);
const { pathname } = props.location;
......@@ -80,10 +82,7 @@ export default class Layout extends React.Component {
this.state = {
appLocale,
theme:
typeof localStorage !== 'undefined'
? localStorage.getItem(SITE_THEME_STORE_KEY) || 'default'
: 'default',
theme: 'default',
setTheme: this.setTheme,
direction: 'ltr',
setIframeTheme: this.setIframeTheme,
......@@ -91,25 +90,46 @@ export default class Layout extends React.Component {
}
componentDidMount() {
const { theme } = this.state;
const { location, router } = this.props;
router.listen(loc => {
router.listen(({ pathname, search }) => {
const { theme } = this.props.location.query;
if (typeof window.ga !== 'undefined') {
window.ga('send', 'pageview', loc.pathname + loc.search);
window.ga('send', 'pageview', pathname + search);
}
// eslint-disable-next-line
if (typeof window._hmt !== 'undefined') {
// eslint-disable-next-line
window._hmt.push(['_trackPageview', loc.pathname + loc.search]);
window._hmt.push(['_trackPageview', pathname + search]);
}
const { pathname } = loc;
const componentPage = /^\/?components/.test(pathname);
// only component page can use `dark` theme
if (!componentPage) {
this.isBeforeComponent = false;
this.setTheme('default', false);
} else if (theme && !this.isBeforeComponent) {
this.isBeforeComponent = true;
this.setTheme(theme, false);
}
});
this.setTheme(/^\/?components/.test(location.pathname) ? theme : 'default');
if (location.query.theme && /^\/?components/.test(location.pathname)) {
this.isBeforeComponent = true;
this.setTheme(location.query.theme, false);
} else {
this.isBeforeComponent = false;
this.setTheme('default', false);
}
if (location.query.direction) {
this.setState({
direction: location.query.direction,
});
} else {
this.setState({
direction: 'ltr',
});
}
const nprogressHiddenStyle = document.getElementById('nprogress-style');
if (nprogressHiddenStyle) {
......@@ -180,6 +200,17 @@ export default class Layout extends React.Component {
this.setState({
direction,
});
const { pathname, hash, query } = this.props.location;
if (direction === 'ltr') {
delete query.direction;
} else {
query.direction = 'rtl';
}
browserHistory.push({
pathname: `/${pathname}`,
query,
hash,
});
};
render() {
......
......@@ -39,7 +39,7 @@ export default function NotFound(props: NotFoundProps) {
for (let i = 0; i < directLinks.length; i += 1) {
const matchPath = directLinks[i];
if (pathname.includes(matchPath)) {
router.replace(utils.getLocalizedPathname(`/${DIRECT_MAP[matchPath]}`, isZhCN));
router.replace(utils.getLocalizedPathname(`/${DIRECT_MAP[matchPath]}`, isZhCN).pathname);
}
}
}, []);
......
......@@ -30,6 +30,7 @@ interface PagesData {
interface ResourcesProps {
location: {
pathname: string;
query: object;
};
data: PagesData;
localizedPageData: PageData;
......@@ -116,7 +117,7 @@ function injectCards(content: ContentUnit[]): ContentUnit[] {
}
const Resources = (props: ResourcesProps) => {
const { localizedPageData } = props;
const { localizedPageData, location } = props;
const { locale } = useIntl();
const content = React.useMemo(() => injectCards(localizedPageData.content), [
......@@ -137,7 +138,7 @@ const Resources = (props: ResourcesProps) => {
titleRegionClassName="title-region"
/>
<Footer />
<Footer location={location} />
</div>
);
};
......
......@@ -118,6 +118,7 @@ export function isZhCN(pathname: string) {
export function getLocalizedPathname(
path: string,
zhCN?: boolean,
query = {},
hash?: {
zhCN: string;
enUS: string;
......@@ -141,7 +142,7 @@ export function getLocalizedPathname(
fullPath += `#${localHash}`;
}
return fullPath;
return { pathname: fullPath, query };
}
export function ping(callback: (status: string) => void) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册