@umijs/plugin-docs 4.0.0-rc.12 → 4.0.0-rc.15

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.
@@ -1,5 +1,6 @@
1
1
  import cx from 'classnames';
2
2
  import React from 'react';
3
+ import { useThemeContext } from './context';
3
4
  import Github from './Github';
4
5
  import LangSwitch from './LangSwitch';
5
6
  import Logo from './Logo';
@@ -13,27 +14,41 @@ interface HeadProps {
13
14
  }
14
15
 
15
16
  export default (props: HeadProps) => {
17
+ const { themeConfig } = useThemeContext()!;
16
18
  return (
17
19
  <div
18
20
  className="w-full flex flex-row items-center justify-between
19
- border-b-gray-100 border-b-2 pt-4 pb-4 px-8 dark:border-b-gray-800"
21
+ border-b-gray-100 border-b-2 pt-4 pb-4 px-4 lg:px-12 dark:border-b-gray-800"
20
22
  >
21
- <Logo />
23
+ <div className="flex flex-row items-center">
24
+ <Logo />
25
+ {themeConfig.extraNavLeft && <themeConfig.extraNavLeft />}
26
+ </div>
22
27
  <div className="flex flex-row items-center">
23
28
  <Search />
24
- <HamburgerButton {...props} />
29
+ {/* 小屏幕显示打开菜单的按钮 */}
30
+ <div
31
+ className="block lg:hidden ml-2 cursor-pointer"
32
+ onClick={() => props.setMenuOpened((o) => !o)}
33
+ >
34
+ <HamburgerButton {...props} />
35
+ </div>
36
+ {/* 大屏幕显示完整的操作按钮 */}
25
37
  <div className="hidden lg:block">
26
38
  <NavBar />
27
39
  </div>
28
40
  <div className="ml-4 hidden lg:block">
29
41
  <LangSwitch />
30
42
  </div>
31
- <div className="ml-4 hidden lg:block">
32
- <ThemeSwitch />
33
- </div>
43
+ {themeConfig.themeSwitch && (
44
+ <div className="ml-4 hidden lg:block">
45
+ <ThemeSwitch />
46
+ </div>
47
+ )}
34
48
  <div className="ml-4 hidden lg:block">
35
49
  <Github />
36
50
  </div>
51
+ {themeConfig.extraNavRight && <themeConfig.extraNavRight />}
37
52
  </div>
38
53
  </div>
39
54
  );
@@ -41,30 +56,27 @@ export default (props: HeadProps) => {
41
56
 
42
57
  interface HamburgerButtonProps {
43
58
  isMenuOpened: boolean;
44
- setMenuOpened: React.Dispatch<React.SetStateAction<boolean>>;
45
59
  }
46
60
 
47
61
  function HamburgerButton(props: HamburgerButtonProps) {
62
+ const { isMenuOpened } = props;
48
63
  const barClass =
49
- 'block absolute h-0.5 w-5 bg-current transform dark:bg-white' +
50
- ' transition duration-500 ease-in-out';
64
+ 'absolute h-0.5 w-5 -translate-x-2.5 bg-current transform dark:bg-white ' +
65
+ 'transition duration-500 ease-in-out';
51
66
 
52
67
  return (
53
- <div
54
- className="relative py-3 sm:max-w-xl mx-auto mx-5 lg:hidden"
55
- onClick={() => props.setMenuOpened((o) => !o)}
56
- >
68
+ <div className="p-4">
57
69
  <span
58
70
  className={cx(
59
71
  barClass,
60
- props.isMenuOpened ? 'rotate-45 ' : '-translate-y-1.5',
72
+ isMenuOpened ? 'rotate-45 ' : '-translate-y-1.5',
61
73
  )}
62
74
  />
63
- <span className={cx(barClass, props.isMenuOpened && 'opacity-0')} />
75
+ <span className={cx(barClass, isMenuOpened && 'opacity-0')} />
64
76
  <span
65
77
  className={cx(
66
78
  barClass,
67
- props.isMenuOpened ? '-rotate-45' : 'translate-y-1.5',
79
+ isMenuOpened ? '-rotate-45' : 'translate-y-1.5',
68
80
  )}
69
81
  />
70
82
  </div>
@@ -17,7 +17,7 @@ export default () => {
17
17
  }
18
18
 
19
19
  function handleClick() {
20
- if (!currentLanguage) return;
20
+ if (!currentLanguage || languages.length === 1) return;
21
21
  if (languages.length === 2) {
22
22
  switchLanguage(
23
23
  languages[0].locale === currentLanguage.locale
@@ -29,6 +29,8 @@ export default () => {
29
29
  setExpanded((e) => !e);
30
30
  }
31
31
 
32
+ if (!currentLanguage || languages.length === 1) return null;
33
+
32
34
  return (
33
35
  <div>
34
36
  <div
@@ -20,7 +20,8 @@ export default (props: any) => {
20
20
 
21
21
  function updateBlur() {
22
22
  if (!offset || !blur) return;
23
- blur.backgroundPosition = `0px ` + `${-window.scrollY + 100}px`;
23
+ blur.backgroundPosition =
24
+ `0px ` + `calc(var(--anchor-offset) + ${-window.scrollY + 64}px)`;
24
25
  }
25
26
 
26
27
  document.addEventListener('scroll', updateBlur, false), updateBlur();
@@ -44,7 +45,10 @@ export default (props: any) => {
44
45
  location: props.location,
45
46
  }}
46
47
  >
47
- <div className="flex flex-col dark:bg-gray-900 min-h-screen transition-all">
48
+ <div
49
+ className="flex flex-col dark:bg-gray-900 min-h-screen transition-all"
50
+ id={isHomePage ? 'home-page' : 'doc-page'}
51
+ >
48
52
  <div
49
53
  id="head-container"
50
54
  className="z-30 sticky top-0 dark:before:bg-gray-800 before:bg-white before:bg-opacity-[.85]
@@ -75,31 +79,32 @@ export default (props: any) => {
75
79
  id="article-body"
76
80
  className="w-full flex flex-row justify-center overflow-x-hidden"
77
81
  >
78
- <div className="container flex flex-row justify-center">
79
- <div className="w-full lg:w-1/2 px-4 lg:px-2 m-8 z-20 lg:py-12">
80
- <article className="flex-1">{props.children}</article>
82
+ {/* 左侧菜单 */}
83
+ <div
84
+ className="fixed left-0 top-0 w-1/4 flex flex-row
85
+ justify-center h-screen z-10 pt-20"
86
+ >
87
+ <div className="container flex flex-row justify-end">
88
+ <div className="hidden lg:block">
89
+ <Sidebar />
90
+ </div>
81
91
  </div>
82
92
  </div>
83
- </div>
84
-
85
- <div
86
- className="fixed left-0 top-0 w-1/4 flex flex-row
87
- justify-center h-screen z-10 pt-20"
88
- >
89
- <div className="container flex flex-row justify-end">
90
- <div className="hidden lg:block">
91
- <Sidebar />
93
+ {/* 文章内容 */}
94
+ <div className="container flex flex-row justify-center">
95
+ <div className="w-full lg:w-1/2 px-4 lg:px-2 m-8 z-20 lg:pb-12 lg:pt-6">
96
+ <article className="flex-1">{props.children}</article>
92
97
  </div>
93
98
  </div>
94
- </div>
95
-
96
- <div
97
- className="fixed right-0 top-0 w-1/4 flex flex-row
98
- justify-center h-screen z-10 pt-20 hidden lg:block"
99
- >
100
- <div className="container flex flex-row justify-start">
101
- <div className="w-2/3 top-32">
102
- <Toc />
99
+ {/* 右侧 Toc */}
100
+ <div
101
+ className="fixed right-0 top-0 w-1/4 hidden lg:block flex-row
102
+ justify-center h-screen z-10 pt-20"
103
+ >
104
+ <div className="container flex flex-row justify-start">
105
+ <div className="w-2/3 top-32">
106
+ <Toc />
107
+ </div>
103
108
  </div>
104
109
  </div>
105
110
  </div>
@@ -110,7 +115,7 @@ export default (props: any) => {
110
115
  <div
111
116
  className={cx(
112
117
  'fixed top-12 w-screen bg-white z-20 dark:bg-gray-800',
113
- 'overflow-hidden transition-all duration-500',
118
+ 'overflow-hidden transition-all duration-500 lg:hidden',
114
119
  isMenuOpened ? 'max-h-screen' : 'max-h-0',
115
120
  )}
116
121
  >
@@ -5,15 +5,19 @@ import useLanguage from './useLanguage';
5
5
  export default () => {
6
6
  const { themeConfig, components } = useThemeContext()!;
7
7
  const { isFromPath, currentLanguage } = useLanguage();
8
-
9
- // @ts-ignore
10
- const { logo } = themeConfig;
8
+ const Logo = themeConfig.logo;
11
9
 
12
10
  return (
13
11
  <components.Link to={isFromPath ? '/' + currentLanguage?.locale : '/'}>
14
12
  <div className="flex flex-row items-center">
15
- <img src={logo} className="w-8 h-8" alt="logo" />
16
- <div className="text-xl font-extrabold ml-2 dark:text-white">
13
+ {typeof Logo === 'string' && (
14
+ <img src={Logo} className="w-8 h-8" alt="logo" />
15
+ )}
16
+ {typeof Logo === 'function' && <Logo />}
17
+ <div
18
+ id="header-title"
19
+ className="text-xl font-extrabold ml-2 dark:text-white"
20
+ >
17
21
  {themeConfig.title}
18
22
  </div>
19
23
  </div>
@@ -1,27 +1,70 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { useThemeContext } from './context';
3
3
  import useLanguage from './useLanguage';
4
4
 
5
5
  export default () => {
6
- const { components, themeConfig } = useThemeContext()!;
7
- const lang = useLanguage();
6
+ const { themeConfig } = useThemeContext()!;
8
7
  return (
9
8
  <ul className="flex">
10
- {themeConfig.navs.map((nav: any) => {
11
- return (
12
- <li key={nav.path} className="ml-4 dark:text-white">
9
+ {themeConfig.navs.map((nav: any) => (
10
+ <NavItem nav={nav} key={nav.path} />
11
+ ))}
12
+ </ul>
13
+ );
14
+ };
15
+
16
+ interface NavItemProps {
17
+ nav: {
18
+ path: string;
19
+ title: string;
20
+ dropdown?: {
21
+ title: string;
22
+ path: string;
23
+ }[];
24
+ };
25
+ }
26
+
27
+ function NavItem(props: NavItemProps) {
28
+ const { components } = useThemeContext()!;
29
+ const { nav } = props;
30
+ const lang = useLanguage();
31
+ const [isExpanded, setExpanded] = useState(false);
32
+ return (
33
+ <li
34
+ className="ml-8 dark:text-white relative"
35
+ onMouseEnter={() => nav.dropdown && setExpanded(true)}
36
+ onMouseLeave={() => nav.dropdown && setExpanded(false)}
37
+ >
38
+ <components.Link
39
+ to={
40
+ lang.isFromPath ? lang.currentLanguage?.locale + nav.path : nav.path
41
+ }
42
+ >
43
+ {lang.render(nav.title)}
44
+ </components.Link>
45
+ {nav.dropdown && (
46
+ <div
47
+ style={{ maxHeight: isExpanded ? nav.dropdown.length * 48 : 0 }}
48
+ className="absolute transition-all duration-300 w-32 rounded-lg
49
+ cursor-pointer shadow overflow-hidden top-8"
50
+ >
51
+ {nav.dropdown.map((n) => (
13
52
  <components.Link
53
+ key={n.path}
14
54
  to={
15
- lang.isFromPath
16
- ? lang.currentLanguage?.locale + nav.path
17
- : nav.path
55
+ lang.isFromPath ? lang.currentLanguage?.locale + n.path : n.path
18
56
  }
19
57
  >
20
- {lang.render(nav.title)}
58
+ <p
59
+ className="p-2 bg-white dark:bg-gray-700 dark:text-white
60
+ hover:bg-gray-50 transition duration-300"
61
+ >
62
+ {n.title}
63
+ </p>
21
64
  </components.Link>
22
- </li>
23
- );
24
- })}
25
- </ul>
65
+ ))}
66
+ </div>
67
+ )}
68
+ </li>
26
69
  );
27
- };
70
+ }
@@ -3,9 +3,11 @@ import key from 'keymaster';
3
3
  import React, { Fragment, useEffect, useState } from 'react';
4
4
  import { useThemeContext } from './context';
5
5
  import useLanguage from './useLanguage';
6
+ import getLinkFromTitle from './utils/getLinkFromTitle';
6
7
 
7
8
  export default () => {
8
- const { render } = useLanguage();
9
+ const { components } = useThemeContext()!;
10
+ const { isFromPath, currentLanguage, render } = useLanguage();
9
11
  const [isFocused, setIsFocused] = useState(false);
10
12
  const [keyword, setKeyword] = useState('');
11
13
 
@@ -34,6 +36,7 @@ export default () => {
34
36
  }
35
37
 
36
38
  useEffect(() => {
39
+ if (!themeConfig.searchHotKey) return;
37
40
  key.filter = () => true;
38
41
 
39
42
  // 在页面中按下 ⌘+k 可以打开搜索框
@@ -63,6 +66,7 @@ export default () => {
63
66
  return (
64
67
  <Fragment>
65
68
  <div
69
+ id="search-input-wrapper"
66
70
  className="rounded-lg w-40 lg:w-64 flex items-center pr-2 flex-row hover:bg-gray-50
67
71
  transition duration-300 bg-gray-100 border border-white focus-within:border-gray-100
68
72
  focus-within:bg-white dark:bg-gray-700 dark:border-gray-700 relative
@@ -72,18 +76,22 @@ export default () => {
72
76
  onFocus={() => setIsFocused(true)}
73
77
  onBlur={() => setIsFocused(false)}
74
78
  value={keyword}
79
+ autoComplete="off"
75
80
  onChange={(e) => setKeyword(e.target.value)}
76
81
  id="search-input"
77
- className="w-full bg-transparent outline-none text-sm px-4 py-2 "
82
+ className="w-full bg-transparent outline-none text-sm px-4 py-2"
78
83
  placeholder={render('Search anything ...')}
79
84
  />
80
- <div
81
- className="bg-gray-200 rounded px-2 h-6 flex flex-row text-gray-400
85
+ {themeConfig.searchHotKey && (
86
+ <div
87
+ className="bg-gray-200 rounded px-2 h-6 flex flex-row text-gray-400
82
88
  items-center justify-center border border-gray-300 text-xs"
83
- >
84
- {isMac ? macSearchKey : windowsSearchKey}
85
- </div>
89
+ >
90
+ {isMac ? macSearchKey : windowsSearchKey}
91
+ </div>
92
+ )}
86
93
  <div
94
+ id="search-results-wrapper"
87
95
  className={cx(
88
96
  'absolute transition-all duration-500 top-12 w-96 rounded-lg',
89
97
  'cursor-pointer shadow overflow-hidden',
@@ -91,9 +99,10 @@ export default () => {
91
99
  )}
92
100
  >
93
101
  {result.map((r, i) => (
94
- <a
95
- href={r.href}
102
+ <components.Link
103
+ to={(isFromPath ? currentLanguage?.locale : '') + r.href}
96
104
  key={i}
105
+ onClick={() => (document.activeElement as HTMLElement)?.blur()}
97
106
  className="group outline-none search-result"
98
107
  onFocus={() => setIsFocused(true)}
99
108
  onBlur={() => setIsFocused(false)}
@@ -104,7 +113,7 @@ export default () => {
104
113
  >
105
114
  {r.path}
106
115
  </p>
107
- </a>
116
+ </components.Link>
108
117
  ))}
109
118
  </div>
110
119
  </div>
@@ -122,9 +131,15 @@ function search(routes: any, keyword: string): SearchResultItem[] {
122
131
 
123
132
  const result: SearchResultItem[] = [];
124
133
 
134
+ function addResult(newResult: { path: string; href: string }) {
135
+ const { path, href } = newResult;
136
+ if (result.find((r) => r.path === path)) return;
137
+ result.push({ path, href });
138
+ }
139
+
125
140
  Object.keys(routes).map((path) => {
126
141
  if (path.toLowerCase().includes(keyword.toLowerCase())) {
127
- result.push({
142
+ addResult({
128
143
  path: path.split('/').slice(1).join(' > '),
129
144
  href: '/' + path,
130
145
  });
@@ -132,16 +147,21 @@ function search(routes: any, keyword: string): SearchResultItem[] {
132
147
 
133
148
  const route = routes[path];
134
149
  if (!route.titles) return;
135
- route.titles
136
- .filter((t: any) => t.level <= 2)
137
- .map((title: any) => {
138
- if (title.title.toLowerCase().includes(keyword.toLowerCase())) {
139
- result.push({
140
- path: path.split('/').slice(1).join(' > ') + ' > ' + title.title,
141
- href: '/' + path + '#' + title.title,
142
- });
143
- }
144
- });
150
+ route.titles.map((title: any) => {
151
+ if (title.title.toLowerCase().includes(keyword.toLowerCase())) {
152
+ addResult({
153
+ path:
154
+ path
155
+ .split('/')
156
+ .map((s) => s.replace(/\.[a-z]{2}-[A-Z]{2}\/?/g, ''))
157
+ .slice(1)
158
+ .join(' > ') +
159
+ ' > ' +
160
+ title.title,
161
+ href: '/' + path + '#' + getLinkFromTitle(title.title),
162
+ });
163
+ }
164
+ });
145
165
  });
146
166
 
147
167
  if (result.length > 8) return result.slice(0, 8);
@@ -28,7 +28,7 @@ export default (props: SidebarProps) => {
28
28
  <ul
29
29
  className={cx(
30
30
  'h-screen lg:h-[calc(100vh-8rem)] overflow-y-scroll',
31
- 'lg:w-64 p-8 pb-12 fadeout w-full',
31
+ 'lg:w-64 px-8 pt-12 lg:pt-8 pb-36 fadeout w-full',
32
32
  )}
33
33
  >
34
34
  {(matchedNav.children || []).map((item) => {
@@ -49,7 +49,8 @@ export default (props: SidebarProps) => {
49
49
  if (to === window.location.pathname) {
50
50
  return (
51
51
  <div
52
- key={child}
52
+ id="active-nav-item"
53
+ key={route.path}
53
54
  className="my-2 hover:text-blue-400 transition-all
54
55
  bg-blue-50 text-blue-400 px-4 py-1
55
56
  rounded-lg cursor-default dark:bg-blue-900 dark:text-blue-200"
@@ -61,6 +62,7 @@ export default (props: SidebarProps) => {
61
62
 
62
63
  return (
63
64
  <components.Link
65
+ key={route.path}
64
66
  to={route.path}
65
67
  onClick={() =>
66
68
  props.setMenuOpened && props.setMenuOpened((o) => !o)
@@ -1,12 +1,20 @@
1
1
  import cx from 'classnames';
2
2
  import React, { useEffect, useState } from 'react';
3
+ import { useThemeContext } from './context';
3
4
  import MoonIcon from './icons/moon.png';
4
5
  import SunIcon from './icons/sun.png';
5
6
 
6
7
  export default () => {
7
8
  const [toggle, setToggle] = useState<Boolean>();
9
+ const { themeConfig } = useThemeContext()!;
8
10
 
9
11
  useEffect(() => {
12
+ // If themeConfig disabled the themeSwitch, just set to light theme
13
+ if (!themeConfig.themeSwitch) {
14
+ document.body.classList.remove('dark');
15
+ return;
16
+ }
17
+
10
18
  // 初始化,获取过去曾经设定过的主题,或是系统当前的主题
11
19
  if (toggle === undefined) {
12
20
  if (localStorage.getItem('theme') === 'dark') {
@@ -2,13 +2,8 @@ import React from 'react';
2
2
  import { Helmet } from 'react-helmet';
3
3
  import { useThemeContext } from './context';
4
4
  import useLanguage from './useLanguage';
5
-
6
- function getLinkFromTitle(title: string) {
7
- return title
8
- .toLowerCase()
9
- .replace(/\s/g, '-')
10
- .replace(/[()]/g, '');
11
- }
5
+ import getLinkFromTitle from './utils/getLinkFromTitle';
6
+ import getTocTitle from './utils/getTocTitle';
12
7
 
13
8
  export default () => {
14
9
  const { location, appData, themeConfig } = useThemeContext()!;
@@ -30,7 +25,7 @@ export default () => {
30
25
  return (
31
26
  <div
32
27
  className="w-full lg:m-12 mb-12 border
33
- border-gray-100 p-8 rounded-xl z-20"
28
+ border-gray-200 dark:border-neutral-700 py-4 rounded-lg z-20"
34
29
  >
35
30
  {/* @ts-ignore */}
36
31
  <Helmet>
@@ -38,22 +33,24 @@ export default () => {
38
33
  {route.titles[0].title} | {themeConfig.title}
39
34
  </title>
40
35
  </Helmet>
41
- <p className="text-lg font-extrabold dark:text-white">
42
- {route.titles[0].title}
36
+ <p className="text-lg font-extrabold text-gray-800 dark:text-neutral-50 pb-2 border-b border-gray-200 dark:border-neutral-700">
37
+ <span className="px-4">{route.titles[0].title}</span>
43
38
  </p>
44
- <ul className="max-h-[calc(100vh-360px)] overflow-y-auto py-2">
39
+ <ul className="max-h-[calc(100vh-360px)] overflow-y-auto px-4">
45
40
  {titles.map((item: any) => {
46
41
  return (
47
42
  <li
48
43
  style={{ paddingLeft: `${item.level - 2}rem` }}
49
- className="mt-3 text-gray-600 cursor-pointer dark:text-gray-400
44
+ className="mt-3 text-gray-600 cursor-pointer dark:text-neutral-400
50
45
  hover:text-blue-500 transition duration-300 dark:hover:text-blue-500"
51
46
  >
52
47
  <a
53
- className={item.level > 2 ? 'text-sm' : ''}
48
+ className={`${
49
+ item.level > 2 ? 'text-sm' : 'text-base'
50
+ } break-all 2xl:break-words`}
54
51
  href={'#' + getLinkFromTitle(item.title)}
55
52
  >
56
- {item.title}
53
+ {getTocTitle(item.title)}
57
54
  </a>
58
55
  </li>
59
56
  );
@@ -6,6 +6,7 @@ function Announcement() {
6
6
  const { themeConfig } = useThemeContext()!;
7
7
 
8
8
  if (!themeConfig.announcement) {
9
+ document.documentElement.style.setProperty('--anchor-offset', '0px');
9
10
  return null;
10
11
  }
11
12
 
@@ -8,7 +8,7 @@ function Features(
8
8
  props: PropsWithChildren<{ title?: string; subtitle?: string }>,
9
9
  ) {
10
10
  return (
11
- <div className="w-screen py-36 features dark:features-dark min-h-screen">
11
+ <div className="w-full py-36 features dark:features-dark min-h-screen">
12
12
  {(props.title || props.subtitle) && (
13
13
  <div className="mb-24 px-4">
14
14
  {props.title && (
@@ -9,11 +9,14 @@ enum MessageType {
9
9
 
10
10
  interface MessageProps {
11
11
  type?: MessageType;
12
- emoji?: string;
12
+ emoji?: string | boolean;
13
+ title?: string;
13
14
  }
14
15
 
15
16
  function Message(props: PropsWithChildren<MessageProps>) {
16
- const messageType = props.type || 'info';
17
+ const messageType = props.type || MessageType.Info;
18
+ const messageTitle = props.title;
19
+ const propsChildren = props.children;
17
20
 
18
21
  let messageClass: string;
19
22
  switch (messageType) {
@@ -30,26 +33,35 @@ function Message(props: PropsWithChildren<MessageProps>) {
30
33
  messageClass = 'mdx-message-info';
31
34
  }
32
35
 
33
- const messageText =
34
- typeof props.children === 'string'
35
- ? props.children
36
- : (props.children as React.ReactElement).props.children;
36
+ let messageEmoji = props.emoji;
37
+ if (!messageEmoji && messageEmoji !== false) {
38
+ switch (messageType) {
39
+ case MessageType.Success:
40
+ messageEmoji = '🏆︎';
41
+ break;
42
+ case MessageType.Warning:
43
+ messageEmoji = '🛎️';
44
+ break;
45
+ case MessageType.Error:
46
+ messageEmoji = '⚠️';
47
+ break;
48
+ default:
49
+ messageEmoji = '💡';
50
+ }
51
+ }
37
52
 
38
53
  return (
39
- <>
40
- <div
41
- className={`w-full py-3 px-4 rounded-lg my-4 mdx-message ${messageClass}`}
42
- >
43
- <p>
44
- {props.emoji && (
45
- <span role="img" className="mr-3 inline">
46
- {props.emoji}
47
- </span>
48
- )}
49
- {messageText}
50
- </p>
54
+ <div
55
+ className={`flex w-full py-5 px-4 rounded-lg my-4 mdx-message ${messageClass}`}
56
+ >
57
+ <span role="img" className="mr-3 dark:text-white">
58
+ {messageEmoji}
59
+ </span>
60
+ <div className="flex-grow">
61
+ {messageTitle && <h5 className="mt-0 mb-3">{messageTitle}</h5>}
62
+ <div className="mdx-message-text">{propsChildren}</div>
51
63
  </div>
52
- </>
64
+ </div>
53
65
  );
54
66
  }
55
67
 
@@ -9,21 +9,27 @@ interface IContext {
9
9
  github: string;
10
10
  // 键盘搜索的快捷键,参考 https://github.com/madrobby/keymaster
11
11
  searchHotKey?: string | { macos: string; windows: string };
12
- logo: string;
12
+ logo: string | React.ComponentType;
13
13
  // 在设置文件中声明该项目的国际化功能支持的语言
14
14
  i18n?: { locale: string; text: string }[];
15
15
  // 插件会从 docs/locales 内将所有 json 文件注入到 themeConfig 中
16
16
  // 供 useLanguage 使用
17
17
  locales: { [locale: string]: { [key: string]: string } };
18
+ // 顶部导航栏右侧自定义组件
19
+ extraNavRight?: React.ComponentType;
20
+ // 底部导航栏左侧自定义组件
21
+ extraNavLeft?: React.ComponentType;
18
22
  navs: {
19
23
  path: string;
20
24
  title: string;
25
+ dropdown?: { title: string; path: string }[];
21
26
  children: any[];
22
27
  }[];
23
28
  announcement?: {
24
29
  title: string;
25
30
  link?: string;
26
31
  };
32
+ themeSwitch?: {};
27
33
  };
28
34
  location: {
29
35
  pathname: string;