make support rtl according to issue 1002

This commit is contained in:
Mohammad Abbasi 2022-09-17 12:51:43 +04:30
parent 64cf624fff
commit 5f43db0181
21 changed files with 184 additions and 120 deletions

View File

@ -1,7 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>ReDoc</title> <title>ReDoc</title>
<style> <style>
@ -14,15 +13,18 @@
display: block; display: block;
} }
</style> </style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> <link
</head> href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet" />
</head>
<body> <body>
<redoc id="example"></redoc> <redoc id="example"></redoc>
<!-- <redoc spec-url="./openapi.yaml"></redoc> --> <!-- <redoc spec-url="./openapi.yaml"></redoc> -->
<script src="https://unpkg.com/lodash@4.17.4/lodash.js"></script> <script src="https://unpkg.com/lodash@4.17.4/lodash.js"></script>
<script src="https://unpkg.com/benchmark@2.1.4/benchmark.js"></script> <script src="https://unpkg.com/benchmark@2.1.4/benchmark.js"></script>
<!-- <script src="../bundles/redoc.standalone.js"></script> --> <!-- <script src="../bundles/redoc.standalone.js"></script> -->
</body> </body>
</html> </html>

View File

@ -1,23 +1,23 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf8" /> <meta charset='utf8' />
<title>{{title}}</title> <title>{{title}}</title>
<!-- needed for adaptive design --> <!-- needed for adaptive design -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name='viewport' content='width=device-width, initial-scale=1' />
<style> <style>
body { body { padding: 0; margin: 0; }
padding: 0;
margin: 0;
}
</style> </style>
{{{redocHead}}} {{{redocHead}}}
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}} {{#unless disableGoogleFont}}<link
</head> href='https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700'
rel='stylesheet'
/>{{/unless}}
<link href='https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css' rel='stylesheet' />
</head>
<body> <body>
{{{redocHTML}}} {{{redocHTML}}}
</body> </body>
</html> </html>

View File

@ -19,6 +19,7 @@
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet" rel="stylesheet"
/> />
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet" />
</head> </head>
<body> <body>

View File

@ -1,16 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>ReDoc Interactive Demo</title> <title>ReDoc Interactive Demo</title>
<meta name="description" content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation" /> <meta
<meta name="viewport" content="width=device-width, initial-scale=1"> name="description"
content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:title" content="ReDoc Interactive Demo"> <meta property="og:title" content="ReDoc Interactive Demo" />
<meta property="og:description" content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation"> <meta
<meta property="og:image" content="https://user-images.githubusercontent.com/3975738/37729752-8a9ea38a-2d46-11e8-8438-42ed26bf1751.png"> property="og:description"
<meta name="twitter:card" content="summary_large_image"> content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation"
/>
<meta
property="og:image"
content="https://user-images.githubusercontent.com/3975738/37729752-8a9ea38a-2d46-11e8-8438-42ed26bf1751.png"
/>
<meta name="twitter:card" content="summary_large_image" />
<style> <style>
body { body {
@ -22,18 +30,29 @@
display: block; display: block;
} }
</style> </style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> <link
</head> href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet" />
</head>
<body> <body>
<div id="container"> </div> <div id="container"></div>
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () { i['GoogleAnalyticsObject'] = r;
(i[r].q = i[r].q || []).push(arguments) (i[r] =
}, i[r].l = 1 * new Date(); a = s.createElement(o), i[r] ||
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'); })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
if (window.location.host === 'rebilly.github.io') { if (window.location.host === 'rebilly.github.io') {
@ -41,6 +60,5 @@
ga('send', 'pageview'); ga('send', 'pageview');
} }
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ReDoc</title> <title>ReDoc</title>
<style> <style>
body { body {
@ -15,11 +14,14 @@
display: block; display: block;
} }
</style> </style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> <link
</head> href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet" />
</head>
<body> <body>
<redoc id="example"></redoc> <redoc id="example"></redoc>
</body> </body>
</html> </html>

View File

@ -1,9 +1,9 @@
import { renderToString } from 'react-dom/server'; import { renderToString } from 'react-dom/server';
import * as React from 'react'; import * as React from 'react';
import { ServerStyleSheet } from 'styled-components'; import { ServerStyleSheet } from 'styled-components';
import { Redoc, createStore } from '../../';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { resolve } from 'path'; import { resolve } from 'path';
import { createStore, Redoc } from '../../src';
const yaml = require('js-yaml'); const yaml = require('js-yaml');
const http = require('http'); const http = require('http');
@ -38,6 +38,7 @@ const server = http.createServer(async (request, response) => {
</style> </style>
<script src="redoc.standalone.js"></script> <script src="redoc.standalone.js"></script>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet">
${css} ${css}
</head> </head>
<body> <body>

View File

@ -162,6 +162,7 @@
"stickyfill": "^1.1.1", "stickyfill": "^1.1.1",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"swagger2openapi": "^7.0.6", "swagger2openapi": "^7.0.6",
"update-notifier": "^6.0.2",
"url-template": "^2.0.8" "url-template": "^2.0.8"
}, },
"size-limit": [ "size-limit": [

View File

@ -9,10 +9,16 @@ export const PropertiesTableCaption = styled.caption`
`; `;
export const PropertyCell = styled.td<{ kind?: string }>` export const PropertyCell = styled.td<{ kind?: string }>`
border-left: 1px solid ${props => props.theme.schema.linesColor}; border-left: ${({ theme }) =>
theme.typography.direction === 'rtl' ? 0 : '1px solid '} ${props =>
props.theme.schema.linesColor};
border-right: ${({ theme }) =>
theme.typography.direction === 'rtl' ? '1px solid ' : 0} ${props =>
props.theme.schema.linesColor};
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
padding: 10px 10px 10px 0; padding: ${({ theme }) =>
theme.typography.direction === 'rtl' ? '10px 0 10px 10px' : '10px 10px 10px 0'}
${media.lessThan('small')` ${media.lessThan('small')`
display: block; display: block;
@ -22,7 +28,8 @@ export const PropertyCell = styled.td<{ kind?: string }>`
tr:first-of-type > &, tr:first-of-type > &,
tr.last > & { tr.last > & {
border-left-width: 0; border-left-width: 0;
background-position: top left; background-position: ${({ theme }) =>
theme.typography.direction === 'rtl' ? 'top right' : 'top left'};
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1px 100%; background-size: 1px 100%;
} }
@ -122,7 +129,7 @@ export const PropertyDetailsCell = styled.td`
export const PropertyBullet = styled.span` export const PropertyBullet = styled.span`
color: ${props => props.theme.schema.linesColor}; color: ${props => props.theme.schema.linesColor};
font-family: ${props => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
margin-right: 10px; margin: ${({ theme }) => (theme.typography.direction === 'rtl' ? '0 0 0 10px ' : '0 10px 0 0')}
&::before { &::before {
content: ''; content: '';
@ -143,6 +150,10 @@ export const PropertyBullet = styled.span`
} }
`; `;
export const WrappedShelfIcon = styled.i`
display: inline-block;
`;
export const InnerPropertiesWrap = styled.div` export const InnerPropertiesWrap = styled.div`
padding: ${({ theme }) => theme.schema.nestingSpacing}; padding: ${({ theme }) => theme.schema.nestingSpacing};
`; `;

View File

@ -4,7 +4,8 @@ import styled, { media } from '../styled-components';
export const MiddlePanel = styled.div<{ compact?: boolean }>` export const MiddlePanel = styled.div<{ compact?: boolean }>`
width: calc(100% - ${props => props.theme.rightPanel.width}); width: calc(100% - ${props => props.theme.rightPanel.width});
padding: 0 ${props => props.theme.spacing.sectionHorizontal}px; padding: 0 ${props => props.theme.spacing.sectionHorizontal}px;
direction: ${props => props.theme.typography.direction || 'ltr'};
text-align: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'right' : 'left')};
${({ compact, theme }) => ${({ compact, theme }) =>
media.lessThan('medium', true)` media.lessThan('medium', true)`
width: 100%; width: 100%;

View File

@ -37,9 +37,14 @@ export const ShelfIcon = styled(IntShelfIcon)`
width: ${props => props.size || '18px'}; width: ${props => props.size || '18px'};
min-width: ${props => props.size || '18px'}; min-width: ${props => props.size || '18px'};
vertical-align: middle; vertical-align: middle;
float: ${props => props.float || ''}; float: ${props => (props.theme.typography.direction === 'rtl' ? 'right' : props.float || '')};
transition: transform 0.2s ease-out; transition: transform 0.2s ease-out;
transform: rotateZ(${props => directionMap[props.direction || 'down']}); transform: rotateZ(
${props =>
props.theme.typography.direction === 'rtl'
? directionMap[props.direction === 'right' ? 'left' : 'down' || 'down']
: directionMap[props.direction || 'down']}
);
polygon { polygon {
fill: ${({ color, theme }) => fill: ${({ color, theme }) =>

View File

@ -70,6 +70,7 @@ export const Tabs = styled(ReactTabs)`
& > div > pre { & > div > pre {
padding: 0; padding: 0;
direction: ltr;
} }
} }
`; `;

View File

@ -28,7 +28,14 @@ export const DownloadButton = styled.a`
export const InfoSpan = styled.span` export const InfoSpan = styled.span`
&::before { &::before {
content: '|'; content: '|';
display: inline-block; display: ${props => (props.theme.typography.direction === 'ltr' ? 'inline-block' : 'none')};
opacity: 0.5;
width: ${delimiterWidth}px;
text-align: center;
}
&::after {
content: '|';
display: ${props => (props.theme.typography.direction === 'rtl' ? 'inline-block' : 'none')};
opacity: 0.5; opacity: 0.5;
width: ${delimiterWidth}px; width: ${delimiterWidth}px;
text-align: center; text-align: center;

View File

@ -30,6 +30,7 @@ export const EndpointInfo = styled.button<{ expanded?: boolean; inverted?: boole
border: ${props => (props.inverted ? '0' : '1px solid transparent')}; border: ${props => (props.inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.inverted ? '1px solid #ccc' : '0')}; border-bottom: ${props => (props.inverted ? '1px solid #ccc' : '0')};
transition: border-color 0.25s ease; transition: border-color 0.25s ease;
direction: ltr;
${props => ${props =>
(props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''} (props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''}
@ -69,6 +70,7 @@ export const ServersOverlay = styled.div<{ expanded: boolean }>`
transition: all 0.25s ease; transition: all 0.25s ease;
visibility: hidden; visibility: hidden;
${props => (props.expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')} ${props => (props.expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')}
text-align: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'right' : 'left')};
`; `;
export const ServerItem = styled.div` export const ServerItem = styled.div`
@ -76,6 +78,7 @@ export const ServerItem = styled.div`
`; `;
export const ServerUrl = styled.div` export const ServerUrl = styled.div`
text-align: left;
padding: 5px; padding: 5px;
border: 1px solid #ccc; border: 1px solid #ccc;
background: ${props => props.theme.rightPanel.servers.url.backgroundColor}; background: ${props => props.theme.rightPanel.servers.url.backgroundColor};

View File

@ -13,6 +13,7 @@ import {
PropertyCellWithInner, PropertyCellWithInner,
PropertyDetailsCell, PropertyDetailsCell,
PropertyNameCell, PropertyNameCell,
WrappedShelfIcon,
} from '../../common-elements/fields-layout'; } from '../../common-elements/fields-layout';
import { ShelfIcon } from '../../common-elements/'; import { ShelfIcon } from '../../common-elements/';
import { Schema } from '../Schema/Schema'; import { Schema } from '../Schema/Schema';
@ -76,7 +77,9 @@ export class Field extends React.Component<FieldProps> {
aria-label="expand properties" aria-label="expand properties"
> >
<span className="property-name">{name}</span> <span className="property-name">{name}</span>
<WrappedShelfIcon>
<ShelfIcon direction={expanded ? 'down' : 'right'} /> <ShelfIcon direction={expanded ? 'down' : 'right'} />
</WrappedShelfIcon>
</button> </button>
{labels} {labels}
</ClickablePropertyNameCell> </ClickablePropertyNameCell>

View File

@ -8,7 +8,7 @@ export const jsonStyles = css`
font-family: ${props => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize}; font-size: ${props => props.theme.typography.code.fontSize};
direction: ltr;
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')}; white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
contain: content; contain: content;
overflow-x: auto; overflow-x: auto;

