Skip to content

Commit

Permalink
feat!: Add page-construclor layout
Browse files Browse the repository at this point in the history
  • Loading branch information
3y3 committed Dec 25, 2023
1 parent d055582 commit 59140d6
Show file tree
Hide file tree
Showing 15 changed files with 610 additions and 151 deletions.
24 changes: 16 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,47 @@
"name": "@diplodoc/client",
"version": "1.2.0",
"description": "",
"main": "build/app.server.js",
"main": "./build/server/app.js",
"scripts": {
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "npm run lint -- --fix",
"build": "webpack && tsc --emitDeclarationOnly --outDir build",
"build": "NODE_ENV=production webpack && tsc --emitDeclarationOnly --outDir build",
"build:dev": "NODE_ENV=development webpack",
"build:watch": "NODE_ENV=development webpack --watch",
"prepublishOnly": "rm -rf build && npm ci --no-workspaces && npm run build",
"test": "exit 0"
},
"author": "",
"license": "ISC",
"types": "./build/index.d.ts",
"engines": {
"node": ">=18",
"npm": ">=9.*"
},
"exports": {
".": {
"node": "./build/app.server.js",
"types": "./build/index.d.ts",
"style": "./build/app.client.css",
"default": "./build/app.client.js"
"style": "./build/client/app.css",
"default": "./build/client/app.js"
},
"./styles": "./build/app.client.css"
"./ssr": {
"types": "./build/index.server.d.ts",
"default": "./build/server/app.js"
},
"./manifest": "./build/client/manifest.json",
"./styles": "./build/client/app.css"
},
"dependencies": {
"@diplodoc/components": "^3.5.1",
"@diplodoc/mermaid-extension": "^1.2.1",
"@diplodoc/openapi-extension": "^1.4.10",
"@diplodoc/transform": "^4.7.2",
"@gravity-ui/page-constructor": "^4.24.0",
"@gravity-ui/uikit": "^5.25.0",
"bem-cn-lite": "^4.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"url": "^0.11.0"
"url": "^0.11.0",
"webpack-manifest-plugin": "^5.0.0"
},
"devDependencies": {
"@diplodoc/babel-preset": "^1.0.2",
Expand Down
17 changes: 17 additions & 0 deletions src/components/App/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,30 @@
@import '@diplodoc/openapi-extension/runtime/styles';
@import '../../styles/default.scss';
@import '../../styles/typography.scss';
@import '../../styles/overrides.scss';

.App {
margin: 0;
min-height: 100vh;
}

.Controls {
height: 100%;

.pc-mobile-navigation & {
margin-left: -14px;
}
}

.g-root {
--dc-header-height: 0px;
--mermaid-zoom-control-color: var(--g-color-text-primary);
--pc-first-block-indent: 0px;
--pc-first-block-mobile-indent: 0px;

.dc-root_full-header & {
--dc-header-height: 64px;
}
}


145 changes: 106 additions & 39 deletions src/components/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import React, {ReactElement, useCallback, useEffect, useState} from 'react';
import React, {ReactElement, useEffect} from 'react';

import {
NavigationData,
PageConstructor,
PageConstructorProvider,
} from '@gravity-ui/page-constructor';
import {
DocLeadingPage,
DocLeadingPageData,
DocPage,
DocPageData,
Lang,
Router,
TextSizes,
Theme,
} from '@diplodoc/components';
import {getDocSettings, updateRootClassName, withSavingSetting} from '../../utils';
import {HeaderControls} from '../HeaderControls';
import {updateRootClassName} from '../../utils';
import {Layout} from '../Layout';
import {useSettings} from '../../hooks/useSettings';
import {useMobile} from '../../hooks/useMobile';

import '../../interceptors/leading-page-links';

Expand All @@ -25,64 +33,123 @@ export interface AppProps {
router: Router;
}

export type DocInnerProps<Data = DocLeadingPageData | DocPageData> = {data: Data} & AppProps;
export type DocInnerProps<Data = DocLeadingPageData | DocPageData> = {
data: Data;
} & AppProps;

export type {DocLeadingPageData, DocPageData};

const MOBILE_VIEW_WIDTH_BREAKPOINT = 900;
function Page(props: DocInnerProps) {
const {data, ...pageProps} = props;

const Page = data.leading ? DocLeadingPage : DocPage;

return (
<Layout>
<Layout.Content>
{/*@ts-ignore*/}
<Page {...data} {...pageProps} />
</Layout.Content>
</Layout>
);
}

type TocData = DocPageData['toc'] & {
navigation?: NavigationData;
};

export function App(props: DocInnerProps): ReactElement {
const {data, router, lang} = props;
const {navigation} = data.toc as TocData;

const docSettings = getDocSettings();
const [isMobileView, setIsMobileView] = useState(
typeof document !== 'undefined' &&
document.body.clientWidth <= MOBILE_VIEW_WIDTH_BREAKPOINT,
);
const [wideFormat, setWideFormat] = useState(docSettings.wideFormat);
const [fullScreen, setFullScreen] = useState(docSettings.fullScreen);
const [showMiniToc, setShowMiniToc] = useState(docSettings.showMiniToc);
const [theme, setTheme] = useState(docSettings.theme);
const [textSize, setTextSize] = useState(docSettings.textSize);
const settings = useSettings();
const mobileView = useMobile();

const {theme, textSize, wideFormat, fullScreen, showMiniToc, onChangeFullScreen} = settings;
const fullHeader = !fullScreen && Boolean(navigation);
const headerHeight = fullHeader ? 64 : 0;
const pageProps = {
headerHeight,
data,
router,
lang,
headerHeight: 0,
wideFormat,
fullScreen,
showMiniToc,
theme,
textSize,
onChangeFullScreen: withSavingSetting<boolean>('fullScreen', setFullScreen),
onChangeWideFormat: withSavingSetting<boolean>('wideFormat', setWideFormat),
onChangeShowMiniToc: withSavingSetting<boolean>('showMiniToc', setShowMiniToc),
onChangeTheme: withSavingSetting<Theme>('theme', setTheme),
onChangeTextSize: withSavingSetting<TextSizes>('textSize', setTextSize),
fullScreen,
onChangeFullScreen,
};

const onResizeHandler = useCallback(() => {
setIsMobileView(document.body.clientWidth <= MOBILE_VIEW_WIDTH_BREAKPOINT);
}, []);
const rebase = (item: any) => {
if (item.type !== 'link') {
return item;
}

return {
...item,
url: item.url.replace(/^\/?/, '/'),
};
};

useEffect(() => {
window.addEventListener('resize', onResizeHandler);
updateRootClassName({
theme,
mobileView,
wideFormat,
fullHeader,
});
}, [theme, mobileView, wideFormat, fullHeader]);

return () => window.removeEventListener('resize', onResizeHandler);
}, []);
if (!navigation) {
return (
<div className="App">
<Page {...pageProps} {...settings} />
</div>
);
}

