diff --git a/docs/demo/simple.md b/docs/demo/simple.md
new file mode 100644
index 0000000..efaf04c
--- /dev/null
+++ b/docs/demo/simple.md
@@ -0,0 +1,3 @@
+## simple
+
+
diff --git a/docs/demo/theme.md b/docs/demo/theme.md
new file mode 100644
index 0000000..173386b
--- /dev/null
+++ b/docs/demo/theme.md
@@ -0,0 +1,3 @@
+## theme
+
+
diff --git a/docs/examples/rows.tsx b/docs/examples/rows.tsx
new file mode 100644
index 0000000..3dbf583
--- /dev/null
+++ b/docs/examples/rows.tsx
@@ -0,0 +1,206 @@
+import '../../assets/index.less';
+import React from 'react';
+import Footer from 'rc-footer';
+
+export default function App() {
+ return (
+
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ ],
+ },
+ {
+ title: '相关资源',
+ items: [
+ {
+ title: 'Ant Design Pro',
+ url: 'https://pro.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Ant Design Mobile',
+ url: 'https://mobile.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Kitchen',
+ url: 'https://kitchen.alipay.com/',
+ description: 'Sketch 工具集',
+ },
+ ],
+ },
+ {
+ title: '社区',
+ items: [
+ {
+ title: 'Ant Design Pro',
+ url: 'https://pro.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Ant Design Mobile',
+ url: 'https://mobile.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Kitchen',
+ url: 'https://kitchen.alipay.com/',
+ description: 'Sketch 工具集',
+ },
+ ],
+ },
+ {
+ title: '帮助',
+ items: [
+ {
+ title: 'Ant Design Pro',
+ url: 'https://pro.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Ant Design Mobile',
+ url: 'https://mobile.ant.design/',
+ openExternal: true,
+ },
+ {
+ title: 'Kitchen',
+ url: 'https://kitchen.alipay.com/',
+ description: 'Sketch 工具集',
+ },
+ ],
+ },
+ {
+ icon: (
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ ],
+ },
+ ]}
+ bottom="Made with ❤️ by AFX"
+ />
+
+ );
+}
diff --git a/docs/examples/simple.tsx b/docs/examples/simple.tsx
new file mode 100644
index 0000000..3843c9f
--- /dev/null
+++ b/docs/examples/simple.tsx
@@ -0,0 +1,110 @@
+import '../../assets/index.less';
+import React from 'react';
+import Footer from 'rc-footer';
+
+export default function App() {
+ return (
+
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ ],
+ },
+ ]}
+ bottom="Made with ❤️ by AFX"
+ />
+
+ );
+}
diff --git a/docs/examples/theme.tsx b/docs/examples/theme.tsx
new file mode 100644
index 0000000..b9bee23
--- /dev/null
+++ b/docs/examples/theme.tsx
@@ -0,0 +1,124 @@
+import '../../assets/index.less';
+import React, { useState } from 'react';
+import Footer from 'rc-footer';
+
+export default function App() {
+ const [theme, setTheme] = useState('light');
+ return (
+
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ {
+ title: (
+
+ ),
+ },
+ ],
+ },
+ ]}
+ bottom="Made with ❤️ by AFX"
+ />
+
+ );
+}
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..9d31e3a
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,5 @@
+---
+title: rc-footer
+---
+
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..fd4d7e5
--- /dev/null
+++ b/index.js
@@ -0,0 +1 @@
+module.exports = require('./src/');
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 0000000..66a2c87
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ snapshotSerializers: [require.resolve('enzyme-to-json/serializer')],
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..39f8373
--- /dev/null
+++ b/package.json
@@ -0,0 +1,88 @@
+{
+ "name": "rc-footer",
+ "version": "0.6.6",
+ "description": "Pretty Footer react component used in ant.design",
+ "keywords": [
+ "react",
+ "react-component",
+ "react-footer",
+ "footer",
+ "antd",
+ "ant-design"
+ ],
+ "main": "./lib/index",
+ "module": "./es/index",
+ "files": [
+ "assets/*.css",
+ "assets/*.less",
+ "es",
+ "lib",
+ "dist"
+ ],
+ "homepage": "https://react-component.github.io/footer",
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:react-component/footer.git"
+ },
+ "bugs": {
+ "url": "http://github.com/react-component/footer/issues"
+ },
+ "license": "MIT",
+ "scripts": {
+ "start": "dumi dev",
+ "docs:build": "dumi build",
+ "docs:deploy": "gh-pages -d .doc",
+ "compile": "father build && lessc assets/index.less assets/index.css",
+ "gh-pages": "npm run docs:build && father doc deploy",
+ "prepublishOnly": "npm run compile && np --yolo --no-publish && npm run gh-pages",
+ "lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md",
+ "prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
+ "pretty-quick": "pretty-quick",
+ "test": "father test",
+ "coverage": "father test --coverage"
+ },
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1"
+ },
+ "devDependencies": {
+ "@types/classnames": "^2.2.9",
+ "@types/react": "^17.0.13",
+ "@types/react-dom": "^16.9.0",
+ "@umijs/fabric": "^2.0.8",
+ "coveralls": "^3.0.6",
+ "cross-env": "^7.0.2",
+ "dumi": "^1.1.0",
+ "enzyme": "^3.0.0",
+ "enzyme-adapter-react-16": "^1.0.1",
+ "enzyme-to-json": "^3.4.0",
+ "eslint": "^7.0.0",
+ "father": "^2.13.4",
+ "father-build": "^1.18.6",
+ "gh-pages": "^3.1.0",
+ "husky": "^4.2.5",
+ "less": "^3.10.3",
+ "np": "^7.0.0",
+ "prettier": "^2.0.5",
+ "pretty-quick": "^3.0.0",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
+ "react-test-renderer": "^16.0.0",
+ "typescript": "^4.0.5"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "pretty-quick --staged"
+ }
+ },
+ "cnpm": {
+ "mode": "npm"
+ },
+ "tnpm": {
+ "mode": "npm"
+ }
+}
diff --git a/src/column.tsx b/src/column.tsx
new file mode 100644
index 0000000..b6cc7bf
--- /dev/null
+++ b/src/column.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+import classNames from 'classnames';
+
+export interface FooterColumnItem {
+ title: React.ReactNode;
+ url?: string;
+ openExternal?: boolean;
+ icon?: React.ReactNode;
+ description?: React.ReactNode;
+ className?: string;
+ style?: React.CSSProperties;
+ LinkComponent?: React.ReactType;
+}
+
+export interface FooterColumn {
+ prefixCls?: string;
+ title?: React.ReactNode;
+ icon?: React.ReactNode;
+ items?: FooterColumnItem[];
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+const Column: React.FC = ({
+ prefixCls,
+ icon,
+ title,
+ items = [],
+ style,
+ className,
+}) => (
+
+ {(title || icon) && (
+
+ {icon && {icon}}
+ {title}
+
+ )}
+ {items.map((item, i) => {
+ const LinkComponent = item.LinkComponent || 'a';
+ return (
+
+
+ {item.icon && (
+ {item.icon}
+ )}
+ {item.title}
+
+ {item.description && (
+ <>
+ -
+
+ {item.description}
+
+ >
+ )}
+
+ );
+ })}
+
+);
+
+export default Column;
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..ee1e737
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import classNames from 'classnames';
+import Column, { FooterColumn } from './column';
+
+export interface FooterProps {
+ prefixCls?: string;
+ bottom?: React.ReactNode;
+ maxColumnsPerRow?: number;
+ columns?: FooterColumn[];
+ theme?: 'dark' | 'light';
+ className?: string;
+ style?: React.CSSProperties;
+ backgroundColor?: string;
+ columnLayout?: 'space-around' | 'space-between';
+}
+
+const Footer: React.FC = ({
+ prefixCls = 'rc-footer',
+ className,
+ style,
+ bottom,
+ columns,
+ maxColumnsPerRow,
+ backgroundColor,
+ columnLayout,
+ theme = 'dark',
+ ...restProps
+}) => {
+ const footerClassName = classNames(`${prefixCls}`, className, {
+ [`${prefixCls}-${theme}`]: !!theme,
+ });
+ const shouldWrap =
+ typeof maxColumnsPerRow === 'number' && maxColumnsPerRow > 0;
+ return (
+
+ );
+};
+
+export default Footer;
diff --git a/tests/__snapshots__/index.spec.js.snap b/tests/__snapshots__/index.spec.js.snap
new file mode 100644
index 0000000..a203e1f
--- /dev/null
+++ b/tests/__snapshots__/index.spec.js.snap
@@ -0,0 +1,562 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`rc-footer render Footer 1`] = `
+
+`;
+
+exports[`rc-footer render Footer with columnLayout and backgroundColor 1`] = `
+
+`;
+
+exports[`rc-footer render Footer with maxColumnsPerRow 1`] = `
+
+`;
+
+exports[`rc-footer render empty Footer 1`] = `
+
+`;
+
+exports[`rc-footer render light theme Footer 1`] = `
+
+`;
diff --git a/tests/index.spec.js b/tests/index.spec.js
new file mode 100644
index 0000000..ce4c8e6
--- /dev/null
+++ b/tests/index.spec.js
@@ -0,0 +1,264 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import Footer from '../index';
+
+describe('rc-footer', () => {
+ it('render empty Footer', () => {
+ const wrapper = mount();
+ expect(wrapper.render()).toMatchSnapshot();
+ });
+
+ it('render Footer', () => {
+ const wrapper = mount(
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ ],
+ },
+ ]}
+ bottom="Made with ❤️ by AFX"
+ />,
+ );
+ expect(wrapper.render()).toMatchSnapshot();
+ });
+
+ it('render Footer with columnLayout and backgroundColor', () => {
+ const wrapper = mount(
+ ,
+ );
+ expect(wrapper.render()).toMatchSnapshot();
+ });
+
+ it('render light theme Footer', () => {
+ const wrapper = mount(
+ ,
+ );
+ expect(wrapper.render()).toMatchSnapshot();
+ });
+
+ it('render Footer with maxColumnsPerRow', () => {
+ const wrapper = mount(
+
+ ),
+ title: '更多产品',
+ items: [
+ {
+ icon: (
+
+ ),
+ title: '语雀',
+ url: 'https://yuque.com',
+ description: '知识创作与分享工具',
+ openExternal: true,
+ },
+ {
+ icon: (
+
+ ),
+ title: '云凤蝶',
+ url: 'https://yunfengdie.com',
+ description: '中台建站平台',
+ openExternal: true,
+ },
+ ],
+ },
+ ]}
+ bottom="Made with ❤️ by AFX"
+ />,
+ );
+ expect(wrapper.render()).toMatchSnapshot();
+ });
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..2e2e5a9
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "baseUrl": "./",
+ "lib": ["dom", "es2017"],
+ "jsx": "react",
+ "strict": true,
+ "esModuleInterop": true,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+ "skipLibCheck": true,
+ "declaration": true,
+ "paths": {
+ "@/*": ["src/*"],
+ "@@/*": ["src/.umi/*"],
+ "rc-footer": ["src/index.tsx"]
+ }
+ }
+}
diff --git a/type.d.ts b/type.d.ts
new file mode 100644
index 0000000..22b274f
--- /dev/null
+++ b/type.d.ts
@@ -0,0 +1,3 @@
+declare module '*.css';
+
+declare module '*.less';