View File

@ -10,6 +10,7 @@ export const RedocWrap = styled.div`
display: flex; display: flex;
position: relative; position: relative;
text-align: left; text-align: left;
direction: ${theme.typography.direction};
-webkit-font-smoothing: ${theme.typography.smoothing}; -webkit-font-smoothing: ${theme.typography.smoothing};
font-smoothing: ${theme.typography.smoothing}; font-smoothing: ${theme.typography.smoothing};
@ -42,7 +43,7 @@ export const BackgroundStub = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
right: 0; ${({ theme }) => (theme.typography.direction === 'rtl' ? 'left: 0;' : 'right: 0;')};
width: ${({ theme }) => { width: ${({ theme }) => {
if (theme.rightPanel.width.endsWith('%')) { if (theme.rightPanel.width.endsWith('%')) {
const percents = parseInt(theme.rightPanel.width, 10); const percents = parseInt(theme.rightPanel.width, 10);

View File

@ -12,7 +12,7 @@ export const StyledResponseTitle = styled(ResponseTitle)`
margin-bottom: 4px; margin-bottom: 4px;
line-height: 1.5em; line-height: 1.5em;
cursor: pointer; cursor: pointer;
text-align: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'right' : 'left')};
color: ${props => props.theme.colors.responses[props.type].color}; color: ${props => props.theme.colors.responses[props.type].color};
background-color: ${props => props.theme.colors.responses[props.type].backgroundColor}; background-color: ${props => props.theme.colors.responses[props.type].backgroundColor};
&:focus { &:focus {
@ -42,7 +42,7 @@ export const ResponseDetailsWrap = styled.div`
`; `;
export const HeadersCaption = styled(UnderlinedHeader.withComponent('caption'))` export const HeadersCaption = styled(UnderlinedHeader.withComponent('caption'))`
text-align: left; text-align: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'right' : 'left')};
margin-top: 1em; margin-top: 1em;
caption-side: top; caption-side: top;
`; `;

View File

@ -29,6 +29,7 @@ export const SearchInput = styled.input.attrs(() => ({
color: ${props => props.theme.sidebar.textColor}; color: ${props => props.theme.sidebar.textColor};
background-color: transparent; background-color: transparent;
outline: none; outline: none;
text-align: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'center' : 'inherit')};
`; `;
export const SearchIcon = styled((props: { className?: string }) => ( export const SearchIcon = styled((props: { className?: string }) => (

View File

@ -139,6 +139,10 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
padding: 12.5px ${props => props.theme.spacing.unit * 4}px; padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
${({ depth, type, theme }) => ${({ depth, type, theme }) =>
(type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''} (type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
direction: ${({ type, theme }) =>
['section', 'group', 'tag'].indexOf(type || '') > -1 && theme.typography.direction === 'rtl'
? 'rtl'
: 'ltr'};
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-family: ${props => props.theme.typography.headings.fontFamily}; font-family: ${props => props.theme.typography.headings.fontFamily};
@ -156,6 +160,7 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
} }
${ShelfIcon} { ${ShelfIcon} {
transform: ${({ theme }) => (theme.typography.direction === 'rtl' ? 'rotate(0deg)' : 'none')};
height: ${({ theme }) => theme.sidebar.arrow.size}; height: ${({ theme }) => theme.sidebar.arrow.size};
width: ${({ theme }) => theme.sidebar.arrow.size}; width: ${({ theme }) => theme.sidebar.arrow.size};
polygon { polygon {

View File

@ -62,5 +62,6 @@ const ChevronContainer = styled.div`
align-self: center; align-self: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
direction: ltr;
color: ${props => props.theme.colors.primary.main}; color: ${props => props.theme.colors.primary.main};
`; `;

View File

@ -107,17 +107,17 @@ const defaultTheme: ThemeInterface = {
fontWeightRegular: '400', fontWeightRegular: '400',
fontWeightBold: '600', fontWeightBold: '600',
fontWeightLight: '300', fontWeightLight: '300',
fontFamily: 'Roboto, sans-serif', fontFamily: 'Roboto, sans-serif, Vazir',
smoothing: 'antialiased', smoothing: 'antialiased',
optimizeSpeed: true, optimizeSpeed: true,
headings: { headings: {
fontFamily: 'Montserrat, sans-serif', fontFamily: 'Montserrat, sans-serif, Vazir',
fontWeight: '400', fontWeight: '400',
lineHeight: '1.6em', lineHeight: '1.6em',
}, },
code: { code: {
fontSize: '13px', fontSize: '13px',
fontFamily: 'Courier, monospace', fontFamily: 'Montserrat, sans-serif, Vazir',
lineHeight: ({ typography }) => typography.lineHeight, lineHeight: ({ typography }) => typography.lineHeight,
fontWeight: ({ typography }) => typography.fontWeightRegular, fontWeight: ({ typography }) => typography.fontWeightRegular,
color: '#e53935', color: '#e53935',
@ -318,7 +318,7 @@ export interface ResolvedThemeInterface {
fontWeightRegular: string; fontWeightRegular: string;
fontWeightBold: string; fontWeightBold: string;
fontFamily: string; fontFamily: string;
direction?: 'ltr' | 'rtl';
smoothing: string; smoothing: string;
optimizeSpeed: boolean; optimizeSpeed: boolean;