Merge branch 'i18n'

This commit is contained in:
ErickSkrauch 2021-03-28 03:02:35 +02:00
commit 3c897845ab
No known key found for this signature in database
GPG Key ID: 669339FCBB30EE0E
55 changed files with 747 additions and 199 deletions

View File

@ -16,6 +16,6 @@ module.exports = {
filePath: 'accounts/site.json',
sourceLang: 'en',
basePath: `${__dirname}/packages/app/i18n`,
minApproved: 80, // Minimal ready percent before translation can be published
minTranslated: 80, // Minimal ready percent before translation can be published
},
};

View File

@ -45,7 +45,8 @@
"build:dll": "babel-node --extensions '.ts,.d.ts' ./packages/scripts/build-dll.ts",
"build:serve": "http-server --proxy https://dev.account.ely.by ./build",
"sb": "APP_ENV=storybook start-storybook -p 9009 --ci",
"sb:build": "APP_ENV=storybook build-storybook"
"sb:build": "APP_ENV=storybook build-storybook",
"postinstall": "node -e \"try{require('./postinstall.js')}catch(e){}\""
},
"lint-staged": {
"*.{json,scss,css,md}": [
@ -144,6 +145,7 @@
"loader-utils": "^2.0.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.14.1",
"postcss-bidirection": "https://github.com/erickskrauch/postcss-bidirection.git#iss_23",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-scss": "^2.1.1",

View File

@ -119,6 +119,7 @@ interface State {
formsHeights: Record<PanelId, number>;
}
// TODO: completely broken for RTL languages
class PanelTransition extends React.PureComponent<Props, State> {
state: State = {
contextHeight: 0,

View File

@ -16,7 +16,6 @@
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 40px;

View File

@ -3,7 +3,7 @@
.accountSwitcher {
background: $black;
text-align: left;
text-align: start;
}
$border: 1px solid lighter($black);
@ -37,12 +37,12 @@ $border: 1px solid lighter($black);
.accountAvatar {
font-size: 35px;
margin-right: 15px;
margin-inline-end: 15px;
}
.accountInfo {
flex-grow: 1;
margin-right: 15px;
margin-inline-end: 15px;
min-width: 0; // Fix for text-overflow. See https://stackoverflow.com/a/40612184
}
@ -76,17 +76,25 @@ $border: 1px solid lighter($black);
composes: arrowRight from '~app/components/ui/icons.scss';
position: relative;
left: 0;
inset-inline-start: 0;
font-size: 24px;
color: #4e4e4e;
line-height: 35px;
transition: color 0.25s, inset-inline-start 0.5s;
// TODO: right now transition property doesn't support the bidirectional value.
// See https://github.com/gasolin/postcss-bidirection/issues/25.
// noinspection CssOverwrittenProperties Graceful degradation
transition: color 0.25s, left 0.5s;
html[dir='rtl'] & {
transition: color 0.25s, right 0.5s;
}
.item:hover & {
color: #aaa;
left: 5px;
inset-inline-start: 5px;
}
}

View File

@ -16,7 +16,7 @@
position: relative;
bottom: 1px;
padding-left: 3px;
padding-inline-start: 3px;
color: #666666;
font-size: 10px;

View File

@ -4,18 +4,18 @@
.authInfo {
// Отступы сверху и снизу разные т.к. мы ужимаем высоту линии строки с логином на 2 пикселя и из-за этого теряем отступ снизу
padding: 5px 20px 7px;
text-align: left;
text-align: start;
}
.authInfoAvatar {
$size: 30px;
float: left;
float: start;
height: $size;
width: $size;
font-size: $size;
line-height: 1;
margin-right: 10px;
margin-inline-end: 10px;
margin-top: 2px;
color: #aaa;
@ -38,7 +38,7 @@
.permissionsContainer {
padding: 15px 12px;
text-align: left;
text-align: start;
}
.permissionsTitle {
@ -57,7 +57,7 @@
font-size: 14px;
line-height: 1.4;
padding-bottom: 4px;
padding-left: 17px;
padding-inline-start: 17px;
position: relative;
&:last-of-type {
@ -71,7 +71,7 @@
line-height: 9px;
position: absolute;
top: 6px;
left: -4px;
inset-inline-start: -4px;
}
}
}

View File

@ -37,7 +37,7 @@
width: 50%;
&:first-of-type {
margin-right: $popupPadding;
margin-inline-end: $popupPadding;
}
}

View File

@ -160,7 +160,7 @@
composes: arrowRight from '~app/components/ui/icons.scss';
position: relative;
left: 0;
inset-inline-start: 0;
font-size: 28px;
color: #ebe8e1;
@ -174,6 +174,10 @@
.appExpanded & {
color: #777;
transform: rotate(360deg)!important; // Prevent it from hover rotating
html[dir='rtl'] & {
transform: rotate(0)!important;
}
}
}
@ -195,7 +199,7 @@ $appDetailsContainerRightLeftPadding: 30px;
.editAppLink {
position: absolute;
top: 4px;
right: 0;
inset-inline-end: 0;
font-size: 12px;
color: #9a9a9a;
@ -221,17 +225,19 @@ $appDetailsContainerRightLeftPadding: 30px;
}
.appActionButton {
margin: 0 10px 10px 0;
margin-inline-end: 10px;
margin-bottom: 10px;
&:last-of-type {
margin-right: 0;
margin-inline-end: 0;
}
}
.appActionContainer {
position: absolute;
width: calc(100% - #{$appDetailsContainerRightLeftPadding * 2});
top: 100%;
left: 0;
inset-inline-start: 0;
padding: 0 $appDetailsContainerRightLeftPadding;
background: #f5f5f5;
}
@ -244,7 +250,7 @@ $appDetailsContainerRightLeftPadding: 30px;
.continueActionButtonWrapper {
display: inline-block;
margin-left: 10px;
margin-inline-start: 10px;
}
.continueActionLink {

View File

@ -24,5 +24,5 @@
position: relative;
bottom: 1px;
font-size: 11px;
margin-right: 3px;
margin-inline-end: 3px;
}

View File

@ -1,5 +1,8 @@
import React, { useState, useEffect, ComponentType } from 'react';
import { RawIntlProvider, IntlShape } from 'react-intl';
import { Helmet } from 'react-helmet-async';
import { getLangDir } from 'rtl-detect';
import i18n from 'app/services/i18n';
import { useReduxSelector } from 'app/functions';
@ -26,7 +29,12 @@ const IntlProvider: ComponentType = ({ children }) => {
return null;
}
return <RawIntlProvider value={intl}>{children}</RawIntlProvider>;
return (
<RawIntlProvider value={intl}>
<Helmet htmlAttributes={{ lang: locale, dir: getLangDir(locale) }} />
{children}
</RawIntlProvider>
);
};
export default IntlProvider;

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="180" viewBox="0 0 63.5 47.625">
<path fill="#000" d="M0 0h63.5v15.875H0z"/>
<path fill="#00783b" d="M0 15.903h63.5v15.875H0z"/>
<path fill="#fff" d="M0 31.75h63.5v15.875H0z"/>
<path fill="#cc1025" d="m0 0 21.167 23.813A16486.171 16486.171 0 0 1 0 47.624V0z"/>
</svg>

After

Width:  |  Height:  |  Size: 343 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480">
<path d="M0 0h204.8v480H0z"/>
<path fill="#D21" d="M435.2 0H640v480H435.2z"/>
<path fill="#FFF" d="M204.8 0h230.4v480H204.8z"/>
<path fill="#D21" d="M286.667 140L420 273.333H220L353.333 140v200L220 206.667h200L286.667 340V140z"/>
</svg>

After

Width:  |  Height:  |  Size: 316 B

View File

@ -10,6 +10,8 @@ const localeToCountryCode: Record<string, string> = {
sr: 'rs',
zh: 'cn',
cs: 'cz',
fil: 'ph',
he: 'il',
};
const SUPPORTED_LANGUAGES: ReadonlyArray<string> = Object.keys(supportedLocales);

View File

@ -26,7 +26,7 @@
position: relative;
top: 1px;
display: inline-block;
margin-right: 4px;
margin-inline-end: 4px;
height: $height;
width: $height * 4 / 3;
box-shadow: 0 0 1px rgba(#000, 0.2);

View File

@ -33,7 +33,7 @@
position: absolute;
top: 14px;
right: 12px;
inset-inline-end: 12px;
font-size: 22px;
color: #edebe5;
pointer-events: none; // Иконка чисто декоративная, так что клик должен проходить сквозь неё
@ -94,7 +94,7 @@ $languageListBorderStyle: 1px solid $languageListBorderColor;
.languageIco {
display: inline-block;
margin-right: 7px;
margin-inline-end: 7px;
width: 40px;
height: 30px;
box-shadow: 0 0 1px rgba(#000, 0.2);
@ -129,7 +129,7 @@ $languageListBorderStyle: 1px solid $languageListBorderColor;
box-sizing: border-box;
width: 22px;
height: 22px;
right: -32px;
inset-inline-end: -32px;
font-size: 10px;
line-height: 18px;
@ -146,13 +146,13 @@ $languageListBorderStyle: 1px solid $languageListBorderColor;
}
.languageItem:hover & {
right: 0;
inset-inline-end: 0;
}
.activeLanguageItem & {
border-color: $green;
background: $green;
right: 0;
inset-inline-end: 0;
&:before {
opacity: 1;
@ -209,7 +209,7 @@ $languageListBorderStyle: 1px solid $languageListBorderColor;
color: lighter($blue);
font-size: 22px;
margin-right: 10px;
margin-inline-end: 10px;
}
.improveTranslatesContent {

View File

@ -19,12 +19,12 @@
li {
position: relative;
padding-left: 11px;
padding-inline-start: 11px;
&:before {
content: '';
position: absolute;
left: 0;
inset-inline-start: 0;
top: 2px;
}

View File

@ -75,7 +75,7 @@ export default function OsInstruction({ os }: { os: OS }) {
<ul className={styles.appList}>
{linksByOs[os].featured.map((item) => (
<li key={item.label}>
<a href={item.link} target="_blank">
<a href={item.link} target="_blank" dir="ltr">
{item.label}
</a>
</li>

View File

@ -22,7 +22,7 @@
.otherApps {
position: absolute;
right: 0;
inset-inline-end: 0;
bottom: 5px;
font-size: 10px;
@ -96,7 +96,7 @@
.androidActive & {
transform: translateX(0);
left: 0;
inset-inline-start: 0;
}
.appleActive &,
@ -111,21 +111,33 @@
$translateX: -51%;
transform: translateX($translateX) scale(1);
left: 49%;
inset-inline-start: 49%;
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(1);
}
&:hover {
transform: translateX($translateX) scale(1.1);
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(1.1);
}
}
.appleActive & {
transform: translateX(0);
left: 0;
transform: translateX(0)!important; // override dir='rtl'
inset-inline-start: 0;
}
.androidActive &,
.windowsActive & {
transform: translateX($translateX) scale(0);
opacity: 0;
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(0);
}
}
}
@ -134,21 +146,33 @@
$translateX: -100%;
transform: translateX($translateX) scale(1);
left: 100%;
inset-inline-start: 100%;
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(1);
}
&:hover {
transform: translateX($translateX) scale(1.1);
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(1.1);
}
}
.windowsActive & {
transform: translateX(0);
left: 0;
transform: translateX(0)!important; // override dir='rtl'
inset-inline-start: 0;
}
.appleActive &,
.androidActive & {
transform: translateX($translateX) scale(0);
opacity: 0;
html[dir='rtl'] & {
transform: translateX(-$translateX) scale(0);
}
}
}
@ -166,8 +190,8 @@
position: relative;
z-index: 1;
margin: 15px;
margin-left: 30%;
padding-left: 15px;
margin-inline-start: 30%;
padding-inline-start: 15px;
padding-bottom: 15px;
min-height: $boxHeight;
}
@ -212,7 +236,7 @@
.osName {
font-family: $font-family-title;
font-size: 16px;
margin-left: 10px;
margin-inline-start: 10px;
}
@mixin commonNonActiveTile() {

View File

@ -16,8 +16,8 @@ $maxQrCodeSize: 242px;
}
.or {
position: absolute;
left: 0;
position: absolute; // Use absolute positioning to put an element between margin
inset-inline-start: 0; // TODO: doesn't have any effect. Probably can be removed
width: 100%;
margin-top: -18px;

View File

@ -13,7 +13,8 @@ $formColumnWidth: 416px;
}
.descriptionColumn {
padding: 12px 20px 0 0;
padding-top: 12px;
padding-inline-end: 20px;
box-sizing: border-box;
}
@ -97,7 +98,8 @@ $formColumnWidth: 416px;
}
.paramMessage {
padding: 10px 40px 0 0;
padding-top: 10px;
padding-inline-end: 40px;
color: $red;
font-size: 11px;
@ -168,7 +170,7 @@ $formColumnWidth: 416px;
}
.paramEditIcon {
margin-left: 5px;
margin-inline-start: 5px;
vertical-align: top;
}

View File

@ -9,7 +9,7 @@
.backButton {
position: absolute;
left: -60px;
inset-inline-start: -60px;
top: 15px;
width: 25px;
height: 25px;
@ -60,7 +60,6 @@
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 86px;
@ -110,7 +109,7 @@
.backButton {
top: 29px;
left: 27px;
inset-inline-start: 27px;
padding: 0;
margin: 0;
width: auto;

View File

@ -29,7 +29,8 @@
}
.iconWrapper {
margin: 4px 12px 0 0;
margin-top: 4px;
margin-inline-end: 12px;
}
.dbIcon {
@ -68,14 +69,15 @@
font-family: $font-family-title;
font-size: 14px;
color: #9a9a9a;
margin: 0 0 5px 1px; // Add 1px from the left to make icon look visually aligned with texts
margin-bottom: 5px;
margin-inline-start: 1px; // Add 1px from the left to make icon look visually aligned with texts
}
.githubIcon {
composes: github from '~app/components/ui/icons.scss';
font-size: 12px;
margin-right: 2px;
margin-inline-end: 2px;
position: relative;
bottom: 1px;
}

View File

@ -1,20 +0,0 @@
.horizontalGroup {
display: flex;
}
.item {
// TODO: in some cases we do not need overflow hidden
// probably, it is better to create a separate class for children, that will
// enable overflow hidden and ellipsis
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
$borderConfig: 1px solid rgba(#fff, 0.15);
border-left: $borderConfig;
&:last-child {
border-right: $borderConfig;
}
}

View File

@ -1,31 +1,31 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { MessageDescriptor } from 'react-intl';
import i18n from 'app/services/i18n';
function isMessageDescriptor(value: any): value is MessageDescriptor {
return typeof value === 'object' && value.id;
}
export default class FormComponent<P, S = {}> extends React.Component<P, S> {
/**
* Formats message resolving intl translations
*
* @param {string|object} message - message string, or intl message descriptor with an `id` field
*
* @deprecated
* @returns {string}
*/
formatMessage(message: string | MessageDescriptor): string {
if (!message) {
throw new Error('A message is required');
}
if (typeof message === 'string') {
return message;
}
if (!message.id) {
throw new Error(`Invalid message format: ${JSON.stringify(message)}`);
}
formatMessage<T extends ReactNode | MessageDescriptor>(message: T): T extends MessageDescriptor ? string : T {
if (isMessageDescriptor(message)) {
// @ts-ignore
return i18n.getIntl().formatMessage(message);
}
// @ts-ignore
return message;
}
/**
* Focuses this field
*/

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { MessageDescriptor } from 'react-intl';
import clsx from 'clsx';
import { uniqueId, omit } from 'app/functions';
@ -17,7 +17,7 @@ export default class Input extends FormInputComponent<
color: Color;
center: boolean;
disabled: boolean;
label?: string | MessageDescriptor;
label?: ReactNode | MessageDescriptor;
placeholder?: string | MessageDescriptor;
icon?: string;
copy?: boolean;

View File

@ -25,8 +25,9 @@ $dropdownPadding: 15px;
display: inline-block;
box-sizing: border-box;
height: 50px;
padding-inline-start: $dropdownPadding;
// 28px - ширина иконки при заданном размере шрифта
padding: 0 ($dropdownPadding * 2 + 28px) 0 $dropdownPadding;
padding-inline-end: $dropdownPadding * 2 + 28px;
position: relative;
font-family: $font-family-title;
@ -48,6 +49,7 @@ $dropdownPadding: 15px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-align: start;
}
.opened {
@ -57,18 +59,26 @@ $dropdownPadding: 15px;
composes: selecter from '~app/components/ui/icons.scss';
position: absolute;
right: $dropdownPadding;
inset-inline-end: $dropdownPadding;
top: 16px;
font-size: 17px;
transition: right 0.3s cubic-bezier(0.23, 1, 0.32, 1); // easeOutQuint
transition: inset-inline-end 0.3s cubic-bezier(0.23, 1, 0.32, 1); // easeOutQuint
// TODO: right now transition property doesn't support the bidirectional value.
// See https://github.com/gasolin/postcss-bidirection/issues/25.
// noinspection CssOverwrittenProperties Graceful degradation
transition: right 0.3s cubic-bezier(0.23, 1, 0.32, 1);
html[dir='rtl'] & {
transition: left 0.3s cubic-bezier(0.23, 1, 0.32, 1);
}
.dropdown:hover & {
right: $dropdownPadding - 5px;
inset-inline-end: $dropdownPadding - 5px;
}
.dropdown:active &,
.dropdown.opened & {
right: $dropdownPadding + 5px;
inset-inline-end: $dropdownPadding + 5px;
}
}
@ -84,7 +94,7 @@ $dropdownPadding: 15px;
.menu {
position: absolute;
top: 60px;
left: 0;
inset-inline-start: 0;
z-index: 10;
width: 120%;

View File

@ -36,7 +36,7 @@
composes: formRow;
.textField {
padding-left: 60px;
padding-inline-start: 60px;
}
}
@ -80,7 +80,7 @@
.textFieldIcon {
box-sizing: border-box;
position: absolute;
left: 0;
inset-inline-start: 0;
top: 0;
height: 50px;
width: 50px;
@ -95,7 +95,7 @@
.copyIcon {
position: absolute;
right: 5px;
inset-inline-end: 5px;
top: 10px;
padding: 5px;
@ -175,6 +175,7 @@
font-family: $font-family-title;
color: #666;
font-size: 18px;
text-align: start;
}
.fieldError {
@ -248,7 +249,7 @@
.markableContainer {
display: inline-block;
position: relative;
padding-left: 27px;
padding-inline-start: 27px;
font-family: $font-family-title;
font-size: 16px;
@ -260,7 +261,7 @@
.markPosition {
position: absolute;
box-sizing: border-box;
left: 0;
inset-inline-start: 0;
top: 0;
margin: 0;

View File

@ -15,10 +15,30 @@
@extend .arrow;
transform: rotate(270deg);
html[dir='rtl'] & {
transform: rotate(90deg);
}
}
.arrowLeft {
@extend .arrow;
transform: rotate(90deg);
html[dir='rtl'] & {
transform: rotate(270deg);
}
}
html[dir='rtl'] {
.brush,
.exit,
.key,
.pencil,
.search {
&:before {
transform: scaleX(-1);
}
}
}

View File

@ -1,4 +1,6 @@
.loader-overlay {
direction: ltr;
background: rgba(255, 255, 255, 0.3);
position: fixed;
top: 0;

View File

@ -77,8 +77,8 @@ class SlideMotion extends React.PureComponent<Props, State> {
<div
className={styles.container}
style={{
WebkitTransform: `translateX(-${interpolatingStyle.transform}%)`,
transform: `translateX(-${interpolatingStyle.transform}%)`,
// @ts-ignore see https://stackoverflow.com/a/52013197/5184751
'--transition-progress': `${interpolatingStyle.transform}%`,
}}
>
{React.Children.map(children, (child, index) => (

View File

@ -1,5 +1,11 @@
.container {
white-space: nowrap;
transform: translate(var(--transition-progress));
html[dir='ltr'] & {
// noinspection CssInvalidFunction works fine in a browser (:
transform: translate(calc(var(--transition-progress) * -1));
}
}
.item {

View File

@ -25,12 +25,12 @@ $headerHeight: 60px;
.headerControl {
composes: black from '~app/components/ui/buttons.scss';
float: left;
float: start;
overflow: hidden;
height: $headerHeight - 1px;
width: 49px;
padding: 0;
border-right: 1px solid lighter($black);
border-inline-end: 1px solid lighter($black);
line-height: 1;
text-align: center;
@ -122,7 +122,7 @@ $bodyTopBottomPadding: 15px;
composes: close from '~app/components/ui/icons.scss';
position: absolute;
right: 5px;
inset-inline-end: 5px;
top: 5px;
font-size: 10px;

View File

@ -59,7 +59,7 @@ $popupMargin: 20px; // Outer popup margins
.popup {
white-space: normal;
text-align: left;
text-align: start;
background: #fff;
box-shadow: 0 0 10px rgba(#000, 0.2);
@ -95,7 +95,7 @@ $popupMargin: 20px; // Outer popup margins
composes: close from '~app/components/ui/icons.scss';
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
padding: 15px;
cursor: pointer;
@ -122,6 +122,10 @@ $popupMargin: 20px; // Outer popup margins
opacity: 0;
transform: translate(100%);
transition: 0s;
html[dir='rtl'] & {
transform: translate(-100%);
}
}
}

View File

@ -47,7 +47,7 @@
position: absolute;
top: 0.16em;
left: -0.145em;
inset-inline-start: -0.145em;
font-size: 0.7em;
color: rgba($red, 0.75);
}

View File

@ -8,7 +8,7 @@
.step {
position: relative;
text-align: right;
text-align: end;
width: 100%;
height: 4px;
@ -24,8 +24,8 @@
position: absolute;
height: 4px;
left: 0;
right: 100%;
inset-inline-start: 0;
inset-inline-end: 100%;
top: 50%;
margin-top: -2px;
@ -53,7 +53,7 @@
.activeStep {
&:before {
right: 0;
inset-inline-end: 0;
transition-delay: unset;
}

View File

@ -47,7 +47,7 @@ const AccountSwitcher: ComponentType<Props> = ({
<div className={clsx(styles.accountSwitcher)} data-testid="account-switcher">
<div className={styles.item} data-testid="active-account">
<PseudoAvatar className={styles.activeAccountIcon} />
<div className={styles.activeAccountInfo}>
<div>
<div className={styles.activeAccountUsername}>{activeAccount.username}</div>
<div className={clsx(styles.accountEmail, styles.activeAccountEmail)}>{activeAccount.email}</div>
<div className={styles.links}>
@ -81,16 +81,16 @@ const AccountSwitcher: ComponentType<Props> = ({
>
<PseudoAvatar index={index + 1} deleted={account.isDeleted} className={styles.accountIcon} />
<div className={styles.accountInfo}>
<div className={styles.accountUsername}>{account.username}</div>
<div className={styles.accountEmail}>{account.email}</div>
</div>
<div
className={styles.logoutIcon}
data-testid="logout-account"
onClick={onAccountRemoveCallback(account)}
/>
<div className={styles.accountInfo}>
<div className={styles.accountUsername}>{account.username}</div>
<div className={styles.accountEmail}>{account.email}</div>
</div>
</div>
))}
<Link to="/login" onClick={onLoginClick}>

View File

@ -8,8 +8,6 @@ $bodyLeftRightPadding: 20px;
$lightBorderColor: #eee;
.accountSwitcher {
text-align: left;
background: #fff;
color: #444;
min-width: 205px;
@ -20,9 +18,6 @@ $lightBorderColor: #eee;
border-bottom: 7px solid darker($green);
}
.accountInfo {
}
.accountUsername,
.accountEmail {
overflow: hidden;
@ -30,6 +25,7 @@ $lightBorderColor: #eee;
}
.item {
display: flex;
padding: 15px;
border-bottom: 1px solid $lightBorderColor;
}
@ -50,8 +46,7 @@ $lightBorderColor: #eee;
.accountIcon {
font-size: 27px;
width: 20px;
text-align: center;
float: left;
margin-inline-end: 9px;
}
.activeAccountIcon {
@ -60,10 +55,6 @@ $lightBorderColor: #eee;
font-size: 40px;
}
.activeAccountInfo {
margin-left: 29px;
}
.activeAccountUsername {
font-family: $font-family-title;
font-size: 20px;
@ -88,8 +79,7 @@ $lightBorderColor: #eee;
}
.accountInfo {
margin-left: 29px;
margin-right: 25px;
flex-grow: 1;
}
.accountUsername {
@ -117,15 +107,16 @@ $lightBorderColor: #eee;
color: $green;
position: relative;
bottom: 1px;
margin-right: 3px;
margin-inline-end: 3px;
}
.logoutIcon {
composes: exit from '~app/components/ui/icons.scss';
align-self: center;
margin-inline-start: 9px;
color: #cdcdcd;
float: right;
line-height: 27px;
transition: 0.25s;
&:hover {

View File

@ -27,6 +27,10 @@
.expandIcon {
transform: rotate(-180deg);
html[dir='rtl'] & {
transform: rotate(180deg); // Fix spin direction
}
}
}
@ -36,13 +40,13 @@
position: relative;
bottom: 2px;
padding-right: 5px;
padding-inline-end: 5px;
}
.expandIcon {
composes: caret from '~app/components/ui/icons.scss';
margin-left: 4px;
margin-inline-start: 4px;
font-size: 6px;
color: #ccc;
transition: 0.2s;
@ -54,7 +58,7 @@
.accountSwitcherContainer {
position: absolute;
top: 100%;
right: -2px;
inset-inline-end: -2px;
cursor: auto;
display: none;

View File

@ -30,6 +30,7 @@
"redux": "^4.0.5",
"redux-localstorage": "^0.4.1",
"redux-thunk": "^2.0.0",
"rtl-detect": "^1.0.2",
"url-search-params-polyfill": "^8.1.0",
"webfontloader": "^1.6.26",
"whatwg-fetch": "^3.0.0"
@ -45,6 +46,7 @@
"@types/react-helmet": "^6.0.0",
"@types/react-motion": "^0.0.29",
"@types/react-transition-group": "^4.2.4",
"@types/rtl-detect": "^1.0.0",
"@types/webfontloader": "^1.6.30",
"@types/webpack-env": "^1.15.2",
"utility-types": "^3.10.0"

View File

@ -26,7 +26,11 @@
width: 50px;
height: 50px;
background: white;
animation: cubeRotate 1s ease-out infinite;
animation: cubeRotateLTR 1s ease-out infinite;
html[dir='rtl'] & {
animation-name: cubeRotateRTL;
}
}
.road {
@ -34,12 +38,12 @@
width: 100%;
height: 1px;
background: white;
left: 0;
inset-inline-start: 0;
bottom: 0;
animation: roadStab 1s ease-out infinite;
}
@keyframes cubeRotate {
@keyframes cubeRotateLTR {
0% {
transform: rotate(0deg) translate3D(0, 0, 0);
}
@ -54,6 +58,21 @@
}
}
@keyframes cubeRotateRTL {
0% {
transform: rotate(0deg) translate3D(0, 0, 0);
}
65% {
transform: rotate(-45deg) translate3D(0, -13px, 0);
}
90% {
transform: rotate(-70deg) translate3D(0, -8px, 0);
}
100% {
transform: rotate(-90deg) translate3D(0, 0, 0);
}
}
@keyframes roadStab {
0% {
transform: translate3D(0, 0, 0);
@ -91,7 +110,7 @@
height: 100%;
position: absolute;
bottom: -50px;
left: 0;
inset-inline-start: 0;
overflow: hidden;
animation: roadStab 1s ease-out infinite;
}
@ -103,7 +122,7 @@
border-right: 2px solid transparent;
border-bottom: 4px solid white;
bottom: $bottom;
right: -2%;
inset-inline-end: -2%;
animation: rockTravelling 10s $delay ease-out infinite;
}
}
@ -116,37 +135,37 @@
@keyframes rockTravelling {
0% {
right: -2%;
inset-inline-end: -2%;
}
10% {
right: 8%;
inset-inline-end: 8%;
}
20% {
right: 18%;
inset-inline-end: 18%;
}
30% {
right: 29%;
inset-inline-end: 29%;
}
40% {
right: 40%;
inset-inline-end: 40%;
}
50% {
right: 51%;
inset-inline-end: 51%;
}
60% {
right: 62%;
inset-inline-end: 62%;
}
70% {
right: 72%;
inset-inline-end: 72%;
}
80% {
right: 82%;
inset-inline-end: 82%;
}
90% {
right: 92%;
inset-inline-end: 92%;
}
100% {
right: 102%;
inset-inline-end: 102%;
}
}
@ -158,7 +177,7 @@
animation: roadStab 1s ease-out infinite, cloudStab 1s ease-out infinite;
position: absolute;
bottom: -50px;
left: -50%;
inset-inline-start: -50%;
overflow: hidden;
}
@ -183,7 +202,7 @@
composes: cloud;
top: 65px;
right: -30%;
inset-inline-end: -30%;
width: 50px;
height: 16px;
animation: cloudTravelling 21s 5s linear infinite;
@ -193,7 +212,7 @@
composes: cloud;
top: 40px;
right: -30%;
inset-inline-end: -30%;
width: 70px;
height: 22px;
animation: cloudTravelling 26s 11s linear infinite;
@ -201,10 +220,10 @@
@keyframes cloudTravelling {
0% {
right: -30%;
inset-inline-end: -30%;
}
100% {
right: 110%;
inset-inline-end: 110%;
}
}

View File

@ -34,12 +34,10 @@ $sidebar-width: 320px;
@media (min-width: 720px) {
.content {
padding: 55px 50px;
margin-left: $sidebar-width;
margin-inline-start: $sidebar-width;
}
.sidebar {
right: auto;
width: $sidebar-width;
}

View File

@ -6,7 +6,7 @@
width: 100%;
position: absolute;
bottom: 10px;
left: 0;
inset-inline-start: 0; // TODO: does nothing. Maybe should be reimplemented?
text-align: center;
}

View File

@ -6,7 +6,7 @@
width: 100%;
position: absolute;
bottom: 10px;
left: 0;
inset-inline-start: 0;
text-align: center;
}

View File

@ -1,6 +1,5 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { Helmet } from 'react-helmet-async';
import clsx from 'clsx';
import { connect } from 'app/functions';
@ -54,10 +53,6 @@ class RootPage extends React.PureComponent<{
return (
<div className={styles.root}>
<Helmet>
<html lang={user.lang} />
</Helmet>
<ScrollIntoView top />
<div

View File

@ -32,7 +32,7 @@ $toolbarHeight: 50px;
.toolbarContent {
composes: wrapper;
position: relative;
display: flex;
}
.siteName {
@ -44,15 +44,11 @@ $toolbarHeight: 50px;
font-family: $font-family-title;
font-size: 33px;
color: #fff!important; // TODO: why?
color: #fff!important; // Important to remove hover effect, which is inherited from the global <a> style
}
.userBar {
position: absolute;
right: 0;
left: 115px;
top: 0;
text-align: right;
margin-inline-start: auto;
}
.body {

View File

@ -50,7 +50,7 @@
.rulesList {
padding: 0;
margin: 0;
padding-left: 20px;
padding-inline-start: 20px;
}
.rulesItem {
@ -71,7 +71,7 @@
content: '';
position: absolute;
top: -10px;
left: -40px;
inset-inline-start: -40px;
width: calc(100% + 60px);
height: calc(100% + 20px);
background: $white;

View File

@ -0,0 +1,250 @@
IntlPolyfill.__addLocaleData({
locale: "udm",
date: {
ca: ["gregory", "generic"],
hourNo0: true,
hour12: false,
formats: {
short: "{1}, {0}",
medium: "{1}, {0}",
full: "{1}, {0}",
long: "{1}, {0}",
availableFormats: {
d: "d",
E: "ccc",
Ed: "ccc, d",
Ehm: "E h:mm a",
EHm: "E HH:mm",
Ehms: "E h:mm:ss a",
EHms: "E HH:mm:ss",
Gy: "G y 'аре'",
GyMMM: "LLL G y",
GyMMMd: "d MMM G y 'аре'",
GyMMMEd: "E, d MMM G y 'аре'",
h: "h a",
H: "H",
hm: "h:mm a",
Hm: "H:mm",
hms: "h:mm:ss a",
Hms: "H:mm:ss",
hmsv: "h:mm:ss a v",
Hmsv: "H:mm:ss v",
hmv: "h:mm a v",
Hmv: "H:mm v",
M: "L",
Md: "dd.MM",
MEd: "E, dd.MM",
MMdd: "dd.MM",
MMM: "LLL",
MMMd: "d MMM",
MMMEd: "ccc, d MMM",
MMMMd: "d MMMM",
ms: "mm:ss",
y: "y",
yM: "MM.y",
yMd: "dd.MM.y",
yMEd: "ccc, d.MM.y 'аре'",
yMM: "MM.y",
yMMM: "LLL y 'аре'",
yMMMd: "d MMM y 'аре'",
yMMMEd: "E, d MMM y 'аре'",
yMMMM: "LLLL y 'аре'",
yQQQ: "QQQ y 'аре'",
yQQQQ: "QQQQ y 'аре'",
},
dateFormats: {
yMMMMEEEEd: "EEEE, d MMMM y 'аре'",
yMMMMd: "d MMMM y 'аре'",
yMMMd: "d MMM y 'аре'",
yMd: "dd.MM.yy",
},
timeFormats: {
hmmsszzzz: "H:mm:ss zzzz",
hmsz: "H:mm:ss z",
hms: "H:mm:ss",
hm: "H:mm",
},
},
calendars: {
generic: {
months: {
narrow: [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
],
short: [
"Т01",
"Т02",
"Т03",
"Т04",
"Т05",
"Т06",
"Т07",
"Т08",
"Т09",
"Т10",
"Т11",
"Т12",
],
long: [
"Т01",
"Т02",
"Т03",
"Т04",
"Т05",
"Т06",
"Т07",
"Т08",
"Т09",
"Т10",
"Т11",
"Т12",
],
},
days: {
narrow: ["А", "В", "П", "В", "П", "У", "К"],
short: ["ан", "вр", "пк", "вн", "па", "уд", "кн"],
long: [
"арнянунал",
"вордӥськон",
"пуксён",
"вирнунал",
"покчиарня",
"удмуртарня",
"кӧснунал",
],
},
eras: {
narrow: ["ERA0", "ERA1"],
short: ["ERA0", "ERA1"],
long: ["ERA0", "ERA1"],
},
dayPeriods: { am: "ЛА", pm: "ЛБ" },
},
gregory: {
months: {
narrow: ["Т", "Т", "М", "А", "М", "И", "И", "А", "С", "О", "Н", "Д"],
short: [
"тшт",
"тпт",
"южт",
"ошт",
"крт",
"ивт",
"пст",
"гкт",
"кут",
"квт",
"шкт",
"тст",
],
long: [
"толшоре",
"тулыспалэ",
"южтолэзе",
"оштолэзе",
"куартолэзе",
"инвожое",
"пӧсьтолэзе",
"гудырикошконэ",
"куарусёнэ",
"коньывуонэ",
"шуркынмонэ",
"толсуре",
],
},
days: {
narrow: ["А", "В", "П", "В", "П", "У", "К"],
short: ["ан", "вр", "пк", "вн", "па", "уд", "кн"],
long: [
"арнянунал",
"вордӥськон",
"пуксён",
"вирнунал",
"покчиарня",
"удмуртарня",
"кӧснунал",
],
},
eras: {
narrow: ["КА", "КБ", "ава", "ав"],
short: ["КА", "КБ", "а.в.а", "а.в."],
long: [
"Кристослэн вордскем азяз",
"Кристослэн вордскем бераз",
"асьме вакытлэсь азьло",
"асьме вакытэ",
],
},
dayPeriods: { am: "ЛА", pm: "ЛБ" },
},
},
},
number: {
nu: ["latn"],
patterns: {
decimal: {
positivePattern: "{number}",
negativePattern: "{minusSign}{number}",
},
currency: {
positivePattern: "{number} {currency}",
negativePattern: "{minusSign}{number} {currency}",
},
percent: {
positivePattern: "{number} {percentSign}",
negativePattern: "{minusSign}{number} {percentSign}",
},
},
symbols: {
latn: {
decimal: ",",
group: " ",
nan: "лыд ӧвӧл",
plusSign: "+",
minusSign: "-",
percentSign: "%",
infinity: "∞",
},
},
currencies: {
AUD: "A$",
BRL: "R$",
CAD: "CA$",
CNY: "CN¥",
EUR: "€",
GBP: "£",
HKD: "HK$",
ILS: "₪",
INR: "₹",
JPY: "¥",
KRW: "₩",
MXN: "MX$",
NZD: "NZ$",
RUB: "₽",
RUR: "р.",
THB: "฿",
TMT: "ТМТ",
TWD: "NT$",
UAH: "₴",
USD: "$",
VND: "₫",
XAF: "FCFA",
XCD: "EC$",
XOF: "CFA",
XPF: "CFPF",
XXX: "XXXX",
},
},
});

View File

@ -0,0 +1,12 @@
Intl.PluralRules && 'function' == typeof Intl.PluralRules.__addLocaleData && Intl.PluralRules.__addLocaleData({
data: {
udm: {
categories: {
cardinal: ['other'],
ordinal: ['other'],
}, fn: function(a, l) {
return 'other';
},
},
}, availableLocales: ['udm'], aliases: {}, parentLocales: {},
});

View File

@ -0,0 +1,159 @@
Intl.RelativeTimeFormat && 'function' == typeof Intl.RelativeTimeFormat.__addLocaleData && Intl.RelativeTimeFormat.__addLocaleData({
data: {
udm: {
nu: ['latn'],
year: {
0: 'таяз аре',
1: 'вуоно аре',
'-1': 'кылем аре',
past: { other: '{0} ар талэсь азьло' },
future: { other: '{0} ар ортчыса' },
},
'year-short': {
0: 'туэ',
1: 'вуоно аре',
'-1': 'кылем аре',
past: { other: '{0} ар талэсь азьло' },
future: { other: '{0} ар ортчыса' },
},
'year-narrow': {
0: 'туэ',
1: 'кайта',
'-1': 'мийым',
past: { other: '{0} ар талэсь азьло' },
future: { other: '{0} ар ортчыса' },
},
quarter: {
0: 'таяз арньыльмосэ',
1: 'вуоно арньыльмосэ',
'-1': 'ортчем арньыльмосэ',
past: { other: '{0} арньыльмос талэсь азьло' },
future: { other: '{0} арныльмос ортчыса' },
},
'quarter-short': {
0: 'таяз арньыльмосэ',
1: 'вуоно арньыльмосэ',
'-1': 'ортчем арньыльмосэ',
past: { other: '{0} арньыльмос талэсь азьло' },
future: { other: '{0} арныльмос ортчыса' },
},
'quarter-narrow': {
0: 'таяз арньыльмосэ',
1: 'вуоно арньыльмосэ',
'-1': 'ортчем арньыльмосэ',
past: { other: '{0} арньыльмос талэсь азьло' },
future: { other: '{0} арныльмос ортчыса' },
},
month: {
0: 'таяз толэзе',
1: 'вуоно толэзе',
'-1': 'ортчем толэзе',
past: { other: '{0} толэзь талэсь азьло' },
future: { other: '{0} толэзь ортчыса' },
},
'month-short': {
0: 'таяз толэзе',
1: 'вуоно толэзе',
'-1': 'ортчем толэзе',
past: { other: '{0} толэзь талэсь азьло' },
future: { other: '{0} толэзь ортчыса' },
},
'month-narrow': {
0: 'таяз толэзе',
1: 'вуоно толэзе',
'-1': 'ортчем толэзе',
past: { other: '{0} толэзь талэсь азьло' },
future: { other: '{0} толэзь ортчыса' },
},
week: {
0: 'таяз арняе',
1: 'вуоно арняе',
'-1': 'ортчем арняе',
past: { other: '{0} арня талэсь азьло' },
future: { other: '{0} арня ортчыса' },
},
'week-short': {
0: 'таяз арняе',
1: 'вуоно арняе',
'-1': 'ортчем арняе',
past: { other: '{0} арня талэсь азьло' },
future: { other: '{0} арня ортчыса' },
},
'week-narrow': {
0: 'таяз арняе',
1: 'вуоно арняе',
'-1': 'ортчем арняе',
past: { other: '{0} арня талэсь азьло' },
future: { other: '{0} арня ортчыса' },
},
day: {
0: 'туннэ',
1: 'ӵуказе',
2: 'ӵуказе улыса',
'-2': 'валлян',
'-1': 'толон',
past: { other: '{0} нунал талэсь азьло' },
future: { other: '{0} нунал ортчыса' },
},
'day-short': {
0: 'туннэ',
1: 'ӵуказе',
2: 'ӵуказе улыса',
'-2': 'валлян',
'-1': 'толон',
past: { other: '{0} нунал талэсь азьло' },
future: { other: '{0} нунал ортчыса' },
},
'day-narrow': {
0: 'туннэ',
1: 'ӵуказе',
2: 'усьсэ',
'-2': 'валлян',
'-1': 'толон',
past: { other: '{0} нунал талэсь азьло' },
future: { other: '{0} нунал ортчыса' },
},
hour: { 0: 'таяз часэ', past: { other: '{0} час талэсь азьло' }, future: { other: '{0} час ортчыса' } },
'hour-short': {
0: 'таяз часэ',
past: { other: '{0} час талэсь азьло' },
future: { other: '{0} час ортчыса' },
},
'hour-narrow': {
0: 'таяз часэ',
past: { other: '{0} час талэсь азьло' },
future: { other: '{0} час ортчыса' },
},
minute: {
0: 'таяз минутэ',
past: { other: '{0} минут талэсь азьло' },
future: { other: '{0} минут ортчыса' },
},
'minute-short': {
0: 'таяз минутэ',
past: { other: '{0} минут талэсь азьло' },
future: { other: '{0} минут ортчыса' },
},
'minute-narrow': {
0: 'таяз минутэ',
past: { other: '{0} минут талэсь азьло' },
future: { other: '{0} минут ортчыса' },
},
second: {
0: 'таяз секундэ',
past: { other: '{0} секунд талэзь азьло' },
future: { other: '{0} секунд ортчыса' },
},
'second-short': {
0: 'таяз секундэ',
past: { other: '{0} секунд талэзь азьло' },
future: { other: '{0} секунд ортчыса' },
},
'second-narrow': {
0: 'таяз секундэ',
past: { other: '{0} секунд талэзь азьло' },
future: { other: '{0} секунд ортчыса' },
},
},
}, availableLocales: ['udm'], aliases: {}, parentLocales: {},
});

View File

@ -28,7 +28,7 @@ const CROWDIN_FILE_PATH = config.filePath;
const SOURCE_LANG = config.sourceLang;
const LANG_DIR = config.basePath;
const INDEX_FILE_NAME = 'index.js';
const MIN_RELEASE_PROGRESS = config.minApproved;
const MIN_RELEASE_PROGRESS = config.minTranslated;
const crowdin = new Crowdin({
token: config.apiKey,
@ -43,6 +43,7 @@ const releasedLocales: ReadonlyArray<string> = ['be', 'fr', 'id', 'pt', 'ru', 'u
* Map Crowdin locales into our internal locales representation
*/
const LOCALES_MAP: Record<string, string> = {
'es-ES': 'es',
'pt-BR': 'pt',
'zh-CN': 'zh',
};
@ -54,6 +55,7 @@ const LOCALES_MAP: Record<string, string> = {
const NATIVE_NAMES_MAP: Record<string, string> = {
be: 'Беларуская',
cs: 'Čeština',
fil: 'Wikang Filipino',
id: 'Bahasa Indonesia',
lt: 'Lietuvių',
pl: 'Polski',
@ -67,6 +69,7 @@ const NATIVE_NAMES_MAP: Record<string, string> = {
* This arrays allows us to override Crowdin English languages names
*/
const ENGLISH_NAMES_MAP: Record<string, string> = {
fil: 'Filipino',
pt: 'Portuguese, Brazilian',
sr: 'Serbian',
zh: 'Simplified Chinese',
@ -225,7 +228,7 @@ async function pull(): Promise<void> {
}
console.log('Pulling translation progress...');
const { data: translationProgress } = await crowdin.translationStatusApi.getFileProgress(PROJECT_ID, fileId, 100);
const { data: fileProgress } = await crowdin.translationStatusApi.getFileProgress(PROJECT_ID, fileId, 100);
const localesToPull: Array<string> = [];
const indexFileEntries: Record<string, IndexFileEntry> = {
@ -238,16 +241,16 @@ async function pull(): Promise<void> {
},
};
translationProgress.forEach(({ data: { languageId, approvalProgress } }) => {
fileProgress.forEach(({ data: { languageId, translationProgress } }) => {
const locale = toInternalLocale(languageId);
if (releasedLocales.includes(locale) || approvalProgress >= MIN_RELEASE_PROGRESS) {
if (releasedLocales.includes(locale) || translationProgress >= MIN_RELEASE_PROGRESS) {
localesToPull.push(languageId);
indexFileEntries[locale] = {
code: locale,
name: NATIVE_NAMES_MAP[locale] || iso639.getNativeName(locale),
englishName: ENGLISH_NAMES_MAP[locale] || iso639.getName(locale),
progress: approvalProgress,
progress: translationProgress,
isReleased: releasedLocales.includes(locale),
};
}
@ -268,7 +271,6 @@ async function pull(): Promise<void> {
data: { url },
} = await crowdin.translationsApi.buildProjectFileTranslation(PROJECT_ID, fileId, {
targetLanguageId: languageId,
exportApprovedOnly: true,
});
const { data: fileContents } = await axios.get(url, {

View File

@ -47,6 +47,7 @@ module.exports = ({ webpack: loader }) => ({
return defaultLoad(filename, importOptions);
})(require('postcss-import/lib/load-content')),
},
'postcss-bidirection': {},
// TODO: for some reason cssnano strips out @mixin declarations
// cssnano: {
// /**

19
postinstall.js Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const localeOverrides = {
'packages/app/services/i18n/overrides/intl': 'node_modules/intl/locale-data/jsonp',
'packages/app/services/i18n/overrides/pluralrules': 'node_modules/@formatjs/intl-pluralrules/dist/locale-data',
// eslint-disable-next-line prettier/prettier
'packages/app/services/i18n/overrides/relativetimeformat': 'node_modules/@formatjs/intl-relativetimeformat/dist/locale-data',
};
Object.entries(localeOverrides).forEach(([sourceDir, targetDir]) => {
fs.readdirSync(sourceDir).forEach((localeFile) => {
fs.copyFileSync(path.join(sourceDir, localeFile), path.join(targetDir, localeFile));
});
});

View File

@ -201,19 +201,6 @@ const webpackConfig = {
type: 'javascript/auto',
use: ['fontgen-loader'],
},
{
// Replace some locales provided by FormatJS with local ones
test: /@formatjs\/intl-\w+\/dist\/locale-data/,
loader: 'file-replace-loader',
options: {
condition: 'if-replacement-exists',
replacement: (resource) =>
resource.replace(
/node_modules\/@formatjs\/intl-(\w+)\/dist\/locale-data\/(\w+)\.js/,
'packages/app/services/i18n/overrides/$1/$2.js',
),
},
},
],
},

View File

@ -3439,6 +3439,11 @@
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/rtl-detect@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/rtl-detect/-/rtl-detect-1.0.0.tgz#5791e18a111f2b8b5b328160af97f3991a5697a5"
integrity sha512-lyYh44YgrejEK9/5rhASghvRUOxrSJyyyQmqK7L6F/V5qs6PY1RfCi1VbjSkY6kuDt7lzQyhd006slhda4Oypg==
"@types/sax@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.1.tgz#e0248be936ece791a82db1a57f3fb5f7c87e8172"
@ -12535,6 +12540,12 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
"postcss-bidirection@https://github.com/erickskrauch/postcss-bidirection.git#iss_23":
version "2.7.2"
resolved "https://github.com/erickskrauch/postcss-bidirection.git#feabf42c8ab5cf6b0e22f78de04984e22cf42ba4"
dependencies:
postcss "^7.0.13"
postcss-calc@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.1.tgz#36d77bab023b0ecbb9789d84dcb23c4941145436"
@ -12917,6 +12928,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.2
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^7.0.13:
version "7.0.35"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24"
integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^7.0.26:
version "7.0.26"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587"
@ -14246,6 +14266,11 @@ rsvp@^4.8.4:
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
rtl-detect@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.2.tgz#8eca316f5c6563d54df4e406171dd7819adda67f"
integrity sha512-5X1422hvphzg2a/bo4tIDbjFjbJUOaPZwqE6dnyyxqwFqfR+tBcvfqapJr0o0VygATVCGKiODEewhZtKF+90AA==
run-async@^2.2.0, run-async@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"