useEffect(() => {
updateRootClassName(theme, isMobileView);
}, [theme, isMobileView]);
const {header = {}, logo} = navigation;
const {leftItems = [], rightItems = []} = header as NavigationData['header'];
const headerWithControls = rightItems.some((item: {type: string}) => item.type === 'controls');

return (
// TODO(vladimirfedin): Replace Layout__content class.
<div className="App Layout__content">
{data.leading ? (
<DocLeadingPage {...data} {...pageProps} />
) : (
// @ts-ignore
<DocPage {...data} {...pageProps} />
)}
<div className="App">
<PageConstructorProvider theme={theme}>
<PageConstructor
custom={{
navigation: {
controls: () => (
<HeaderControls {...settings} mobileView={mobileView} />
),
},
blocks: {
page: () => (
<Page {...pageProps} {...(headerWithControls ? {} : settings)} />
),
},
}}
content={{
blocks: [
{
type: 'page',
},
],
}}
navigation={
fullHeader
? {
header: {
withBorder: true,
leftItems: leftItems.map(rebase),
rightItems: rightItems.map(rebase),
},
logo,
}
: undefined
}
/>
</PageConstructorProvider>
<OpenapiSandbox />
<MermaidRuntime
theme={theme === Theme.Dark ? 'dark' : 'neutral'}
Expand Down
60 changes: 60 additions & 0 deletions src/components/HeaderControls/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, {memo} from 'react';

import {ControlSizes, Controls, ControlsLayout, TextSizes, Theme} from '@diplodoc/components';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type OnChangeCallback = (value: any) => void;

type Props = {
mobileView: boolean;

theme: Theme;
onChangeTheme: OnChangeCallback;
textSize: TextSizes;
onChangeTextSize: OnChangeCallback;
wideFormat: boolean;
onChangeWideFormat: OnChangeCallback;
showMiniToc: boolean;
onChangeShowMiniToc: OnChangeCallback;
};

export const HeaderControls = memo<Props>(
({
mobileView,

theme,
onChangeTheme,

textSize,
onChangeTextSize,

wideFormat,
onChangeWideFormat,

showMiniToc,
onChangeShowMiniToc,
}) => {
return (
<ControlsLayout
controlClassName={'Control'}
controlSize={ControlSizes.L}
isWideView={mobileView}
isMobileView={mobileView}
>
<Controls
className={'Controls'}
theme={theme}
onChangeTheme={onChangeTheme}
wideFormat={wideFormat}
onChangeWideFormat={onChangeWideFormat}
showMiniToc={showMiniToc}
onChangeShowMiniToc={onChangeShowMiniToc}
textSize={textSize}
onChangeTextSize={onChangeTextSize}
/>
</ControlsLayout>
);
},
);

HeaderControls.displayName = 'HeaderControls';
56 changes: 56 additions & 0 deletions src/components/Layout/Layout.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.Layout {
&__header {
position: sticky;
top: 0;
z-index: 150;
}

&__body {
display: flex;
flex-flow: column;
min-height: calc(100vh - var(--dc-header-height));
}

.pc-page-constructor & {
&__content {
flex: 1 1 auto;
margin: 0 -10px;

.desktop.dc-root_wide-format & {
margin: 0px -30px 0 -48px;
}

.mobile.dc-root_wide-format & {
margin: 0px -28px;
}
}
}

&__footer {
position: relative;
z-index: 90;
margin-top: 0;
flex: 0 0 auto;
}

.mobile & {
&__footer {
margin-top: 70px;

&_doc {
margin-top: 0;
}
}
}

@media only screen and (min-width: 1920px) {
&__body {
margin-left: calc(100vw - 100%);
margin-right: 0;

.pc-page-constructor & {
margin: 0;
}
}
}
}
Loading

0 comments on commit 59140d6

Please sign in to comment.