mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 01:13:58 +08:00
Adapt to the mobile mode of the new official website (#39043)
* feat: add basic css for title feat: add basic Carousel structure feat: modify some card with mobile mode feat: style change for theme feat: Extract public styles and improve some styles fix: Fix code loss caused by handling conflicts * feat: change the theme to carousel with image
This commit is contained in:
parent
5552571131
commit
53470fc476
@ -1,10 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import { Button, Space, Typography } from 'antd';
|
||||
import { Link, useLocation } from 'dumi';
|
||||
import { css } from '@emotion/react';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import { GroupMask } from './Group';
|
||||
import * as utils from '../../../theme/utils';
|
||||
import SiteContext from './SiteContext';
|
||||
import topicImage from './images/topic.png';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
@ -20,6 +23,35 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const { isMobile } = React.useContext(SiteContext);
|
||||
|
||||
return {
|
||||
titleBase: css`
|
||||
h1& {
|
||||
font-family: AliPuHui, ${token.fontFamily};
|
||||
}
|
||||
`,
|
||||
title: isMobile
|
||||
? css`
|
||||
h1& {
|
||||
margin-bottom: ${token.margin}px;
|
||||
font-weight: normal;
|
||||
font-size: ${token.fontSizeHeading1 + 2}px;
|
||||
line-height: ${token.lineHeightHeading2};
|
||||
}
|
||||
`
|
||||
: css`
|
||||
h1& {
|
||||
margin-bottom: ${token.marginMD}px;
|
||||
font-weight: 900;
|
||||
font-size: 68px;
|
||||
}
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
||||
export interface BannerProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
@ -28,53 +60,59 @@ export default function Banner({ children }: BannerProps) {
|
||||
const [locale] = useLocale(locales);
|
||||
const { pathname, search } = useLocation();
|
||||
const { token } = useSiteToken();
|
||||
const styles = useStyle();
|
||||
const { isMobile } = React.useContext(SiteContext);
|
||||
|
||||
const isZhCN = utils.isZhCN(pathname);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Banner Placeholder Motion */}
|
||||
<div
|
||||
style={{
|
||||
height: 320,
|
||||
background: '#77C6FF',
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{isMobile ? (
|
||||
<img src={topicImage} alt="" style={{ width: '100%' }} />
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*6d50SboraPIAAAAAAAAAAAAAARQnAQ)`,
|
||||
flex: 'auto',
|
||||
backgroundRepeat: 'repeat-x',
|
||||
backgroundPosition: '100% 0',
|
||||
backgroundSize: 'auto 100%',
|
||||
height: 320,
|
||||
background: '#77C6FF',
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
/>
|
||||
|
||||
<video style={{ height: '100%', objectFit: 'contain' }} autoPlay muted loop>
|
||||
<source
|
||||
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ"
|
||||
type="video/webm"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*6d50SboraPIAAAAAAAAAAAAAARQnAQ)`,
|
||||
flex: 'auto',
|
||||
backgroundRepeat: 'repeat-x',
|
||||
backgroundPosition: '100% 0',
|
||||
backgroundSize: 'auto 100%',
|
||||
}}
|
||||
/>
|
||||
<source
|
||||
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/file/A*XYYNQJ3NbmMAAAAAAAAAAAAAARQnAQ"
|
||||
type="video/mp4"
|
||||
/>
|
||||
</video>
|
||||
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*8ILtRrQlVDMAAAAAAAAAAAAAARQnAQ)`,
|
||||
flex: 'auto',
|
||||
backgroundRepeat: 'repeat-x',
|
||||
backgroundPosition: '0 0',
|
||||
backgroundSize: 'auto 100%',
|
||||
marginLeft: -1,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<video style={{ height: '100%', objectFit: 'contain' }} autoPlay muted loop>
|
||||
<source
|
||||
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ"
|
||||
type="video/webm"
|
||||
/>
|
||||
<source
|
||||
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/file/A*XYYNQJ3NbmMAAAAAAAAAAAAAARQnAQ"
|
||||
type="video/mp4"
|
||||
/>
|
||||
</video>
|
||||
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*8ILtRrQlVDMAAAAAAAAAAAAAARQnAQ)`,
|
||||
flex: 'auto',
|
||||
backgroundRepeat: 'repeat-x',
|
||||
backgroundPosition: '0 0',
|
||||
backgroundSize: 'auto 100%',
|
||||
marginLeft: -1,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Logo */}
|
||||
<div style={{ position: 'relative', background: '#fff' }}>
|
||||
@ -94,34 +132,26 @@ export default function Banner({ children }: BannerProps) {
|
||||
>
|
||||
{/* Image Left Top */}
|
||||
<img
|
||||
style={{ position: 'absolute', left: 0, top: 0, width: 240 }}
|
||||
style={{ position: 'absolute', left: isMobile ? -120 : 0, top: 0, width: 240 }}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/49f963db-b2a8-4f15-857a-270d771a1204.svg"
|
||||
alt="bg"
|
||||
/>
|
||||
{/* Image Left Top */}
|
||||
{/* Image Right Top */}
|
||||
<img
|
||||
style={{ position: 'absolute', right: 120, top: 0, width: 240 }}
|
||||
style={{ position: 'absolute', right: isMobile ? 0 : 120, top: 0, width: 240 }}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/e152223c-bcae-4913-8938-54fda9efe330.svg"
|
||||
alt="bg"
|
||||
/>
|
||||
|
||||
<Typography.Title
|
||||
level={1}
|
||||
style={{
|
||||
fontFamily: `AliPuHui, ${token.fontFamily}`,
|
||||
fontSize: token.fontSizes[9],
|
||||
lineHeight: token.lineHeights[9],
|
||||
fontWeight: 900,
|
||||
marginBottom: token.marginMD,
|
||||
}}
|
||||
>
|
||||
<Typography.Title level={1} css={[styles.titleBase, styles.title]}>
|
||||
Ant Design 5.0
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph
|
||||
style={{
|
||||
fontSize: token.fontSizeHeading5,
|
||||
lineHeight: token.lineHeightHeading5,
|
||||
fontSize: isMobile ? token.fontSizeHeading5 - 2 : token.fontSizeHeading5,
|
||||
lineHeight: isMobile ? token.lineHeightSM : token.lineHeightHeading5,
|
||||
marginBottom: token.marginMD * 2,
|
||||
padding: isMobile ? `0 ${token.paddingLG + 2}px` : 0,
|
||||
}}
|
||||
>
|
||||
<div>{locale.slogan}</div>
|
||||
|
@ -1,75 +1,122 @@
|
||||
import * as React from 'react';
|
||||
import { Skeleton, Typography } from 'antd';
|
||||
import { Typography, Skeleton, Carousel } from 'antd';
|
||||
import type { SerializedStyles } from '@emotion/react';
|
||||
import { css } from '@emotion/react';
|
||||
import type { Extra, Icon } from './util';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import SiteContext from './SiteContext';
|
||||
import { useCarouselStyle } from './util';
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const { carousel } = useCarouselStyle();
|
||||
|
||||
return {
|
||||
card: css`
|
||||
border: ${token.lineWidth}px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
padding-block: ${token.paddingMD}px;
|
||||
padding-inline: ${token.paddingLG}px;
|
||||
flex: 1 1 0;
|
||||
width: 33%;
|
||||
itemBase: css`
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
text-decoration: none;
|
||||
transition: all ${token.motionDurationSlow};
|
||||
background: ${token.colorBgContainer};
|
||||
|
||||
border: ${token.lineWidth}px solid ${token.colorBorderSecondary};
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
transition: all ${token.motionDurationSlow};
|
||||
padding-block: ${token.paddingMD}px;
|
||||
padding-inline: ${token.paddingLG}px;
|
||||
`,
|
||||
cardItem: css`
|
||||
width: 33%;
|
||||
&:hover {
|
||||
box-shadow: ${token.boxShadowCard};
|
||||
}
|
||||
`,
|
||||
sliderItem: css`
|
||||
margin: 0 ${token.margin}px;
|
||||
text-align: start;
|
||||
`,
|
||||
container: css`
|
||||
display: flex;
|
||||
max-width: 1208px;
|
||||
margin-inline: auto;
|
||||
box-sizing: border-box;
|
||||
padding-inline: ${token.marginXXL}px;
|
||||
column-gap: ${token.paddingMD * 2}px;
|
||||
align-items: stretch;
|
||||
text-align: start;
|
||||
`,
|
||||
carousel,
|
||||
};
|
||||
};
|
||||
|
||||
interface RecommendItemProps {
|
||||
extra: Extra;
|
||||
index: number;
|
||||
icons: Icon[];
|
||||
itemCss: SerializedStyles;
|
||||
}
|
||||
const RecommendItem = ({ extra, index, icons, itemCss }: RecommendItemProps) => {
|
||||
const style = useStyle();
|
||||
const { token } = useSiteToken();
|
||||
|
||||
if (!extra) {
|
||||
return <Skeleton key={index} />;
|
||||
}
|
||||
const icon = icons.find((i) => i.name === extra.source);
|
||||
|
||||
return (
|
||||
<a key={extra?.title} href={extra.href} target="_blank" css={[style.itemBase, itemCss]} rel="noreferrer">
|
||||
<Typography.Title level={5}>{extra?.title}</Typography.Title>
|
||||
<Typography.Paragraph type="secondary" style={{ flex: 'auto' }}>
|
||||
{extra.description}
|
||||
</Typography.Paragraph>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Typography.Text>{extra.date}</Typography.Text>
|
||||
{icon && <img src={icon.href} style={{ height: token.fontSize }} alt="banner"/>}
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export interface BannerRecommendsProps {
|
||||
extras?: Extra[];
|
||||
icons?: Icon[];
|
||||
}
|
||||
|
||||
export default function BannerRecommends({ extras = [], icons = [] }: BannerRecommendsProps) {
|
||||
const style = useStyle();
|
||||
const styles = useStyle();
|
||||
const { isMobile } = React.useContext(SiteContext);
|
||||
const first3 = extras.length === 0 ? Array(3).fill(null) : extras.slice(0, 3);
|
||||
const { token } = useSiteToken();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
maxWidth: 1208,
|
||||
marginInline: 'auto',
|
||||
boxSizing: 'border-box',
|
||||
paddingInline: token.marginXXL,
|
||||
display: 'flex',
|
||||
columnGap: token.paddingMD * 2,
|
||||
alignItems: 'stretch',
|
||||
textAlign: 'start',
|
||||
}}
|
||||
>
|
||||
{first3.map((extra, index) => {
|
||||
if (!extra) {
|
||||
return <Skeleton key={index} />;
|
||||
}
|
||||
const icon = icons.find((i) => i.name === extra.source);
|
||||
return (
|
||||
<a key={extra?.title} href={extra.href} target="_blank" css={style.card} rel="noreferrer">
|
||||
<Typography.Title level={5}>{extra?.title}</Typography.Title>
|
||||
<Typography.Paragraph type="secondary" style={{ flex: 'auto' }}>
|
||||
{extra.description}
|
||||
</Typography.Paragraph>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Typography.Text>{extra.date}</Typography.Text>
|
||||
{icon && <img src={icon.href} style={{ height: token.fontSize }} alt="banner" />}
|
||||
<div>
|
||||
{isMobile ? (
|
||||
<Carousel css={styles.carousel}>
|
||||
{first3.map((extra, index) => (
|
||||
<div key={index}>
|
||||
<RecommendItem
|
||||
extra={extra}
|
||||
index={index}
|
||||
icons={icons}
|
||||
itemCss={styles.sliderItem}
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
))}
|
||||
</Carousel>
|
||||
) : (
|
||||
<div css={styles.container}>
|
||||
{first3.map((extra, index) => (
|
||||
<RecommendItem
|
||||
extra={extra}
|
||||
index={index}
|
||||
icons={icons}
|
||||
itemCss={styles.cardItem}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable react/jsx-pascal-case */
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import {
|
||||
Space,
|
||||
Typography,
|
||||
@ -10,12 +10,15 @@ import {
|
||||
Modal,
|
||||
FloatButton,
|
||||
Progress,
|
||||
Carousel,
|
||||
} from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { CustomerServiceOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons';
|
||||
import { css } from '@emotion/react';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import SiteContext from './SiteContext';
|
||||
import { useCarouselStyle } from './util';
|
||||
|
||||
const SAMPLE_CONTENT_EN =
|
||||
'Ant Design 5.0 use CSS-in-JS technology to provide dynamic & mix theme ability. And which use component level CSS-in-JS solution get your application a better performance.';
|
||||
@ -54,6 +57,7 @@ const locales = {
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const { carousel } = useCarouselStyle();
|
||||
|
||||
return {
|
||||
card: css`
|
||||
@ -80,13 +84,25 @@ const useStyle = () => {
|
||||
filter: blur(40px);
|
||||
opacity: 0.1;
|
||||
`,
|
||||
mobileCard: css`
|
||||
height: 395px;
|
||||
`,
|
||||
carousel,
|
||||
};
|
||||
};
|
||||
|
||||
interface ComponentItemProps {
|
||||
title: React.ReactNode;
|
||||
node: React.ReactNode;
|
||||
type: 'new' | 'update';
|
||||
index: number;
|
||||
}
|
||||
|
||||
export default function ComponentsList() {
|
||||
const { token } = useSiteToken();
|
||||
const styles = useStyle();
|
||||
const [locale] = useLocale(locales);
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
|
||||
const COMPONENTS: {
|
||||
title: React.ReactNode;
|
||||
@ -110,12 +126,16 @@ export default function ComponentsList() {
|
||||
node: (
|
||||
<DatePicker._InternalPanelDoNotUseOrYouWillBeFired
|
||||
showToday={false}
|
||||
presets={[
|
||||
{ label: locale.yesterday, value: dayjs().add(-1, 'd') },
|
||||
{ label: locale.lastWeek, value: dayjs().add(-7, 'd') },
|
||||
{ label: locale.lastMonth, value: dayjs().add(-1, 'month') },
|
||||
{ label: locale.lastYear, value: dayjs().add(-1, 'year') },
|
||||
]}
|
||||
presets={
|
||||
isMobile
|
||||
? []
|
||||
: [
|
||||
{ label: locale.yesterday, value: dayjs().add(-1, 'd') },
|
||||
{ label: locale.lastWeek, value: dayjs().add(-7, 'd') },
|
||||
{ label: locale.lastMonth, value: dayjs().add(-1, 'month') },
|
||||
{ label: locale.lastYear, value: dayjs().add(-1, 'year') },
|
||||
]
|
||||
}
|
||||
value={dayjs('2022-11-18 14:00:00')}
|
||||
/>
|
||||
),
|
||||
@ -149,7 +169,7 @@ export default function ComponentsList() {
|
||||
<Tour._InternalPanelDoNotUseOrYouWillBeFired
|
||||
title="Ant Design 5.0"
|
||||
description={locale.tour}
|
||||
style={{ width: 350 }}
|
||||
style={{ width: isMobile ? 'auto' : 350 }}
|
||||
current={3}
|
||||
total={9}
|
||||
/>
|
||||
@ -211,49 +231,61 @@ export default function ComponentsList() {
|
||||
),
|
||||
},
|
||||
],
|
||||
[],
|
||||
[isMobile],
|
||||
);
|
||||
|
||||
return (
|
||||
const ComponentItem = ({ title, node, type, index }: ComponentItemProps) => {
|
||||
const tagColor = type === 'new' ? 'processing' : 'warning';
|
||||
const tagText = type === 'new' ? locale.new : locale.update;
|
||||
|
||||
return (
|
||||
<div key={index} css={[styles.card, isMobile && styles.mobileCard]}>
|
||||
{/* Decorator */}
|
||||
<div
|
||||
css={styles.cardCircle}
|
||||
style={{
|
||||
right: (index % 2) * -20 - 20,
|
||||
bottom: (index % 3) * -40 - 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Title */}
|
||||
<Space>
|
||||
<Typography.Title level={4} style={{ fontWeight: 'normal', margin: 0 }}>
|
||||
{title}
|
||||
</Typography.Title>
|
||||
<Tag color={tagColor}>{tagText}</Tag>
|
||||
</Space>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: token.paddingLG,
|
||||
flex: 'auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return isMobile ? (
|
||||
<div style={{ margin: '0 16px' }}>
|
||||
<Carousel css={styles.carousel}>
|
||||
{COMPONENTS.map(({ title, node, type }, index) => (
|
||||
<ComponentItem title={title} node={node} type={type} index={index} key={index} />
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ width: '100%', overflow: 'hidden', display: 'flex', justifyContent: 'center' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'stretch', columnGap: token.paddingLG }}>
|
||||
{COMPONENTS.map(({ title, node, type }, index) => {
|
||||
const tagColor = type === 'new' ? 'processing' : 'warning';
|
||||
const tagText = type === 'new' ? locale.new : locale.update;
|
||||
|
||||
return (
|
||||
<div key={index} css={styles.card}>
|
||||
{/* Decorator */}
|
||||
<div
|
||||
css={styles.cardCircle}
|
||||
style={{
|
||||
right: (index % 2) * -20 - 20,
|
||||
bottom: (index % 3) * -40 - 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Title */}
|
||||
<Space>
|
||||
<Typography.Title level={4} style={{ fontWeight: 'normal', margin: 0 }}>
|
||||
{title}
|
||||
</Typography.Title>
|
||||
<Tag color={tagColor}>{tagText}</Tag>
|
||||
</Space>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: token.paddingLG,
|
||||
flex: 'auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{node}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{COMPONENTS.map(({ title, node, type }, index) => (
|
||||
<ComponentItem title={title} node={node} type={type} index={index} key={index} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { Col, Row, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { Link, useLocation } from 'dumi';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import * as utils from '../../../theme/utils';
|
||||
import SiteContext from './SiteContext';
|
||||
|
||||
const SECONDARY_LIST = [
|
||||
{
|
||||
@ -98,6 +99,8 @@ export default function DesignFramework() {
|
||||
const style = useStyle();
|
||||
const { pathname, search } = useLocation();
|
||||
const isZhCN = utils.isZhCN(pathname);
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
const colSpan = isMobile ? 24 : 8;
|
||||
|
||||
const MAINLY_LIST = [
|
||||
{
|
||||
@ -124,7 +127,7 @@ export default function DesignFramework() {
|
||||
const desc = locale[`${key}Desc` as keyof typeof locale];
|
||||
|
||||
return (
|
||||
<Col key={index} span={8}>
|
||||
<Col key={index} span={colSpan}>
|
||||
<Link to={path}>
|
||||
<div css={style.card}>
|
||||
<img alt={title} src={img} />
|
||||
@ -149,7 +152,7 @@ export default function DesignFramework() {
|
||||
const desc = locale[`${key}Desc` as keyof typeof locale];
|
||||
|
||||
return (
|
||||
<Col key={index} span={8}>
|
||||
<Col key={index} span={colSpan}>
|
||||
<a css={style.cardMini} target="_blank" href={url} rel="noreferrer">
|
||||
<img alt={title} src={img} style={{ transform: `scale(${imgScale})` }} />
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { Typography } from 'antd';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import SiteContext from './SiteContext';
|
||||
|
||||
export interface GroupMaskProps {
|
||||
style?: React.CSSProperties;
|
||||
@ -49,6 +51,7 @@ export interface GroupProps {
|
||||
export default function Group(props: GroupProps) {
|
||||
const { id, title, titleColor, description, children, decoration, background, collapse } = props;
|
||||
const { token } = useSiteToken();
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
|
||||
const marginStyle: React.CSSProperties = collapse
|
||||
? {}
|
||||
@ -56,7 +59,7 @@ export default function Group(props: GroupProps) {
|
||||
maxWidth: 1208,
|
||||
marginInline: 'auto',
|
||||
boxSizing: 'border-box',
|
||||
paddingInline: token.marginXXL,
|
||||
paddingInline: isMobile ? token.margin : token.marginXXL,
|
||||
};
|
||||
const childNode = (
|
||||
<>
|
||||
@ -69,11 +72,17 @@ export default function Group(props: GroupProps) {
|
||||
color: titleColor,
|
||||
// Special for the title
|
||||
fontFamily: `AliPuHui, ${token.fontFamily}`,
|
||||
fontSize: isMobile ? token.fontSizeHeading2 : token.fontSizeHeading1,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph style={{ marginBottom: token.marginFarXS, color: titleColor }}>
|
||||
<Typography.Paragraph
|
||||
style={{
|
||||
marginBottom: isMobile ? token.marginXXL : token.marginFarXS,
|
||||
color: titleColor,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
|
11
.dumi/pages/index/components/SiteContext.tsx
Normal file
11
.dumi/pages/index/components/SiteContext.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface SiteContextProps {
|
||||
isMobile: boolean;
|
||||
}
|
||||
|
||||
const SiteContext = React.createContext<SiteContextProps>({
|
||||
isMobile: false,
|
||||
});
|
||||
|
||||
export default SiteContext;
|
119
.dumi/pages/index/components/Theme/MobileCarousel.tsx
Normal file
119
.dumi/pages/index/components/Theme/MobileCarousel.tsx
Normal file
@ -0,0 +1,119 @@
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { Typography, Carousel } from 'antd';
|
||||
import { useCarouselStyle } from '../util';
|
||||
import useSiteToken from '../../../../hooks/useSiteToken';
|
||||
|
||||
const useStyle = () => {
|
||||
const { carousel } = useCarouselStyle();
|
||||
return {
|
||||
carousel,
|
||||
container: css`
|
||||
position: relative;
|
||||
`,
|
||||
title: css`
|
||||
position: absolute;
|
||||
top: 15%;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
||||
const mobileImageConfigList = [
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*KsMrRZaciFcAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: 'rgba(0,0,0,.88)',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3FkqR6XRNgoAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*cSX_RbD3k9wAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*MldsRZeax6EAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xCAmSL0xlZ8AAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*vCfCSbiI_VIAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xCAmSL0xlZ8AAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*BeDBTY9UnXIAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
{
|
||||
imageSrc:
|
||||
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Q63XTbk8YaMAAAAAAAAAAAAADrJ8AQ/original',
|
||||
titleColor: '#fff',
|
||||
},
|
||||
];
|
||||
|
||||
export interface MobileCarouselProps {
|
||||
id?: string;
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function MobileCarousel(props: MobileCarouselProps) {
|
||||
const styles = useStyle();
|
||||
const { id, title, description } = props;
|
||||
const { token } = useSiteToken();
|
||||
const [currentSlider, setCurrentSlider] = useState<number>(0);
|
||||
|
||||
return (
|
||||
<div css={styles.container}>
|
||||
<div css={styles.title}>
|
||||
<Typography.Title
|
||||
id={id}
|
||||
level={1}
|
||||
style={{
|
||||
fontWeight: 900,
|
||||
color: mobileImageConfigList[currentSlider].titleColor,
|
||||
// Special for the title
|
||||
fontFamily: `AliPuHui, ${token.fontFamily}`,
|
||||
fontSize: token.fontSizeHeading2,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph
|
||||
style={{
|
||||
marginBottom: token.marginXXL,
|
||||
color: mobileImageConfigList[currentSlider].titleColor,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
<Carousel css={styles.carousel} afterChange={setCurrentSlider}>
|
||||
{mobileImageConfigList.map((item, index) => (
|
||||
<div key={index}>
|
||||
<img src={item.imageSrc} alt="" style={{ width: '100%' }} />
|
||||
</div>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -30,6 +30,9 @@ import RadiusPicker from './RadiusPicker';
|
||||
import Group from '../Group';
|
||||
import BackgroundImage from './BackgroundImage';
|
||||
import { DEFAULT_COLOR, getAvatarURL, getClosetColor, PINK_COLOR } from './colorUtil';
|
||||
import SiteContext from '../SiteContext';
|
||||
import { useCarouselStyle } from '../util';
|
||||
import MobileCarousel from './MobileCarousel';
|
||||
|
||||
const { Header, Content, Sider } = Layout;
|
||||
|
||||
@ -81,6 +84,7 @@ const locales = {
|
||||
// ============================= Style =============================
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const { carousel } = useCarouselStyle();
|
||||
|
||||
return {
|
||||
demo: css`
|
||||
@ -177,6 +181,7 @@ const useStyle = () => {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
`,
|
||||
carousel,
|
||||
};
|
||||
};
|
||||
|
||||
@ -278,6 +283,7 @@ export default function Theme() {
|
||||
const { compact, themeType, ...themeToken } = themeData;
|
||||
const isLight = themeType !== 'dark';
|
||||
const [form] = Form.useForm();
|
||||
const { isMobile } = React.useContext(SiteContext);
|
||||
|
||||
// const algorithmFn = isLight ? theme.defaultAlgorithm : theme.darkAlgorithm;
|
||||
const algorithmFn = React.useMemo(() => {
|
||||
@ -487,8 +493,22 @@ export default function Theme() {
|
||||
const posStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
};
|
||||
const leftTopImageStyle = {
|
||||
left: '50%',
|
||||
transform: 'translate3d(-900px, 0, 0)',
|
||||
top: -100,
|
||||
height: 500,
|
||||
};
|
||||
const rightBottomImageStyle = {
|
||||
right: '50%',
|
||||
transform: 'translate3d(750px, 0, 0)',
|
||||
bottom: -100,
|
||||
height: 287,
|
||||
};
|
||||
|
||||
return (
|
||||
return isMobile ? (
|
||||
<MobileCarousel title={locale.themeTitle} description={locale.themeDesc} id="flexible" />
|
||||
) : (
|
||||
<Group
|
||||
title={locale.themeTitle}
|
||||
titleColor={getTitleColor(themeData.colorPrimary, isLight)}
|
||||
@ -509,10 +529,7 @@ export default function Theme() {
|
||||
<img
|
||||
style={{
|
||||
...posStyle,
|
||||
left: '50%',
|
||||
transform: 'translate3d(-900px, 0, 0)',
|
||||
top: -100,
|
||||
height: 500,
|
||||
...leftTopImageStyle,
|
||||
}}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/bd71b0c6-f93a-4e52-9c8a-f01a9b8fe22b.svg"
|
||||
alt=""
|
||||
@ -521,10 +538,7 @@ export default function Theme() {
|
||||
<img
|
||||
style={{
|
||||
...posStyle,
|
||||
right: '50%',
|
||||
transform: 'translate3d(750px, 0, 0)',
|
||||
bottom: -100,
|
||||
height: 287,
|
||||
...rightBottomImageStyle,
|
||||
}}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/84ad805a-74cb-4916-b7ba-9cdc2bdec23a.svg"
|
||||
alt=""
|
||||
|
BIN
.dumi/pages/index/components/images/topic.png
Normal file
BIN
.dumi/pages/index/components/images/topic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 196 KiB |
@ -1,5 +1,6 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import * as React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
export interface Author {
|
||||
avatar: string;
|
||||
@ -98,3 +99,28 @@ export function useSiteData(): [Partial<SiteData>, boolean] {
|
||||
|
||||
return [data, loading];
|
||||
}
|
||||
|
||||
export const useCarouselStyle = () => ({
|
||||
carousel: css`
|
||||
.slick-dots.slick-dots-bottom {
|
||||
bottom: -22px;
|
||||
li {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #e1eeff;
|
||||
border-radius: 50%;
|
||||
button {
|
||||
height: 6px;
|
||||
background: #e1eeff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&.slick-active {
|
||||
background: #4b9cff;
|
||||
button {
|
||||
background: #4b9cff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { useLocale as useDumiLocale } from 'dumi';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import useLocale from '../../hooks/useLocale';
|
||||
@ -9,6 +9,7 @@ import Theme from './components/Theme';
|
||||
import BannerRecommends from './components/BannerRecommends';
|
||||
import ComponentsList from './components/ComponentsList';
|
||||
import DesignFramework from './components/DesignFramework';
|
||||
import SiteContext from './components/SiteContext';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
@ -33,44 +34,61 @@ const Homepage: React.FC = () => {
|
||||
const localeStr = localeId === 'zh-CN' ? 'cn' : 'en';
|
||||
|
||||
const [siteData] = useSiteData();
|
||||
const [isMobile, setIsMobile] = React.useState<boolean>(false);
|
||||
|
||||
const updateMobileMode = () => {
|
||||
setIsMobile(window.innerWidth < 768);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateMobileMode();
|
||||
window.addEventListener('resize', updateMobileMode);
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateMobileMode);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const siteValue = useMemo(() => ({ isMobile }), [isMobile]);
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={{ algorithm: undefined }}>
|
||||
<section>
|
||||
<Banner>
|
||||
<BannerRecommends extras={siteData?.extras?.[localeStr]} icons={siteData?.icons} />
|
||||
</Banner>
|
||||
<SiteContext.Provider value={siteValue}>
|
||||
<section>
|
||||
<Banner>
|
||||
<BannerRecommends extras={siteData?.extras?.[localeStr]} icons={siteData?.icons} />
|
||||
</Banner>
|
||||
|
||||
<div>
|
||||
<Theme />
|
||||
<Group
|
||||
background="#fff"
|
||||
collapse
|
||||
title={locale.assetsTitle}
|
||||
description={locale.assetsDesc}
|
||||
id="design"
|
||||
>
|
||||
<ComponentsList />
|
||||
</Group>
|
||||
<Group
|
||||
title={locale.designTitle}
|
||||
description={locale.designDesc}
|
||||
background="#F5F8FF"
|
||||
decoration={
|
||||
<>
|
||||
{/* Image Left Top */}
|
||||
<img
|
||||
style={{ position: 'absolute', left: 0, top: -50, height: 160 }}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
|
||||
alt=""
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<DesignFramework />
|
||||
</Group>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<Theme />
|
||||
<Group
|
||||
background="#fff"
|
||||
collapse
|
||||
title={locale.assetsTitle}
|
||||
description={locale.assetsDesc}
|
||||
id="design"
|
||||
>
|
||||
<ComponentsList />
|
||||
</Group>
|
||||
<Group
|
||||
title={locale.designTitle}
|
||||
description={locale.designDesc}
|
||||
background="#F5F8FF"
|
||||
decoration={
|
||||
<>
|
||||
{/* Image Left Top */}
|
||||
<img
|
||||
style={{ position: 'absolute', left: 0, top: -50, height: 160 }}
|
||||
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
|
||||
alt=""
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<DesignFramework />
|
||||
</Group>
|
||||
</div>
|
||||
</section>
|
||||
</SiteContext.Provider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import RcFooter from 'rc-footer';
|
||||
import { Link, FormattedMessage } from 'dumi';
|
||||
import type { FooterColumn } from 'rc-footer/lib/column';
|
||||
@ -23,6 +23,7 @@ import useLocation from '../../../hooks/useLocation';
|
||||
import useLocale from '../../../hooks/useLocale';
|
||||
import useSiteToken from '../../../hooks/useSiteToken';
|
||||
import AdditionalInfo from './AdditionalInfo';
|
||||
import SiteContext from '../SiteContext';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
@ -35,6 +36,7 @@ const locales = {
|
||||
|
||||
const useStyle = () => {
|
||||
const { token } = useSiteToken();
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
const background = new TinyColor(getAlphaColor('#f0f3fa', '#fff'))
|
||||
.onBackground(token.colorBgContainer)
|
||||
.toHexString();
|
||||
@ -59,7 +61,10 @@ const useStyle = () => {
|
||||
}
|
||||
|
||||
.rc-footer-column {
|
||||
margin-bottom: 0;
|
||||
margin-bottom: ${isMobile ? 60 : 0}px;
|
||||
:last-child {
|
||||
margin-bottom: ${isMobile ? 20 : 0}px;
|
||||
}
|
||||
}
|
||||
|
||||
.rc-footer-container {
|
||||
@ -69,8 +74,10 @@ const useStyle = () => {
|
||||
}
|
||||
|
||||
.rc-footer-bottom {
|
||||
font-size: ${token.fontSize}px;
|
||||
box-shadow: inset 0 106px 36px -116px rgba(0, 0, 0, 0.14);
|
||||
.rc-footer-bottom-container {
|
||||
font-size: ${token.fontSize}px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
@ -369,7 +376,10 @@ const Footer = () => {
|
||||
css={style.footer}
|
||||
bottom={
|
||||
<>
|
||||
Made with <span style={{ color: '#fff' }}>❤</span> by {locale.owner}
|
||||
<div style={{ opacity: '0.4' }}>
|
||||
Made with <span style={{ color: '#fff' }}>❤</span> by
|
||||
</div>
|
||||
<div>{locale.owner}</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
@ -116,6 +116,7 @@
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@ctrl/tinycolor": "^3.4.0",
|
||||
"@rc-component/tour": "~1.0.1-2",
|
||||
"antd-token-previewer": "^1.1.0-21",
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"dayjs": "^1.11.1",
|
||||
@ -193,7 +194,6 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"antd-img-crop": "^4.2.8",
|
||||
"antd-token-previewer": "^1.1.0-6",
|
||||
"array-move": "^4.0.0",
|
||||
"bundlesize2": "^0.0.31",
|
||||
"chalk": "^4.0.0",
|
||||
|
Loading…
Reference in New Issue
Block a user