Skip to content

Commit

Permalink
[Docs] Add ThemeLanguages and new Breakpoints page (elastic#5227)
Browse files Browse the repository at this point in the history
* Added a ThemeSelector for optionally showing/changing content based on JS or Sass theming language
* Added some theme helper components like alert banners, values table, and example row
* [Manual] Copied the outputs json version of Sass for easier consumption in docs rather that sass-loader
* Rearranging sidenav to promote Theme section and adding “Breakpoints”
* Fixed some routing and notices
  • Loading branch information
cchaos authored and ym committed Oct 29, 2021
1 parent 8a59d7c commit 843d629
Show file tree
Hide file tree
Showing 33 changed files with 3,987 additions and 278 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
"test-docker": "node ./scripts/test-docker.js",
"sync-docs": "node ./scripts/docs-sync.js",
"build-docs": "cross-env BABEL_MODULES=false cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=4096 webpack --config=src-docs/webpack.config.js",
"build": "yarn extract-i18n-strings && node ./scripts/compile-clean.js && node ./scripts/compile-eui.js && node ./scripts/compile-scss.js $npm_package_name",
"build": "yarn extract-i18n-strings && node ./scripts/compile-clean.js && node ./scripts/compile-eui.js && yarn compile-scss",
"build-pack": "yarn build && npm pack",
"compile-icons": "node ./scripts/compile-icons.js && prettier --write --loglevel=warn \"./src/components/icon/assets/**/*.tsx\"",
"compile-scss": "node ./scripts/compile-scss.js $npm_package_name",
"extract-i18n-strings": "node ./scripts/babel/fetch-i18n-strings",
"lint": "yarn tsc --noEmit && yarn lint-es && yarn lint-sass",
"lint-fix": "yarn lint-es-fix",
Expand Down
34 changes: 23 additions & 11 deletions scripts/compile-scss.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ const postcssConfigurationWithMinification = {
],
};

