├── test ├── fixtures │ └── normal │ │ ├── pages │ │ ├── index.css │ │ └── index.tsx │ │ ├── .umirc.ts │ │ └── test.ts └── index.e2e.ts ├── example ├── src │ ├── index.ts │ └── btn │ │ ├── index.vue │ │ └── button1.md ├── typings.d.ts ├── .dumi │ └── theme │ │ ├── global.d.ts │ │ ├── builtins │ │ ├── Alert.tsx │ │ ├── design │ │ │ ├── color │ │ │ │ ├── index.ts │ │ │ │ ├── Text.tsx │ │ │ │ ├── LargeBlock.tsx │ │ │ │ ├── SquareBlock.tsx │ │ │ │ ├── LongBlock.tsx │ │ │ │ ├── types.ts │ │ │ │ ├── CardBlock.tsx │ │ │ │ └── color.less │ │ │ ├── about.less │ │ │ ├── border │ │ │ │ └── border.less │ │ │ └── About.tsx │ │ ├── Shadow.tsx │ │ ├── Design.tsx │ │ ├── Tree.less │ │ ├── Previewer.tsx │ │ ├── Border.tsx │ │ ├── Alert.less │ │ ├── SourceCode.tsx │ │ ├── API.tsx │ │ ├── Comments.tsx │ │ ├── Tree.tsx │ │ ├── Previewer.less │ │ ├── SourceCode.less │ │ └── preview-default │ │ │ ├── use-code-sandbox.tsx │ │ │ ├── Previewer.tsx │ │ │ └── Previewer.less │ │ ├── components │ │ ├── Arrow.less │ │ ├── SlugList.tsx │ │ ├── Arrow.tsx │ │ ├── SlugList.less │ │ ├── LocaleSelect.less │ │ ├── Device.tsx │ │ ├── LocaleSelect.tsx │ │ ├── Dark.less │ │ ├── Device.less │ │ ├── SideMenu.tsx │ │ ├── Dark.tsx │ │ └── SideMenu.less │ │ ├── layout.tsx │ │ └── style │ │ ├── markdown.less │ │ ├── variables.less │ │ └── layout.less ├── README.md ├── tsconfig.json ├── assets │ └── h5.svg ├── .umirc.ts ├── vite.config.ts └── package.json ├── .prettierignore ├── .gitignore ├── typings.d.ts ├── .prettierrc ├── .editorconfig ├── src ├── cache.ts ├── additionalAssetsPlugin.ts ├── previewer.tsx ├── buildVue.ts └── index.ts ├── tsconfig.json ├── CONTRIBUTING.md ├── tsconfig-previewer.json ├── README.md └── package.json /test/fixtures/normal/pages/index.css: -------------------------------------------------------------------------------- 1 | 2 | .normal { 3 | background: #7F79F2; 4 | } 5 | -------------------------------------------------------------------------------- /example/src/index.ts: -------------------------------------------------------------------------------- 1 | import Button from './btn/index.vue'; 2 | 3 | export { Button }; 4 | -------------------------------------------------------------------------------- /test/fixtures/normal/.umirc.ts: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | plugins: [require.resolve('../../../lib')] 4 | } 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | 3 | 4 | # fixtures 5 | **/fixtures/** 6 | 7 | # templates 8 | **/templates/** 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .changelog 3 | .umi 4 | .umi-test 5 | .umi-production 6 | .DS_Store 7 | docs-dist 8 | dist 9 | lib -------------------------------------------------------------------------------- /test/index.e2e.ts: -------------------------------------------------------------------------------- 1 | const { join } = require('path'); 2 | 3 | require('test-umi-plugin')({ 4 | fixtures: join(__dirname, 'fixtures'), 5 | }); 6 | -------------------------------------------------------------------------------- /example/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; 2 | declare module '*.less'; 3 | declare module '*.js'; 4 | declare module '*.umd'; 5 | declare module '*.vue'; 6 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.js'; 2 | declare module '*.umd'; 3 | 4 | interface Global { 5 | assetsCache: string; 6 | } 7 | 8 | declare let foo: Global['assetsCache']; 9 | -------------------------------------------------------------------------------- /example/.dumi/theme/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'qrcode.react'; 2 | 3 | declare module '*.svg'; 4 | declare module '*.png'; 5 | declare module '*.jpeg'; 6 | declare module '*.jpg'; 7 | -------------------------------------------------------------------------------- /example/.dumi/theme/builtins/Alert.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './Alert.less'; 3 | 4 | export default (props: any) => ( 5 |
6 | ); 7 | -------------------------------------------------------------------------------- /example/.dumi/theme/builtins/design/color/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CardBlock'; 2 | export * from './LargeBlock'; 3 | export * from './LongBlock'; 4 | export * from './SquareBlock'; 5 | export * from './Text'; 6 | -------------------------------------------------------------------------------- /test/fixtures/normal/pages/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import styles from './index.css'; 4 | 5 | export default function() { 6 | return ( 7 |
27 | {showCopy && (
28 |
42 | )}
43 | | {texts.name} | 37 |{texts.description} | 38 |{texts.type} | 39 |{texts.default} | 40 |
|---|---|---|---|
| {row.identifier} | 46 |{row.description || '--'} | 47 |
48 | {row.type}
49 | |
50 |
51 |
52 | {row.default || (row.required && texts.required) || '--'}
53 |
54 | |
55 |
` 标签,则返回自定义的组件
75 | return {
76 | previewerProps: {
77 | sources: {
78 | _: { path: absVuePath },
79 | },
80 | // 该 demo 依赖的三方库
81 | dependencies: {},
82 | },
83 | // demo 渲染器的 props,会传递给上面注册的渲染器组件 即: previewer.js
84 | // rendererProps: { demoPath: '/vue/Foo/index.js' },
85 | rendererProps: {
86 | // ! 需要加 ‘/’ 修改
87 | demoPath: '/' + buildJsPath,
88 | },
89 | };
90 | },
91 | };
92 | },
93 | });
94 |
95 | api.chainWebpack((config) => {
96 | config.plugin('copy-process-assets-plugin').use(CopyPlugin);
97 | return config;
98 | });
99 |
100 | api.addTmpGenerateWatcherPaths(() => [
101 | join(api.paths.absSrcPath ?? '', '**/*.vue'),
102 | ]);
103 |
104 | api.onGenerateFiles(({ files }) => {
105 | if (files.length > 0 && files.some((file) => file.path.endsWith('.vue'))) {
106 | api.restartServer();
107 | }
108 | });
109 | };
110 |
--------------------------------------------------------------------------------
/example/.dumi/theme/components/Device.less:
--------------------------------------------------------------------------------
1 | @import (reference) '../style/variables.less';
2 |
3 | .adm-doc-device {
4 | display: flex;
5 | flex-direction: column;
6 | width: 375px;
7 | height: 100%;
8 | overflow: hidden;
9 | padding: 10px;
10 | background-color: #f2f2f2;
11 | border: 1px solid @c-border;
12 | border-radius: 15px;
13 |
14 | @media only screen and (max-width: 1440px) {
15 | width: 340px;
16 | }
17 | @media only screen and (max-width: 960px) {
18 | width: 300px;
19 | }
20 |
21 | &-action {
22 | display: flex;
23 | justify-content: space-between;
24 | align-items: center;
25 | padding: 0 22px;
26 | }
27 |
28 | &-action {
29 | height: 40px;
30 | background: #ffffff;
31 | border-top: 1px solid @c-border;
32 |
33 | > a,
34 | > button {
35 | padding: 0;
36 | width: 16px;
37 | height: 16px;
38 | box-sizing: content-box;
39 | border: 2px solid transparent;
40 | transition: opacity 0.2s, background 0.2s;
41 | outline: none;
42 | cursor: pointer;
43 |
44 | &:hover {
45 | opacity: 0.8;
46 | }
47 |
48 | &:active {
49 | opacity: 0.9;
50 | }
51 |
52 | &[role='refresh'] {
53 | background-position-x: -144px;
54 | }
55 |
56 | &[role='open-demo'] {
57 | background-position-x: -126px;
58 | }
59 |
60 | &[role='qrcode'] {
61 | position: relative;
62 | z-index: 1;
63 | background-position-x: -218px;
64 |
65 | > canvas {
66 | position: absolute;
67 | bottom: 120%;
68 | left: 50%;
69 | border: 4px solid #fff;
70 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
71 | box-sizing: content-box;
72 | transform: translateX(-50%) scale(0);
73 | transform-origin: center bottom;
74 | }
75 |
76 | &:hover > canvas,
77 | &:focus > canvas {
78 | transform: translateX(-50%) scale(1);
79 | }
80 | }
81 |
82 | &[role='qrcode-h5'] {
83 | background: url('../../../assets/h5.svg') no-repeat center !important;
84 | }
85 |
86 | &.__dumi-default-icon-mini {
87 | position: relative;
88 | z-index: 1;
89 | // background-position-x: -36px;
90 | background-size: 20px !important;
91 |
92 | > canvas {
93 | position: absolute;
94 | bottom: 120%;
95 | left: 50%;
96 | border: 4px solid #fff;
97 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
98 | box-sizing: content-box;
99 | transform: translateX(-50%) scale(0);
100 | transform-origin: center bottom;
101 | }
102 |
103 | &:hover > canvas,
104 | &:focus > canvas {
105 | transform: translateX(-50%) scale(1);
106 | }
107 |
108 | > .ant-image {
109 | position: absolute;
110 | bottom: 120%;
111 | left: 50%;
112 | border: 4px solid #fff;
113 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
114 | box-sizing: content-box;
115 | width: 120px;
116 | transform: translateX(-50%) scale(0);
117 | transform-origin: center bottom;
118 |
119 | .ant-image-img {
120 | width: 100%;
121 | height: 100%;
122 | }
123 | }
124 |
125 | &:hover > .ant-image,
126 | &:focus > .ant-image {
127 | transform: translateX(-50%) scale(1);
128 | }
129 | }
130 | }
131 | }
132 |
133 | > iframe {
134 | flex: 1;
135 | border: 0;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/example/.dumi/theme/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { IRouteComponentProps } from '@umijs/types';
2 | import { context, Link } from 'dumi/theme';
3 | import React, { useContext, useState } from 'react';
4 | import Dark from './components/Dark';
5 | import SideMenu from './components/SideMenu';
6 | import SlugList from './components/SlugList';
7 | import './style/layout.less';
8 |
9 | const Hero = (hero) => (
10 | <>
11 |
12 | {hero.image &&
}
13 | {hero.title}
14 |
15 | {hero.actions &&
16 | hero.actions.map((action) => (
17 |
18 |
19 |
20 | ))}
21 |
22 | >
23 | );
24 |
25 | const Features = (features) => (
26 |
27 | {features.map((feat) => (
28 |
32 | {feat.link ? (
33 |
34 | - {feat.title}
35 |
36 | ) : (
37 | - {feat.title}
38 | )}
39 |
40 |
41 | ))}
42 |
43 | );
44 |
45 | const Layout: React.FC = ({ children, location }) => {
46 | const {
47 | config: { mode, repository },
48 | meta,
49 | } = useContext(context);
50 | const { url: repoUrl, branch, platform } = repository;
51 | const [menuCollapsed, setMenuCollapsed] = useState(true);
52 | const [darkSwitch, setDarkSwitch] = useState(false);
53 | const isSiteMode = mode === 'site';
54 | const showHero = isSiteMode && meta.hero;
55 | const showFeatures = isSiteMode && meta.features;
56 | const showSideMenu =
57 | meta.sidemenu !== false && !showHero && !showFeatures && !meta.gapless;
58 | const showSlugs =
59 | !showHero &&
60 | !showFeatures &&
61 | Boolean(meta.slugs?.length) &&
62 | (meta.toc === 'content' || meta.toc === undefined) &&
63 | !meta.gapless;
64 |
65 | const updatedTimeIns = new Date(meta.updatedTime);
66 | const updatedTime: any = `${updatedTimeIns.toLocaleDateString([], {
67 | hour12: false,
68 | })} ${updatedTimeIns.toLocaleTimeString([], { hour12: false })}`;
69 | const repoPlatform =
70 | { github: 'GitHub', gitlab: 'GitLab' }[
71 | (repoUrl || '').match(/(github|gitlab)/)?.[1] || 'nothing'
72 | ] || platform;
73 |
74 | return (
75 | {
83 | setDarkSwitch(false);
84 | if (menuCollapsed) return;
85 | setMenuCollapsed(true);
86 | }}
87 | >
88 | }
90 | mobileMenuCollapsed={menuCollapsed}
91 | location={location}
92 | />
93 | {showSlugs && (
94 |
95 | )}
96 | {showHero && Hero(meta.hero)}
97 | {showFeatures && Features(meta.features)}
98 |
99 | {children}
100 | {!showHero && !showFeatures && meta.filePath && !meta.gapless && (
101 |
102 | {repoPlatform && (
103 |
104 | {`在 ${repoPlatform} 上编辑此页`}
105 |
106 | )}
107 | {updatedTime}
108 |
109 | )}
110 | {(showHero || showFeatures) && meta.footer && (
111 |
115 | )}
116 |
117 |
118 | );
119 | };
120 |
121 | export default Layout;
122 |
--------------------------------------------------------------------------------
/example/.dumi/theme/builtins/preview-default/use-code-sandbox.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import LZString from 'lz-string';
3 | import type { IPreviewerComponentProps } from 'dumi/theme';
4 |
5 | const CSB_API_ENDPOINT = 'https://codesandbox.io/api/v1/sandboxes/define';
6 |
7 | // ref: https://github.com/codesandbox/codesandbox-importers/blob/master/packages/import-utils/src/api/define.ts
8 | function serialize(data: Record) {
9 | return LZString.compressToBase64(JSON.stringify(data))
10 | .replace(/\+/g, '-') // Convert '+' to '-'
11 | .replace(/\//g, '_') // Convert '/' to '_'
12 | .replace(/=+$/, ''); // Remove ending '='
13 | }
14 |
15 | /**
16 | * get serialized data that use to submit to codesandbox.io
17 | * @param opts previewer props
18 | */
19 | function getCSBData(opts: IPreviewerComponentProps) {
20 | const isTSX = Boolean(opts.sources._.tsx);
21 | const ext = isTSX ? '.tsx' : '.jsx';
22 | const files: Record = {};
23 | const deps: Record = {};
24 | const CSSDeps = Object.values(opts.dependencies).filter((dep) => dep.css);
25 | const appFileName = `app${ext}`;
26 | const entryFileName = `index${ext}`;
27 |
28 | // generate dependencies
29 | Object.entries(opts.dependencies).forEach(([dep, { version }]) => {
30 | deps[dep] = version;
31 | });
32 |
33 | // add react-dom dependency
34 | if (!deps['react-dom']) {
35 | deps['react-dom'] = deps.react || 'latest';
36 | }
37 |
38 | // append sandbox.config.json
39 | files['sandbox.config.json'] = {
40 | content: JSON.stringify(
41 | {
42 | template: isTSX ? 'create-react-app-typescript' : 'create-react-app',
43 | },
44 | null,
45 | 2,
46 | ),
47 | };
48 |
49 | // append package.json
50 | files['package.json'] = {
51 | content: JSON.stringify(
52 | {
53 | name: opts.title,
54 | main: entryFileName,
55 | dependencies: deps,
56 | // add TypeScript dependency if required, must in devDeps to avoid csb compile error
57 | devDependencies: isTSX ? { typescript: '^3' } : {},
58 | },
59 | null,
60 | 2,
61 | ),
62 | };
63 |
64 | // append index.html
65 | files['index.html'] = {
66 | content: '',
67 | };
68 |
69 | // append entry file
70 | files[entryFileName] = {
71 | content: `/**
72 | * This is an auto-generated demo by dumi
73 | * if you think it is not working as expected,
74 | * please report the issue at
75 | * https://github.com/umijs/dumi/issues
76 | **/
77 |
78 | import React from 'react';
79 | import ReactDOM from 'react-dom';
80 | ${CSSDeps.map(({ css }) => `import '${css}';`).join('\n')}
81 | import App from './App';
82 |
83 | ReactDOM.render(
84 | ,
85 | document.getElementById('root'),
86 | );`,
87 | };
88 |
89 | // append other imported local files
90 | console.log(opts.sources);
91 | Object.entries(opts.sources).forEach(([filename, { tsx, jsx, content }]) => {
92 | // handle primary content
93 | files[filename === '_' ? appFileName : filename] = {
94 | content: tsx || jsx || content,
95 | };
96 | });
97 |
98 | return serialize({ files });
99 | }
100 |
101 | export function useCodeSandbox(
102 | opts: IPreviewerComponentProps | null,
103 | api: string = CSB_API_ENDPOINT,
104 | ) {
105 | const [handler, setHandler] = useState<(...args: any) => void | undefined>();
106 |
107 | useEffect(() => {
108 | if (opts) {
109 | const form = document.createElement('form');
110 | const data = getCSBData(opts);
111 |
112 | form.method = 'POST';
113 | form.target = '_blank';
114 | form.style.display = 'none';
115 | form.action = api;
116 | function addField(name: string, value: string) {
117 | const input = document.createElement('input');
118 | form.appendChild(input);
119 | input.name = name;
120 | input.value = value;
121 | }
122 | addField('parameters', data);
123 | addField(
124 | 'query',
125 | 'file=/app.tsx&resolutionWidth=375&resolutionHeight=700',
126 | );
127 |
128 | form.setAttribute('data-demo', opts.title || '');
129 |
130 | document.body.appendChild(form);
131 |
132 | setHandler(() => () => form.submit());
133 |
134 | return () => form.remove();
135 | }
136 | }, [opts]);
137 |
138 | return handler;
139 | }
140 |
--------------------------------------------------------------------------------
/example/.dumi/theme/builtins/design/About.tsx:
--------------------------------------------------------------------------------
1 | import { Avatar } from 'antd';
2 | import 'antd/es/avatar/style';
3 | import { CSSProperties } from 'react';
4 | import './about.less';
5 |
6 | const createStyle = (
7 | fontSize: CSSProperties['fontSize'],
8 | fontWeight: CSSProperties['fontWeight'],
9 | color: CSSProperties['color'],
10 | lineHeight: CSSProperties['lineHeight'],
11 | marginTop: CSSProperties['marginTop'],
12 | ): CSSProperties => ({
13 | // display: 'block',
14 | fontSize,
15 | fontWeight,
16 | color,
17 | marginTop,
18 | lineHeight: lineHeight + 'px',
19 | });
20 |
21 | type Contributor = {
22 | name: string;
23 | title: string;
24 | avatar: string;
25 | };
26 |
27 | const designers: Contributor[][] = [
28 | [
29 | {
30 | name: '夏天宇',
31 | title: '规范主理设计',
32 | avatar:
33 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/2361856c-31a8-4dfa-9d50-7418f0171e95.png',
34 | },
35 | {
36 | name: '张秋兰',
37 | title: '交互设计',
38 | avatar:
39 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/f9fb2a89-d18b-4d16-ad80-ee35d911be1c.png',
40 | },
41 | {
42 | name: '张帅',
43 | title: '视觉设计',
44 | avatar:
45 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/d6b11d5a-bec2-43b3-8805-b06e7cb5e76f.png',
46 | },
47 | {
48 | name: '夏洁',
49 | title: '交互设计',
50 | avatar:
51 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/28bfeb7f-e056-492a-92e1-e173b395642d.png',
52 | },
53 | {
54 | name: '辛磊磊',
55 | title: '视觉设计',
56 | avatar:
57 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/9ec5555b-3eae-4d92-b41e-4e208cf6c335.png',
58 | },
59 | {
60 | name: '杨秋晨',
61 | title: '视觉设计',
62 | avatar:
63 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/46a73bb9-4c5c-4a1e-b0a7-2589ffbff258.png',
64 | },
65 | ],
66 | [
67 | {
68 | name: '居东',
69 | title: '交互设计',
70 | avatar:
71 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/89a6fba1-cdbc-41d8-9674-8509639eb129.png',
72 | },
73 | {
74 | name: '臧文桃',
75 | title: '视觉设计',
76 | avatar:
77 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/6177e1fb-3ede-41af-8b22-d2291e8a15f1.png',
78 | },
79 | {
80 | name: '王晶晶',
81 | title: '视觉设计',
82 | avatar:
83 | 'https://imagecdn.ymm56.com/ymmfile/static/resource/b04d7b93-1cf4-4cd7-8e0e-fc7eb7d1e652.png',
84 | },
85 | ],
86 | ];
87 |
88 | /** 设计团队介绍 */
89 | export function About(): JSX.Element {
90 | return (
91 | <>
92 |
97 |
98 | 设计团队
99 | About DLC
100 |
101 | 满帮中台用户体验设计团队,简称DLC(Design,Love,Create),主要负责公司中后台B端
102 | / C端产品体验设计,保持用户体验的一致性,易用性及差异性。
103 |
104 |
105 | DLC秉承设计·友爱·创新的价值观点,致力为满帮集团用户体验进行赋能。
106 |
107 |
108 | {designers.map((persons, index) => (
109 |
110 | {persons.map((person, i) => (
111 |
112 |
120 | {person.name}
121 | {person.title}
122 |
123 | ))}
124 |
125 | ))}
126 |
127 | 开发团队
128 | 业务中台前端
129 | 业务中台前端用户中心组。
130 | 共建FTA Family前端研发工程化体系。
131 |
132 |
133 | >
134 | );
135 | }
136 |
137 | type PropsWithStringChildren = {
138 | children: string;
139 | };
140 |
141 | function Title(props: PropsWithStringChildren): JSX.Element {
142 | return (
143 |
144 |
149 | {props.children}
150 |
151 | );
152 | }
153 |
154 | function SubTitle(props: PropsWithStringChildren) {
155 | return (
156 | {props.children}
157 | );
158 | }
159 |
160 | function Text(props: PropsWithStringChildren) {
161 | return (
162 | {props.children}
163 | );
164 | }
165 |
--------------------------------------------------------------------------------
/example/.dumi/theme/style/markdown.less:
--------------------------------------------------------------------------------
1 | @import (reference) './variables.less';
2 |
3 | .markdown {
4 | color: @c-text;
5 | font-size: 15px;
6 | line-height: 1.60625;
7 |
8 | [data-prefers-color='dark'] & {
9 | color: @c-secondary-dark;
10 | }
11 |
12 | &:not(:first-child):empty {
13 | min-height: 32px;
14 | }
15 |
16 | > p:nth-child(1) {
17 | width: auto;
18 | }
19 |
20 | // titles
21 | h1,
22 | h2,
23 | h3,
24 | h4,
25 | h5,
26 | h6 {
27 | margin: 42px 0 16px;
28 | color: #141414;
29 | font-weight: 500;
30 | line-height: 1.40625;
31 | position: relative;
32 |
33 | [data-prefers-color='dark'] & {
34 | color: @c-heading-dark;
35 | }
36 |
37 | // anchor link
38 | &:hover > a[aria-hidden] {
39 | float: left;
40 | margin-left: -1.3em;
41 | width: 0.8em;
42 | padding-left: 0.5em;
43 | line-height: 1.15;
44 | box-sizing: border-box;
45 |
46 | @media @mobile {
47 | width: 14px;
48 | margin-left: -14px;
49 | }
50 |
51 | &::after {
52 | content: '#';
53 | display: inline-block;
54 | vertical-align: middle;
55 | width: 1em;
56 | }
57 |
58 | span {
59 | display: none;
60 | }
61 | }
62 |
63 | + h1,
64 | + h2,
65 | + h3,
66 | + h4,
67 | + h5,
68 | + h6 {
69 | margin-top: 16px;
70 | }
71 | }
72 |
73 | h1 {
74 | margin-top: 34px !important;
75 | margin-bottom: 16px;
76 | font-size: 30px;
77 | line-height: 45px;
78 | }
79 |
80 | h2 {
81 | margin-top: 48px !important;
82 | font-size: 24px;
83 | // padding-bottom: 6px;
84 | // border-bottom: 4px solid @c-border;
85 | }
86 |
87 | h3 {
88 | margin-top: 40px !important;
89 | font-size: 18px;
90 | line-height: 26px;
91 | }
92 |
93 | h4 {
94 | margin-top: 28px !important;
95 | font-size: 16px;
96 | color: #4c4c4c;
97 | }
98 |
99 | h5 {
100 | color: #4c4c4c;
101 | font-size: 15px;
102 | }
103 |
104 | h6 {
105 | color: #4c4c4c;
106 | font-size: 14px;
107 | }
108 |
109 | // paragraph
110 | p {
111 | margin: 8px 0;
112 | font-size: 14px;
113 | line-height: 22px;
114 | font-weight: 400;
115 | color: #4c4c4c;
116 | width: 912px;
117 | }
118 |
119 | // inline code
120 | *:not(pre) code {
121 | padding: 2px 5px;
122 | color: @c-text;
123 | background: @c-light-bg;
124 | border-radius: 2px;
125 |
126 | [data-prefers-color='dark'] & {
127 | color: #ff7875;
128 | background: @c-light-bg-dark;
129 | }
130 | }
131 |
132 | code {
133 | font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
134 | 'Liberation Mono', monospace;
135 | font-size: 14px;
136 | }
137 |
138 | // code block
139 | pre {
140 | font-size: 14px;
141 | background: @c-light-bg;
142 |
143 | &:not([class^='language-']) {
144 | padding: 1em;
145 | }
146 | }
147 |
148 | // horizontal line
149 | hr {
150 | margin: 16px 0;
151 | border: 0;
152 | border-top: 1px solid @c-border;
153 | }
154 |
155 | // blockquote
156 | blockquote {
157 | margin: 16px 0;
158 | padding: 0 24px;
159 | color: fadeout(@c-text, 30%);
160 | border-left: 4px solid @c-border;
161 | overflow: hidden;
162 |
163 | [data-prefers-color='dark'] & {
164 | color: fadeout(@c-text-dark, 30%);
165 | border-color: @c-border-dark;
166 | }
167 | }
168 |
169 | // list
170 | ul,
171 | ol {
172 | margin: 8px 0 8px 32px;
173 | padding: 0;
174 |
175 | li {
176 | color: #4c4c4c;
177 | font-size: 14px;
178 | line-height: 22px;
179 | margin-bottom: 4px;
180 |
181 | &::marker {
182 | // font-size: 12px;
183 | color: #4c4c4c;
184 | }
185 | }
186 | }
187 |
188 | // table
189 | table {
190 | width: 100%;
191 | border-collapse: collapse;
192 | border: 1px solid @c-border;
193 |
194 | [data-prefers-color='dark'] & {
195 | border: 1px solid #3b434b;
196 | }
197 |
198 | th,
199 | td {
200 | padding: 10px 24px;
201 | border: 1px solid @c-border;
202 |
203 | [data-prefers-color='dark'] & {
204 | border: 1px solid #3b434b;
205 | }
206 | }
207 |
208 | th {
209 | font-weight: 600;
210 | background: @c-light-bg;
211 |
212 | [data-prefers-color='dark'] & {
213 | background: @c-light-bg-dark;
214 | }
215 | }
216 |
217 | td:first-child {
218 | font-weight: 500;
219 | }
220 |
221 | a {
222 | svg {
223 | display: none;
224 | }
225 | }
226 | }
227 |
228 | // links
229 | a {
230 | color: @c-link;
231 | text-decoration: none;
232 | transition: opacity 0.2s;
233 | outline: none;
234 |
235 | [data-prefers-color='dark'] & {
236 | color: @c-primary-dark;
237 | }
238 |
239 | &:hover {
240 | opacity: 0.7;
241 | text-decoration: underline;
242 | }
243 |
244 | &:active {
245 | opacity: 0.9;
246 | }
247 | }
248 |
249 | // images
250 | img {
251 | max-width: 100%;
252 | }
253 |
254 | p + img {
255 | margin-top: 20px;
256 | }
257 | }
258 |
259 | .@{prefix} {
260 | &-external-link-icon {
261 | vertical-align: -0.155em;
262 | margin-left: 2px;
263 | }
264 | }
265 |
266 | // For demo
267 | [data-prefers-color='dark'] {
268 | h1,
269 | h2,
270 | h3,
271 | h4 {
272 | color: @c-heading-dark;
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/example/.dumi/theme/builtins/design/color/color.less:
--------------------------------------------------------------------------------
1 | // @platform-primary-blue: #1f5de9;
2 | // @platform-primary-dark: #091739;
3 | // @platform-basic-blue-1: #e8eefc;
4 | // @platform-basic-blue-2: #d2dffb;
5 | // @platform-basic-blue-3: #BBCEF8;
6 | // @platform-basic-blue-4: #8FAEF4;
7 | // @platform-basic-blue-5: #e8eefc;
8 | // @platform-basic-blue-6: #e8eefc;
9 | // @platform-basic-blue-7: #e8eefc;
10 | // @platform-basic-blue-8: #e8eefc;
11 | // @platform-basic-blue-9: #e8eefc;
12 | // @platform-basic-blue-10: #e8eefc;
13 | @prefix: __design-color;
14 |
15 | .@{prefix}-box-large {
16 | margin-top: 18px;
17 | width: 448px;
18 | height: 96px;
19 | display: inline-block;
20 | box-sizing: border-box;
21 | padding-left: 28px;
22 | border-radius: 4px;
23 | color: #fff;
24 | cursor: pointer;
25 |
26 | &__title{
27 | margin-top: 20px;
28 | font-size: 18px;
29 | line-height: 26px;
30 | font-weight: 500;
31 | display: block;
32 | }
33 |
34 | &__text{
35 | margin-top: 8px;
36 | font-size: 14px;
37 | line-height: 22px;
38 | font-weight: 400;
39 | display: block;
40 | }
41 |
42 | + .@{prefix}-box-large {
43 | margin-left: 16px;
44 | }
45 | }
46 |
47 | .@{prefix}-box-large--medium {
48 | width: 274px;
49 |
50 | + .@{prefix}-box-large--medium {
51 | margin-left: 42px;
52 | }
53 | }
54 |
55 | .@{prefix}-box-square-container{
56 | display: flex;
57 | flex-direction: row;
58 | justify-content: flex-start;
59 | align-items: flex-end;
60 | height: 116px;
61 | width: fit-content;
62 | &:hover {
63 | .@{prefix}-box-square__title{
64 | transform: translateY(-14px);
65 | }
66 |
67 | .@{prefix}-box-square__text{
68 | opacity: 1;
69 | transform: translateY(0px);
70 | }
71 | }
72 |
73 | + .@{prefix}-box-square-container{
74 | margin-top: 10px;
75 | }
76 | }
77 |
78 | .@{prefix}-box-square{
79 | box-sizing: border-box;
80 | width: 91px;
81 | height: 98px;
82 | display: block;
83 | cursor: pointer;
84 | color: #fff;
85 | padding-top: 36px;
86 | padding-left: 12px;
87 | overflow: hidden;
88 | transition: height 0.2s;
89 | position: relative;
90 |
91 | &:hover{
92 | height: 116px;
93 | border-radius: 4px 4px 0 0;
94 | }
95 |
96 | &__title{
97 | font-size: 18px;
98 | font-weight: 400;
99 | line-height: 26px;
100 | display: block;
101 | transition: 0.2s;
102 | }
103 |
104 | &__text{
105 | // opacity: 0;
106 | transition: 0.3s;
107 | font-size: 12px;
108 | font-weight: 400;
109 | line-height: 20px;
110 | opacity: 0;
111 | position: absolute;
112 | bottom: 8px;
113 | transform: translateY(14px);
114 | }
115 | }
116 |
117 |
118 | .@{prefix}-box-long{
119 | width: 274px;
120 | height: 48px;
121 | display: flex;
122 | flex-direction: row;
123 | justify-content: space-between;
124 | transition: width 0.2s;
125 | line-height: 48px;
126 | box-sizing: border-box;
127 | padding: 0 12px;
128 | font-weight: 400;
129 | font-size: 16px;
130 | cursor: pointer;
131 | color: #fff;
132 |
133 | &:hover{
134 | width: 282px;
135 | border-radius: 0 8px 8px 0;
136 | }
137 |
138 | &__text{
139 | opacity: 0;
140 | transition: all 0.3s;
141 | transform: translateX(10px);
142 | font-weight: 400;
143 | }
144 | }
145 |
146 |
147 | .@{prefix}-box-long-container{
148 | width: 282px;
149 | height: 48px;
150 | display: inline-block;
151 | transition: width 0.2s;
152 |
153 | &__title{
154 | display: block;
155 | margin-top: 20px;
156 | margin-bottom: 16px;
157 | font-size: 16px;
158 | font-weight: 500;
159 | text-align: center;
160 | }
161 |
162 | &:hover{
163 | .@{prefix}-box-long__text{
164 | opacity: 1;
165 | transform: translateX(0);
166 | }
167 | }
168 |
169 | + .@{prefix}-box-long-container{
170 | margin-left: 34px;
171 | }
172 | }
173 |
174 |
175 | .@{prefix}-box-card{
176 | display: inline-block;
177 | width: 274px;
178 | height: 76px;
179 | box-sizing: border-box;
180 | padding: 12px 16px;
181 | border-radius: 4px;
182 | color: #fff;
183 | overflow: hidden;
184 | cursor: pointer;
185 | position: relative;
186 |
187 | &__title{
188 | font-size: 18px;
189 | line-height: 26px;
190 | font-weight: 400px;
191 | white-space: nowrap;
192 | }
193 |
194 | &__text{
195 | margin-top: 4px;
196 | line-height: 22px;
197 | font-weight: 400;
198 | font-size: 14px;
199 | display: flex;
200 | position: relative;
201 | z-index: 1;
202 | justify-content: space-between;
203 | }
204 |
205 | + .@{prefix}-box-card{
206 | margin-left: 42px;
207 | }
208 |
209 | &:nth-of-type(3n+1){
210 | margin-left: 0;
211 | }
212 |
213 | &-extra-bg{
214 | position: absolute;
215 | width: 98px;
216 | top: 0;
217 | bottom: 0;
218 | right: 0;
219 | }
220 | }
221 |
222 |
223 | .flex-row-reverse{
224 | flex-direction: row-reverse;
225 | pointer-events: none;
226 | }
227 |
228 | .__design-link{
229 | position: relative;
230 | &::after{
231 | content: '';
232 | position: relative;
233 | top:2px;
234 | width: 15px;
235 | height: 15px;
236 | display: inline-block;
237 | background-image: url('data:image/svg+xml;utf8,');
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/example/.dumi/theme/builtins/preview-default/Previewer.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext, useRef } from 'react';
2 | import Tabs, { TabPane } from 'rc-tabs';
3 | // @ts-ignore
4 | import { history } from 'dumi';
5 | import type { IPreviewerComponentProps } from 'dumi/theme';
6 | import {
7 | context,
8 | // useRiddle,
9 | useMotions,
10 | useCopy,
11 | useLocaleProps,
12 | useTSPlaygroundUrl,
13 | Link,
14 | AnchorLink,
15 | usePrefersColor,
16 | } from 'dumi/theme';
17 | // import { useCodeSandbox } from './use-code-sandbox'
18 | import type { ICodeBlockProps } from '../SourceCode';
19 | import SourceCode from '../SourceCode';
20 | import './Previewer.less';
21 |
22 | export interface IPreviewerProps extends IPreviewerComponentProps {
23 | /**
24 | * enable transform to change CSS containing block for demo
25 | */
26 | transform?: boolean;
27 | /**
28 | * modify background for demo area
29 | */
30 | background?: string;
31 | /**
32 | * configurations for action button
33 | */
34 | hideActions?: ('CSB' | 'RIDDLE')[];
35 | /**
36 | * replace builtin demo url
37 | */
38 | demoUrl?: string;
39 | }
40 |
41 | /**
42 | * get source code type for file
43 | * @param file file path
44 | * @param source file source object
45 | */
46 | function getSourceType(
47 | file: string,
48 | source: IPreviewerComponentProps['sources']['_'],
49 | ) {
50 | // use file extension as source type first
51 | let type = file.match(/\.(\w+)$/)?.[1];
52 |
53 | if (!type) {
54 | type = source.tsx ? 'tsx' : 'jsx';
55 | }
56 |
57 | return type as ICodeBlockProps['lang'];
58 | }
59 |
60 | const Previewer: React.FC = (oProps) => {
61 | const demoRef = useRef(null);
62 | const { locale } = useContext(context);
63 | const props = useLocaleProps(locale, oProps);
64 | const isActive = history?.location.hash === `#${props.identifier}`;
65 | const isSingleFile = Object.keys(props.sources).length === 1;
66 | // const openCSB = useCodeSandbox(
67 | // props.hideActions?.includes('CSB') ? null : props
68 | // )
69 | // const openRiddle = useRiddle(
70 | // props.hideActions?.includes('RIDDLE') ? null : props
71 | // )
72 | const [execMotions, isMotionRunning] = useMotions(
73 | props.motions || [],
74 | demoRef.current,
75 | );
76 | const [copyCode, copyStatus] = useCopy();
77 | const [currentFile, setCurrentFile] = useState('_');
78 | const [sourceType, setSourceType] = useState(
79 | getSourceType(currentFile, props.sources[currentFile]),
80 | );
81 | const currentFileCode =
82 | props.sources[currentFile][sourceType] ||
83 | props.sources[currentFile].content;
84 | const playgroundUrl = useTSPlaygroundUrl(locale, currentFileCode);
85 | const [color] = usePrefersColor();
86 |
87 | function handleFileChange(filename: string) {
88 | setCurrentFile(filename);
89 | setSourceType(getSourceType(filename, props.sources[filename]));
90 | }
91 |
92 | return (
93 |
105 |
106 | {props.title && (
107 | {props.title}
108 | )}
109 | {props.description && (
110 |
111 | )}
112 |
113 |
114 | {props.debug && Debug Only}
115 | {/*{openCSB && (*/}
116 | {/* */}
122 | {/*)}*/}
123 | {/*{openRiddle && (*/}
124 | {/* */}
130 | {/*)}*/}
131 | {props.motions && (
132 |
159 |
160 | {!isSingleFile && (
161 |
168 | {Object.keys(props.sources).map((filename) => (
169 |
180 | ))}
181 |
182 | )}
183 |
184 |
189 |
190 |
191 |
192 | );
193 | };
194 |
195 | export default Previewer;
196 |
--------------------------------------------------------------------------------
/example/.dumi/theme/components/SideMenu.tsx:
--------------------------------------------------------------------------------
1 | import { IMenuItem } from '@umijs/preset-dumi/lib/routes/getMenuFromRoutes';
2 | import { context, Link, NavLink } from 'dumi/theme';
3 | import type { FC } from 'react';
4 | import React, { useContext, useEffect, useRef, useState } from 'react';
5 | import { Arrow } from './Arrow';
6 | import LocaleSelect from './LocaleSelect';
7 | import './SideMenu.less';
8 | import SlugList from './SlugList';
9 |
10 | interface MenuItem extends IMenuItem {
11 | unfolded: boolean;
12 | }
13 | interface INavbarProps {
14 | mobileMenuCollapsed: boolean;
15 | location: any;
16 | darkPrefix?: React.ReactNode;
17 | }
18 |
19 | const getStatefulMenu = (rawMenu: IMenuItem[]) =>
20 | rawMenu.map((menuItem) => ({ ...menuItem, unfolded: true }));
21 |
22 | const SideMenu: FC = ({
23 | mobileMenuCollapsed,
24 | location,
25 | darkPrefix,
26 | }) => {
27 | const {
28 | config: {
29 | logo,
30 | title,
31 | description,
32 | mode,
33 | repository: { url: repoUrl },
34 | },
35 | menu: rawMenu,
36 | nav: navItems,
37 | base,
38 | meta,
39 | } = useContext(context);
40 |
41 | const [menu, toggleMenu] = useState(getStatefulMenu(rawMenu));
42 | const ref = useRef(false);
43 |
44 | useEffect(() => {
45 | ref.current = true;
46 | });
47 |
48 | useEffect(() => {
49 | ref.current && toggleMenu(getStatefulMenu(rawMenu));
50 | }, [rawMenu]);
51 |
52 | // console.log('rawMenu', rawMenu)
53 |
54 | const isHiddenMenus =
55 | Boolean((meta.hero || meta.features || meta.gapless) && mode === 'site') ||
56 | meta.sidemenu === false ||
57 | undefined;
58 |
59 | function onMenuClick(e: MouseEvent, item: MenuItem): any {
60 | if (item.children?.length) {
61 | e.preventDefault();
62 | item.unfolded = !item.unfolded;
63 | toggleMenu([...menu]);
64 | }
65 | }
66 |
67 | return (
68 |
74 |
75 |
76 |
83 | {title}
84 | {description}
85 | {/* github star badge */}
86 | {/github\.com/.test(repoUrl) && mode === 'doc' && (
87 |
88 |
94 |
95 | )}
96 |
97 | {/* mobile nav list */}
98 |
99 | {!!navItems.length && (
100 |
101 | {navItems.map((nav) => {
102 | const child = Boolean(nav.children?.length) && (
103 |
104 | {nav.children.map((item) => (
105 | -
106 |
{item.title}
107 |
108 | ))}
109 |
110 | );
111 |
112 | return (
113 | -
114 | {nav.path ? (
115 |
{nav.title}
116 | ) : (
117 | nav.title
118 | )}
119 | {child}
120 |
121 | );
122 | })}
123 |
124 | )}
125 | {/* site mode locale select */}
126 |
127 | {darkPrefix}
128 |
129 | {/* menu list */}
130 |
131 | {!isHiddenMenus &&
132 | menu.map((item) => {
133 | // always use meta from routes to reduce menu data size
134 | const hasSlugs = Boolean(meta.slugs?.length);
135 | const hasChildren =
136 | item.children && Boolean(item.children.length);
137 | const show1LevelSlugs =
138 | meta.toc === 'menu' &&
139 | !hasChildren &&
140 | hasSlugs &&
141 | item.path === location.pathname.replace(/([^^])\/$/, '$1');
142 | const menuPaths = hasChildren
143 | ? item.children.map((i) => i.path)
144 | : [
145 | item.path,
146 | // handle menu group which has no index route and no valid children
147 | location.pathname.startsWith(`${item.path}/`) &&
148 | meta.title === item.title
149 | ? location.pathname
150 | : null,
151 | ];
152 |
153 | return (
154 | -
155 |
menuPaths.includes(location.pathname)}
160 | onClick={(e) => onMenuClick(e, item)}
161 | >
162 | {item.title}
163 | {item.children?.length ? (
164 |
165 | ) : null}
166 | {/* down={menuPaths.includes(location.pathname)} */}
167 |
168 | {/* group children */}
169 | {Boolean(item.children && item.children.length) && (
170 |
171 | {item.unfolded
172 | ? item.children.map((child) => (
173 | -
181 |
182 | {child.title}
183 |
184 | {/* group children slugs */}
185 | {Boolean(
186 | meta.toc === 'menu' &&
187 | typeof window !== 'undefined' &&
188 | child.path === location.pathname &&
189 | hasSlugs,
190 | ) && }
191 |
192 | ))
193 | : null}
194 |
195 | )}
196 | {/* group slugs */}
197 | {show1LevelSlugs && }
198 |
199 | );
200 | })}
201 |
202 |
203 |
204 | );
205 | };
206 |
207 | export default SideMenu;
208 |
--------------------------------------------------------------------------------
/example/.dumi/theme/components/Dark.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from 'react';
2 | import React from 'react';
3 | import { usePrefersColor } from 'dumi/theme';
4 | import './Dark.less';
5 |
6 | interface darkProps {
7 | darkSwitch: boolean;
8 | isSideMenu: boolean;
9 | onDarkSwitchClick?: (ev) => void;
10 | }
11 |
12 | const Dark: FC = ({ darkSwitch, onDarkSwitchClick, isSideMenu }) => {
13 | const allState = ['dark', 'light', 'auto'];
14 | const [color, setColor] = usePrefersColor();
15 | const prefersColor = color;
16 |
17 | const sunSvg = (
18 |
31 | );
32 | const moonSvg = (
33 |
46 | );
47 | const autoSvg = (
48 |
61 | );
62 |
63 | const list = allState.filter((state) => state !== prefersColor);
64 |
65 | const changeColor = (ev, toColor) => {
66 | if (!isSideMenu && onDarkSwitchClick) {
67 | onDarkSwitchClick(ev);
68 | }
69 | if (toColor === prefersColor) return;
70 | setColor(toColor);
71 | };
72 |
73 | const getSvg = (baseColor) => {
74 | switch (baseColor) {
75 | case 'dark':
76 | return (
77 | changeColor(ev, baseColor)}
81 | className={`__dumi-default-dark-moon ${
82 | baseColor === prefersColor
83 | ? '__dumi-default-dark-switch-active'
84 | : ''
85 | }`}
86 | >
87 | {moonSvg}
88 |
89 | );
90 | case 'light':
91 | return (
92 | changeColor(ev, baseColor)}
96 | className={`__dumi-default-dark-sun ${
97 | baseColor === prefersColor
98 | ? '__dumi-default-dark-switch-active'
99 | : ''
100 | }`}
101 | >
102 | {sunSvg}
103 |
104 | );
105 | case 'auto':
106 | return (
107 | changeColor(ev, baseColor)}
111 | className={`__dumi-default-dark-auto ${
112 | baseColor === prefersColor
113 | ? '__dumi-default-dark-switch-active'
114 | : ''
115 | }`}
116 | >
117 | {autoSvg}
118 |
119 | );
120 | default:
121 | }
122 | };
123 |
124 | return (
125 |
126 |
131 | {isSideMenu
132 | ? allState.map((item) => getSvg(item))
133 | : getSvg(prefersColor)}
134 |
135 | {!isSideMenu && darkSwitch && (
136 |
137 | {list.map((item) => getSvg(item))}
138 |
139 | )}
140 |
141 | );
142 | };
143 |
144 | export default Dark;
145 |
--------------------------------------------------------------------------------
/example/.dumi/theme/style/variables.less:
--------------------------------------------------------------------------------
1 | /* 颜色表 */
2 | @c-primary: #1f5de9;
3 | @c-heading: #454d64;
4 | @c-text: #454d64;
5 | @c-secondary: #717484;
6 | @c-weak: #a8a8ad;
7 | @c-link: @c-primary;
8 | @c-border: #ebedf1;
9 | @c-btn-border: #dadadf;
10 | @c-light-bg: #f5f7fa;
11 |
12 | /* 尺寸表 */
13 | @s-nav-height: 64px;
14 | @s-mobile-nav-height: 50px;
15 | @s-menu-width: 260px;
16 | @s-site-menu-width: 300px;
17 | @s-menu-mobile-width: 240px;
18 | @s-content-margin: 58px;
19 |
20 | @img-logo: 'data:image/png;base64,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';
21 | @prefix: __dumi-default;
22 | @mobile: ~'only screen and (max-width: 767px)';
23 | @desktop: ~'only screen and (min-width: 768px)';
24 | @icons: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcwAAAA8CAMAAADc4HoZAAABFFBMVEUAAABGT2VGTmZaYXpCvGtIUGg3tGBGTmU3s2A/tmFKUGxFTmRFTWVQWmxFTWRJUGZFTWRGTmRLWWpFTWRGTmVGTmVLVG1FTmRGTWVHTmVFTWRHUGdFTWRGT2ZFTWVGTmU6t2I7xHA3tF9GTWRIT2dFTmRGTmVFTWQ3s2BFTWRGTmVGTmZKUmVFTWRFTWRGTWRGTmVcXHxFTmVFTmVGTmVFTWRIUGdGTWVNU3FGT2ZGTmVHTmVFTWRFTWVFTmVITWRHUGZFTWVFTmRGTmZGTmVFTWVLU2g4tF83tGBFTWQ3s1/LzdT09faoq7Zwdoieoq58gpLj5OeCh5fq6+2/wsmTmKWQlKJfZnpIUGfU1tu0t8BOVWynlyFSAAAASXRSTlMAkoAHEkDQ/dgYFuf0C8gj+KQQmm1oEuyNWNg53kSXfCYI5tEtzq7ivbOgTBy924R1BfHUibcpYw1JcU7v+7E3Nav6XVPDGraPqQuKawAACh1JREFUeNrsm2lT6kgUhg9QFFUkgWDYZfnAVsi+KQJeQdGqt1xm7jZ3lv//PyYdhe7QWQw1zP0w83xQsY9Um4fTp7vToeBczmaX5MN5rXZO/+NGJzGuLejnkw3dADehLHkQyceAWD5C/0my9XqWPLlCK9WHQScirUMk18g7J9ZosYLFajFyT8siLIpuyQkHKBDw4NgYsnDr0Xybaii60rjYzsmdbrqnw0TvpbvkhjYuzinygDXJXLewR2/O/f73w1cWCUj0LkmiU8SeYsc9LXMZIJNjyXkqmbWQCzV8ICawzLO8jh3q4IyciYfugMnMMGYT4C4UJ2fOEbbSc0EyrVp4T/7u4kiZs6jANjwBxkupWMLG7NIlLZvxM+As3nRLTsD/N5xtekmHIEQuhBAoBuREtmaXWVgB41Smc97JbMZA7pqcKKgopbu7FC1BLUgD22MyeVnPWD0bonLLeCQRhIkzQNnz6gHiK0HmxeF4qkKPSsVygh2x2q50SmlZIGIyiQo8OY+XGVExOLVM2WVRbAkDSma0609aQaxKMgOo6YjQ77Tc8d3laxPRxS7R564yI8WSFkymgUNuJqlbomQLisblpnNAf0nrB1j06rTsA7n0SE5L2skkh+Qcm2CP3vGV2QHWp5Ypu4wDosumRpyzNrBwcFmqk4166dBmrFgJ5aeDKhvSklWLBLokgBhcaF3bFL59lV45EQsR3QLVfV0uAuNFhEy2JaC/fcveMVC8ltKSy3RITtjRl34yDSj0r8rMNkyXQksByJOdCmIdslNAKS7V0BIKdpmGQ1+S9slA2IVa60My89HoRKyZ5XTD8rhBX1DwEN85Gw53drIsT6W0FGTKyYmYtgcI427rI1NB5bQyZZeTuNCSXaEpBX2Cotm9qWqdJOqqajN85y8zTC6E8SGZGalmjja4uaQC0OUy0UzSAckNTKS0FGTKyYmYbfQP42brcFGr/X5+N/XDNVG+36+eXCZ3Kbbkbd644cHBW6bpnTlx0vZO6PL0NI/LE8uksxtUqQ7sUgpoAfp0TgLzqQ4oAFkkeFqadCwFxJMz4SKTwogVpIsaBtrv+qdQzZ8ibSB8cpncJW+Z68iQTBq5EXG6N6UIvTHVr2hPpHTX9ZY5Rf0ImfIEyEMmFWHQmk89gHKhBShCP68UoHVfFtZnqV0yahWYVLTdJyMFwE0ms8l+cnFJfWyIuM2TyuQuecsW4xFJMMcd0S1PzBRQGdkaOKosc4DKYn1amSM2rb4H5lwmaVUVqEXJItoA1LBGokwoHWKUS0AqBZTKxOgocJXJl74uLi+Be+I2TyuTu+SkkCInmrZS3kNXkMnnF9RFT5Qpv1cVJkYwmRzxlavMIRClmTgBYmIeU1bpfC+WqS6RKPOKOTxjaWlZXSpWcp4xq1dBZIaBTxH+v95kySLyCQifSCZ3WYuTnYbDKNvpnVMVPUpulvSGPiFRJlq39M5E95bZNYZXD1icTOaoHophQ1EgLcpkrBOsdLJimbglsstMzpnGxZtSE0vjwlKalGVyuEzZJSXQIxJs2kVVDJOLC6NKVK/0jLWrzEzPYB/G6SxV9pJZq2XlyXSHDqlAjW5XjaSCzfsfom2XiX3hbEN4y3G/r64agy7ZifRrXOa6wmMkmT7YZfbwTuPsUoGi2WUyWOlkxZJIkskGWD7YkpWcb4NtAJlVm8tHYEF2m6KofW/pXLe2INxkTs0QeszB5N5rmJVckg55RzI+gTpEToFySRZ1GAcy94lg8AmOtmtSh2QnNebrTCnmWJlzHRatYeRegbomWSZpU2Cq0UdkdgLKlBMzA2EZNpJkmnmZQ9EwqtSDMijqGU+ZeeSqD/pCkikhZ6ZsU8cNc+kuc3EoU0tgT4hE5q3ELgZCTIBh1nECVAWm0fMs3daA8bV4wUN7f0nhAkdCgkztnx9mZ5iQ+zDLSLxdx5bZFK+Tp8wZDNLqFEAmr5myzRh36TfM8obXX01eAeyaqT4LhYvouMccLzNSRIlZmwGzLnGskVWWWWhBmgBZlXPpOwHieEyA5joGsktZJvumXBN5yzSQW/puGhy2XGBDTjZbWDGXLhMgRZ4ArQF8f375+vnP5y/gFawKYHzlEuOzNPGRSVFgSkT37LcCYDSidpnnCUCQaTmUlyaW1QAyxaVJAVjLLmWZViQSUW+Z9RsWE1DmFuMIOZAddIMtTSrA69PTy/dfXr798QMo7GVmzjXyijleJqVwV7d6t4rL2+NlUeY5GE6bBnNp0yCQTG4zBYVIWGa6y6SMCmDoKZOuFQDVYDI1FWlyJtimQR8/vv76/O319enrl89/wdjLZEnsFeO/nee6NImv8MAW6zpSssylKLMMxrHbebJM2eZohYrkUpL5HhKfqohdesokbZED1oFk0gC5M/Kje+e7nafi9fnl8y8mn1+ef6AtyXSNOV4mZd4q7wAo+8s8fqOdA7httJd3Hwlpo12WeUZUv0PaVWaCuTSVqxgGkznPYTYiP/w32lfAr0+/fAF+++2PV6ApyvSK8ZcpL034LbAWclm2kEU/4i8z8C0wf5mcENQIcTxkJnuTOMV1ZBxkniceqYkmnRmtR4ooQWVSJwbD16b/LbAGTEffnvD705NpC3lZphxzrEwbYVZg2Dd+c9pZZpCb08FltrChj8nsAGpiDD0py9RWUIvAkFWOuwcFuA0ok4bALCuKswQFvTk9gMnL85fvz99h0ttsmp8+tdt9LlOKuXC5OS1fOa42c3jUUrW6sIGetB8bwVCUuUCgYyPBZa6B+w/KpHsVgOq4adBhTQ8RonIOwE3ACRBjGMNquJ/ODcc9YgQ8NtJVYfLn568vMImtVrmcoiitVmLuFON6bMRfpiOPY/QOD3T16juZ9V6AA10+MhkkE0Ys6yuzXFgTY35fzTw6L03iV8MOMbTt8CpJwWVa02C9PSyUt8NPKtBK0hEHuoYAzAH0G0z0c+IEjIGALDMfdeYCuD88ahmrxJnMuBE77qilLHPkKnOZlhLz9CcNnFu06hg7lLBGRx21DMHkr9+ZJ6HFKya4TC9atIOf6woBIX6SK8AhaM8D0D//ELR3ryLXlV4xV0qElhEiz0PQbcNoOx+CvlJgIT6H4xUTHCMGd1LE4aVTKpa+jyf4y/z5jycE7lXwxxO0gtFu5svECRrz/4NDf7dvxjYQwzAMdGEE8RaWq2ySh/cf6OGoyQCRANLkBHenWqnzxyGU6aVP0zRN0zTtmzUru64ZWZ923kC0n6tT9WnnnL+y5R51pj6L9ahlx7k6UR8kVt2Sh1W35GHVLXlYdUseVt2Sh1W3fK8aDmuSOmyfelyGwpqkjtvnnvMyENYcdeA+fSxaDNYUdeg+TovBmqAO3sdpMVjD1eH7OC0Ga7A6QR+nxWANVafo47QYrIHqJH0eWhDWMHWaPosWhTVInahPHzisIepUffrAYQ1QJ+vTgVgD1IP6/AHM0QJdY511NAAAAABJRU5ErkJggg==';
25 |
26 | .@{prefix}-icon {
27 | background: url(@icons) no-repeat ~'0 0/230px auto';
28 | }
29 |
30 | /* 颜色表 - dark */
31 | @c-bg-dark: #141414;
32 | @c-light-bg-dark: rgba(255, 255, 255, 0.08);
33 | @c-primary-dark: #7395f7;
34 | @c-heading-dark: rgba(255, 255, 255, 0.85);
35 | @c-text-dark: rgba(255, 255, 255, 0.85);
36 | @c-secondary-dark: rgba(255, 255, 255, 0.65);
37 | @c-border-dark: #6b6c6d;
38 | @c-btn-border-dark: #464646;
39 |
40 | /* 响应式断点 */
41 | @v-device-show: ~'only screen and (min-width: 961px)';
42 | @v-device-hide: ~'only screen and (max-width: 960px)';
43 |
44 | /* 移动设备尺寸 */
45 | @s-device-gap-top: 36px;
46 | @s-device-border-width: 14px;
47 | @s-device-shell-width: @s-device-border-width + 2px;
48 | @s-device-width: 320px;
49 | @s-device-ratio: 19.5 / 9;
50 |
51 | @prefix: ~'__dumi-default';
52 |
--------------------------------------------------------------------------------
/example/.dumi/theme/builtins/preview-default/Previewer.less:
--------------------------------------------------------------------------------
1 | @import (reference) '../../style/variables.less';
2 |
3 | .@{prefix}-previewer {
4 | background-color: #fff;
5 | border: 1px solid @c-border;
6 | border-radius: 1px;
7 |
8 | [data-prefers-color='dark'] & {
9 | background-color: @c-bg-dark;
10 | border-color: @c-border-dark;
11 | }
12 |
13 | &[data-debug] {
14 | border-color: #ffcb00;
15 | .debug-badge {
16 | display: inline-block;
17 | background-color: #ffcb00;
18 | color: #735600;
19 | border-radius: 2px;
20 | padding: 2px 6px;
21 | }
22 | &::before {
23 | content: 'DEV ONLY';
24 | float: left;
25 | margin-left: -1px;
26 | margin-top: -18px;
27 | padding: 3px 6px;
28 | font-size: 12px;
29 | line-height: 1;
30 | background-color: #ffcb00;
31 | color: #735600;
32 | text-shadow: 0.5px 0.5px 0 rgba(255, 255, 255, 0.5);
33 | border-top-left-radius: 1px;
34 | border-top-right-radius: 1px;
35 | }
36 | }
37 |
38 | &[data-iframe] {
39 | .@{prefix}-previewer-browser-nav {
40 | padding: 2px 6px;
41 | background-color: @c-border;
42 |
43 | &::before {
44 | @s-btn: 12px;
45 | @s-btn-gap: 8px;
46 |
47 | content: '';
48 | display: inline-block;
49 | width: @s-btn;
50 | height: @s-btn;
51 | border-radius: 50%;
52 | background-color: #fd6458;
53 | box-shadow: (@s-btn + @s-btn-gap) 0 0 #ffbf2b,
54 | (@s-btn + @s-btn-gap) * 2 0 0 #24cc3d;
55 | }
56 | }
57 |
58 | .@{prefix}-previewer-demo > iframe {
59 | border: 0;
60 | width: 100%;
61 | height: 300px;
62 | }
63 | }
64 |
65 | + .@{prefix}-previewer {
66 | margin-top: 32px;
67 | }
68 |
69 | &-demo {
70 | padding: 40px 24px;
71 | }
72 |
73 | &-target {
74 | border-color: fade(@c-primary, 50%);
75 | box-shadow: 0 0 0 5px fade(@c-primary, 5%);
76 | }
77 |
78 | &-desc {
79 | > div:last-child {
80 | padding: 1.2em 1em 1em;
81 | color: @c-text;
82 | border-top: 1px solid @c-border;
83 |
84 | [data-prefers-color='dark'] & {
85 | border-color: @c-border-dark;
86 | }
87 | }
88 |
89 | .markdown > p:first-child {
90 | margin-top: 0;
91 | }
92 |
93 | .markdown > p:last-child {
94 | margin-bottom: 0;
95 | }
96 |
97 | &[data-title] {
98 | position: relative;
99 |
100 | > a:first-child {
101 | position: absolute;
102 | top: 0;
103 | left: 1em;
104 | margin-left: -4px;
105 | padding: 0 4px;
106 | color: @c-heading;
107 | font-size: inherit;
108 | font-weight: 500;
109 | background: linear-gradient(
110 | to top,
111 | rgba(255, 255, 255, 1),
112 | rgba(255, 255, 255, 1) 50%,
113 | rgba(255, 255, 255, 0)
114 | )
115 | 100%;
116 | transform: translateY(-50%);
117 | pointer-events: auto;
118 | cursor: pointer;
119 |
120 | [data-prefers-color='dark'] & {
121 | color: @c-heading-dark;
122 | background: linear-gradient(
123 | to top,
124 | @c-bg-dark,
125 | @c-bg-dark 50%,
126 | rgba(255, 255, 255, 0)
127 | )
128 | 100%;
129 | }
130 | }
131 |
132 | &:empty {
133 | padding-top: 0;
134 |
135 | // modify action area style when only has title field
136 | + .@{prefix}-previewer-actions {
137 | height: 46px;
138 | border-top-style: solid;
139 | }
140 | }
141 | }
142 | }
143 |
144 | &-actions {
145 | display: flex;
146 | height: 40px;
147 | padding: 0 1em;
148 | align-items: center;
149 | border-top: 1px dashed @c-border;
150 |
151 | [data-prefers-color='dark'] & {
152 | border-color: @c-border-dark;
153 | }
154 |
155 | > a:not(:last-child),
156 | > button:not(:last-child) {
157 | margin-right: 8px;
158 | }
159 |
160 | > a {
161 | display: flex;
162 | }
163 |
164 | button {
165 | position: relative;
166 | display: inline-block;
167 | width: 16px;
168 | height: 16px;
169 | padding: 0;
170 | border: 0;
171 | box-sizing: border-box;
172 | cursor: pointer;
173 | opacity: 0.6;
174 | outline: none;
175 | transition: opacity 0.2s, background 0.2s;
176 |
177 | [data-prefers-color='dark'] & {
178 | opacity: 1;
179 | }
180 |
181 | // expand click area
182 | &::after {
183 | content: '';
184 | position: absolute;
185 | top: -8px;
186 | left: -8px;
187 | right: -8px;
188 | bottom: -8px;
189 | }
190 |
191 | &:hover {
192 | opacity: 0.8;
193 | }
194 |
195 | &:active {
196 | opacity: 0.9;
197 | }
198 |
199 | &:disabled {
200 | opacity: 0.2;
201 | cursor: not-allowed;
202 | }
203 |
204 | &[role='codesandbox'] {
205 | background-position: -18px 0;
206 | }
207 |
208 | &[role='codepen'] {
209 | background-position: -36px 0;
210 | }
211 |
212 | &[role='source'] {
213 | background-position: -72px 0;
214 | }
215 |
216 | &[role='change-jsx'] {
217 | background-position: -90px 0;
218 | }
219 |
220 | &[role='change-tsx'] {
221 | background-position: -108px 0;
222 | }
223 |
224 | &[role='open-demo'] {
225 | background-position: -126px 0;
226 | }
227 |
228 | &[role='motions'] {
229 | background-position: -162px 0;
230 | }
231 |
232 | &[role='sketch-component'] {
233 | background-position: -182px 0;
234 | }
235 |
236 | &[role='sketch-group'] {
237 | background-position: -200px 0;
238 | }
239 |
240 | &[role='copy'][data-status='ready'] {
241 | background-position: -54px 0;
242 | }
243 |
244 | &[role='copy'][data-status='copied'] {
245 | pointer-events: none;
246 | background-position: -54px -16px;
247 | }
248 |
249 | &[role='refresh'] {
250 | background-position-x: -144px;
251 | }
252 | }
253 |
254 | .spacer {
255 | flex: 1;
256 | }
257 | }
258 |
259 | &-source {
260 | border-top: 1px dashed @c-border;
261 |
262 | [data-prefers-color='dark'] & {
263 | border-color: @c-border-dark;
264 | }
265 |
266 | &-tab {
267 | border-top: 1px dashed @c-border;
268 |
269 | [data-prefers-color='dark'] & {
270 | border-color: @c-border-dark;
271 | }
272 |
273 | .@{prefix}-tabs-tab-btn {
274 | position: relative;
275 | padding-left: 32px;
276 |
277 | &::before,
278 | &::after {
279 | content: '';
280 | position: absolute;
281 | margin-right: 4px;
282 | display: inline-block;
283 | box-sizing: border-box;
284 | }
285 |
286 | &::before {
287 | left: 16px;
288 | top: 50%;
289 | margin-top: -6px;
290 | width: 10px;
291 | height: 12px;
292 | border: 1px solid @c-secondary;
293 | }
294 |
295 | &::after {
296 | top: 50%;
297 | left: 23px;
298 | margin-top: -7px;
299 | width: 4px;
300 | height: 4px;
301 | background: #fff;
302 | border-bottom: 1px solid @c-secondary;
303 | transform: rotate(45deg);
304 | [data-prefers-color='dark'] & {
305 | background: @c-bg-dark;
306 | }
307 | }
308 | }
309 | }
310 | }
311 | }
312 |
313 | .@{prefix}-tabs {
314 | overflow: hidden;
315 |
316 | &.@{prefix}-tabs-top {
317 | flex-direction: column;
318 |
319 | .@{prefix}-tabs-ink-bar {
320 | bottom: 0;
321 | }
322 | }
323 |
324 | &-nav {
325 | display: flex;
326 |
327 | &-wrap {
328 | display: flex;
329 | white-space: nowrap;
330 | overflow: hidden;
331 |
332 | &&-ping-left {
333 | box-shadow: 5px 0 5px -5px rgba(0, 0, 0, 0.1) inset;
334 | }
335 |
336 | &&-ping-right ~ * > .@{prefix}-tabs-nav-more {
337 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
338 | }
339 | }
340 |
341 | &-list {
342 | position: relative;
343 | display: flex;
344 | transition: transform 0.2s;
345 | }
346 |
347 | &-more {
348 | height: 100%;
349 | cursor: pointer;
350 | background: none;
351 | border: 0;
352 | transition: box-shadow 0.2s;
353 | }
354 | }
355 |
356 | &-tab {
357 | display: flex;
358 |
359 | &-btn {
360 | padding: 0 16px;
361 | font-size: 14px;
362 | line-height: 36px;
363 | border: 0;
364 | outline: none;
365 | background: transparent;
366 | box-sizing: border-box;
367 | cursor: pointer;
368 |
369 | &:hover {
370 | color: @c-primary;
371 | }
372 | }
373 | }
374 |
375 | &-ink-bar {
376 | position: absolute;
377 | height: 2px;
378 | background: @c-primary;
379 | transition: left 0.2s, width 0.2s;
380 | pointer-events: none;
381 |
382 | [data-prefers-color='dark'] & {
383 | background: @c-primary-dark;
384 | }
385 | }
386 |
387 | &-dropdown {
388 | position: absolute;
389 | background: #fff;
390 | border: 1px solid @c-border;
391 | max-height: 200px;
392 | overflow: auto;
393 |
394 | > ul {
395 | list-style: none;
396 | margin: 0;
397 | padding: 0;
398 |
399 | > li {
400 | padding: 4px 12px;
401 | font-size: 14px;
402 | cursor: pointer;
403 |
404 | &:hover {
405 | color: @c-primary;
406 | }
407 |
408 | &:not(:last-child) {
409 | border-bottom: 1px dashed @c-border;
410 | }
411 | }
412 | }
413 |
414 | &-hidden {
415 | display: none;
416 | }
417 | }
418 | }
419 |
--------------------------------------------------------------------------------
/example/.dumi/theme/components/SideMenu.less:
--------------------------------------------------------------------------------
1 | @import (reference) '../style/variables.less';
2 |
3 | .@{prefix}-menu {
4 | position: fixed;
5 | z-index: 100;
6 | top: 0;
7 | left: 0;
8 | bottom: 0;
9 | width: @s-menu-width;
10 | background-color: #f2f5fa;
11 | box-sizing: border-box;
12 | transition: left 0.3s;
13 |
14 | &[data-hidden] {
15 | display: none;
16 | }
17 |
18 | @media @mobile {
19 | left: -@s-menu-mobile-width;
20 | top: @s-mobile-nav-height;
21 | display: block !important;
22 | width: @s-menu-mobile-width;
23 | background-color: #fff;
24 |
25 | &[data-mobile-show] {
26 | left: 0;
27 | }
28 |
29 | [data-prefers-color='dark'] & {
30 | background-color: @c-bg-dark;
31 | }
32 | }
33 |
34 | // shadow
35 | &::after {
36 | content: '';
37 | position: absolute;
38 | top: 0;
39 | right: 0;
40 | bottom: 0;
41 | display: block;
42 | width: 20px;
43 | background: linear-gradient(
44 | to right,
45 | rgba(0, 0, 0, 0),
46 | rgba(0, 0, 0, 0.03)
47 | );
48 | pointer-events: none;
49 |
50 | // use border on mobile devices
51 | @media @mobile {
52 | width: 1px;
53 | background: @c-border;
54 | }
55 | }
56 |
57 | &-header {
58 | position: relative;
59 | padding-top: 40px;
60 | text-align: center;
61 | border-bottom: 1px solid @c-border;
62 |
63 | [data-prefers-color='dark'] & {
64 | border-color: @c-border-dark;
65 | }
66 |
67 | @media @mobile {
68 | display: none;
69 | }
70 |
71 | .@{prefix}-menu-logo {
72 | display: inline-block;
73 | width: 66px;
74 | height: 65px;
75 | background: url(@img-logo) no-repeat 0 / contain;
76 | }
77 |
78 | h1 {
79 | margin: 10px 0 0;
80 | color: @c-heading;
81 | font-weight: 500;
82 | line-height: 1.40625;
83 | }
84 |
85 | p {
86 | margin: 0 0 5px;
87 | color: lighten(@c-secondary, 10%);
88 |
89 | // badges
90 | > object[data^='https://img.shields.io']
91 | {
92 | max-height: 20px;
93 | }
94 |
95 | + p {
96 | margin-bottom: 10px;
97 | }
98 | }
99 | }
100 |
101 | &-doc-locale {
102 | padding: 16px 0;
103 | text-align: center;
104 | border-bottom: 1px solid @c-border;
105 | display: flex;
106 | justify-content: space-evenly;
107 |
108 | [data-prefers-color='dark'] & {
109 | border-color: @c-border-dark;
110 | }
111 |
112 | [data-mode='doc'][data-mobile-show='true'] & {
113 | display: grid;
114 | }
115 |
116 | &:empty {
117 | display: none;
118 | }
119 | }
120 |
121 | &-inner {
122 | width: 100%;
123 | height: 100%;
124 | overflow: auto;
125 | overscroll-behavior: contain;
126 |
127 | [data-prefers-color='dark'] & {
128 | background-color: #262626;
129 | }
130 |
131 | // common list styles
132 | ul {
133 | list-style: none;
134 | margin: 0;
135 | padding: 0;
136 | font-size: 16px;
137 |
138 | li {
139 | color: @c-text;
140 | a,
141 | > span {
142 | position: relative;
143 | display: block;
144 | padding-right: 24px;
145 | color: @c-heading;
146 | line-height: 46px;
147 | height: 46px;
148 | text-decoration: none;
149 | outline: none;
150 | transition: color 0.3s, background 0.3s;
151 |
152 | [data-prefers-color='dark'] & {
153 | color: @c-heading-dark;
154 | }
155 |
156 | span {
157 | display: block;
158 | overflow: hidden;
159 | white-space: nowrap;
160 | text-overflow: ellipsis;
161 | font-size: 14px;
162 | }
163 |
164 | &:hover,
165 | &.active {
166 | color: @c-primary;
167 |
168 | [data-prefers-color='dark'] & {
169 | color: @c-primary-dark;
170 | }
171 | }
172 |
173 | // &::before {
174 | // content: '';
175 | // position: absolute;
176 | // top: 50%;
177 | // left: -10px;
178 | // margin-top: -2.5px;
179 | // display: inline-block;
180 | // width: 5px;
181 | // height: 5px;
182 | // background-color: @c-primary;
183 | // border-radius: 50%;
184 | // opacity: 0;
185 | // transition: transform 0.2s, opacity 0.2s;
186 | // transform: scale(0) translateX(-10px);
187 | // }
188 | }
189 |
190 | &.active a,
191 | a.active {
192 | &::before {
193 | opacity: 1;
194 | transform: scale(1) translateX(0);
195 | }
196 | }
197 |
198 | // level larger, offset larger, font size smaller
199 | ul {
200 | font-size: 0.9em;
201 | padding-left: 1em;
202 | }
203 | }
204 | }
205 |
206 | // 1-level list styles
207 | > ul {
208 | > li > a {
209 | line-height: 2.875;
210 |
211 | &:not([href]) {
212 | padding-top: 24px;
213 | line-height: 1;
214 | font-weight: 500;
215 | color: @c-heading !important;
216 | background: transparent !important;
217 | cursor: default;
218 |
219 | [data-prefers-color='dark'] & {
220 | color: @c-heading-dark !important;
221 | }
222 | }
223 | }
224 |
225 | > li:first-child > a:not([href]) {
226 | padding-top: 0;
227 | }
228 | }
229 |
230 | // n-level list styles
231 | > ul ul {
232 | a {
233 | font-size: 14px;
234 | // color: @c-secondary;
235 | color: #4c4c4c;
236 | [data-prefers-color='dark'] & {
237 | color: @c-secondary-dark;
238 | }
239 | &.active {
240 | color: #1f5de9;
241 | [data-prefers-color='dark'] & {
242 | color: @c-primary-dark;
243 | }
244 | }
245 | }
246 | }
247 |
248 | .@{prefix}-menu-mobile-area {
249 | display: none;
250 | padding-bottom: 16px;
251 | margin-bottom: 16px;
252 | text-align: center;
253 | border-bottom: 1px solid @c-border;
254 |
255 | [data-prefers-color='dark'] & {
256 | border-color: @c-border-dark;
257 | }
258 |
259 | @media @mobile {
260 | display: block;
261 | }
262 | }
263 |
264 | // mobile nav list
265 | .@{prefix}-menu-nav-list {
266 | padding: 16px 0 0 0;
267 |
268 | > li,
269 | > li > a {
270 | padding-right: 0;
271 | line-height: 2.4;
272 |
273 | ul {
274 | padding-left: 0;
275 |
276 | a {
277 | padding-right: 0;
278 | font-size: 90%;
279 | }
280 | }
281 | }
282 | }
283 |
284 | // menu list
285 | .@{prefix}-menu-list {
286 | padding: 8px 0;
287 | margin-bottom: 40px;
288 |
289 | > li > a {
290 | @c-active-bg: #e8ecf4;
291 |
292 | padding-left: 28px;
293 |
294 | &.active {
295 | background: linear-gradient(to left, #e8ecf4, rgba(232, 236, 244, 0));
296 |
297 | [data-prefers-color='dark'] & {
298 | background: linear-gradient(
299 | to left,
300 | #3d3d3e,
301 | rgba(255, 255, 255, 0.06)
302 | );
303 | }
304 | }
305 |
306 | ~ ul {
307 | margin-top: 8px;
308 | margin-left: 28px;
309 | }
310 |
311 | @media @mobile {
312 | padding-left: 16px;
313 |
314 | ~ ul {
315 | margin-left: 16px;
316 | }
317 | }
318 | }
319 | }
320 |
321 | // FTA View自定义样式
322 | .@{prefix}-menu-item-title {
323 | height: 48px;
324 | padding-left: 20px !important;
325 | color: #4c4c4c;
326 | font-size: 16px;
327 | font-weight: 500;
328 | position: relative;
329 | }
330 |
331 | .@{prefix}-menu-item-title--active {
332 | color: #1f5de9 !important;
333 | }
334 | }
335 |
336 | &[data-mode='site'] {
337 | &::after {
338 | width: 1px;
339 | background: @c-border;
340 |
341 | [data-prefers-color='dark'] & {
342 | background: @c-border-dark;
343 | }
344 | }
345 |
346 | .@{prefix}-menu-list {
347 | padding: 0;
348 |
349 | > li > a {
350 | position: relative;
351 |
352 | &::after {
353 | content: '';
354 | position: absolute;
355 | top: 0;
356 | bottom: 0;
357 | right: 0;
358 | display: block;
359 | width: 3px;
360 | background-color: @c-primary;
361 | visibility: hidden;
362 | opacity: 0;
363 | transition: all 0.3s;
364 | border-radius: 1px;
365 | }
366 |
367 | &.active {
368 | z-index: 1;
369 | background: linear-gradient(to left, #f8faff, rgba(248, 250, 255, 0));
370 |
371 | [data-prefers-color='dark'] & {
372 | background: linear-gradient(
373 | to left,
374 | #3d3d3e,
375 | rgba(255, 255, 255, 0.06)
376 | );
377 | }
378 | &::after {
379 | opacity: 1;
380 | visibility: visible;
381 | }
382 | }
383 | }
384 | }
385 |
386 | @media @desktop {
387 | top: @s-nav-height;
388 | width: @s-site-menu-width;
389 | padding-top: 50px;
390 | background: transparent;
391 |
392 | [data-prefers-color='dark'] & {
393 | background: @c-light-bg-dark;
394 | }
395 |
396 | .@{prefix}-menu-nav,
397 | .@{prefix}-menu-header {
398 | display: none;
399 | }
400 |
401 | .@{prefix}-menu-list > li > a {
402 | padding-left: 58px;
403 |
404 | ~ ul {
405 | margin-top: 0 !important;
406 | margin-left: 0 !important;
407 | padding: 0 8px !important;
408 | }
409 | }
410 | }
411 | }
412 | }
413 |
414 | .__dumi-default-menu-subitem {
415 | padding-left: 28px;
416 | }
417 |
418 | .__dumi-default-menu-subitem--active {
419 | background: #f6f6f6;
420 | border-radius: 4px;
421 | }
422 |
--------------------------------------------------------------------------------
/example/.dumi/theme/style/layout.less:
--------------------------------------------------------------------------------
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 | // &[data-route='/'] p {
24 | // width: auto !important;
25 | // }
26 |
27 | box-sizing: border-box;
28 | min-height: 100vh;
29 | padding: 16px (@s-content-margin + @s-toc-width) 50px @s-menu-width +
30 | @s-content-margin;
31 |
32 | @media @mobile {
33 | padding-top: 66px !important;
34 | padding-left: 16px !important;
35 | padding-right: 16px !important;
36 | }
37 |
38 | &[data-gapless='true'] {
39 | padding-top: @s-nav-height !important;
40 | padding-right: 0 !important;
41 | padding-left: 0 !important;
42 | padding-bottom: 0;
43 |
44 | @media @mobile {
45 | padding-top: @s-mobile-nav-height !important;
46 | }
47 | }
48 |
49 | &[data-show-sidemenu='false'] {
50 | padding-left: @s-content-margin;
51 | }
52 |
53 | &[data-show-slugs='false'] {
54 | padding-right: @s-content-margin;
55 | }
56 |
57 | &[data-site-mode='true'] {
58 | padding-top: @s-nav-height + 50px;
59 |
60 | &[data-show-sidemenu='true'] {
61 | padding-left: @s-site-menu-width + 50px;
62 | }
63 |
64 | &[data-show-slugs='true'] {
65 | padding-right: @s-content-margin + @s-toc-width + 14;
66 | }
67 |
68 | .@{prefix}-layout-content > .markdown:first-child > *:first-child {
69 | margin-top: 0;
70 | }
71 |
72 | .@{prefix}-layout-toc {
73 | top: 126px;
74 | max-height: calc(90vh - 144px);
75 | }
76 | }
77 |
78 | &-hero {
79 | margin: -50px -58px 0;
80 | padding: 100px 0;
81 | text-align: center;
82 | background-color: #f5f6f8;
83 |
84 | [data-prefers-color='dark'] & {
85 | background-color: @c-light-bg-dark;
86 | }
87 |
88 | @media @mobile {
89 | margin: -16px -16px 0;
90 | padding: 48px 0;
91 | }
92 |
93 | img {
94 | max-width: 100%;
95 | max-height: 200px;
96 | margin-bottom: 1rem;
97 | }
98 |
99 | h1 {
100 | margin: 0 0 16px;
101 | font-size: 48px;
102 | font-weight: 600;
103 | line-height: 56px;
104 | color: #080e29;
105 |
106 | [data-prefers-color='dark'] & {
107 | color: @c-heading-dark;
108 | }
109 |
110 | + div {
111 | margin: 16px 0 32px;
112 | opacity: 0.78;
113 |
114 | .markdown {
115 | font-size: 16px;
116 | }
117 | }
118 | }
119 |
120 | button {
121 | margin-right: 16px;
122 | padding: 0 32px;
123 | height: 44px;
124 | color: @c-primary;
125 | font-size: 16px;
126 | background: transparent;
127 | border: 1px solid @c-primary;
128 | border-radius: 22px;
129 | box-sizing: border-box;
130 | cursor: pointer;
131 | outline: none;
132 | transition: all 0.3s;
133 |
134 | &:hover {
135 | opacity: 0.8;
136 | }
137 |
138 | &:active {
139 | opacity: 0.9;
140 | }
141 | }
142 |
143 | a:last-child button {
144 | margin-right: 0;
145 | color: #fff;
146 | background: @c-primary;
147 | }
148 | }
149 |
150 | &-features {
151 | display: grid;
152 | grid-template-columns: repeat(3, 1fr);
153 | grid-column-gap: 96px;
154 | grid-row-gap: 56px;
155 | padding: 72px 0;
156 |
157 | > dl {
158 | flex: 1;
159 | margin: 0;
160 | text-align: center;
161 | background: no-repeat center top / auto 48px;
162 |
163 | &[style*='background-image'] {
164 | padding-top: 64px;
165 | }
166 |
167 | dt {
168 | margin-bottom: 12px;
169 | font-size: 20px;
170 | line-height: 1;
171 | color: @c-heading;
172 | [data-prefers-color='dark'] & {
173 | color: @c-text-dark;
174 | }
175 | }
176 |
177 | a {
178 | transition-duration: none;
179 | }
180 |
181 | a dt {
182 | color: @c-link;
183 | transition: opacity 0.2s;
184 | &:hover {
185 | opacity: 0.7;
186 | text-decoration: underline;
187 | }
188 |
189 | &:active {
190 | opacity: 0.9;
191 | }
192 | }
193 |
194 | dd {
195 | margin: 0;
196 |
197 | .markdown {
198 | color: @c-secondary;
199 | font-size: 14px;
200 | line-height: 22px;
201 |
202 | [data-prefers-color='dark'] & {
203 | color: @c-secondary-dark;
204 | }
205 |
206 | > p:first-child {
207 | margin-top: 0;
208 | }
209 |
210 | > p:last-child {
211 | margin-bottom: 0;
212 | }
213 | }
214 | }
215 | }
216 |
217 | @media @mobile {
218 | display: block;
219 | padding: 40px 0;
220 |
221 | > dl {
222 | text-align: left;
223 | background-position: left top;
224 |
225 | &[style*='background-image'] {
226 | padding: 0 0 0 60px;
227 | }
228 |
229 | + dl {
230 | margin-top: 32px;
231 | }
232 | }
233 | }
234 | }
235 |
236 | &-features,
237 | &-features + &-content,
238 | &-hero + &-content {
239 | margin-left: auto;
240 | margin-right: auto;
241 | max-width: 960px;
242 | }
243 |
244 | &-hero + &-content {
245 | margin-top: 60px;
246 | }
247 |
248 | &-toc {
249 | list-style: none;
250 | position: fixed;
251 | z-index: 10;
252 | top: 50px;
253 | right: 0;
254 | width: @s-toc-width;
255 | max-height: calc(90vh - 80px);
256 | margin: 0;
257 | padding: 0 24px 0 0;
258 | background-color: #fff;
259 | box-sizing: content-box;
260 | overflow: auto;
261 |
262 | [data-prefers-color='dark'] & {
263 | background-color: @c-bg-dark;
264 | }
265 |
266 | @media @mobile {
267 | display: none;
268 | }
269 |
270 | li {
271 | position: relative;
272 | margin: 0;
273 | padding: 4px 0 4px 6px;
274 | text-indent: 12px;
275 | font-size: 13px;
276 | line-height: 1.40625;
277 | white-space: nowrap;
278 | text-overflow: ellipsis;
279 | overflow: hidden;
280 |
281 | a {
282 | color: #4c4c4c;
283 | text-decoration: none;
284 |
285 | [data-prefers-color='dark'] & {
286 | color: @c-text-dark;
287 | }
288 |
289 | &::before {
290 | content: '';
291 | position: absolute;
292 | top: 0;
293 | left: 0;
294 | bottom: 0;
295 | display: inline-block;
296 | width: 2px;
297 | background: @c-border;
298 | }
299 |
300 | &:hover {
301 | color: lighten(@c-primary, 5%);
302 |
303 | [data-prefers-color='dark'] & {
304 | color: lighten(@c-primary-dark, 5%);
305 | }
306 | }
307 |
308 | &:active {
309 | color: lighten(@c-primary, 3%);
310 |
311 | [data-prefers-color='dark'] & {
312 | color: lighten(@c-primary-dark, 3%);
313 | }
314 | }
315 |
316 | &.active {
317 | color: @c-primary;
318 |
319 | [data-prefers-color='dark'] & {
320 | color: @c-primary-dark;
321 | }
322 |
323 | &::before {
324 | background: @c-primary;
325 |
326 | [data-prefers-color='dark'] & {
327 | background: @c-primary-dark;
328 | }
329 | }
330 | }
331 | }
332 | }
333 | }
334 |
335 | &-footer-meta {
336 | margin-top: 40px;
337 | padding-top: 24px;
338 | display: flex;
339 | color: @c-secondary;
340 | font-size: 14px;
341 | justify-content: space-between;
342 | border-top: 1px solid @c-border;
343 |
344 | [data-prefers-color='dark'] & {
345 | color: @c-secondary-dark;
346 | border-color: @c-border-dark;
347 | }
348 |
349 | @media only screen and (max-width: 960px) {
350 | display: block;
351 | }
352 |
353 | > a {
354 | margin-bottom: 4px;
355 | display: block;
356 | color: @c-primary;
357 | transition: opacity 0.2s;
358 | text-decoration: none;
359 |
360 | [data-prefers-color='dark'] & {
361 | color: @c-primary-dark;
362 | }
363 |
364 | &:hover {
365 | opacity: 0.7;
366 | text-decoration: underline;
367 | }
368 |
369 | &:active {
370 | opacity: 0.9;
371 | }
372 | }
373 |
374 | > span:last-child {
375 | &::before {
376 | content: attr(data-updated-text);
377 | color: @c-primary;
378 |
379 | [data-prefers-color='dark'] & {
380 | color: @c-primary-dark;
381 | }
382 | }
383 | }
384 | }
385 | }
386 |
387 | .__dumi-default-layout-footer {
388 | margin: 72px 0 -32px;
389 | padding-top: 24px;
390 | border-top: 1px solid @c-border;
391 | text-align: center;
392 |
393 | [data-prefers-color='dark'] & {
394 | border-color: @c-border-dark;
395 | }
396 |
397 | .markdown {
398 | color: #b0b1ba;
399 |
400 | [data-prefers-color='dark'] & {
401 | color: rgba(255, 255, 255, 0.45);
402 | }
403 | }
404 | }
405 |
406 | .__dumi-default-navbar {
407 | box-shadow: none;
408 | border-bottom: 1px solid #e0e0e0;
409 | }
410 |
411 | ::-webkit-scrollbar {
412 | width: 6px;
413 | // height: 6px;
414 | background-color: transparent;
415 | }
416 |
417 | ::-webkit-scrollbar-track {
418 | // -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
419 | // border-radius: 10px;
420 | // background-color: #fafafa;
421 | background-color: #fefefe;
422 | }
423 |
424 | ::-webkit-scrollbar-thumb {
425 | width: 6px;
426 | border-radius: 3px;
427 | background-color: #d8d8d8;
428 | }
429 |
430 | html::-webkit-scrollbar {
431 | width: 20px;
432 | // height: 6px;
433 | background-color: transparent;
434 | }
435 |
436 | html::-webkit-scrollbar-track {
437 | // -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
438 | // border-radius: 10px;
439 | // background-color: #fafafa;
440 | // background-color: #fefefe;
441 | background-color: red;
442 | }
443 |
444 | html::-webkit-scrollbar-thumb {
445 | width: 20px;
446 | border-radius: 4px;
447 | background-color: #d8d8d8;
448 | }
449 |
--------------------------------------------------------------------------------