mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 11:08:45 +08:00
Merge branch 'master' into feature-merge-master
This commit is contained in:
commit
9b99c815fa
@ -1,5 +1,5 @@
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import Comment from '../index';
|
||||
@ -9,7 +9,7 @@ describe('Comment', () => {
|
||||
rtlTest(Comment);
|
||||
|
||||
it('should support empty actions', () => {
|
||||
const wrapper = mount(
|
||||
const wrapper = render(
|
||||
<Comment
|
||||
actions={[]}
|
||||
author={<a>Han Solo</a>}
|
||||
@ -23,6 +23,6 @@ describe('Comment', () => {
|
||||
datetime="YYYY-MM-DD HH:mm:ss"
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(wrapper.container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -43,6 +43,7 @@ import Spin from '../../spin';
|
||||
import Statistic from '../../statistic';
|
||||
import Steps from '../../steps';
|
||||
import Switch from '../../switch';
|
||||
import type { ColumnsType } from '../../table';
|
||||
import Table from '../../table';
|
||||
import Tabs from '../../tabs';
|
||||
import Tag from '../../tag';
|
||||
@ -59,7 +60,7 @@ jest.mock('rc-util/lib/Portal');
|
||||
|
||||
describe('ConfigProvider', () => {
|
||||
describe('components', () => {
|
||||
function testPair(name, renderComponent) {
|
||||
function testPair(name: string, renderComponent: (props?: any) => React.ReactElement): void {
|
||||
const isArray = ['Menu', 'TimePicker', 'Tooltip'].includes(name);
|
||||
describe(`${name}`, () => {
|
||||
// normal
|
||||
@ -303,8 +304,8 @@ describe('ConfigProvider', () => {
|
||||
|
||||
// Grid
|
||||
testPair('Grid', props => {
|
||||
const rowProps = {};
|
||||
const colProps = {};
|
||||
const rowProps: { prefixCls?: string } = {};
|
||||
const colProps: { prefixCls?: string } = {};
|
||||
if (props.prefixCls) {
|
||||
rowProps.prefixCls = 'prefix-row';
|
||||
colProps.prefixCls = 'prefix-col';
|
||||
@ -334,10 +335,10 @@ describe('ConfigProvider', () => {
|
||||
|
||||
// Layout
|
||||
testPair('Layout', props => {
|
||||
const siderProps = {};
|
||||
const headerProps = {};
|
||||
const contentProps = {};
|
||||
const footerProps = {};
|
||||
const siderProps: { prefixCls?: string } = {};
|
||||
const headerProps: { prefixCls?: string } = {};
|
||||
const contentProps: { prefixCls?: string } = {};
|
||||
const footerProps: { prefixCls?: string } = {};
|
||||
if (props.prefixCls) {
|
||||
siderProps.prefixCls = 'prefix-sider';
|
||||
headerProps.prefixCls = 'prefix-header';
|
||||
@ -499,7 +500,7 @@ describe('ConfigProvider', () => {
|
||||
|
||||
// Table
|
||||
testPair('Table', props => {
|
||||
const columns = [
|
||||
const columns: ColumnsType<any> = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,9 @@
|
||||
import { mount } from 'enzyme';
|
||||
import React, { memo, useContext, useRef, useState } from 'react';
|
||||
import { render, fireEvent } from '../../../tests/utils';
|
||||
import LocaleProvider, { ANT_MARK } from '..';
|
||||
import LocaleContext from '../context';
|
||||
|
||||
const defaultLocale = {
|
||||
locale: 'locale',
|
||||
};
|
||||
const defaultLocale = { locale: 'locale' };
|
||||
// we use'memo' here in order to only render inner component while context changed.
|
||||
const CacheInner = memo(() => {
|
||||
const countRef = useRef(0);
|
||||
@ -19,7 +17,7 @@ const CacheInner = memo(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const CacheOuter = () => {
|
||||
const CacheOuter: React.FC = () => {
|
||||
// We use 'useState' here in order to trigger parent component rendering.
|
||||
const [count, setCount] = useState(1);
|
||||
const handleClick = () => {
|
||||
@ -41,13 +39,13 @@ const CacheOuter = () => {
|
||||
};
|
||||
|
||||
it("Rendering on LocaleProvider won't trigger rendering on child component.", () => {
|
||||
const wrapper = mount(<CacheOuter />);
|
||||
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||
expect(wrapper.find('#parent_count').text()).toBe('2');
|
||||
const { container } = render(<CacheOuter />);
|
||||
fireEvent.click(container.querySelector('#parent_btn')!);
|
||||
expect(container.querySelector('#parent_count')?.innerHTML).toBe('2');
|
||||
// child component won't rerender
|
||||
expect(wrapper.find('#child_count').text()).toBe('1');
|
||||
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||
expect(wrapper.find('#parent_count').text()).toBe('3');
|
||||
expect(container.querySelector('#child_count')?.innerHTML).toBe('1');
|
||||
fireEvent.click(container.querySelector('#parent_btn')!);
|
||||
expect(container.querySelector('#parent_count')?.innerHTML).toBe('3');
|
||||
// child component won't rerender
|
||||
expect(wrapper.find('#child_count').text()).toBe('1');
|
||||
expect(container.querySelector('#child_count')?.innerHTML).toBe('1');
|
||||
});
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Modal } from '../..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import { sleep, render, fireEvent } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import zhCN from '../zh_CN';
|
||||
|
||||
class Demo extends React.Component {
|
||||
class Demo extends React.Component<{ type: string }> {
|
||||
static defaultProps = {};
|
||||
|
||||
componentDidMount() {
|
||||
@ -24,8 +23,8 @@ describe('Locale Provider demo', () => {
|
||||
it('change type', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const BasicExample = () => {
|
||||
const [type, setType] = React.useState('');
|
||||
const BasicExample: React.FC = () => {
|
||||
const [type, setType] = React.useState<string>('');
|
||||
return (
|
||||
<div>
|
||||
<a className="about" onClick={() => setType('about')}>
|
||||
@ -49,21 +48,21 @@ describe('Locale Provider demo', () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const wrapper = mount(<BasicExample />);
|
||||
const { container } = render(<BasicExample />);
|
||||
|
||||
wrapper.find('.about').at(0).simulate('click');
|
||||
fireEvent.click(container.querySelector('.about')!);
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
wrapper.find('.dashboard').at(0).simulate('click');
|
||||
fireEvent.click(container.querySelector('.dashboard')!);
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(document.body.querySelectorAll('.ant-btn-primary span')[0].textContent).toBe('确 定');
|
||||
expect(document.body.querySelectorAll('.ant-btn-primary span')[0]?.textContent).toBe('确 定');
|
||||
Modal.destroyAll();
|
||||
jest.useRealTimers();
|
||||
});
|
@ -1,8 +1,9 @@
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
import { mount } from 'enzyme';
|
||||
import MockDate from 'mockdate';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import type { Locale } from '..';
|
||||
import LocaleProvider from '..';
|
||||
import {
|
||||
Calendar,
|
||||
@ -16,7 +17,6 @@ import {
|
||||
Transfer,
|
||||
} from '../..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import { act } from '../../../tests/utils';
|
||||
import arEG from '../ar_EG';
|
||||
import azAZ from '../az_AZ';
|
||||
import bgBG from '../bg_BG';
|
||||
@ -162,20 +162,12 @@ const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
filters: [
|
||||
{
|
||||
text: 'filter1',
|
||||
value: 'filter1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
filters: [{ text: 'filter1', value: 'filter1' }],
|
||||
},
|
||||
{ title: 'Age', dataIndex: 'age' },
|
||||
];
|
||||
|
||||
const App = () => (
|
||||
const App: React.FC = () => (
|
||||
<div>
|
||||
<Pagination defaultCurrent={1} total={50} showSizeChanger />
|
||||
<Select showSearch style={{ width: 200 }}>
|
||||
@ -188,7 +180,7 @@ const App = () => (
|
||||
<Popconfirm title="Question?" visible>
|
||||
<a>Click to confirm</a>
|
||||
</Popconfirm>
|
||||
<Transfer dataSource={[]} showSearch targetKeys={[]} render={item => item.title} />
|
||||
<Transfer dataSource={[]} showSearch targetKeys={[]} render={(item: any) => item.title} />
|
||||
<Calendar fullscreen={false} value={moment()} />
|
||||
<Table dataSource={[]} columns={columns} />
|
||||
<Modal title="Locale Modal" open getContainer={false}>
|
||||
@ -214,57 +206,37 @@ describe('Locale Provider', () => {
|
||||
|
||||
locales.forEach(locale => {
|
||||
it(`should display the text as ${locale.locale}`, () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<LocaleProvider locale={locale}>
|
||||
<App />
|
||||
</LocaleProvider>,
|
||||
);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('should change locale of Modal.xxx', () => {
|
||||
class ModalDemo extends React.Component {
|
||||
componentDidMount() {
|
||||
jest.useFakeTimers();
|
||||
Modal.confirm({
|
||||
title: 'Hello World!',
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
jest.useRealTimers();
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
locales.forEach(locale => {
|
||||
mount(
|
||||
const { container } = render(
|
||||
<LocaleProvider locale={locale}>
|
||||
<ModalDemo />
|
||||
<Modal title="Locale Modal" visible getContainer={false}>
|
||||
Modal
|
||||
</Modal>
|
||||
</LocaleProvider>,
|
||||
);
|
||||
const currentConfirmNode =
|
||||
document.querySelectorAll('.ant-modal-confirm')[
|
||||
document.querySelectorAll('.ant-modal-confirm').length - 1
|
||||
];
|
||||
let cancelButtonText = currentConfirmNode.querySelectorAll(
|
||||
'.ant-btn:not(.ant-btn-primary) span',
|
||||
)[0].innerHTML;
|
||||
let okButtonText = currentConfirmNode.querySelectorAll('.ant-btn-primary span')[0].innerHTML;
|
||||
if (locale.locale.indexOf('zh-') === 0) {
|
||||
cancelButtonText = cancelButtonText.replace(' ', '');
|
||||
okButtonText = okButtonText.replace(' ', '');
|
||||
let cancelButtonText = container?.querySelector('button.ant-btn-default span')?.innerHTML;
|
||||
let okButtonText = container?.querySelector('button.ant-btn-primary span')?.innerHTML;
|
||||
if (locale.locale.includes('zh-')) {
|
||||
cancelButtonText = cancelButtonText?.replace(' ', '');
|
||||
okButtonText = okButtonText?.replace(' ', '');
|
||||
}
|
||||
expect(cancelButtonText).toBe(locale.Modal.cancelText);
|
||||
expect(okButtonText).toBe(locale.Modal.okText);
|
||||
expect(cancelButtonText).toBe(locale.Modal?.cancelText);
|
||||
expect(okButtonText).toBe(locale.Modal?.okText);
|
||||
});
|
||||
});
|
||||
|
||||
it('set moment locale when locale changes', () => {
|
||||
const Test = ({ locale }) => (
|
||||
const Test: React.FC<{ locale?: Locale }> = ({ locale }) => (
|
||||
<LocaleProvider locale={locale}>
|
||||
<div>
|
||||
<DatePicker defaultValue={moment()} open />
|
||||
@ -272,11 +244,13 @@ describe('Locale Provider', () => {
|
||||
</LocaleProvider>
|
||||
);
|
||||
|
||||
const wrapper = mount(<Test locale={zhCN} />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
wrapper.setProps({ locale: frFR });
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
wrapper.setProps({ locale: null });
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
const { container, rerender } = render(<Test locale={zhCN} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
|
||||
rerender(<Test locale={frFR} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
|
||||
rerender(<Test />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -10,24 +10,24 @@ import MenuDivider from '../MenuDivider';
|
||||
import MenuItem from '../MenuItem';
|
||||
import SubMenu from '../SubMenu';
|
||||
|
||||
interface MenuItemType extends RcMenuItemType {
|
||||
export interface MenuItemType extends RcMenuItemType {
|
||||
danger?: boolean;
|
||||
icon?: React.ReactNode;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface SubMenuType extends Omit<RcSubMenuType, 'children'> {
|
||||
export interface SubMenuType extends Omit<RcSubMenuType, 'children'> {
|
||||
icon?: React.ReactNode;
|
||||
theme?: 'dark' | 'light';
|
||||
children: ItemType[];
|
||||
}
|
||||
|
||||
interface MenuItemGroupType extends Omit<RcMenuItemGroupType, 'children'> {
|
||||
export interface MenuItemGroupType extends Omit<RcMenuItemGroupType, 'children'> {
|
||||
children?: ItemType[];
|
||||
key?: React.Key;
|
||||
}
|
||||
|
||||
interface MenuDividerType extends RcMenuDividerType {
|
||||
export interface MenuDividerType extends RcMenuDividerType {
|
||||
dashed?: boolean;
|
||||
key?: React.Key;
|
||||
}
|
||||
|
@ -231,7 +231,6 @@ exports[`TreeSelect TreeSelect Custom Icons should support customized icons 1`]
|
||||
aria-hidden="true"
|
||||
class="ant-select-selection-search-mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
@ -1,5 +1,5 @@
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { render } from '../../../tests/utils';
|
||||
import TreeSelect, { TreeNode } from '..';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
@ -12,7 +12,7 @@ describe('TreeSelect', () => {
|
||||
|
||||
describe('TreeSelect Custom Icons', () => {
|
||||
it('should support customized icons', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<TreeSelect
|
||||
showSearch
|
||||
clearIcon={<span>clear</span>}
|
||||
@ -32,23 +32,24 @@ describe('TreeSelect', () => {
|
||||
</TreeSelect>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should `treeIcon` work', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<TreeSelect treeIcon open>
|
||||
<TreeNode value="parent 1" title="parent 1" icon={<span>Bamboo</span>} />
|
||||
</TreeSelect>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support notFoundContent', () => {
|
||||
const wrapper = mount(<TreeSelect treeIcon open notFoundContent="notFoundContent" />);
|
||||
expect(wrapper.text()).toBe('notFoundContent');
|
||||
const content = 'notFoundContent';
|
||||
const { container } = render(<TreeSelect treeIcon open notFoundContent={content} />);
|
||||
expect(container.querySelector('.ant-select-empty')?.innerHTML).toBe(content);
|
||||
});
|
||||
|
||||
it('should show warning when use dropdownClassName', () => {
|
@ -18,34 +18,42 @@ Please find below some of the design resources and tools about Ant Design that w
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
|
||||
- Sketch Symbols for Desktop
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/a5ff1d86-44cd-4b86-92f8-daab59cba5b7.sketch
|
||||
- Official
|
||||
- Sketch Symbols (Dark)
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
|
||||
- Sketch Symbols for Desktop with dark theme
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/6b670a1c-26e3-4379-9c86-7a2b95e170e5.sketch
|
||||
- Official
|
||||
- Mobile Components
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
|
||||
- Sketch Symbols File for Mobile
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/d6266aef-25b7-4892-b275-ce214121831c.sketch
|
||||
- Official
|
||||
- Ant Design Pro
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg
|
||||
- Common Templates and Pages
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/22208f9d-f8c5-4d7c-b87a-fec290e96527.sketch
|
||||
- Official
|
||||
- Ant Design Library
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg
|
||||
- A powerful Axure library
|
||||
- http://library.ant.design
|
||||
- Official
|
||||
- Kitchen
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg
|
||||
- A Sketch plugin collection
|
||||
- http://kitchen.alipay.com
|
||||
- Official
|
||||
- Ant Design Landing
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg
|
||||
- Landing Templates
|
||||
- https://landing.ant.design/docs/download-cn
|
||||
- Official
|
||||
- Ant UX
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg
|
||||
- A set of page logic prototype libraries
|
||||
- http://ux.ant.design
|
||||
- Official
|
||||
- Ant Design Prototype (xiaopiu)
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg
|
||||
- Online library and prototype
|
||||
@ -66,6 +74,7 @@ Please find below some of the design resources and tools about Ant Design that w
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg
|
||||
- Sketch Symbols for Chart
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/704968a5-2641-484e-9f65-c2735b2c0287.sketch
|
||||
- Official
|
||||
- MockingBot
|
||||
- https://cdn.modao.cc/logo_mockingbot.svg
|
||||
- Rich component resources
|
||||
|
@ -18,34 +18,42 @@ toc: false
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
|
||||
- 桌面组件 Sketch 模板包
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/82c08c51-9993-4568-90c1-249c8301c0af.sketch
|
||||
- 官方
|
||||
- Sketch 组件包 (暗色)
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
|
||||
- 桌面组件 Sketch 模板包,内含暗色版本的 antd 组件
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/f002145c-33d9-408e-ba75-a1a68896dfa3.sketch
|
||||
- 官方
|
||||
- Mobile Components
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
|
||||
- 移动组件 Sketch 模板
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/d6266aef-25b7-4892-b275-ce214121831c.sketch
|
||||
- 官方
|
||||
- Ant Design Pro
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg
|
||||
- 典型页面 + 通用业务模板
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/22208f9d-f8c5-4d7c-b87a-fec290e96527.sketch
|
||||
- 官方
|
||||
- Ant Design Library
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg
|
||||
- 一套强大的 Axure 部件库
|
||||
- http://library.ant.design
|
||||
- 官方
|
||||
- Kitchen
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg
|
||||
- Sketch 工具集
|
||||
- http://kitchen.alipay.com
|
||||
- 官方
|
||||
- Ant Design Landing
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg
|
||||
- 首页模板集
|
||||
- https://landing.ant.design/docs/download-cn
|
||||
- 官方
|
||||
- Ant UX
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg
|
||||
- 一套页面逻辑原型库
|
||||
- http://ux.ant.design
|
||||
- 官方
|
||||
- Ant Design 原型 (xiaopiu)
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg
|
||||
- 可在线编辑的组件库和交互原型
|
||||
@ -62,6 +70,7 @@ toc: false
|
||||
- https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg
|
||||
- 桌面组件 Chart 模板包
|
||||
- https://gw.alipayobjects.com/os/bmw-prod/704968a5-2641-484e-9f65-c2735b2c0287.sketch
|
||||
- 官方
|
||||
- 墨刀原型设计
|
||||
- https://cdn.modao.cc/logo_mockingbot.svg
|
||||
- 内置丰富的 Ant Design 组件资源
|
||||
|
@ -68,6 +68,7 @@
|
||||
|
||||
.resource-cards {
|
||||
.resource-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
@ -90,6 +91,19 @@
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.resource-card-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
padding: 4px 8px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
border-radius: 1px;
|
||||
box-shadow: 0 0 2px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.resource-card-title {
|
||||
margin: 16px 20px 8px;
|
||||
color: #0d1a26;
|
||||
|
@ -43,7 +43,7 @@ interface ResourcesProps {
|
||||
}
|
||||
|
||||
function getUnitString(unit: ContentUnit[]): string {
|
||||
if (!unit) return '';
|
||||
if (!unit || unit.length <= 1) return '';
|
||||
|
||||
const last = unit[unit.length - 1];
|
||||
return Array.isArray(last) ? getUnitString(last) : (last as string);
|
||||
@ -53,8 +53,9 @@ function toCardList([, ...items]: ContentUnit[]): ContentUnit[] {
|
||||
return [
|
||||
'div',
|
||||
{ className: 'ant-row resource-cards', style: 'margin: -12px -12px 0 -12px' },
|
||||
...items.map(([, title, [, image, description, link]]: any) => {
|
||||
...items.map(([, title, [, image, description, link, badge]]: any) => {
|
||||
let titleStr = getUnitString(title);
|
||||
const badgeStr = getUnitString(badge);
|
||||
const imageStr = getUnitString(image);
|
||||
const descStr = getUnitString(description);
|
||||
const linkStr = getUnitString(link);
|
||||
@ -90,9 +91,17 @@ function toCardList([, ...items]: ContentUnit[]): ContentUnit[] {
|
||||
: {},
|
||||
},
|
||||
],
|
||||
badgeStr &&
|
||||
badgeStr !== '-' && [
|
||||
'div',
|
||||
{
|
||||
className: 'resource-card-badge',
|
||||
},
|
||||
badgeStr,
|
||||
],
|
||||
['p', { className: 'resource-card-title' }, titleStr],
|
||||
['p', { className: 'resource-card-description' }, descStr],
|
||||
],
|
||||
].filter(c => c),
|
||||
];
|
||||
}),
|
||||
];
|
||||
@ -123,9 +132,10 @@ const Resources = (props: ResourcesProps) => {
|
||||
const { localizedPageData, location } = props;
|
||||
const { locale } = useIntl();
|
||||
|
||||
const content = React.useMemo(() => injectCards(localizedPageData.content), [
|
||||
localizedPageData.content,
|
||||
]);
|
||||
const content = React.useMemo(
|
||||
() => injectCards(localizedPageData.content),
|
||||
[localizedPageData.content],
|
||||
);
|
||||
|
||||
return (
|
||||
<div id="resources-page">
|
||||
|
Loading…
Reference in New Issue
Block a user