async function compileScssFiles(
async function compileScssFiles({
sourcePattern,
destinationDirectory,
docsVariablesDirectory,
packageName
) {
}) {
try {
await mkdir(destinationDirectory);
} catch (err) {
Expand All @@ -44,13 +45,14 @@ async function compileScssFiles(

try {
const { name } = path.parse(inputFilename);
const outputFilenames = await compileScssFile(
const outputFilenames = await compileScssFile({
inputFilename,
path.join(destinationDirectory, `eui_${name}.css`),
path.join(destinationDirectory, `eui_${name}.json`),
path.join(destinationDirectory, `eui_${name}.json.d.ts`),
outputCssFilename: path.join(destinationDirectory, `eui_${name}.css`),
outputVarsFilename: path.join(destinationDirectory, `eui_${name}.json`),
outputVarTypesFilename: path.join(destinationDirectory, `eui_${name}.json.d.ts`),
outputDocsVarsFilename: path.join(docsVariablesDirectory, `eui_${name}.json`),
packageName
);
});

console.log(
chalk`{green ✔} Finished compiling {gray ${inputFilename}} to ${outputFilenames
Expand All @@ -68,13 +70,14 @@ async function compileScssFiles(
);
}

async function compileScssFile(
async function compileScssFile({
inputFilename,
outputCssFilename,
outputVarsFilename,
outputVarTypesFilename,
outputDocsVarsFilename,
packageName
) {
}) {
const outputCssMinifiedFilename = outputCssFilename.replace(
/\.css$/,
'.min.css'
Expand Down Expand Up @@ -111,18 +114,22 @@ async function compileScssFile(
to: outputCssMinifiedFilename,
});

const jsonVars = JSON.stringify(extractedVars, undefined, 2)

await Promise.all([
writeFile(outputCssFilename, postprocessedCss),
writeFile(outputCssMinifiedFilename, postprocessedMinifiedCss),
writeFile(outputVarsFilename, JSON.stringify(extractedVars, undefined, 2)),
writeFile(outputVarsFilename, jsonVars),
writeFile(outputVarTypesFilename, extractedVarTypes),
writeFile(outputDocsVarsFilename, jsonVars),
]);

return [
outputCssFilename,
outputCssMinifiedFilename,
outputVarsFilename,
outputVarTypesFilename,
outputDocsVarsFilename
];
}

Expand All @@ -134,5 +141,10 @@ if (require.main === module) {
process.exit(1);
}

compileScssFiles(path.join('src', 'theme_*.scss'), 'dist', euiPackageName);
compileScssFiles({
sourcePattern: path.join('src', 'theme_*.scss'),
destinationDirectory: 'dist',
docsVariablesDirectory: 'src-docs/src/views/theme/_json',
packageName: euiPackageName
});
}
36 changes: 35 additions & 1 deletion src-docs/src/components/guide_page/guide_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import {
EuiPageHeader,
EuiPageContent,
EuiPageContentBody,
EuiSpacer,
} from '../../../../src/components';

import { LanguageSelector } from '../with_theme';

const GuidePageComponent = ({
children,
title,
Expand All @@ -18,6 +21,11 @@ const GuidePageComponent = ({
location,
match,
history,
description,
rightSideItems: _rightSideItems,
tabs: _tabs,
notice,
showThemeLanguageToggle,
}) => {
const betaBadge = isBeta ? (
<EuiBetaBadge
Expand Down Expand Up @@ -78,16 +86,37 @@ const GuidePageComponent = ({
});
};

const renderNotice = () => {
if (notice) {
return (
<>
<EuiPageContentBody role="region" aria-label="Notice" restrictWidth>
{notice}
</EuiPageContentBody>
<EuiSpacer size="l" />
</>
);
}
};

const rightSideItems = _rightSideItems || [];
if (showThemeLanguageToggle) {
rightSideItems.push(<LanguageSelector />);
}

return (
<>
{renderNotice()}
<EuiPageHeader
restrictWidth
pageTitle={
<>
{title} {betaBadge}
</>
}
tabs={renderTabs()}
tabs={renderTabs() || _tabs}
description={description}
rightSideItems={rightSideItems}
>
{intro}
</EuiPageHeader>
Expand Down Expand Up @@ -127,6 +156,11 @@ GuidePageComponent.propTypes = {
location: PropTypes.object,
match: PropTypes.object,
history: PropTypes.object,
description: PropTypes.node,
notice: PropTypes.node,
tabs: PropTypes.arrayOf(PropTypes.object),
rightSideItems: PropTypes.arrayOf(PropTypes.node),
showThemeLanguageToggle: PropTypes.bool,
};

export const GuidePage = withRouter(GuidePageComponent);
2 changes: 2 additions & 0 deletions src-docs/src/components/guide_page/guide_page_header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export const GuidePageHeader: React.FunctionComponent<GuidePageHeaderProps> = ({

return (
<EuiHeader
role="region"
aria-label="EUI Docs app bar"
position="fixed"
theme="dark"
sections={[
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export { GuideSectionContainer as GuideSection } from './guide_section/guide_sec

export { GuideSectionTypes } from './guide_section/guide_section_types';

export { ThemeProvider, ThemeContext } from './with_theme';
export { ThemeProvider, ThemeContext, LanguageSelector } from './with_theme';
1 change: 1 addition & 0 deletions src-docs/src/components/with_theme/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { ThemeProvider, ThemeContext } from './theme_context';
export { LanguageSelector } from './language_selector';
70 changes: 70 additions & 0 deletions src-docs/src/components/with_theme/language_selector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useContext, useState } from 'react';

import {
EuiButtonGroup,
EuiIcon,
EuiLink,
EuiText,
EuiTourStep,
} from '../../../../src/components';

import {
ThemeContext,
theme_languages,
THEME_LANGUAGES,
} from './theme_context';

const NOTIF_STORAGE_KEY = 'js_vs_sass_notification';

export const LanguageSelector = ({
onChange,
}: {
onChange?: (id: string) => void;
}) => {
const themeContext = useContext(ThemeContext);
const toggleIdSelected = themeContext.themeLanguage;
const onLanguageChange = (optionId: string) => {
themeContext.changeThemeLanguage(optionId as THEME_LANGUAGES['id']);
onChange?.(optionId);
setTourIsOpen(false);
localStorage.setItem(NOTIF_STORAGE_KEY, 'dismissed');
};

const [isTourOpen, setTourIsOpen] = useState(
localStorage.getItem(NOTIF_STORAGE_KEY) !== 'dismissed'
);

const onTourDismiss = () => {
setTourIsOpen(false);
localStorage.setItem(NOTIF_STORAGE_KEY, 'dismissed');
};

return (
<EuiTourStep
content={
<EuiText style={{ maxWidth: 320 }}>
<p>Select your preferred styling language with this toggle button.</p>
</EuiText>
}
isStepOpen={isTourOpen}
onFinish={onTourDismiss}
step={1}
stepsTotal={1}
title={
<>
<EuiIcon type="bell" size="s" /> &nbsp; Theming update
</>
}
footerAction={<EuiLink onClick={onTourDismiss}>Got it!</EuiLink>}
>
<EuiButtonGroup
buttonSize="m"
color="accent"
legend="Language selector"
options={theme_languages}
idSelected={toggleIdSelected}
onChange={(id) => onLanguageChange(id)}
/>
</EuiTourStep>
);
};
45 changes: 43 additions & 2 deletions src-docs/src/components/with_theme/theme_context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,43 @@ import { EuiThemeProvider } from '../../../../src/services';
import { EuiThemeAmsterdam } from '../../../../src/themes/eui-amsterdam/theme';
import { EuiThemeDefault } from '../../../../src/themes/eui/theme';

export const STYLE_STORAGE_KEY = 'js_vs_sass_preference';

export type THEME_LANGUAGES = {
id: 'language--js' | 'language--sass';
label: string;
title: string;
};

export const theme_languages: THEME_LANGUAGES[] = [
{
id: 'language--js',
label: 'CSS-in-JS',
title: 'Language selector: CSS-in-JS',
},
{
id: 'language--sass',
label: 'Sass',
title: 'Language selector: Sass',
},
];

const THEME_NAMES = EUI_THEMES.map(({ value }) => value);
const THEME_LANGS = theme_languages.map(({ id }) => id);

const defaultState = {
theme: THEME_NAMES[2],
themeLanguage: THEME_LANGS[0],
// eslint-disable-next-line @typescript-eslint/no-unused-vars
changeThemeLanguage: (language: THEME_LANGUAGES['id']) => {},
theme: THEME_NAMES[0],
changeTheme: (themeValue: EUI_THEME['value']) => {
applyTheme(themeValue);
},
};

interface State {
theme: EUI_THEME['value'];
themeLanguage: THEME_LANGUAGES['id'];
}

export const ThemeContext = React.createContext(defaultState);
Expand All @@ -25,12 +51,19 @@ export class ThemeProvider extends React.Component<object, State> {
constructor(props: object) {
super(props);

let themeLanguage = localStorage.getItem(
STYLE_STORAGE_KEY
) as THEME_LANGUAGES['id'];
if (!themeLanguage || !THEME_LANGS.includes(themeLanguage))
themeLanguage = defaultState.themeLanguage;

let theme = localStorage.getItem('theme');
if (!theme || !THEME_NAMES.includes(theme)) theme = defaultState.theme;
applyTheme(theme);

this.state = {
theme,
themeLanguage,
};
}

Expand All @@ -41,14 +74,22 @@ export class ThemeProvider extends React.Component<object, State> {
});
};

changeThemeLanguage = (language: THEME_LANGUAGES['id']) => {
this.setState({ themeLanguage: language }, () => {
localStorage.setItem(STYLE_STORAGE_KEY, language);
});
};

render() {
const { children } = this.props;
const { theme } = this.state;
const { theme, themeLanguage } = this.state;
return (
<ThemeContext.Provider
value={{
theme,
themeLanguage,
changeTheme: this.changeTheme,
changeThemeLanguage: this.changeThemeLanguage,
}}
>
<EuiThemeProvider
Expand Down
Loading

0 comments on commit 843d629

Please sign in to comment.