diff --git a/src/common-elements/fields-layout.ts b/src/common-elements/fields-layout.ts index 14b5f1d776..a1a24cd2bf 100644 --- a/src/common-elements/fields-layout.ts +++ b/src/common-elements/fields-layout.ts @@ -2,6 +2,7 @@ import { transparentize } from 'polished'; import * as React from 'react'; import styled, { + extensionsHook, ResolvedThemeInterface, StyledComponentClass, withProps, @@ -75,6 +76,8 @@ export const PropertyNameCell = withProps<{ kind?: string }>(PropertyCell.extend } ${({ kind }) => (kind !== 'field' ? 'font-style: italic' : '')}; + + ${extensionsHook('PropertyNameCell')}; `; export const PropertyDetailsCell = styled.td` diff --git a/src/common-elements/headers.ts b/src/common-elements/headers.ts index 4797b2d3e7..96a64aa0cb 100644 --- a/src/common-elements/headers.ts +++ b/src/common-elements/headers.ts @@ -1,7 +1,12 @@ import * as React from 'react'; 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 = { 1: '1.85714em', @@ -18,16 +23,28 @@ export const headerCommonMixin = level => css` export const H1 = styled.h1` ${headerCommonMixin(1)}; color: ${props => props.theme.colors.main}; + + ${extensionsHook('H1')}; `; export const H2 = styled.h2` ${headerCommonMixin(2)}; color: black; + + ${extensionsHook('H2')}; `; export const H3 = styled.h2` ${headerCommonMixin(3)}; color: black; + + ${extensionsHook('H3')}; +`; + +export const RightPanelHeader = styled.h3` + color: ${({ theme }) => theme.rightPanel.textColor}; + + ${extensionsHook('RightPanelHeader')}; `; export const UnderlinedHeader = styled.h5` @@ -38,4 +55,6 @@ export const UnderlinedHeader = styled.h5` text-transform: uppercase; font-size: 0.929em; line-height: 20px; + + ${extensionsHook('UnderlinedHeader')}; `; diff --git a/src/components/ApiInfo/ApiInfo.tsx b/src/components/ApiInfo/ApiInfo.tsx index 683dd5288d..e7058a8ae9 100644 --- a/src/components/ApiInfo/ApiInfo.tsx +++ b/src/components/ApiInfo/ApiInfo.tsx @@ -7,6 +7,7 @@ import { MiddlePanel, Row } from '../../common-elements/'; import { Markdown } from '../Markdown/Markdown'; import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes'; +import { StyledMarkdownBlock } from '../Markdown/styled.elements'; import { ApiHeader, DownloadButton, @@ -77,22 +78,23 @@ export class ApiInfo extends React.Component {

)} + + {((info.license || info.contact || info.termsOfService) && ( + + + {email} {website} {license} {terms} + + + )) || + null} - {((info.license || info.contact || info.termsOfService) && ( - - - {email} {website} {license} {terms} - - - )) || - null} - - {(externalDocs && ( -

- {externalDocs.description || externalDocs.url} -

- )) || - null} + {(externalDocs && ( +

+ {externalDocs.description || externalDocs.url} +

+ )) || + null} +
); diff --git a/src/components/ApiInfo/styled.elements.ts b/src/components/ApiInfo/styled.elements.ts index 7852821fd9..583ff9f59e 100644 --- a/src/components/ApiInfo/styled.elements.ts +++ b/src/components/ApiInfo/styled.elements.ts @@ -1,7 +1,11 @@ import { AnchorHTMLAttributes, ClassAttributes, HTMLAttributes } from 'react'; import { H1, MiddlePanel } from '../../common-elements'; -import styled, { ResolvedThemeInterface, StyledComponentClass } from '../../styled-components'; +import styled, { + extensionsHook, + ResolvedThemeInterface, + StyledComponentClass, +} from '../../styled-components'; const delimiterWidth = 15; @@ -10,6 +14,8 @@ export const ApiInfoWrap = MiddlePanel; export const ApiHeader = H1.extend` margin-top: 0; margin-bottom: 0.5em; + + ${extensionsHook('ApiHeader')}; `; export const DownloadButton = styled.a` @@ -20,6 +26,8 @@ export const DownloadButton = styled.a` padding: 4px 8px 4px; display: inline-block; text-decoration: none; + + ${extensionsHook('DownloadButton')}; `; export const InfoSpan = styled.span` diff --git a/src/components/Markdown/styled.elements.ts b/src/components/Markdown/styled.elements.ts index 2e94b65d6c..ff743c2b04 100644 --- a/src/components/Markdown/styled.elements.ts +++ b/src/components/Markdown/styled.elements.ts @@ -4,6 +4,7 @@ import { InterpolationFunction, Styles, ThemeProps } from 'styled-components'; import { headerCommonMixin, linkifyMixin } from '../../common-elements'; import styled, { css, + extensionsHook, ResolvedThemeInterface, StyledComponentClass, withProps, @@ -132,4 +133,19 @@ export const StyledMarkdownBlock = withProps<{ dense?: boolean; inline?: boolean } ${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}; + } + } `; diff --git a/src/components/Redoc/styled.elements.tsx b/src/components/Redoc/styled.elements.tsx index 4963a13d1a..1716cacb20 100644 --- a/src/components/Redoc/styled.elements.tsx +++ b/src/components/Redoc/styled.elements.tsx @@ -32,19 +32,6 @@ export const RedocWrap = styled.div` .redoc-markdown h1 { 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` diff --git a/src/components/RequestSamples/RequestSamples.tsx b/src/components/RequestSamples/RequestSamples.tsx index d895dc41a8..d8d74dcd6f 100644 --- a/src/components/RequestSamples/RequestSamples.tsx +++ b/src/components/RequestSamples/RequestSamples.tsx @@ -4,7 +4,7 @@ import { OperationModel } from '../../services/models'; import { PayloadSamples } from '../PayloadSamples/PayloadSamples'; 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 { operation: OperationModel; @@ -24,7 +24,7 @@ export class RequestSamples extends React.Component { return ( (hasSamples && (
-

Request samples

+ Request samples diff --git a/src/components/ResponseSamples/ResponseSamples.tsx b/src/components/ResponseSamples/ResponseSamples.tsx index 54f04baa62..aba643954d 100644 --- a/src/components/ResponseSamples/ResponseSamples.tsx +++ b/src/components/ResponseSamples/ResponseSamples.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; 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'; export interface ResponseSamplesProps { @@ -23,7 +23,7 @@ export class ResponseSamples extends React.Component { return ( (responses.length > 0 && (
-

Response samples

+ Response samples diff --git a/src/services/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index f1a7373ce3..f5f65505b4 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -98,7 +98,14 @@ export class RedocNormalizedOptions { unstable_ignoreMimeParameters: boolean; 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.extensionsHook = hook; + this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset); this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname); this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses); diff --git a/src/styled-components.ts b/src/styled-components.ts index a9dee9a9fe..74466f4225 100644 --- a/src/styled-components.ts +++ b/src/styled-components.ts @@ -1,7 +1,7 @@ import { ComponentClass, StatelessComponent } from 'react'; import * as styledComponents from 'styled-components'; -import { ResolvedThemeInterface } from './theme'; +import { ResolvedThemeInterface, ThemeInterface } from './theme'; export { ResolvedThemeInterface }; @@ -56,3 +56,12 @@ export const media = { export { css, injectGlobal, keyframes, ThemeProvider, withProps }; export { StyledComponentClass } from 'styled-components'; export default styled; + +export function extensionsHook(styledName: string) { + return props => { + if (!props.theme.extensionsHook) { + return; + } + return props.theme.extensionsHook(styledName, props); + }; +} diff --git a/src/theme.ts b/src/theme.ts index 526c69b54c..ffefc3d28c 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -2,6 +2,7 @@ import { adjustHue, desaturate, lighten, transparentize } from 'polished'; const defaultTheme: ThemeInterface = { spacingUnit: 20, + breakpoints: { small: '50rem', medium: '85rem', @@ -74,6 +75,7 @@ const defaultTheme: ThemeInterface = { rightPanel: { backgroundColor: '#263238', width: '40%', + textColor: '#ffffff', }, }; @@ -187,7 +189,10 @@ export interface ResolvedThemeInterface { rightPanel: { backgroundColor: string; width: string; + textColor: string; }; + + extensionsHook?: (name: string, props: any) => string; } export type primitive = string | number | boolean | undefined | null;