@antv/dumi-theme-antv 0.1.0

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.
Files changed (111) hide show
  1. package/README.md +9 -0
  2. package/es/antv/404/index.js +20 -0
  3. package/es/antv/Banner/Banner.module.less +412 -0
  4. package/es/antv/Banner/Notification.js +44 -0
  5. package/es/antv/Banner/Notification.module.less +108 -0
  6. package/es/antv/Banner/index.js +115 -0
  7. package/es/antv/Cases/Cases.js +124 -0
  8. package/es/antv/Cases/Cases.module.less +203 -0
  9. package/es/antv/Features/FeatureCard.js +25 -0
  10. package/es/antv/Features/FeatureCard.module.less +51 -0
  11. package/es/antv/Features/Features.module.less +169 -0
  12. package/es/antv/Features/index.js +102 -0
  13. package/es/antv/Footer/Footer.module.less +36 -0
  14. package/es/antv/Footer/index.js +232 -0
  15. package/es/antv/Header/Logo.js +130 -0
  16. package/es/antv/Products/Product.js +61 -0
  17. package/es/antv/Products/Product.module.less +146 -0
  18. package/es/antv/Products/getNewProducts.js +41 -0
  19. package/es/antv/Products/getProducts.js +466 -0
  20. package/es/antv/Products/index.js +81 -0
  21. package/es/antv/hooks.js +81 -0
  22. package/es/antv/mixins.less +21 -0
  23. package/es/antv/utils.js +49 -0
  24. package/es/builtins/API.js +37 -0
  25. package/es/builtins/Alert.js +9 -0
  26. package/es/builtins/Alert.less +62 -0
  27. package/es/builtins/Badge.js +9 -0
  28. package/es/builtins/Badge.less +31 -0
  29. package/es/builtins/Example.js +48 -0
  30. package/es/builtins/Example.less +47 -0
  31. package/es/builtins/Previewer.js +225 -0
  32. package/es/builtins/Previewer.less +406 -0
  33. package/es/builtins/SourceCode.js +72 -0
  34. package/es/builtins/SourceCode.less +103 -0
  35. package/es/builtins/Table.js +56 -0
  36. package/es/builtins/Table.less +43 -0
  37. package/es/builtins/Tree.js +219 -0
  38. package/es/builtins/Tree.less +159 -0
  39. package/es/components/Dark.js +125 -0
  40. package/es/components/Dark.less +121 -0
  41. package/es/components/LocaleSelect.js +53 -0
  42. package/es/components/LocaleSelect.less +59 -0
  43. package/es/components/Navbar.js +155 -0
  44. package/es/components/Navbar.less +180 -0
  45. package/es/components/SearchBar.js +83 -0
  46. package/es/components/SearchBar.less +165 -0
  47. package/es/components/SideMenu.js +99 -0
  48. package/es/components/SideMenu.less +379 -0
  49. package/es/components/SlugList.js +33 -0
  50. package/es/components/SlugList.less +18 -0
  51. package/es/layout.js +276 -0
  52. package/es/style/layout.less +402 -0
  53. package/es/style/markdown.less +240 -0
  54. package/es/style/variables.less +37 -0
  55. package/package.json +58 -0
  56. package/src/antv/404/index.tsx +25 -0
  57. package/src/antv/Banner/Banner.module.less +412 -0
  58. package/src/antv/Banner/Notification.module.less +108 -0
  59. package/src/antv/Banner/Notification.tsx +45 -0
  60. package/src/antv/Banner/index.tsx +121 -0
  61. package/src/antv/Cases/Cases.module.less +203 -0
  62. package/src/antv/Cases/Cases.tsx +116 -0
  63. package/src/antv/Features/FeatureCard.module.less +51 -0
  64. package/src/antv/Features/FeatureCard.tsx +24 -0
  65. package/src/antv/Features/Features.module.less +169 -0
  66. package/src/antv/Features/index.tsx +86 -0
  67. package/src/antv/Footer/Footer.module.less +36 -0
  68. package/src/antv/Footer/index.tsx +272 -0
  69. package/src/antv/Header/Logo.tsx +85 -0
  70. package/src/antv/Products/Product.module.less +146 -0
  71. package/src/antv/Products/Product.tsx +80 -0
  72. package/src/antv/Products/getNewProducts.tsx +53 -0
  73. package/src/antv/Products/getProducts.tsx +626 -0
  74. package/src/antv/Products/index.tsx +70 -0
  75. package/src/antv/hooks.ts +87 -0
  76. package/src/antv/mixins.less +21 -0
  77. package/src/antv/utils.ts +44 -0
  78. package/src/builtins/API.tsx +57 -0
  79. package/src/builtins/Alert.less +62 -0
  80. package/src/builtins/Alert.tsx +4 -0
  81. package/src/builtins/Badge.less +31 -0
  82. package/src/builtins/Badge.tsx +4 -0
  83. package/src/builtins/Example.less +47 -0
  84. package/src/builtins/Example.tsx +34 -0
  85. package/src/builtins/Previewer.less +406 -0
  86. package/src/builtins/Previewer.tsx +264 -0
  87. package/src/builtins/SourceCode.less +103 -0
  88. package/src/builtins/SourceCode.tsx +55 -0
  89. package/src/builtins/Table.less +43 -0
  90. package/src/builtins/Table.tsx +42 -0
  91. package/src/builtins/Tree.less +159 -0
  92. package/src/builtins/Tree.tsx +130 -0
  93. package/src/components/Dark.less +121 -0
  94. package/src/components/Dark.tsx +78 -0
  95. package/src/components/LocaleSelect.less +59 -0
  96. package/src/components/LocaleSelect.tsx +53 -0
  97. package/src/components/Navbar.less +180 -0
  98. package/src/components/Navbar.tsx +152 -0
  99. package/src/components/SearchBar.less +165 -0
  100. package/src/components/SearchBar.tsx +68 -0
  101. package/src/components/SideMenu.less +379 -0
  102. package/src/components/SideMenu.tsx +148 -0
  103. package/src/components/SlugList.less +18 -0
  104. package/src/components/SlugList.tsx +20 -0
  105. package/src/layout.tsx +225 -0
  106. package/src/style/layout.less +402 -0
  107. package/src/style/markdown.less +240 -0
  108. package/src/style/variables.less +37 -0
  109. package/src/test/SearchBar.test.ts +32 -0
  110. package/src/test/Table.test.tsx +41 -0
  111. package/src/test/index.test.tsx +377 -0
