mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-10-31 07:47:29 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as React from 'react';
 | |
| import { createRoot } from 'react-dom/client';
 | |
| import styled from 'styled-components';
 | |
| import { RedocStandalone } from '../src';
 | |
| import ComboBox from './ComboBox';
 | |
| import FileInput from './components/FileInput';
 | |
| 
 | |
| const DEFAULT_SPEC = 'museum.yaml';
 | |
| const NEW_VERSION_PETSTORE = 'openapi-3-1.yaml';
 | |
| 
 | |
| const demos = [
 | |
|   { value: DEFAULT_SPEC, label: 'Museum API' },
 | |
|   { value: NEW_VERSION_PETSTORE, label: 'Petstore OpenAPI 3.1' },
 | |
|   { value: 'https://api.apis.guru/v2/specs/instagram.com/1.0.0/swagger.yaml', label: 'Instagram' },
 | |
|   {
 | |
|     value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/openapi.yaml',
 | |
|     label: 'Google Calendar',
 | |
|   },
 | |
|   { value: 'https://api.apis.guru/v2/specs/slack.com/1.7.0/openapi.yaml', label: 'Slack' },
 | |
|   { value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/openapi.yaml', label: 'Zoom.us' },
 | |
| ];
 | |
| 
 | |
| class DemoApp extends React.Component<
 | |
|   Record<string, unknown>,
 | |
|   { spec: object | undefined; specUrl: string; dropdownOpen: boolean; cors: boolean }
 | |
| > {
 | |
|   constructor(props) {
 | |
|     super(props);
 | |
| 
 | |
|     let parts = window.location.search.match(/url=([^&]+)/);
 | |
|     let url = DEFAULT_SPEC;
 | |
|     if (parts && parts.length > 1) {
 | |
|       url = decodeURIComponent(parts[1]);
 | |
|     }
 | |
| 
 | |
|     parts = window.location.search.match(/[?&]nocors(&|#|$)/);
 | |
|     let cors = true;
 | |
|     if (parts && parts.length > 1) {
 | |
|       cors = false;
 | |
|     }
 | |
| 
 | |
|     this.state = {
 | |
|       spec: undefined,
 | |
|       specUrl: url,
 | |
|       dropdownOpen: false,
 | |
|       cors,
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   handleUploadFile = (spec: object) => {
 | |
|     this.setState({
 | |
|       spec,
 | |
|       specUrl: '',
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   handleChange = (url: string) => {
 | |
|     if (url === NEW_VERSION_PETSTORE) {
 | |
|       this.setState({ cors: false });
 | |
|       0;
 | |
|     }
 | |
|     this.setState({
 | |
|       specUrl: url,
 | |
|     });
 | |
|     window.history.pushState(
 | |
|       undefined,
 | |
|       '',
 | |
|       updateQueryStringParameter(location.search, 'url', url),
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   toggleCors = (e: React.ChangeEvent<HTMLInputElement>) => {
 | |
|     const cors = e.currentTarget.checked;
 | |
|     this.setState({
 | |
|       cors,
 | |
|     });
 | |
|     window.history.pushState(
 | |
|       undefined,
 | |
|       '',
 | |
|       updateQueryStringParameter(location.search, 'nocors', cors ? undefined : ''),
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   render() {
 | |
|     const { specUrl, cors } = this.state;
 | |
|     let proxiedUrl = specUrl;
 | |
|     if (specUrl !== DEFAULT_SPEC) {
 | |
|       proxiedUrl = cors
 | |
|         ? 'https://cors.redoc.ly/' + new URL(specUrl, window.location.href).href
 | |
|         : specUrl;
 | |
|     }
 | |
|     return (
 | |
|       <>
 | |
|         <Heading>
 | |
|           <a href=".">
 | |
|             <Logo
 | |
|               src="https://github.com/Redocly/redoc/raw/main/docs/images/redoc.png"
 | |
|               alt="Redoc logo"
 | |
|             />
 | |
|           </a>
 | |
|           <ControlsContainer>
 | |
|             <FileInput onUpload={this.handleUploadFile} />
 | |
|             <ComboBox
 | |
|               placeholder={'URL to a spec to try'}
 | |
|               options={demos}
 | |
|               onChange={this.handleChange}
 | |
|               value={specUrl === DEFAULT_SPEC ? '' : specUrl}
 | |
|             />
 | |
|             <CorsCheckbox title="Use CORS proxy">
 | |
|               <input id="cors_checkbox" type="checkbox" onChange={this.toggleCors} checked={cors} />
 | |
|               <label htmlFor="cors_checkbox">CORS</label>
 | |
|             </CorsCheckbox>
 | |
|           </ControlsContainer>
 | |
|           <iframe
 | |
|             src="https://ghbtns.com/github-btn.html?user=Redocly&repo=redoc&type=star&count=true&size=large"
 | |
|             frameBorder="0"
 | |
|             scrolling="0"
 | |
|             width="160px"
 | |
|             height="30px"
 | |
|           />
 | |
|         </Heading>
 | |
|         <RedocStandalone
 | |
|           spec={this.state.spec}
 | |
|           specUrl={proxiedUrl}
 | |
|           options={{ scrollYOffset: 'nav', untrustedSpec: true }}
 | |
|         />
 | |
|       </>
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* ====== Styled components ====== */
 | |
| 
 | |
| const ControlsContainer = styled.div`
 | |
|   display: flex;
 | |
|   justify-content: center;
 | |
|   flex: 1;
 | |
|   margin: 0 15px;
 | |
|   align-items: center;
 | |
| `;
 | |
| 
 | |
| const CorsCheckbox = styled.div`
 | |
|   margin-left: 10px;
 | |
|   white-space: nowrap;
 | |
| 
 | |
|   label {
 | |
|     font-size: 13px;
 | |
|   }
 | |
| 
 | |
|   @media screen and (max-width: 550px) {
 | |
|     display: none;
 | |
|   }
 | |
| `;
 | |
| 
 | |
| const Heading = styled.nav`
 | |
|   position: sticky;
 | |
|   top: 0;
 | |
|   width: 100%;
 | |
|   height: 50px;
 | |
|   box-sizing: border-box;
 | |
|   background: white;
 | |
|   border-bottom: 1px solid #cccccc;
 | |
|   z-index: 10;
 | |
|   padding: 5px;
 | |
| 
 | |
|   display: flex;
 | |
|   align-items: center;
 | |
|   font-family: Roboto, sans-serif;
 | |
| `;
 | |
| 
 | |
| const Logo = styled.img`
 | |
|   height: 40px;
 | |
|   width: 124px;
 | |
|   display: inline-block;
 | |
|   margin-right: 15px;
 | |
| 
 | |
|   @media screen and (max-width: 950px) {
 | |
|     display: none;
 | |
|   }
 | |
| `;
 | |
| 
 | |
| const container = document.getElementById('container');
 | |
| const root = createRoot(container!);
 | |
| root.render(<DemoApp />);
 | |
| 
 | |
| /* ====== Helpers ====== */
 | |
| function updateQueryStringParameter(uri, key, value) {
 | |
|   const keyValue = value === '' ? key : key + '=' + value;
 | |
|   const re = new RegExp('([?|&])' + key + '=?.*?(&|#|$)', 'i');
 | |
|   if (uri.match(re)) {
 | |
|     if (value !== undefined) {
 | |
|       return uri.replace(re, '$1' + keyValue + '$2');
 | |
|     } else {
 | |
|       return uri.replace(re, (_, separator: string, rest: string) => {
 | |
|         if (rest.startsWith('&')) {
 | |
|           rest = rest.substring(1);
 | |
|         }
 | |
|         return separator === '&' ? rest : separator + rest;
 | |
|       });
 | |
|     }
 | |
|   } else {
 | |
|     if (value === undefined) {
 | |
|       return uri;
 | |
|     }
 | |
|     let hash = '';
 | |
|     if (uri.indexOf('#') !== -1) {
 | |
|       hash = uri.replace(/.*#/, '#');
 | |
|       uri = uri.replace(/#.*/, '');
 | |
|     }
 | |
|     const separator = uri.indexOf('?') !== -1 ? '&' : '?';
 | |
|     return uri + separator + keyValue + hash;
 | |
|   }
 | |
| }
 |