mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-07 13:44:54 +03:00
feat: make dropdown to switch between code samples
This commit is contained in:
parent
f805271d90
commit
b80ab2b1c6
|
@ -6,7 +6,7 @@ import styled from '../styled-components';
|
||||||
export { Tab, TabList, TabPanel } from 'react-tabs';
|
export { Tab, TabList, TabPanel } from 'react-tabs';
|
||||||
|
|
||||||
export const Tabs = styled(ReactTabs)`
|
export const Tabs = styled(ReactTabs)`
|
||||||
> ul {
|
.react-tabs__tab-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -101,7 +101,7 @@ export const SmallTabs = styled(Tabs)`
|
||||||
> .react-tabs__tab-panel {
|
> .react-tabs__tab-panel {
|
||||||
& > div,
|
& > div,
|
||||||
& > pre {
|
& > pre {
|
||||||
padding: ${props => props.theme.spacing.unit * 2}px 0;
|
padding: ${(props) => props.theme.spacing.unit * 2}px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,52 +1,120 @@
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { isPayloadSample, OperationModel, RedocNormalizedOptions } from '../../services';
|
import {
|
||||||
|
isPayloadSample,
|
||||||
|
OperationModel,
|
||||||
|
RedocNormalizedOptions,
|
||||||
|
XPayloadSample,
|
||||||
|
} from '../../services';
|
||||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||||
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
|
||||||
|
|
||||||
import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
import {
|
||||||
|
DropdownOption,
|
||||||
|
RightPanelHeader,
|
||||||
|
Tab,
|
||||||
|
TabList,
|
||||||
|
TabPanel,
|
||||||
|
Tabs,
|
||||||
|
} from '../../common-elements';
|
||||||
import { OptionsContext } from '../OptionsProvider';
|
import { OptionsContext } from '../OptionsProvider';
|
||||||
|
import { SamplesDropdown, Flex } from './styled.elements';
|
||||||
|
|
||||||
export interface RequestSamplesProps {
|
export interface RequestSamplesProps {
|
||||||
operation: OperationModel;
|
operation: OperationModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RequestSamplesState {
|
||||||
|
codeSampleIdx: number;
|
||||||
|
tabIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class RequestSamples extends React.Component<RequestSamplesProps> {
|
export class RequestSamples extends React.Component<RequestSamplesProps, RequestSamplesState> {
|
||||||
static contextType = OptionsContext;
|
static contextType = OptionsContext;
|
||||||
context: RedocNormalizedOptions;
|
context: RedocNormalizedOptions;
|
||||||
operation: OperationModel;
|
operation: OperationModel;
|
||||||
|
|
||||||
|
state = {
|
||||||
|
codeSampleIdx: 0,
|
||||||
|
tabIndex: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeLang = (option: DropdownOption, updatedTabIndex: number) => {
|
||||||
|
this.setState({
|
||||||
|
codeSampleIdx: option.idx,
|
||||||
|
});
|
||||||
|
if (this.state.tabIndex !== updatedTabIndex) {
|
||||||
|
this.setState({
|
||||||
|
tabIndex: updatedTabIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeTab = (index: number) => {
|
||||||
|
this.setState({
|
||||||
|
tabIndex: index,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { operation } = this.props;
|
const { operation } = this.props;
|
||||||
const samples = operation.codeSamples;
|
const samples = operation.codeSamples;
|
||||||
|
|
||||||
const hasSamples = samples.length > 0;
|
const hasSamples = samples.length > 0;
|
||||||
const hideTabList = samples.length === 1 ? this.context.hideSingleRequestSampleTab : false;
|
const hideTabList = samples.length === 1 ? this.context.hideSingleRequestSampleTab : false;
|
||||||
|
|
||||||
|
const payloadSample = samples.find((sample) => isPayloadSample(sample));
|
||||||
|
const codeSamples = samples.filter((sample) => !isPayloadSample(sample));
|
||||||
|
const isCodeSamples = codeSamples.length > 0;
|
||||||
|
const options = isCodeSamples
|
||||||
|
? codeSamples.map((codeSample, idx) => {
|
||||||
|
return {
|
||||||
|
idx,
|
||||||
|
value: codeSample.label || codeSample.lang,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(hasSamples && (
|
(hasSamples && (
|
||||||
<div>
|
<div>
|
||||||
<RightPanelHeader> Request samples </RightPanelHeader>
|
<RightPanelHeader> Request samples </RightPanelHeader>
|
||||||
|
<Tabs selectedIndex={this.state.tabIndex} onSelect={this.handleChangeTab}>
|
||||||
<Tabs defaultIndex={0}>
|
<Flex>
|
||||||
<TabList hidden={hideTabList}>
|
<TabList hidden={hideTabList}>
|
||||||
{samples.map(sample => (
|
{payloadSample && (
|
||||||
<Tab key={sample.lang + '_' + (sample.label || '')}>
|
<Tab>
|
||||||
{sample.label !== undefined ? sample.label : sample.lang}
|
{payloadSample.label !== undefined ? payloadSample.label : payloadSample.lang}
|
||||||
</Tab>
|
</Tab>
|
||||||
))}
|
|
||||||
</TabList>
|
|
||||||
{samples.map(sample => (
|
|
||||||
<TabPanel key={sample.lang + '_' + (sample.label || '')}>
|
|
||||||
{isPayloadSample(sample) ? (
|
|
||||||
<div>
|
|
||||||
<PayloadSamples content={sample.requestBodyContent} />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<SourceCodeWithCopy lang={sample.lang} source={sample.source} />
|
|
||||||
)}
|
)}
|
||||||
|
{isCodeSamples && <Tab>Code samples</Tab>}
|
||||||
|
</TabList>
|
||||||
|
{isCodeSamples && (
|
||||||
|
<SamplesDropdown
|
||||||
|
value={options[this.state.codeSampleIdx].value}
|
||||||
|
onChange={(option: DropdownOption) =>
|
||||||
|
this.handleChangeLang(option, payloadSample ? 1 : 0)
|
||||||
|
}
|
||||||
|
options={options}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
{payloadSample && (
|
||||||
|
<TabPanel>
|
||||||
|
<div>
|
||||||
|
<PayloadSamples content={(payloadSample as XPayloadSample).requestBodyContent} />
|
||||||
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
))}
|
)}
|
||||||
|
{isCodeSamples && (
|
||||||
|
<TabPanel>
|
||||||
|
<SourceCodeWithCopy
|
||||||
|
lang={codeSamples[this.state.codeSampleIdx].lang}
|
||||||
|
source={codeSamples[this.state.codeSampleIdx].source}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
)}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
)) ||
|
)) ||
|
||||||
|
|
26
src/components/RequestSamples/styled.elements.ts
Normal file
26
src/components/RequestSamples/styled.elements.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
import { InvertedSimpleDropdown } from '../PayloadSamples/styled.elements';
|
||||||
|
import { darken } from 'polished';
|
||||||
|
|
||||||
|
export const Flex = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SamplesDropdown = styled(InvertedSimpleDropdown)`
|
||||||
|
&& {
|
||||||
|
background-color: ${({ theme }) => theme.codeBlock.backgroundColor};
|
||||||
|
height: 33px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid ${({ theme }) => darken(0.05, theme.codeBlock.backgroundColor)};
|
||||||
|
border-radius: 5px;
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
border: 1px solid ${({ theme }) => darken(0.05, theme.codeBlock.backgroundColor)};
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
&:focus-within {
|
||||||
|
background-color: ${({ theme }) => theme.codeBlock.backgroundColor};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
Loading…
Reference in New Issue
Block a user