package/src/layout.tsx ADDED
@@ -0,0 +1,225 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
2
+ /* eslint-disable react/no-danger */
3
+ import type { IRouteComponentProps } from '@umijs/types';
4
+ import { context, Link } from 'dumi/theme';
5
+ import i18n from 'i18next';
6
+ import React, { useContext, useState } from 'react';
7
+ import { initReactI18next } from 'react-i18next';
8
+ import NotFoundPage from './antv/404';
9
+ import Banner from './antv/Banner/index';
10
+ import Cases from './antv/Cases/Cases';
11
+ import Ideas from './antv/Features';
12
+ import Footer from './antv/Footer';
13
+ import Navbar from './components/Navbar';
14
+ import SearchBar from './components/SearchBar';
15
+ import SideMenu from './components/SideMenu';
16
+ import SlugList from './components/SlugList';
17
+ import './style/layout.less';
18
+ i18n
19
+ .use(initReactI18next) // passes i18n down to react-i18next
20
+ .init({
21
+ initImmediate: false,
22
+ fallbackLng: 'zh',
23
+ keySeparator: false,
24
+ react: {
25
+ useSuspense: false,
26
+ },
27
+ });
28
+
29
+
30
+ const isEmpty = obj => {
31
+ return Object.keys(obj).length === 0;
32
+ };
33
+
34
+ const processRedirect = (context, location) => {
35
+ const { pathname } = location;
36
+ const { meta, routes } = context;
37
+
38
+ const isEmptyMeta = isEmpty(meta);
39
+ let matchRoute = { meta: {} };
40
+ const needRedirectPath = ['/zh', '/zh/', '/zh-CN', '/zh-CN/', '/en', '/en/', '/en-US', '/en-US/'];
41
+ const isInclude = needRedirectPath.some(item => item === pathname);
42
+ if (isEmptyMeta) {
43
+ if (isInclude) {
44
+ // 存在重定向需求
45
+ const isZh = pathname.slice(1, 3) === 'zh';
46
+ const isEn = pathname.slice(1, 3) === 'en';
47
+ if (isZh) {
48
+ matchRoute = routes.find(item => {
49
+ return item.path === '/';
50
+ });
51
+ }
52
+ if (isEn) {
53
+ matchRoute = routes.find(item => {
54
+ return item.path === '/en-US';
55
+ });
56
+ }
57
+ }
58
+ }
59
+
60
+ return {
61
+ meta: isEmptyMeta ? matchRoute.meta : meta,
62
+ isDirect: isInclude,
63
+ };
64
+ };
65
+
66
+ const Hero = hero => (
67
+ <div className="__dumi-default-layout-hero">
68
+ {hero.image && <img src={hero.image} alt="banner" />}
69
+ <h1>{hero.title}</h1>
70
+ <div dangerouslySetInnerHTML={{ __html: hero.desc }} />
71
+ {hero.actions &&
72
+ hero.actions.map(action => (
73
+ <Link to={action.link} key={action.text}>
74
+ <button type="button">{action.text}</button>
75
+ </Link>
76
+ ))}
77
+ </div>
78
+ );
79
+
80
+ const BannerPanel = banner => {
81
+ const { image, title, desc, actions, notifications } = banner;
82
+ const description = <div dangerouslySetInnerHTML={{ __html: desc }} />;
83
+ const coverImage = <img alt="graphin" style={{ width: '100%', marginTop: '20%' }} src={image} />;
84
+
85
+ return (
86
+ <Banner
87
+ coverImage={coverImage}
88
+ title={title}
89
+ // @ts-ignore
90
+ description={description}
91
+ notifications={notifications}
92
+ buttons={actions}
93
+ className="banner"
94
+ />
95
+ );
96
+ };
97
+
98
+ const Features = features => (
99
+ <div className="__dumi-default-layout-features">
100
+ {features.map(feat => (
101
+ <dl key={feat.title} style={{ backgroundImage: feat.icon ? `url(${feat.icon})` : undefined }}>
102
+ {feat.link ? (
103
+ <Link to={feat.link}>
104
+ <dt>{feat.title}</dt>
105
+ </Link>
106
+ ) : (
107
+ <dt>{feat.title}</dt>
108
+ )}
109
+ <dd dangerouslySetInnerHTML={{ __html: feat.desc }} />
110
+ </dl>
111
+ ))}
112
+ </div>
113
+ );
114
+
115
+ const Layout: React.FC<IRouteComponentProps> = ({ children, location }) => {
116
+ const Context = useContext(context);
117
+ const {
118
+ config: { mode, repository },
119
+ locale,
120
+ } = Context;
121
+
122
+ const { meta, isDirect } = processRedirect(Context, location);
123
+ console.log('Context', Context, 'calculate meta', meta);
124
+ const { url: repoUrl, branch, platform } = repository;
125
+ const [menuCollapsed, setMenuCollapsed] = useState<boolean>(true);
126
+ const isSiteMode = mode === 'site';
127
+ const showHero = isSiteMode && meta.hero;
128
+ const showBanner = isSiteMode && meta.banner;
129
+ const showCases = isSiteMode && meta.cases;
130
+ const showFeatures = isSiteMode && meta.features;
131
+ const showIdeas = isSiteMode && meta.ideas;
132
+ const showSideMenu = meta.sidemenu !== false && !showHero && !showBanner && !showFeatures && !meta.gapless;
133
+ const showSlugs =
134
+ !showHero &&
135
+ !showBanner &&
136
+ !showFeatures &&
137
+ Boolean(meta.slugs?.length) &&
138
+ (meta.toc === 'content' || meta.toc === undefined) &&
139
+ !meta.gapless;
140
+ const isCN = /^zh|cn$/i.test(locale);
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ const updatedTime: any = new Date(meta.updatedTime).toLocaleString([], { hour12: false });
143
+ const repoPlatform =
144
+ { github: 'GitHub', gitlab: 'GitLab' }[(repoUrl || '').match(/(github|gitlab)/)?.[1] || 'nothing'] || platform;
145
+ // 等dumi最新版发布后解决路由匹配问题
146
+ if (isEmpty(meta) && !isDirect) {
147
+ return (
148
+ <div>
149
+ <div
150
+ style={{ marginBottom: '60px' }}
151
+ className="__dumi-default-layout home"
152
+ data-route={location.pathname}
153
+ data-show-sidemenu={false}
154
+ data-show-slugs={false}
155
+ data-site-mode="site"
156
+ data-gapless={String(!!meta.gapless)}
157
+ onClick={() => {
158
+ if (menuCollapsed) return;
159
+ setMenuCollapsed(true);
160
+ }}
161
+ >
162
+ <div style={{ height: '60px' }} />
163
+ <Navbar
164
+ location={location}
165
+ navPrefix={<SearchBar />}
166
+ onMobileMenuClick={ev => {
167
+ setMenuCollapsed(val => !val);
168
+ ev.stopPropagation();
169
+ }}
170
+ />
171
+ <NotFoundPage />
172
+
173
+ <Footer location={window.location} githubUrl={repoUrl} rootDomain="https://antv.vision" />
174
+ </div>
175
+ </div>
176
+ );
177
+ }
178
+
179
+ return (
180
+ <div
181
+ className={`__dumi-default-layout ${showBanner ? 'home' : ''}`}
182
+ data-route={location.pathname}
183
+ data-show-sidemenu={String(showSideMenu)}
184
+ data-show-slugs={String(showSlugs)}
185
+ data-site-mode={isSiteMode}
186
+ data-gapless={String(!!meta.gapless)}
187
+ onClick={() => {
188
+ if (menuCollapsed) return;
189
+ setMenuCollapsed(true);
190
+ }}
191
+ >
192
+ <Navbar
193
+ location={location}
194
+ navPrefix={<SearchBar />}
195
+ onMobileMenuClick={ev => {
196
+ setMenuCollapsed(val => !val);
197
+ ev.stopPropagation();
198
+ }}
199
+ />
200
+ {showSideMenu && <SideMenu mobileMenuCollapsed={menuCollapsed} location={location} />}
201
+ {showSlugs && <SlugList slugs={meta.slugs} className="__dumi-default-layout-toc" />}
202
+ {showBanner && BannerPanel(meta.banner)}
203
+ {showHero && Hero(meta.hero)}
204
+ {showFeatures && Features(meta.features)}
205
+ {showIdeas && <Ideas features={meta.ideas} style={{ width: '100%' }} />}
206
+ {showCases && <Cases cases={meta.cases} className="graph-cases" />}
207
+ <div className="__dumi-default-layout-content">
208
+ {children}
209
+ {showSideMenu && (
210
+ <div className="__dumi-default-layout-footer-meta">
211
+ {repoPlatform && (
212
+ <Link to={`${repoUrl}/edit/${branch}/${meta.filePath}`}>
213
+ {isCN ? `在 ${repoPlatform} 上编辑此页` : `Edit this doc on ${repoPlatform}`}
214
+ </Link>
215
+ )}
216
+ <span data-updated-text={isCN ? '最后更新时间:' : 'Last update: '}>{updatedTime}</span>
217
+ </div>
218
+ )}
219
+ {!showSideMenu && <Footer location={window.location} githubUrl={repoUrl} rootDomain="https://antv.vision" />}
220
+ </div>
221
+ </div>
222
+ );
223
+ };
224
+
225
+ export default Layout;
@@ -0,0 +1,402 @@
1
+ @import "./markdown.less";
2
+ @import "./variables.less";
3
+
4
+ @s-toc-width: 136px;
5
+
6
+ body {
7
+ margin: 0;
8
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC,
9
+ Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial,
10
+ sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
11
+ font-variant: tabular-nums;
12
+ font-feature-settings: "tnum";
13
+ transition: background 0.2s cubic-bezier(0.075, 0.82, 0.165, 1),
14
+ color 0.2s cubic-bezier(0.075, 0.82, 0.165, 1);
15
+
16
+ [data-prefers-color="dark"] & {
17
+ color: @c-text-dark;
18
+ background-color: @c-bg-dark;
19
+ }
20
+ }
21
+
22
+ .@{prefix}-layout {
23
+ box-sizing: border-box;
24
+ min-height: 100vh;
25
+ padding: 16px (@s-content-margin + @s-toc-width) 50px @s-menu-width +
26
+ @s-content-margin;
27
+ &.home {
28
+ padding: 0px !important;
29
+ }
30
+ @media @mobile {
31
+ padding-top: 66px !important;
32
+ padding-left: 16px !important;
33
+ padding-right: 16px !important;
34
+ }
35
+
36
+ &[data-gapless="true"] {
37
+ padding-top: @s-nav-height !important;
38
+ padding-right: 0 !important;
39
+ padding-left: 0 !important;
40
+ padding-bottom: 0;
41
+
42
+ @media @mobile {
43
+ padding-top: @s-mobile-nav-height !important;
44
+ }
45
+ }
46
+
47
+ &[data-show-sidemenu="false"] {
48
+ padding-left: @s-content-margin;
49
+ }
50
+
51
+ &[data-show-slugs="false"] {
52
+ padding-right: @s-content-margin;
53
+ }
54
+
55
+ &[data-site-mode="true"] {
56
+ padding-top: @s-nav-height + 50px;
57
+
58
+ &[data-show-sidemenu="true"] {
59
+ padding-left: @s-site-menu-width + 50px;
60
+ }
61
+
62
+ &[data-show-slugs="true"] {
63
+ padding-right: @s-content-margin + @s-toc-width + 14;
64
+ }
65
+
66
+ .@{prefix}-layout-content > .markdown:first-child > *:first-child {
67
+ margin-top: 0;
68
+ }
69
+
70
+ .@{prefix}-layout-toc {
71
+ top: 114px;
72
+ max-height: calc(90vh - 144px);
73
+ }
74
+ }
75
+
76
+ &-hero {
77
+ margin: -50px -58px 0;
78
+ padding: 100px 0;
79
+ text-align: center;
80
+ background-color: #f5f6f8;
81
+
82
+ [data-prefers-color="dark"] & {
83
+ background-color: @c-light-bg-dark;
84
+ }
85
+
86
+ @media @mobile {
87
+ margin: -16px -16px 0;
88
+ padding: 48px 0;
89
+ }
90
+
91
+ img {
92
+ max-width: 100%;
93
+ max-height: 200px;
94
+ margin-bottom: 1rem;
95
+ }
96
+
97
+ h1 {
98
+ margin: 0 0 16px;
99
+ font-size: 48px;
100
+ font-weight: 600;
101
+ line-height: 56px;
102
+ color: #080e29;
103
+
104
+ [data-prefers-color="dark"] & {
105
+ color: @c-heading-dark;
106
+ }
107
+
108
+ + div {
109
+ margin: 16px 0 32px;
110
+ opacity: 0.78;
111
+
112
+ .markdown {
113
+ font-size: 16px;
114
+ }
115
+ }
116
+ }
117
+
118
+ button {
119
+ margin-right: 16px;
120
+ padding: 0 32px;
121
+ height: 44px;
122
+ color: @c-primary;
123
+ font-size: 16px;
124
+ background: transparent;
125
+ border: 1px solid @c-primary;
126
+ border-radius: 22px;
127
+ box-sizing: border-box;
128
+ cursor: pointer;
129
+ outline: none;
130
+ transition: all 0.3s;
131
+
132
+ &:hover {
133
+ opacity: 0.8;
134
+ }
135
+
136
+ &:active {
137
+ opacity: 0.9;
138
+ }
139
+ }
140
+
141
+ a:last-child button {
142
+ margin-right: 0;
143
+ color: #fff;
144
+ background: @c-primary;
145
+ }
146
+ }
147
+
148
+ &-features {
149
+ display: grid;
150
+ grid-template-columns: repeat(3, 1fr);
151
+ grid-column-gap: 96px;
152
+ grid-row-gap: 56px;
153
+ padding: 72px 0;
154
+
155
+ > dl {
156
+ flex: 1;
157
+ margin: 0;
158
+ text-align: center;
159
+ background: no-repeat center top / auto 48px;
160
+
161
+ &[style*="background-image"] {
162
+ padding-top: 64px;
163
+ }
164
+
165
+ dt {
166
+ margin-bottom: 12px;
167
+ font-size: 20px;
168
+ line-height: 1;
169
+ color: @c-heading;
170
+ [data-prefers-color="dark"] & {
171
+ color: @c-text-dark;
172
+ }
173
+ }
174
+
175
+ a {
176
+ transition-duration: none;
177
+ }
178
+
179
+ a dt {
180
+ color: @c-link;
181
+ transition: opacity 0.2s;
182
+ &:hover {
183
+ opacity: 0.7;
184
+ text-decoration: underline;
185
+ }
186
+
187
+ &:active {
188
+ opacity: 0.9;
189
+ }
190
+ }
191
+
192
+ dd {
193
+ margin: 0;
194
+
195
+ .markdown {
196
+ color: @c-secondary;
197
+ font-size: 14px;
198
+ line-height: 22px;
199
+
200
+ [data-prefers-color="dark"] & {
201
+ color: @c-secondary-dark;
202
+ }
203
+
204
+ > p:first-child {
205
+ margin-top: 0;
206
+ }
207
+
208
+ > p:last-child {
209
+ margin-bottom: 0;
210
+ }
211
+ }
212
+ }
213
+ }
214
+
215
+ @media @mobile {
216
+ display: block;
217
+ padding: 40px 0;
218
+
219
+ > dl {
220
+ text-align: left;
221
+ background-position: left top;
222
+
223
+ &[style*="background-image"] {
224
+ padding: 0 0 0 60px;
225
+ }
226
+
227
+ + dl {
228
+ margin-top: 32px;
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ &-features,
235
+ &-features + &-content,
236
+ &-hero + &-content {
237
+ margin-left: auto;
238
+ margin-right: auto;
239
+ max-width: 960px;
240
+ }
241
+
242
+ &-hero + &-content {
243
+ margin-top: 60px;
244
+ }
245
+
246
+ &-toc {
247
+ list-style: none;
248
+ position: fixed;
249
+ z-index: 10;
250
+ top: 50px;
251
+ right: 0;
252
+ width: @s-toc-width;
253
+ max-height: calc(90vh - 80px);
254
+ margin: 0;
255
+ padding: 0 24px 0 0;
256
+ background-color: #fff;
257
+ box-sizing: content-box;
258
+ overflow: auto;
259
+
260
+ [data-prefers-color="dark"] & {
261
+ background-color: @c-bg-dark;
262
+ }
263
+
264
+ @media @mobile {
265
+ display: none;
266
+ }
267
+
268
+ li {
269
+ position: relative;
270
+ margin: 0;
271
+ padding: 4px 0 4px 6px;
272
+ text-indent: 12px;
273
+ font-size: 13px;
274
+ line-height: 1.40625;
275
+ white-space: nowrap;
276
+ text-overflow: ellipsis;
277
+ overflow: hidden;
278
+
279
+ a {
280
+ color: @c-text;
281
+ text-decoration: none;
282
+
283
+ [data-prefers-color="dark"] & {
284
+ color: @c-text-dark;
285
+ }
286
+
287
+ &::before {
288
+ content: "";
289
+ position: absolute;
290
+ top: 0;
291
+ left: 0;
292
+ bottom: 0;
293
+ display: inline-block;
294
+ width: 2px;
295
+ background: @c-border;
296
+ }
297
+
298
+ &:hover {
299
+ color: lighten(@c-primary, 5%);
300
+
301
+ [data-prefers-color="dark"] & {
302
+ color: lighten(@c-primary-dark, 5%);
303
+ }
304
+ }
305
+
306
+ &:active {
307
+ color: lighten(@c-primary, 3%);
308
+
309
+ [data-prefers-color="dark"] & {
310
+ color: lighten(@c-primary-dark, 3%);
311
+ }
312
+ }
313
+
314
+ &.active {
315
+ color: @c-primary;
316
+
317
+ [data-prefers-color="dark"] & {
318
+ color: @c-primary-dark;
319
+ }
320
+
321
+ &::before {
322
+ background: @c-primary;
323
+
324
+ [data-prefers-color="dark"] & {
325
+ background: @c-primary-dark;
326
+ }
327
+ }
328
+ }
329
+ }
330
+ }
331
+ }
332
+
333
+ &-footer-meta {
334
+ margin-top: 40px;
335
+ padding-top: 24px;
336
+ display: flex;
337
+ color: @c-secondary;
338
+ font-size: 14px;
339
+ justify-content: space-between;
340
+ border-top: 1px solid @c-border;
341
+
342
+ [data-prefers-color="dark"] & {
343
+ color: @c-secondary-dark;
344
+ border-color: @c-border-dark;
345
+ }
346
+
347
+ @media only screen and (max-width: 960px) {
348
+ display: block;
349
+ }
350
+
351
+ > a {
352
+ margin-bottom: 4px;
353
+ display: block;
354
+ color: @c-primary;
355
+ transition: opacity 0.2s;
356
+ text-decoration: none;
357
+
358
+ [data-prefers-color="dark"] & {
359
+ color: @c-primary-dark;
360
+ }
361
+
362
+ &:hover {
363
+ opacity: 0.7;
364
+ text-decoration: underline;
365
+ }
366
+
367
+ &:active {
368
+ opacity: 0.9;
369
+ }
370
+ }
371
+
372
+ > span:last-child {
373
+ &::before {
374
+ content: attr(data-updated-text);
375
+ color: @c-primary;
376
+
377
+ [data-prefers-color="dark"] & {
378
+ color: @c-primary-dark;
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+
385
+ .__dumi-default-layout-footer {
386
+ margin: 72px 0 -32px;
387
+ padding-top: 24px;
388
+ border-top: 1px solid @c-border;
389
+ text-align: center;
390
+
391
+ [data-prefers-color="dark"] & {
392
+ border-color: @c-border-dark;
393
+ }
394
+
395
+ .markdown {
396
+ color: #b0b1ba;
397
+
398
+ [data-prefers-color="dark"] & {
399
+ color: rgba(255, 255, 255, 0.45);
400
+ }
401
+ }
402
+ }