mirror of
https://github.com/Redocly/redoc.git
synced 2025-01-31 10:04:08 +03:00
feat: theme hooks experimental hooks
This commit is contained in:
parent
b2c3c00e8c
commit
55bd8535b4
|
@ -2,6 +2,7 @@ import { transparentize } from 'polished';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import styled, {
|
import styled, {
|
||||||
|
extensionsHook,
|
||||||
ResolvedThemeInterface,
|
ResolvedThemeInterface,
|
||||||
StyledComponentClass,
|
StyledComponentClass,
|
||||||
withProps,
|
withProps,
|
||||||
|
@ -75,6 +76,8 @@ export const PropertyNameCell = withProps<{ kind?: string }>(PropertyCell.extend
|
||||||
}
|
}
|
||||||
|
|
||||||
${({ kind }) => (kind !== 'field' ? 'font-style: italic' : '')};
|
${({ kind }) => (kind !== 'field' ? 'font-style: italic' : '')};
|
||||||
|
|
||||||
|
${extensionsHook('PropertyNameCell')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const PropertyDetailsCell = styled.td`
|
export const PropertyDetailsCell = styled.td`
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { InterpolationFunction, Styles, ThemeProps } from 'styled-components';
|
import { InterpolationFunction, Styles, ThemeProps } from 'styled-components';
|
||||||
|
|
||||||
import styled, { css, ResolvedThemeInterface, StyledComponentClass } from '../styled-components';
|
import styled, {
|
||||||
|
css,
|
||||||
|
extensionsHook,
|
||||||
|
ResolvedThemeInterface,
|
||||||
|
StyledComponentClass,
|
||||||
|
} from '../styled-components';
|
||||||
|
|
||||||
const headerFontSize = {
|
const headerFontSize = {
|
||||||
1: '1.85714em',
|
1: '1.85714em',
|
||||||
|
@ -18,16 +23,28 @@ export const headerCommonMixin = level => css`
|
||||||
export const H1 = styled.h1`
|
export const H1 = styled.h1`
|
||||||
${headerCommonMixin(1)};
|
${headerCommonMixin(1)};
|
||||||
color: ${props => props.theme.colors.main};
|
color: ${props => props.theme.colors.main};
|
||||||
|
|
||||||
|
${extensionsHook('H1')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const H2 = styled.h2`
|
export const H2 = styled.h2`
|
||||||
${headerCommonMixin(2)};
|
${headerCommonMixin(2)};
|
||||||
color: black;
|
color: black;
|
||||||
|
|
||||||
|
${extensionsHook('H2')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const H3 = styled.h2`
|
export const H3 = styled.h2`
|
||||||
${headerCommonMixin(3)};
|
${headerCommonMixin(3)};
|
||||||
color: black;
|
color: black;
|
||||||
|
|
||||||
|
${extensionsHook('H3')};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RightPanelHeader = styled.h3`
|
||||||
|
color: ${({ theme }) => theme.rightPanel.textColor};
|
||||||
|
|
||||||
|
${extensionsHook('RightPanelHeader')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UnderlinedHeader = styled.h5`
|
export const UnderlinedHeader = styled.h5`
|
||||||
|
@ -38,4 +55,6 @@ export const UnderlinedHeader = styled.h5`
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 0.929em;
|
font-size: 0.929em;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
|
||||||
|
${extensionsHook('UnderlinedHeader')};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { MiddlePanel, Row } from '../../common-elements/';
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
import { Markdown } from '../Markdown/Markdown';
|
||||||
import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes';
|
import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes';
|
||||||
|
|
||||||
|
import { StyledMarkdownBlock } from '../Markdown/styled.elements';
|
||||||
import {
|
import {
|
||||||
ApiHeader,
|
ApiHeader,
|
||||||
DownloadButton,
|
DownloadButton,
|
||||||
|
@ -77,22 +78,23 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
|
||||||
</DownloadButton>
|
</DownloadButton>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
<StyledMarkdownBlock>
|
||||||
|
{((info.license || info.contact || info.termsOfService) && (
|
||||||
|
<InfoSpanBoxWrap>
|
||||||
|
<InfoSpanBox>
|
||||||
|
{email} {website} {license} {terms}
|
||||||
|
</InfoSpanBox>
|
||||||
|
</InfoSpanBoxWrap>
|
||||||
|
)) ||
|
||||||
|
null}
|
||||||
|
|
||||||
{((info.license || info.contact || info.termsOfService) && (
|
{(externalDocs && (
|
||||||
<InfoSpanBoxWrap>
|
<p>
|
||||||
<InfoSpanBox>
|
<a href={externalDocs.url}>{externalDocs.description || externalDocs.url}</a>
|
||||||
{email} {website} {license} {terms}
|
</p>
|
||||||
</InfoSpanBox>
|
)) ||
|
||||||
</InfoSpanBoxWrap>
|
null}
|
||||||
)) ||
|
</StyledMarkdownBlock>
|
||||||
null}
|
|
||||||
|
|
||||||
{(externalDocs && (
|
|
||||||
<p>
|
|
||||||
<a href={externalDocs.url}>{externalDocs.description || externalDocs.url}</a>
|
|
||||||
</p>
|
|
||||||
)) ||
|
|
||||||
null}
|
|
||||||
</MiddlePanel>
|
</MiddlePanel>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { AnchorHTMLAttributes, ClassAttributes, HTMLAttributes } from 'react';
|
import { AnchorHTMLAttributes, ClassAttributes, HTMLAttributes } from 'react';
|
||||||
|
|
||||||
import { H1, MiddlePanel } from '../../common-elements';
|
import { H1, MiddlePanel } from '../../common-elements';
|
||||||
import styled, { ResolvedThemeInterface, StyledComponentClass } from '../../styled-components';
|
import styled, {
|
||||||
|
extensionsHook,
|
||||||
|
ResolvedThemeInterface,
|
||||||
|
StyledComponentClass,
|
||||||
|
} from '../../styled-components';
|
||||||
|
|
||||||
const delimiterWidth = 15;
|
const delimiterWidth = 15;
|
||||||
|
|
||||||
|
@ -10,6 +14,8 @@ export const ApiInfoWrap = MiddlePanel;
|
||||||
export const ApiHeader = H1.extend`
|
export const ApiHeader = H1.extend`
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
${extensionsHook('ApiHeader')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const DownloadButton = styled.a`
|
export const DownloadButton = styled.a`
|
||||||
|
@ -20,6 +26,8 @@ export const DownloadButton = styled.a`
|
||||||
padding: 4px 8px 4px;
|
padding: 4px 8px 4px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
|
${extensionsHook('DownloadButton')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InfoSpan = styled.span`
|
export const InfoSpan = styled.span`
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { InterpolationFunction, Styles, ThemeProps } from 'styled-components';
|
||||||
import { headerCommonMixin, linkifyMixin } from '../../common-elements';
|
import { headerCommonMixin, linkifyMixin } from '../../common-elements';
|
||||||
import styled, {
|
import styled, {
|
||||||
css,
|
css,
|
||||||
|
extensionsHook,
|
||||||
ResolvedThemeInterface,
|
ResolvedThemeInterface,
|
||||||
StyledComponentClass,
|
StyledComponentClass,
|
||||||
withProps,
|
withProps,
|
||||||
|
@ -132,4 +133,19 @@ export const StyledMarkdownBlock = withProps<{ dense?: boolean; inline?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
${linkifyMixin('.share-link')};
|
${linkifyMixin('.share-link')};
|
||||||
|
|
||||||
|
${extensionsHook('Markdown')};
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: ${props => props.theme.links.color};
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: ${props => props.theme.links.visited};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${props => props.theme.links.hover};
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -32,19 +32,6 @@ export const RedocWrap = styled.div`
|
||||||
.redoc-markdown h1 {
|
.redoc-markdown h1 {
|
||||||
padding-top: ${props => props.theme.spacingUnit * 4}px;
|
padding-top: ${props => props.theme.spacingUnit * 4}px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: ${props => props.theme.links.color};
|
|
||||||
|
|
||||||
&:visited {
|
|
||||||
color: ${props => props.theme.links.visited};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: ${props => props.theme.links.hover};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ApiContentWrap = styled.div`
|
export const ApiContentWrap = styled.div`
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { OperationModel } from '../../services/models';
|
||||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||||
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
||||||
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
||||||
|
|
||||||
export interface RequestSamplesProps {
|
export interface RequestSamplesProps {
|
||||||
operation: OperationModel;
|
operation: OperationModel;
|
||||||
|
@ -24,7 +24,7 @@ export class RequestSamples extends React.Component<RequestSamplesProps> {
|
||||||
return (
|
return (
|
||||||
(hasSamples && (
|
(hasSamples && (
|
||||||
<div>
|
<div>
|
||||||
<h3> Request samples </h3>
|
<RightPanelHeader> Request samples </RightPanelHeader>
|
||||||
|
|
||||||
<Tabs defaultIndex={0}>
|
<Tabs defaultIndex={0}>
|
||||||
<TabList>
|
<TabList>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
||||||
|
|
||||||
import { MediaContentModel, OperationModel } from '../../services/models';
|
import { MediaContentModel, OperationModel } from '../../services/models';
|
||||||
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
||||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||||
|
|
||||||
export interface ResponseSamplesProps {
|
export interface ResponseSamplesProps {
|
||||||
|
@ -23,7 +23,7 @@ export class ResponseSamples extends React.Component<ResponseSamplesProps> {
|
||||||
return (
|
return (
|
||||||
(responses.length > 0 && (
|
(responses.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h3> Response samples </h3>
|
<RightPanelHeader> Response samples </RightPanelHeader>
|
||||||
|
|
||||||
<Tabs defaultIndex={0}>
|
<Tabs defaultIndex={0}>
|
||||||
<TabList>
|
<TabList>
|
||||||
|
|
|
@ -98,7 +98,14 @@ export class RedocNormalizedOptions {
|
||||||
unstable_ignoreMimeParameters: boolean;
|
unstable_ignoreMimeParameters: boolean;
|
||||||
|
|
||||||
constructor(raw: RedocRawOptions) {
|
constructor(raw: RedocRawOptions) {
|
||||||
|
let hook;
|
||||||
|
if (raw.theme && raw.theme.extensionsHook) {
|
||||||
|
hook = raw.theme.extensionsHook;
|
||||||
|
raw.theme.extensionsHook = undefined;
|
||||||
|
}
|
||||||
this.theme = resolveTheme(mergeObjects({} as any, defaultTheme, raw.theme || {}));
|
this.theme = resolveTheme(mergeObjects({} as any, defaultTheme, raw.theme || {}));
|
||||||
|
this.theme.extensionsHook = hook;
|
||||||
|
|
||||||
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
||||||
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
||||||
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { ComponentClass, StatelessComponent } from 'react';
|
import { ComponentClass, StatelessComponent } from 'react';
|
||||||
import * as styledComponents from 'styled-components';
|
import * as styledComponents from 'styled-components';
|
||||||
|
|
||||||
import { ResolvedThemeInterface } from './theme';
|
import { ResolvedThemeInterface, ThemeInterface } from './theme';
|
||||||
|
|
||||||
export { ResolvedThemeInterface };
|
export { ResolvedThemeInterface };
|
||||||
|
|
||||||
|
@ -56,3 +56,12 @@ export const media = {
|
||||||
export { css, injectGlobal, keyframes, ThemeProvider, withProps };
|
export { css, injectGlobal, keyframes, ThemeProvider, withProps };
|
||||||
export { StyledComponentClass } from 'styled-components';
|
export { StyledComponentClass } from 'styled-components';
|
||||||
export default styled;
|
export default styled;
|
||||||
|
|
||||||
|
export function extensionsHook(styledName: string) {
|
||||||
|
return props => {
|
||||||
|
if (!props.theme.extensionsHook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return props.theme.extensionsHook(styledName, props);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { adjustHue, desaturate, lighten, transparentize } from 'polished';
|
||||||
|
|
||||||
const defaultTheme: ThemeInterface = {
|
const defaultTheme: ThemeInterface = {
|
||||||
spacingUnit: 20,
|
spacingUnit: 20,
|
||||||
|
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
small: '50rem',
|
small: '50rem',
|
||||||
medium: '85rem',
|
medium: '85rem',
|
||||||
|
@ -74,6 +75,7 @@ const defaultTheme: ThemeInterface = {
|
||||||
rightPanel: {
|
rightPanel: {
|
||||||
backgroundColor: '#263238',
|
backgroundColor: '#263238',
|
||||||
width: '40%',
|
width: '40%',
|
||||||
|
textColor: '#ffffff',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,7 +189,10 @@ export interface ResolvedThemeInterface {
|
||||||
rightPanel: {
|
rightPanel: {
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
width: string;
|
width: string;
|
||||||
|
textColor: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extensionsHook?: (name: string, props: any) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type primitive = string | number | boolean | undefined | null;
|
export type primitive = string | number | boolean | undefined | null;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user