Skip to content

Commit 8007951

Browse files
authored
feat(doc-tools): add doc medium-zoom plugin (#3716)
1 parent ad78387 commit 8007951

File tree

34 files changed

+3403
-1055
lines changed

34 files changed

+3403
-1055
lines changed

.changeset/tidy-eagles-cover.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@modern-js/doc-core': patch
3+
---
4+
5+
feat: add doc medium-zoom plugin
6+
7+
feat: 增加 medium-zoom 插件

packages/builder/builder-shared/tests/plugins/__snapshots__/AutoSetRootFontSizePlugin.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ exports[`test getRootPixelCode > should getRootPixelCode with custom options 1`]
5757
typeof window !== 'undefined' && setRootPixel();"
5858
`;
5959

60-
exports[`test getRootPixelCode > should getRootPixelCode with custom options 2`] = `"function setRootPixel(){function n(n){return(new RegExp(\\"[?&]\\"+n+\\"=([^&#\\\\b]+)\\").exec(location.search||\\"\\")||[])[1]}function e(){var e,i=\\"widthKey\\",t=document.documentElement;if(i&&+n(i))e=+n(i);else if(e=window.innerWidth&&t.clientWidth?Math.min(window.innerWidth,t.clientWidth):window.innerWidth||t.clientWidth||document.body&&document.body.clientWidth||750,(screen.orientation&&screen.orientation.angle||window.orientation)/90%2){var o=window.innerHeight&&t.clientHeight?Math.min(window.innerHeight,t.clientHeight):window.innerHeight||t.clientHeight||document.body&&document.body.clientHeight||750;e=Math.max(o,350)}var d=5*e/750;d=d<64?d:5,window.ROOT_FONT_SIZE=d,t.style.fontSize=d+\\"px\\"}function i(n){n?e():setTimeout(e,30)}i(!0),window.addEventListener(\\"resize\\",i,!1),\\"onorientationchange\\"in window&&window.addEventListener(\\"orientationchange\\",i,!1)}\\"undefined\\"!=typeof window&&setRootPixel();"`;
60+
exports[`test getRootPixelCode > should getRootPixelCode with custom options 2`] = `"function setRootPixel(){function n(n){return(new RegExp(\\"[?&]\\"+n+\\"=([^&#\\\\b]+)\\").exec(location.search||\\"\\")||[])[1]}function e(){var e,i=\\"widthKey\\",t=document.documentElement;if(+n(i))e=+n(i);else if(e=window.innerWidth&&t.clientWidth?Math.min(window.innerWidth,t.clientWidth):window.innerWidth||t.clientWidth||document.body&&document.body.clientWidth||750,(screen.orientation&&screen.orientation.angle||window.orientation)/90%2){var o=window.innerHeight&&t.clientHeight?Math.min(window.innerHeight,t.clientHeight):window.innerHeight||t.clientHeight||document.body&&document.body.clientHeight||750;e=Math.max(o,350)}var d=5*e/750;d=d<64?d:5,window.ROOT_FONT_SIZE=d,t.style.fontSize=d+\\"px\\"}function i(n){n?e():setTimeout(e,30)}i(!0),window.addEventListener(\\"resize\\",i,!1),\\"onorientationchange\\"in window&&window.addEventListener(\\"orientationchange\\",i,!1)}\\"undefined\\"!=typeof window&&setRootPixel();"`;
6161

6262
exports[`test getRootPixelCode > should getRootPixelCode with default options 1`] = `
6363
"function setRootPixel() {

packages/cli/doc-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"@modern-js/builder-rspack-provider": "workspace:*",
6262
"@modern-js/mdx-rs-binding": "^0.1.8",
6363
"@modern-js/remark-container": "workspace:*",
64+
"@modern-js/doc-plugin-medium-zoom": "workspace:*",
6465
"@modern-js/utils": "workspace:*",
6566
"@types/compression": "^1.7.2",
6667
"@types/polka": "^0.5.4",
@@ -79,7 +80,6 @@
7980
"html-to-text": "^9.0.3",
8081
"lodash-es": "^4.17.21",
8182
"mdast-util-mdxjs-esm": "^1.3.0",
82-
"medium-zoom": "1.0.8",
8383
"node-fetch": "3.3.0",
8484
"nprogress": "^0.2.0",
8585
"ora": "5.4.1",

packages/cli/doc-core/src/node/build.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from './constants';
1313
import { createModernBuilder } from './createBuilder';
1414
import { writeSearchIndex } from './searchIndex';
15-
import { modifyConfig, beforeBuild, afterBuild } from './hooks';
15+
import { modifyConfig, beforeBuild, afterBuild, loadPlugins } from './hooks';
1616
import { logger } from './utils';
1717
import { APPEARANCE_KEY, normalizeSlash } from '@/shared/utils';
1818
import type { Route } from '@/node/route/RouteService';
@@ -137,6 +137,8 @@ export async function renderPages(config: UserConfig) {
137137

138138
export async function build(rootDir: string, config: UserConfig) {
139139
const isProd = true;
140+
await loadPlugins(config);
141+
140142
const modifiedConfig = await modifyConfig({
141143
config,
142144
});

packages/cli/doc-core/src/node/dev.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { UserConfig } from 'shared/types';
22
import { removeLeadingSlash } from '../shared/utils';
33
import { createModernBuilder } from './createBuilder';
44
import { writeSearchIndex } from './searchIndex';
5-
import { modifyConfig, beforeBuild, afterBuild } from './hooks';
5+
import { modifyConfig, beforeBuild, afterBuild, loadPlugins } from './hooks';
66

77
interface ServerInstance {
88
close: () => Promise<void>;
@@ -14,7 +14,7 @@ export async function dev(
1414
): Promise<ServerInstance> {
1515
const base = config.doc?.base ?? '';
1616
const isProd = false;
17-
17+
await loadPlugins(config);
1818
try {
1919
const modifiedConfig = await modifyConfig({
2020
config,

packages/cli/doc-core/src/node/hooks.ts

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { UserConfig, PageIndexInfo, DocPlugin } from 'shared/types';
2-
import { pluginLastUpdated } from './plugins/lastUpdated';
32
import { AdditionalPage } from '@/shared/types/Plugin';
43

54
type HookOptions = {
@@ -8,20 +7,35 @@ type HookOptions = {
87
pageData?: PageIndexInfo;
98
};
109

11-
function getPlugins(config: UserConfig) {
12-
const plugins: DocPlugin[] = config.doc?.plugins || [];
10+
let docPlugins: DocPlugin[] = [];
11+
12+
// The init function is used to initialize the doc plugins and will execute before the build process.
13+
export async function loadPlugins(config: UserConfig) {
14+
// Clear docPlugins first, for the watch mode
15+
docPlugins = [];
1316
const enableLastUpdated =
1417
config.doc.themeConfig?.lastUpdated ||
1518
config.doc.themeConfig?.locales?.some(locale => locale.lastUpdated);
19+
const mediumZoomConfig = config.doc.mediumZoom ?? true;
1620
if (enableLastUpdated) {
17-
plugins.push(pluginLastUpdated());
21+
const { pluginLastUpdated } = await import('./plugins/lastUpdated');
22+
docPlugins.push(pluginLastUpdated());
23+
}
24+
if (mediumZoomConfig) {
25+
const { pluginMediumZoom } = await import(
26+
'@modern-js/doc-plugin-medium-zoom'
27+
);
28+
docPlugins.push(
29+
pluginMediumZoom(
30+
typeof mediumZoomConfig === 'object' ? mediumZoomConfig : undefined,
31+
),
32+
);
1833
}
19-
return plugins;
34+
docPlugins.push(...(config.doc.plugins || []));
2035
}
2136

2237
export async function modifyConfig(hookOptions: HookOptions) {
2338
const { config } = hookOptions;
24-
const docPlugins = getPlugins(config);
2539

2640
// config hooks
2741
for (const plugin of docPlugins) {
@@ -35,7 +49,6 @@ export async function modifyConfig(hookOptions: HookOptions) {
3549

3650
export async function beforeBuild(hookOptions: HookOptions) {
3751
const { config, isProd = true } = hookOptions;
38-
const docPlugins = getPlugins(config);
3952

4053
// beforeBuild hooks
4154
return await Promise.all(
@@ -49,7 +62,6 @@ export async function beforeBuild(hookOptions: HookOptions) {
4962

5063
export async function afterBuild(hookOptions: HookOptions) {
5164
const { config, isProd = true } = hookOptions;
52-
const docPlugins = getPlugins(config);
5365

5466
// afterBuild hooks
5567
return await Promise.all(
@@ -63,7 +75,6 @@ export async function afterBuild(hookOptions: HookOptions) {
6375

6476
export async function extendPageData(hookOptions: HookOptions): Promise<void> {
6577
const { pageData } = hookOptions;
66-
const docPlugins = getPlugins(hookOptions.config);
6778
// extendPageData hooks
6879
await Promise.all(
6980
docPlugins
@@ -78,7 +89,6 @@ export async function addPages(
7889
hookOptions: HookOptions,
7990
): Promise<AdditionalPage[]> {
8091
const { config } = hookOptions;
81-
const docPlugins = getPlugins(config);
8292

8393
// addPages hooks
8494
const result = await Promise.all(
@@ -91,3 +101,23 @@ export async function addPages(
91101

92102
return result.flat();
93103
}
104+
105+
export async function globalUIComponents(): Promise<string[]> {
106+
// globalUIComponents hooks
107+
const result = docPlugins.map(plugin => {
108+
return plugin.globalUIComponents || [];
109+
});
110+
111+
return result.flat();
112+
}
113+
114+
export async function globalStyles(): Promise<string[]> {
115+
// globalStyles hooks
116+
const result = docPlugins
117+
.filter(plugin => typeof plugin.globalStyles === 'string')
118+
.map(plugin => {
119+
return plugin.globalStyles;
120+
});
121+
122+
return result;
123+
}

packages/cli/doc-core/src/node/runtimeModule/globalStyles.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import { join } from 'path';
2+
import { globalStyles } from '../hooks';
23
import RuntimeModulesPlugin from './RuntimeModulePlugin';
34
import { RuntimeModuleID } from '.';
45
import { UserConfig } from '@/shared/types';
56

6-
export function globalStylesVMPlugin(
7+
export async function globalStylesVMPlugin(
78
_scanDir: string,
89
config: UserConfig,
910
_isSSR: boolean,
1011
runtimeTempDir: string,
1112
) {
1213
const modulePath = join(runtimeTempDir, `${RuntimeModuleID.GlobalStyles}.js`);
14+
const globalStylesByPlugins = await globalStyles();
1315
const moduleContent = [
1416
config.doc?.globalStyles || '',
15-
...(config.doc?.plugins || []).map(plugin => plugin.globalStyles || ''),
17+
...globalStylesByPlugins,
1618
]
1719
.filter(source => source.length > 0)
1820
.map(source => `import '${source}';`)

packages/cli/doc-core/src/node/runtimeModule/globalUIComponents.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { join } from 'path';
2+
import { globalUIComponents } from '../hooks';
23
import RuntimeModulesPlugin from './RuntimeModulePlugin';
34
import { RuntimeModuleID } from '.';
45
import { UserConfig } from '@/shared/types';
56

6-
export function globalUIComponentsVMPlugin(
7+
export async function globalUIComponentsVMPlugin(
78
_scanDir: string,
89
config: UserConfig,
910
_isSSR: boolean,
@@ -14,11 +15,10 @@ export function globalUIComponentsVMPlugin(
1415
runtimeTempDir,
1516
`${RuntimeModuleID.GlobalComponents}.js`,
1617
);
18+
const globalUIComponentsByPlugins = await globalUIComponents();
1719
const moduleContent = [
1820
...(config.doc?.globalUIComponents || []),
19-
...(config.doc?.plugins || [])
20-
.map(plugin => plugin.globalUIComponents || [])
21-
.flat(),
21+
...globalUIComponentsByPlugins,
2222
]
2323
.map(source => `import Comp_${index++} from '${source}';`)
2424
.concat(

packages/cli/doc-core/src/shared/types/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ export interface DocConfig<ThemeConfig = DefaultThemeConfig> {
119119
* Search options
120120
*/
121121
search?: SearchOptions;
122+
/**
123+
* Whether to enable medium-zoom, default is true
124+
*/
125+
mediumZoom?:
126+
| boolean
127+
| {
128+
selector?: string;
129+
};
122130
}
123131

124132
export type BaseRuntimePageInfo = Omit<

packages/cli/doc-core/src/theme-default/layout/DocLayout/index.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useLocation } from 'react-router-dom';
22
import { useEffect, useState } from 'react';
33
import { MDXProvider } from '@mdx-js/react';
4-
import mediumZoom from 'medium-zoom';
54
import { Aside } from '../../components/Aside';
65
import { DocFooter } from '../../components/DocFooter';
76
import { useLocaleSiteData, useSidebarData } from '../../logic';
@@ -20,15 +19,6 @@ export interface DocLayoutProps {
2019
afterOutline?: React.ReactNode;
2120
}
2221

23-
function DocContent() {
24-
const { pathname } = useLocation();
25-
useEffect(() => {
26-
const images = document.querySelectorAll('.modern-doc img');
27-
mediumZoom(images);
28-
}, [pathname]);
29-
return <Content />;
30-
}
31-
3222
export function DocLayout(props: DocLayoutProps) {
3323
const { beforeDocFooter, beforeDoc, afterDoc, beforeOutline, afterOutline } =
3424
props;
@@ -86,7 +76,7 @@ export function DocLayout(props: DocLayoutProps) {
8676
<div className="modern-doc">
8777
<TabDataContext.Provider value={{ tabData, setTabData }}>
8878
<MDXProvider components={getCustomMDXComponent()}>
89-
<DocContent />
79+
<Content />
9080
</MDXProvider>
9181
</TabDataContext.Provider>
9282
<div>

0 commit comments

Comments
 (0)