@blocklet/ui-react 2.1.8 → 2.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Footer/brand.js +67 -0
- package/lib/Footer/copyright.js +44 -0
- package/lib/Footer/index.js +56 -29
- package/lib/Footer/links.js +129 -0
- package/lib/Footer/row.js +59 -0
- package/lib/Footer/social-media.js +75 -0
- package/lib/Icon/index.js +81 -0
- package/lib/utils.js +34 -0
- package/package.json +4 -4
- package/src/Footer/brand.js +70 -0
- package/src/Footer/copyright.js +26 -0
- package/src/Footer/index.js +44 -70
- package/src/Footer/links.js +202 -0
- package/src/Footer/row.js +53 -0
- package/src/Footer/social-media.js +52 -0
- package/src/Icon/index.js +45 -0
- package/src/utils.js +16 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = Brand;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
+
|
|
14
|
+
var _useTheme = _interopRequireDefault(require("@mui/styles/useTheme"));
|
|
15
|
+
|
|
16
|
+
const _excluded = ["name", "logo", "description"];
|
|
17
|
+
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
|
|
20
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
21
|
+
|
|
22
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
23
|
+
|
|
24
|
+
function Brand(_ref) {
|
|
25
|
+
let {
|
|
26
|
+
name,
|
|
27
|
+
logo,
|
|
28
|
+
description
|
|
29
|
+
} = _ref,
|
|
30
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
31
|
+
|
|
32
|
+
const theme = (0, _useTheme.default)();
|
|
33
|
+
|
|
34
|
+
if (!name && !logo && !description) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const logoElement = /*#__PURE__*/_react.default.isValidElement(logo) ? logo : /*#__PURE__*/_react.default.createElement("img", {
|
|
39
|
+
src: logo,
|
|
40
|
+
alt: name
|
|
41
|
+
});
|
|
42
|
+
return /*#__PURE__*/_react.default.createElement(Root, Object.assign({}, rest, {
|
|
43
|
+
$theme: theme
|
|
44
|
+
}), /*#__PURE__*/_react.default.createElement("div", null, logo && /*#__PURE__*/_react.default.createElement("div", {
|
|
45
|
+
className: "footer-brand-logo"
|
|
46
|
+
}, logoElement), name && /*#__PURE__*/_react.default.createElement("div", {
|
|
47
|
+
className: "footer-brand-name"
|
|
48
|
+
}, name)), description && /*#__PURE__*/_react.default.createElement("div", {
|
|
49
|
+
className: "footer-brand-desc"
|
|
50
|
+
}, description));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Brand.propTypes = {
|
|
54
|
+
name: _propTypes.default.node,
|
|
55
|
+
logo: _propTypes.default.node,
|
|
56
|
+
description: _propTypes.default.string
|
|
57
|
+
};
|
|
58
|
+
Brand.defaultProps = {
|
|
59
|
+
name: '',
|
|
60
|
+
logo: '',
|
|
61
|
+
description: ''
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const Root = _styledComponents.default.div.withConfig({
|
|
65
|
+
displayName: "brand__Root",
|
|
66
|
+
componentId: "sc-6z2c3k-0"
|
|
67
|
+
})(["display:flex;flex-direction:column;width:240px;font-size:14px;a{text-decoration:none;color:inherit;}> div:first-child{display:flex;align-items:center;}.footer-brand-logo{height:32px;margin-right:8px;img,svg{max-width:100%;max-height:100%;}}.footer-brand-name{font-size:16px;font-weight:bold;}.footer-brand-desc{margin-top:16px;}", "{width:auto;}"], props => props.$theme.breakpoints.down('sm'));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = Copyright;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
+
|
|
14
|
+
const _excluded = ["owner", "year"];
|
|
15
|
+
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
+
|
|
18
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
19
|
+
|
|
20
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
21
|
+
|
|
22
|
+
function Copyright(_ref) {
|
|
23
|
+
let {
|
|
24
|
+
owner,
|
|
25
|
+
year
|
|
26
|
+
} = _ref,
|
|
27
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
28
|
+
|
|
29
|
+
return /*#__PURE__*/_react.default.createElement(Root, rest, "Copyright \xA9 ", year, " ", owner);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Copyright.propTypes = {
|
|
33
|
+
owner: _propTypes.default.string,
|
|
34
|
+
year: _propTypes.default.string
|
|
35
|
+
};
|
|
36
|
+
Copyright.defaultProps = {
|
|
37
|
+
owner: 'ArcBlock, Inc.',
|
|
38
|
+
year: "".concat(new Date().getFullYear())
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const Root = _styledComponents.default.p.withConfig({
|
|
42
|
+
displayName: "copyright__Root",
|
|
43
|
+
componentId: "sc-g2r3zf-0"
|
|
44
|
+
})(["margin:0;font-size:14px;"]);
|
package/lib/Footer/index.js
CHANGED
|
@@ -11,9 +11,21 @@ var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
|
11
11
|
|
|
12
12
|
var _useTheme = _interopRequireDefault(require("@mui/styles/useTheme"));
|
|
13
13
|
|
|
14
|
+
var _Box = _interopRequireDefault(require("@mui/material/Box"));
|
|
15
|
+
|
|
14
16
|
var _Container = _interopRequireDefault(require("@mui/material/Container"));
|
|
15
17
|
|
|
16
|
-
var
|
|
18
|
+
var _brand = _interopRequireDefault(require("./brand"));
|
|
19
|
+
|
|
20
|
+
var _links = _interopRequireDefault(require("./links"));
|
|
21
|
+
|
|
22
|
+
var _socialMedia = _interopRequireDefault(require("./social-media"));
|
|
23
|
+
|
|
24
|
+
var _copyright = _interopRequireDefault(require("./copyright"));
|
|
25
|
+
|
|
26
|
+
var _row = _interopRequireDefault(require("./row"));
|
|
27
|
+
|
|
28
|
+
var _utils = require("../utils");
|
|
17
29
|
|
|
18
30
|
var _types = require("../types");
|
|
19
31
|
|
|
@@ -21,6 +33,12 @@ const _excluded = ["meta"];
|
|
|
21
33
|
|
|
22
34
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
35
|
|
|
36
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
37
|
+
|
|
38
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
39
|
+
|
|
40
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
41
|
+
|
|
24
42
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
25
43
|
|
|
26
44
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
@@ -45,35 +63,44 @@ function Footer(_ref) {
|
|
|
45
63
|
appLogo,
|
|
46
64
|
appName,
|
|
47
65
|
theme: blockletTheme,
|
|
48
|
-
navigation = []
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
navigation = [],
|
|
67
|
+
copyrightOwner,
|
|
68
|
+
footerNavigation,
|
|
69
|
+
footerLinks,
|
|
70
|
+
socialMedia
|
|
71
|
+
} = blocklet;
|
|
72
|
+
const navMenuItems = (0, _utils.mapRecursive)( // TODO: 需要讨论 blocklet.yml 是否需要专门为 footer navigation 提供配置, 暂时与 header 共用 navigation 配置
|
|
73
|
+
footerNavigation || navigation, item => _objectSpread(_objectSpread({}, item), {}, {
|
|
74
|
+
label: item.title,
|
|
75
|
+
link: item.link
|
|
76
|
+
}), 'items');
|
|
57
77
|
return /*#__PURE__*/_react.default.createElement(Root, Object.assign({}, rest, {
|
|
58
78
|
$bgcolor: blockletTheme === null || blockletTheme === void 0 ? void 0 : blockletTheme.background,
|
|
59
79
|
$theme: theme
|
|
60
|
-
}), /*#__PURE__*/_react.default.createElement(_Container.default, null, /*#__PURE__*/_react.default.createElement(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
}))
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
}), /*#__PURE__*/_react.default.createElement(_Container.default, null, /*#__PURE__*/_react.default.createElement(_row.default, null, /*#__PURE__*/_react.default.createElement(_Box.default, null, /*#__PURE__*/_react.default.createElement(_brand.default, {
|
|
81
|
+
name: appName,
|
|
82
|
+
logo: appLogo,
|
|
83
|
+
description: "Official DID Wallet webapp implementation that makes it possible to manage your digital identities and assets from the browser."
|
|
84
|
+
}), /*#__PURE__*/_react.default.createElement(_socialMedia.default, {
|
|
85
|
+
items: socialMedia,
|
|
86
|
+
style: {
|
|
87
|
+
marginTop: 24
|
|
88
|
+
}
|
|
89
|
+
})), /*#__PURE__*/_react.default.createElement(_links.default, {
|
|
90
|
+
links: navMenuItems
|
|
91
|
+
})), /*#__PURE__*/_react.default.createElement(_row.default, {
|
|
92
|
+
autoCenter: true,
|
|
93
|
+
style: {
|
|
94
|
+
marginTop: 72
|
|
95
|
+
}
|
|
96
|
+
}, /*#__PURE__*/_react.default.createElement(_copyright.default, {
|
|
97
|
+
owner: copyrightOwner || appName
|
|
98
|
+
}), /*#__PURE__*/_react.default.createElement(_links.default, {
|
|
99
|
+
flowLayout: true,
|
|
100
|
+
links: footerLinks,
|
|
101
|
+
style: {
|
|
102
|
+
color: '#999'
|
|
103
|
+
}
|
|
77
104
|
}))));
|
|
78
105
|
}
|
|
79
106
|
|
|
@@ -87,9 +114,9 @@ Footer.defaultProps = {
|
|
|
87
114
|
const Root = _styledComponents.default.div.withConfig({
|
|
88
115
|
displayName: "Footer__Root",
|
|
89
116
|
componentId: "sc-1iwl1nd-0"
|
|
90
|
-
})(["padding:
|
|
117
|
+
})(["padding:48px 0;border-top:1px solid #eee;color:", ";", ""], props => props.$theme.palette.grey[600], _ref2 => {
|
|
91
118
|
let {
|
|
92
119
|
$bgcolor
|
|
93
120
|
} = _ref2;
|
|
94
121
|
return $bgcolor && "background-color: ".concat($bgcolor, ";");
|
|
95
|
-
}
|
|
122
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = Links;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
+
|
|
14
|
+
var _useTheme = _interopRequireDefault(require("@mui/styles/useTheme"));
|
|
15
|
+
|
|
16
|
+
var _clsx = _interopRequireDefault(require("clsx"));
|
|
17
|
+
|
|
18
|
+
const _excluded = ["links", "flowLayout"];
|
|
19
|
+
|
|
20
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
|
|
22
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
23
|
+
|
|
24
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
25
|
+
|
|
26
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
27
|
+
|
|
28
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* footer 中的 links (支持分组, 最多支持 2 级)
|
|
32
|
+
* TODO: dark/light theme
|
|
33
|
+
*/
|
|
34
|
+
function Links(_ref) {
|
|
35
|
+
let {
|
|
36
|
+
links,
|
|
37
|
+
flowLayout
|
|
38
|
+
} = _ref,
|
|
39
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
40
|
+
|
|
41
|
+
const theme = (0, _useTheme.default)();
|
|
42
|
+
const [activeIndex, setActiveIndex] = (0, _react.useState)(-1);
|
|
43
|
+
|
|
44
|
+
if (!(links !== null && links !== void 0 && links.length)) {
|
|
45
|
+
return null;
|
|
46
|
+
} // 只要发现一项元素有子元素, 就认为是分组 (大字号突出 group title)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
const isGroupMode = links.some(item => {
|
|
50
|
+
var _item$items;
|
|
51
|
+
|
|
52
|
+
return (_item$items = item.items) === null || _item$items === void 0 ? void 0 : _item$items.length;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const renderItem = _ref2 => {
|
|
56
|
+
let {
|
|
57
|
+
label,
|
|
58
|
+
link,
|
|
59
|
+
render,
|
|
60
|
+
props
|
|
61
|
+
} = _ref2;
|
|
62
|
+
let result = label;
|
|
63
|
+
|
|
64
|
+
if (render) {
|
|
65
|
+
result = render({
|
|
66
|
+
label,
|
|
67
|
+
link,
|
|
68
|
+
props
|
|
69
|
+
});
|
|
70
|
+
} else if (link) {
|
|
71
|
+
result = /*#__PURE__*/_react.default.createElement("a", Object.assign({
|
|
72
|
+
href: link
|
|
73
|
+
}, props), label);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return /*#__PURE__*/_react.default.createElement(Root, Object.assign({}, rest, {
|
|
80
|
+
className: (0, _clsx.default)(rest.className, {
|
|
81
|
+
'footer-links--grouped': isGroupMode,
|
|
82
|
+
'footer-links--flow': flowLayout
|
|
83
|
+
}),
|
|
84
|
+
$theme: theme
|
|
85
|
+
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
86
|
+
className: "footer-links-inner"
|
|
87
|
+
}, flowLayout && links.map((item, i) => /*#__PURE__*/_react.default.createElement("span", {
|
|
88
|
+
key: i,
|
|
89
|
+
className: "footer-links-item"
|
|
90
|
+
}, renderItem(item))), !flowLayout && links.map((item, i) => {
|
|
91
|
+
const {
|
|
92
|
+
items
|
|
93
|
+
} = item;
|
|
94
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
95
|
+
key: i,
|
|
96
|
+
className: (0, _clsx.default)('footer-links-group', {
|
|
97
|
+
'footer-links-group--active': i === activeIndex
|
|
98
|
+
}),
|
|
99
|
+
onClick: () => setActiveIndex(activeIndex === i ? -1 : i)
|
|
100
|
+
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
101
|
+
className: "footer-links-item"
|
|
102
|
+
}, renderItem(item)), !!(items !== null && items !== void 0 && items.length) && /*#__PURE__*/_react.default.createElement("div", {
|
|
103
|
+
className: "footer-links-sub"
|
|
104
|
+
}, items.map((child, j) => /*#__PURE__*/_react.default.createElement("span", {
|
|
105
|
+
key: j,
|
|
106
|
+
className: "footer-links-item"
|
|
107
|
+
}, renderItem(child)))));
|
|
108
|
+
})));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
Links.propTypes = {
|
|
112
|
+
links: _propTypes.default.arrayOf(_propTypes.default.shape({
|
|
113
|
+
label: _propTypes.default.string,
|
|
114
|
+
link: _propTypes.default.string,
|
|
115
|
+
render: _propTypes.default.func,
|
|
116
|
+
props: _propTypes.default.object
|
|
117
|
+
})),
|
|
118
|
+
// 流动布局, 简单的从左到右排列
|
|
119
|
+
flowLayout: _propTypes.default.bool
|
|
120
|
+
};
|
|
121
|
+
Links.defaultProps = {
|
|
122
|
+
links: [],
|
|
123
|
+
flowLayout: false
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const Root = _styledComponents.default.div.withConfig({
|
|
127
|
+
displayName: "links__Root",
|
|
128
|
+
componentId: "sc-19wysi2-0"
|
|
129
|
+
})(["overflow:hidden;color:", ";.footer-links-inner{display:flex;justify-content:space-between;margin:0 -8px;}.footer-links-group,.footer-links-sub{display:flex;flex-direction:column;}.footer-links-item{display:inline-block;padding:0 8px;font-size:14px;line-height:1.6;}.footer-links-group + .footer-links-group{margin-left:128px;}&.footer-links--grouped{.footer-links-group{> .footer-links-item{font-weight:bold;}.footer-links-sub{margin-top:8px;}}}a{color:inherit;text-decoration:none;&:hover{text-decoration:underline;}}&.footer-links--flow{display:inline-flex;.footer-links-inner{justify-content:center;flex-wrap:wrap;margin:0 -8px;.footer-links-item{padding:0 8px;}}}", "{.footer-links-group + .footer-links-group{margin-left:56px;}}", "{.footer-links-group + .footer-links-group{margin-left:40px;}}", "{.footer-links-inner{flex-direction:column;margin:0;}.footer-links-sub{display:none;}.footer-links-group{padding:12px 0;border-top:1px solid ", ";}.footer-links-group + .footer-links-group{margin-left:0;}.footer-links-group--active{.footer-links-sub{display:flex;flex-direction:row;flex-wrap:wrap;.footer-links-item{flex:0 0 50%;}}}.footer-links-item{padding:0;font-size:13px;}&.footer-links--grouped{.footer-links-group{> .footer-links-item{font-size:14px;}}}&.footer-links--flow{.footer-links-inner{flex-direction:row;}}}"], props => props.$theme.palette.grey[600], props => props.$theme.breakpoints.down('lg'), props => props.$theme.breakpoints.down('lg'), props => props.$theme.breakpoints.down('sm'), props => props.$theme.palette.grey[200]);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = Row;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
+
|
|
14
|
+
var _useTheme = _interopRequireDefault(require("@mui/styles/useTheme"));
|
|
15
|
+
|
|
16
|
+
var _clsx = _interopRequireDefault(require("clsx"));
|
|
17
|
+
|
|
18
|
+
const _excluded = ["children", "autoCenter"];
|
|
19
|
+
|
|
20
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
|
|
22
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
23
|
+
|
|
24
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
25
|
+
|
|
26
|
+
function Row(_ref) {
|
|
27
|
+
let {
|
|
28
|
+
children,
|
|
29
|
+
autoCenter
|
|
30
|
+
} = _ref,
|
|
31
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
32
|
+
|
|
33
|
+
const theme = (0, _useTheme.default)();
|
|
34
|
+
|
|
35
|
+
if (!children) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return /*#__PURE__*/_react.default.createElement(RowRoot, Object.assign({}, rest, {
|
|
40
|
+
className: (0, _clsx.default)(rest.className, {
|
|
41
|
+
'footer-row-auto-center': autoCenter
|
|
42
|
+
}),
|
|
43
|
+
$theme: theme
|
|
44
|
+
}), children);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Row.propTypes = {
|
|
48
|
+
children: _propTypes.default.any,
|
|
49
|
+
autoCenter: _propTypes.default.bool
|
|
50
|
+
};
|
|
51
|
+
Row.defaultProps = {
|
|
52
|
+
children: null,
|
|
53
|
+
autoCenter: false
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const RowRoot = _styledComponents.default.div.withConfig({
|
|
57
|
+
displayName: "row__RowRoot",
|
|
58
|
+
componentId: "sc-11upj1u-0"
|
|
59
|
+
})(["display:flex;justify-content:space-between;& + &{margin-top:24px;}&.footer-row-auto-center > *:only-child{margin:0 auto;}", "{align-items:stretch;flex-direction:column;gap:16px;> *{flex:1 0 100%;}&.footer-row-auto-center > *{margin:0 auto;}}"], props => props.$theme.breakpoints.down('md'));
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = SocialMedia;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
13
|
+
|
|
14
|
+
var _useTheme = _interopRequireDefault(require("@mui/styles/useTheme"));
|
|
15
|
+
|
|
16
|
+
var _Icon = _interopRequireDefault(require("../Icon"));
|
|
17
|
+
|
|
18
|
+
const _excluded = ["items"];
|
|
19
|
+
|
|
20
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
|
|
22
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
23
|
+
|
|
24
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
25
|
+
|
|
26
|
+
function SocialMedia(_ref) {
|
|
27
|
+
let {
|
|
28
|
+
items
|
|
29
|
+
} = _ref,
|
|
30
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
31
|
+
|
|
32
|
+
const theme = (0, _useTheme.default)();
|
|
33
|
+
|
|
34
|
+
if (!(items !== null && items !== void 0 && items.length)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return /*#__PURE__*/_react.default.createElement(Root, rest, items.map((item, i) => {
|
|
39
|
+
return (
|
|
40
|
+
/*#__PURE__*/
|
|
41
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
42
|
+
_react.default.createElement("a", {
|
|
43
|
+
key: i,
|
|
44
|
+
href: item.link,
|
|
45
|
+
target: "_blank",
|
|
46
|
+
rel: "noreferrer"
|
|
47
|
+
}, /*#__PURE__*/_react.default.createElement(_Icon.default, {
|
|
48
|
+
icon: item.icon,
|
|
49
|
+
sx: {
|
|
50
|
+
bgcolor: theme.palette.grey[600],
|
|
51
|
+
color: '#fff'
|
|
52
|
+
},
|
|
53
|
+
size: 44,
|
|
54
|
+
variant: "rounded",
|
|
55
|
+
component: "span"
|
|
56
|
+
}))
|
|
57
|
+
);
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
SocialMedia.propTypes = {
|
|
62
|
+
items: _propTypes.default.arrayOf(_propTypes.default.shape({
|
|
63
|
+
// icon 对应 Icon#icon prop, 支持 iconify name 和 url 2 种形式:
|
|
64
|
+
icon: _propTypes.default.string,
|
|
65
|
+
link: _propTypes.default.string
|
|
66
|
+
}))
|
|
67
|
+
};
|
|
68
|
+
SocialMedia.defaultProps = {
|
|
69
|
+
items: null
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const Root = _styledComponents.default.div.withConfig({
|
|
73
|
+
displayName: "social-media__Root",
|
|
74
|
+
componentId: "sc-w4ariy-0"
|
|
75
|
+
})(["display:inline-flex;align-items:center;a + a{margin-left:12px;}"]);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = Icon;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
|
|
12
|
+
var _Avatar = _interopRequireDefault(require("@mui/material/Avatar"));
|
|
13
|
+
|
|
14
|
+
require("@iconify/iconify");
|
|
15
|
+
|
|
16
|
+
var _utils = require("../utils");
|
|
17
|
+
|
|
18
|
+
const _excluded = ["icon", "size"];
|
|
19
|
+
|
|
20
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
|
|
22
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
23
|
+
|
|
24
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
25
|
+
|
|
26
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
27
|
+
|
|
28
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
29
|
+
|
|
30
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Icon 组件, 基于 mui Avatar 组件扩展对 iconify 的支持
|
|
34
|
+
*/
|
|
35
|
+
function Icon(_ref) {
|
|
36
|
+
let {
|
|
37
|
+
icon,
|
|
38
|
+
size
|
|
39
|
+
} = _ref,
|
|
40
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
41
|
+
|
|
42
|
+
const sx = _objectSpread({}, rest.sx);
|
|
43
|
+
|
|
44
|
+
if (size) {
|
|
45
|
+
sx.width = size;
|
|
46
|
+
sx.height = size;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if ((0, _utils.isUrl)(icon)) {
|
|
50
|
+
return /*#__PURE__*/_react.default.createElement(_Avatar.default, Object.assign({}, rest, {
|
|
51
|
+
src: icon,
|
|
52
|
+
sx: sx
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (icon) {
|
|
57
|
+
// y = 0.6 * x + 4
|
|
58
|
+
const iconHeight = size ? 0.6 * size + 4 : 0;
|
|
59
|
+
return /*#__PURE__*/_react.default.createElement(_Avatar.default, Object.assign({}, rest, {
|
|
60
|
+
sx: sx
|
|
61
|
+
}), /*#__PURE__*/_react.default.createElement("span", Object.assign({
|
|
62
|
+
className: "iconify",
|
|
63
|
+
"data-icon": icon
|
|
64
|
+
}, iconHeight && {
|
|
65
|
+
'data-height': iconHeight
|
|
66
|
+
})));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Icon.propTypes = {
|
|
73
|
+
// icon 支持 2 种形式:
|
|
74
|
+
// 1. iconify icon name: <prefix>:<name>
|
|
75
|
+
// 2. url
|
|
76
|
+
icon: _propTypes.default.string.isRequired,
|
|
77
|
+
size: _propTypes.default.number
|
|
78
|
+
};
|
|
79
|
+
Icon.defaultProps = {
|
|
80
|
+
size: null
|
|
81
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.mapRecursive = exports.isUrl = void 0;
|
|
7
|
+
|
|
8
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
9
|
+
|
|
10
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
11
|
+
|
|
12
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
13
|
+
|
|
14
|
+
const mapRecursive = function mapRecursive(array, fn) {
|
|
15
|
+
let childrenKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
|
|
16
|
+
return array.map(item => {
|
|
17
|
+
if (Array.isArray(item[childrenKey])) {
|
|
18
|
+
return fn(_objectSpread(_objectSpread({}, item), {}, {
|
|
19
|
+
[childrenKey]: mapRecursive(item[childrenKey], fn, childrenKey)
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return fn(item);
|
|
24
|
+
});
|
|
25
|
+
}; // "http://", "https://", "//" 开头的 3 种情况
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
exports.mapRecursive = mapRecursive;
|
|
29
|
+
|
|
30
|
+
const isUrl = str => {
|
|
31
|
+
return /^(https?:)?\/\//.test(str);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
exports.isUrl = isUrl;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/ui-react",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.11",
|
|
4
4
|
"description": "Some useful front-end web components that can be used in Blocklets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"url": "https://github.com/ArcBlock/ux/issues"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@arcblock/did-connect": "^2.1.
|
|
38
|
-
"@arcblock/ux": "^2.1.
|
|
37
|
+
"@arcblock/did-connect": "^2.1.11",
|
|
38
|
+
"@arcblock/ux": "^2.1.11",
|
|
39
39
|
"@iconify/iconify": "^2.2.1",
|
|
40
40
|
"@mui/material": "^5.6.4",
|
|
41
41
|
"core-js": "^3.6.4",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"eslint-plugin-react-hooks": "^4.2.0",
|
|
57
57
|
"jest": "^24.1.0"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "ce03cc62eb231442c6c2e29d262ea073925a8cb2"
|
|
60
60
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import useTheme from '@mui/styles/useTheme';
|
|
5
|
+
|
|
6
|
+
export default function Brand({ name, logo, description, ...rest }) {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
if (!name && !logo && !description) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const logoElement = React.isValidElement(logo) ? logo : <img src={logo} alt={name} />;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Root {...rest} $theme={theme}>
|
|
16
|
+
<div>
|
|
17
|
+
{logo && <div className="footer-brand-logo">{logoElement}</div>}
|
|
18
|
+
{name && <div className="footer-brand-name">{name}</div>}
|
|
19
|
+
</div>
|
|
20
|
+
{description && <div className="footer-brand-desc">{description}</div>}
|
|
21
|
+
</Root>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Brand.propTypes = {
|
|
26
|
+
name: PropTypes.node,
|
|
27
|
+
logo: PropTypes.node,
|
|
28
|
+
description: PropTypes.string,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Brand.defaultProps = {
|
|
32
|
+
name: '',
|
|
33
|
+
logo: '',
|
|
34
|
+
description: '',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const Root = styled.div`
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
width: 240px;
|
|
41
|
+
font-size: 14px;
|
|
42
|
+
a {
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
color: inherit;
|
|
45
|
+
}
|
|
46
|
+
> div:first-child {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
.footer-brand-logo {
|
|
51
|
+
height: 32px;
|
|
52
|
+
margin-right: 8px;
|
|
53
|
+
img,
|
|
54
|
+
svg {
|
|
55
|
+
max-width: 100%;
|
|
56
|
+
max-height: 100%;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
.footer-brand-name {
|
|
60
|
+
font-size: 16px;
|
|
61
|
+
font-weight: bold;
|
|
62
|
+
}
|
|
63
|
+
.footer-brand-desc {
|
|
64
|
+
margin-top: 16px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
${props => props.$theme.breakpoints.down('sm')} {
|
|
68
|
+
width: auto;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
export default function Copyright({ owner, year, ...rest }) {
|
|
6
|
+
return (
|
|
7
|
+
<Root {...rest}>
|
|
8
|
+
Copyright © {year} {owner}
|
|
9
|
+
</Root>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Copyright.propTypes = {
|
|
14
|
+
owner: PropTypes.string,
|
|
15
|
+
year: PropTypes.string,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
Copyright.defaultProps = {
|
|
19
|
+
owner: 'ArcBlock, Inc.',
|
|
20
|
+
year: `${new Date().getFullYear()}`,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const Root = styled.p`
|
|
24
|
+
margin: 0;
|
|
25
|
+
font-size: 14px;
|
|
26
|
+
`;
|
package/src/Footer/index.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import useTheme from '@mui/styles/useTheme';
|
|
4
|
+
import Box from '@mui/material/Box';
|
|
4
5
|
import Container from '@mui/material/Container';
|
|
5
|
-
import
|
|
6
|
+
import Brand from './brand';
|
|
7
|
+
import Links from './links';
|
|
8
|
+
import SocialMedia from './social-media';
|
|
9
|
+
import Copyright from './copyright';
|
|
10
|
+
import Row from './row';
|
|
11
|
+
import { mapRecursive } from '../utils';
|
|
6
12
|
|
|
7
13
|
import { blockletMetaProps } from '../types';
|
|
8
14
|
|
|
@@ -16,33 +22,45 @@ export default function Footer({ meta, ...rest }) {
|
|
|
16
22
|
return null;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const {
|
|
26
|
+
appLogo,
|
|
27
|
+
appName,
|
|
28
|
+
theme: blockletTheme,
|
|
29
|
+
navigation = [],
|
|
30
|
+
copyrightOwner,
|
|
31
|
+
footerNavigation,
|
|
32
|
+
footerLinks,
|
|
33
|
+
socialMedia,
|
|
34
|
+
} = blocklet;
|
|
35
|
+
const navMenuItems = mapRecursive(
|
|
36
|
+
// TODO: 需要讨论 blocklet.yml 是否需要专门为 footer navigation 提供配置, 暂时与 header 共用 navigation 配置
|
|
37
|
+
footerNavigation || navigation,
|
|
38
|
+
item => ({
|
|
39
|
+
...item,
|
|
40
|
+
label: item.title,
|
|
41
|
+
link: item.link,
|
|
42
|
+
}),
|
|
43
|
+
'items'
|
|
44
|
+
);
|
|
27
45
|
|
|
28
46
|
return (
|
|
29
47
|
<Root {...rest} $bgcolor={blockletTheme?.background} $theme={theme}>
|
|
30
48
|
<Container>
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
</
|
|
49
|
+
<Row>
|
|
50
|
+
<Box>
|
|
51
|
+
<Brand
|
|
52
|
+
name={appName}
|
|
53
|
+
logo={appLogo}
|
|
54
|
+
description="Official DID Wallet webapp implementation that makes it possible to manage your digital identities and assets from the browser."
|
|
55
|
+
/>
|
|
56
|
+
<SocialMedia items={socialMedia} style={{ marginTop: 24 }} />
|
|
57
|
+
</Box>
|
|
58
|
+
<Links links={navMenuItems} />
|
|
59
|
+
</Row>
|
|
60
|
+
<Row autoCenter style={{ marginTop: 72 }}>
|
|
61
|
+
{<Copyright owner={copyrightOwner || appName} />}
|
|
62
|
+
{<Links flowLayout links={footerLinks} style={{ color: '#999' }} />}
|
|
63
|
+
</Row>
|
|
46
64
|
</Container>
|
|
47
65
|
</Root>
|
|
48
66
|
);
|
|
@@ -57,52 +75,8 @@ Footer.defaultProps = {
|
|
|
57
75
|
};
|
|
58
76
|
|
|
59
77
|
const Root = styled.div`
|
|
60
|
-
padding:
|
|
78
|
+
padding: 48px 0;
|
|
61
79
|
border-top: 1px solid #eee;
|
|
62
|
-
color:
|
|
80
|
+
color: ${props => props.$theme.palette.grey[600]};
|
|
63
81
|
${({ $bgcolor }) => $bgcolor && `background-color: ${$bgcolor};`}
|
|
64
|
-
.footer_line {
|
|
65
|
-
display: flex;
|
|
66
|
-
justify-content: space-between;
|
|
67
|
-
}
|
|
68
|
-
.footer_line + .footer_line {
|
|
69
|
-
margin-top: 32px;
|
|
70
|
-
}
|
|
71
|
-
.footer_brand {
|
|
72
|
-
display: flex;
|
|
73
|
-
align-items: center;
|
|
74
|
-
color: #777;
|
|
75
|
-
img {
|
|
76
|
-
height: 36px;
|
|
77
|
-
}
|
|
78
|
-
span {
|
|
79
|
-
margin-left: 8px;
|
|
80
|
-
font-size: 20px;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
.footer_nav {
|
|
84
|
-
.navmenu {
|
|
85
|
-
padding-left: 0;
|
|
86
|
-
padding-right: 0;
|
|
87
|
-
}
|
|
88
|
-
> * {
|
|
89
|
-
background: transparent;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
${props => props.$theme.breakpoints.down('md')} {
|
|
93
|
-
.footer_line {
|
|
94
|
-
flex-direction: column;
|
|
95
|
-
}
|
|
96
|
-
.footer_line + .footer_line {
|
|
97
|
-
margin-top: 0;
|
|
98
|
-
}
|
|
99
|
-
.footer_brand {
|
|
100
|
-
img {
|
|
101
|
-
height: 24px;
|
|
102
|
-
}
|
|
103
|
-
span {
|
|
104
|
-
font-size: 16px;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
82
|
`;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/* eslint-disable react/no-array-index-key */
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
import useTheme from '@mui/styles/useTheme';
|
|
6
|
+
import clsx from 'clsx';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* footer 中的 links (支持分组, 最多支持 2 级)
|
|
10
|
+
* TODO: dark/light theme
|
|
11
|
+
*/
|
|
12
|
+
export default function Links({ links, flowLayout, ...rest }) {
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
15
|
+
if (!links?.length) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
// 只要发现一项元素有子元素, 就认为是分组 (大字号突出 group title)
|
|
19
|
+
const isGroupMode = links.some(item => item.items?.length);
|
|
20
|
+
const renderItem = ({ label, link, render, props }) => {
|
|
21
|
+
let result = label;
|
|
22
|
+
if (render) {
|
|
23
|
+
result = render({ label, link, props });
|
|
24
|
+
} else if (link) {
|
|
25
|
+
result = (
|
|
26
|
+
<a href={link} {...props}>
|
|
27
|
+
{label}
|
|
28
|
+
</a>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Root
|
|
36
|
+
{...rest}
|
|
37
|
+
className={clsx(rest.className, {
|
|
38
|
+
'footer-links--grouped': isGroupMode,
|
|
39
|
+
'footer-links--flow': flowLayout,
|
|
40
|
+
})}
|
|
41
|
+
$theme={theme}>
|
|
42
|
+
<div className="footer-links-inner">
|
|
43
|
+
{flowLayout &&
|
|
44
|
+
links.map((item, i) => (
|
|
45
|
+
<span key={i} className="footer-links-item">
|
|
46
|
+
{renderItem(item)}
|
|
47
|
+
</span>
|
|
48
|
+
))}
|
|
49
|
+
{!flowLayout &&
|
|
50
|
+
links.map((item, i) => {
|
|
51
|
+
const { items } = item;
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
key={i}
|
|
55
|
+
className={clsx('footer-links-group', {
|
|
56
|
+
'footer-links-group--active': i === activeIndex,
|
|
57
|
+
})}
|
|
58
|
+
onClick={() => setActiveIndex(activeIndex === i ? -1 : i)}>
|
|
59
|
+
<span className="footer-links-item">{renderItem(item)}</span>
|
|
60
|
+
{!!items?.length && (
|
|
61
|
+
<div className="footer-links-sub">
|
|
62
|
+
{items.map((child, j) => (
|
|
63
|
+
<span key={j} className="footer-links-item">
|
|
64
|
+
{renderItem(child)}
|
|
65
|
+
</span>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
})}
|
|
72
|
+
</div>
|
|
73
|
+
</Root>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Links.propTypes = {
|
|
78
|
+
links: PropTypes.arrayOf(
|
|
79
|
+
PropTypes.shape({
|
|
80
|
+
label: PropTypes.string,
|
|
81
|
+
link: PropTypes.string,
|
|
82
|
+
render: PropTypes.func,
|
|
83
|
+
props: PropTypes.object,
|
|
84
|
+
})
|
|
85
|
+
),
|
|
86
|
+
// 流动布局, 简单的从左到右排列
|
|
87
|
+
flowLayout: PropTypes.bool,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
Links.defaultProps = {
|
|
91
|
+
links: [],
|
|
92
|
+
flowLayout: false,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const Root = styled.div`
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
color: ${props => props.$theme.palette.grey[600]};
|
|
98
|
+
.footer-links-inner {
|
|
99
|
+
display: flex;
|
|
100
|
+
justify-content: space-between;
|
|
101
|
+
margin: 0 -8px;
|
|
102
|
+
}
|
|
103
|
+
.footer-links-group,
|
|
104
|
+
.footer-links-sub {
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
}
|
|
108
|
+
.footer-links-item {
|
|
109
|
+
display: inline-block;
|
|
110
|
+
padding: 0 8px;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
line-height: 1.6;
|
|
113
|
+
}
|
|
114
|
+
.footer-links-group + .footer-links-group {
|
|
115
|
+
margin-left: 128px;
|
|
116
|
+
}
|
|
117
|
+
&.footer-links--grouped {
|
|
118
|
+
.footer-links-group {
|
|
119
|
+
> .footer-links-item {
|
|
120
|
+
font-weight: bold;
|
|
121
|
+
}
|
|
122
|
+
.footer-links-sub {
|
|
123
|
+
margin-top: 8px;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
a {
|
|
128
|
+
color: inherit;
|
|
129
|
+
text-decoration: none;
|
|
130
|
+
&:hover {
|
|
131
|
+
text-decoration: underline;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&.footer-links--flow {
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
.footer-links-inner {
|
|
138
|
+
justify-content: center;
|
|
139
|
+
flex-wrap: wrap;
|
|
140
|
+
margin: 0 -8px;
|
|
141
|
+
.footer-links-item {
|
|
142
|
+
padding: 0 8px;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
${props => props.$theme.breakpoints.down('lg')} {
|
|
148
|
+
.footer-links-group + .footer-links-group {
|
|
149
|
+
margin-left: 56px;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
${props => props.$theme.breakpoints.down('lg')} {
|
|
154
|
+
.footer-links-group + .footer-links-group {
|
|
155
|
+
margin-left: 40px;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
${props => props.$theme.breakpoints.down('sm')} {
|
|
160
|
+
.footer-links-inner {
|
|
161
|
+
flex-direction: column;
|
|
162
|
+
margin: 0;
|
|
163
|
+
}
|
|
164
|
+
.footer-links-sub {
|
|
165
|
+
display: none;
|
|
166
|
+
}
|
|
167
|
+
.footer-links-group {
|
|
168
|
+
padding: 12px 0;
|
|
169
|
+
border-top: 1px solid ${props => props.$theme.palette.grey[200]};
|
|
170
|
+
}
|
|
171
|
+
.footer-links-group + .footer-links-group {
|
|
172
|
+
margin-left: 0;
|
|
173
|
+
}
|
|
174
|
+
.footer-links-group--active {
|
|
175
|
+
.footer-links-sub {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: row;
|
|
178
|
+
flex-wrap: wrap;
|
|
179
|
+
.footer-links-item {
|
|
180
|
+
flex: 0 0 50%;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
.footer-links-item {
|
|
185
|
+
padding: 0;
|
|
186
|
+
font-size: 13px;
|
|
187
|
+
}
|
|
188
|
+
&.footer-links--grouped {
|
|
189
|
+
.footer-links-group {
|
|
190
|
+
> .footer-links-item {
|
|
191
|
+
font-size: 14px;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
&.footer-links--flow {
|
|
197
|
+
.footer-links-inner {
|
|
198
|
+
flex-direction: row;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import useTheme from '@mui/styles/useTheme';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
|
|
7
|
+
export default function Row({ children, autoCenter, ...rest }) {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
if (!children) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return (
|
|
13
|
+
<RowRoot
|
|
14
|
+
{...rest}
|
|
15
|
+
className={clsx(rest.className, { 'footer-row-auto-center': autoCenter })}
|
|
16
|
+
$theme={theme}>
|
|
17
|
+
{children}
|
|
18
|
+
</RowRoot>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Row.propTypes = {
|
|
23
|
+
children: PropTypes.any,
|
|
24
|
+
autoCenter: PropTypes.bool,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
Row.defaultProps = {
|
|
28
|
+
children: null,
|
|
29
|
+
autoCenter: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const RowRoot = styled.div`
|
|
33
|
+
display: flex;
|
|
34
|
+
justify-content: space-between;
|
|
35
|
+
& + & {
|
|
36
|
+
margin-top: 24px;
|
|
37
|
+
}
|
|
38
|
+
&.footer-row-auto-center > *:only-child {
|
|
39
|
+
margin: 0 auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
${props => props.$theme.breakpoints.down('md')} {
|
|
43
|
+
align-items: stretch;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: 16px;
|
|
46
|
+
> * {
|
|
47
|
+
flex: 1 0 100%;
|
|
48
|
+
}
|
|
49
|
+
&.footer-row-auto-center > * {
|
|
50
|
+
margin: 0 auto;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import useTheme from '@mui/styles/useTheme';
|
|
5
|
+
import Icon from '../Icon';
|
|
6
|
+
|
|
7
|
+
export default function SocialMedia({ items, ...rest }) {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
if (!items?.length) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return (
|
|
13
|
+
<Root {...rest}>
|
|
14
|
+
{items.map((item, i) => {
|
|
15
|
+
return (
|
|
16
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
17
|
+
<a key={i} href={item.link} target="_blank" rel="noreferrer">
|
|
18
|
+
<Icon
|
|
19
|
+
icon={item.icon}
|
|
20
|
+
sx={{ bgcolor: theme.palette.grey[600], color: '#fff' }}
|
|
21
|
+
size={44}
|
|
22
|
+
variant="rounded"
|
|
23
|
+
component="span"
|
|
24
|
+
/>
|
|
25
|
+
</a>
|
|
26
|
+
);
|
|
27
|
+
})}
|
|
28
|
+
</Root>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
SocialMedia.propTypes = {
|
|
33
|
+
items: PropTypes.arrayOf(
|
|
34
|
+
PropTypes.shape({
|
|
35
|
+
// icon 对应 Icon#icon prop, 支持 iconify name 和 url 2 种形式:
|
|
36
|
+
icon: PropTypes.string,
|
|
37
|
+
link: PropTypes.string,
|
|
38
|
+
})
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
SocialMedia.defaultProps = {
|
|
43
|
+
items: null,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const Root = styled.div`
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
a + a {
|
|
50
|
+
margin-left: 12px;
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Avatar from '@mui/material/Avatar';
|
|
4
|
+
import '@iconify/iconify';
|
|
5
|
+
import { isUrl } from '../utils';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Icon 组件, 基于 mui Avatar 组件扩展对 iconify 的支持
|
|
9
|
+
*/
|
|
10
|
+
export default function Icon({ icon, size, ...rest }) {
|
|
11
|
+
const sx = { ...rest.sx };
|
|
12
|
+
if (size) {
|
|
13
|
+
sx.width = size;
|
|
14
|
+
sx.height = size;
|
|
15
|
+
}
|
|
16
|
+
if (isUrl(icon)) {
|
|
17
|
+
return <Avatar {...rest} src={icon} sx={sx} />;
|
|
18
|
+
}
|
|
19
|
+
if (icon) {
|
|
20
|
+
// y = 0.6 * x + 4
|
|
21
|
+
const iconHeight = size ? 0.6 * size + 4 : 0;
|
|
22
|
+
return (
|
|
23
|
+
<Avatar {...rest} sx={sx}>
|
|
24
|
+
<span
|
|
25
|
+
className="iconify"
|
|
26
|
+
data-icon={icon}
|
|
27
|
+
{...(iconHeight && { 'data-height': iconHeight })}
|
|
28
|
+
/>
|
|
29
|
+
</Avatar>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Icon.propTypes = {
|
|
36
|
+
// icon 支持 2 种形式:
|
|
37
|
+
// 1. iconify icon name: <prefix>:<name>
|
|
38
|
+
// 2. url
|
|
39
|
+
icon: PropTypes.string.isRequired,
|
|
40
|
+
size: PropTypes.number,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
Icon.defaultProps = {
|
|
44
|
+
size: null,
|
|
45
|
+
};
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const mapRecursive = (array, fn, childrenKey = 'children') => {
|
|
2
|
+
return array.map(item => {
|
|
3
|
+
if (Array.isArray(item[childrenKey])) {
|
|
4
|
+
return fn({
|
|
5
|
+
...item,
|
|
6
|
+
[childrenKey]: mapRecursive(item[childrenKey], fn, childrenKey),
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
return fn(item);
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// "http://", "https://", "//" 开头的 3 种情况
|
|
14
|
+
export const isUrl = str => {
|
|
15
|
+
return /^(https?:)?\/\//.test(str);
|
|
16
|
+
};
|