Первичная реализация нового переключателя языков

This commit is contained in:
ErickSkrauch 2017-10-15 22:00:21 +03:00
parent 3176ada238
commit ddd5ddab2e
31 changed files with 527 additions and 546 deletions

View File

@ -29,6 +29,7 @@
"babel-polyfill": "^6.3.14",
"classnames": "^2.1.3",
"debounce": "^1.0.0",
"flag-icon-css": "^2.8.0",
"intl": "^1.2.2",
"intl-format-cache": "^2.0.4",
"intl-messageformat": "^2.1.0",

View File

@ -26,6 +26,24 @@ const LOCALES_MAP = {
lt: 'lt-LT',
};
/**
* Некоторые языки, после выгрузки из OneSky, имеют не очень информативные названия,
* так что здесь можно указать точные имена для результирующего файла index.json
*/
const ORIGINAL_NAMES_MAP = {
en: 'English, UK',
pt: 'Português do Brasil',
};
/**
* Некоторые языки, после выгрузки из OneSky, имеют не очень точные английские названия,
* так что здесь можно указать точные имена для результирующего файла index.json
*/
const ENGLISH_NAMES_MAP = {
en: 'English, UK',
pt: 'Portuguese, Brazilian',
};
// https://ely-translates.oneskyapp.com/admin/site/settings
const defaultOptions = {
apiKey: '5MaW9TYp0S3qdJgkZ5QLgEIDeabkFDzB',
@ -83,6 +101,17 @@ function sortByKeys(object) {
}, {});
}
/**
* Убирает значение в скобках.
* Например: "French (France)" => "French".
*
* @param {string} value
* @return {string}
*/
function trimValueInBrackets(value) {
return value.match(/^([^\(]+)/)[0].trim();
}
async function pullReadyLanguages() {
const languages = JSON.parse(await onesky.getLanguages({...defaultOptions}));
return languages.data
@ -112,7 +141,8 @@ async function pull() {
const mapFileContent = {};
langs.map((elem) => {
mapFileContent[elem.locale] = {
name: elem.local_name.match(/^([^\(]+)/)[0].trim(), // Обрезаем значения в скобках
name: ORIGINAL_NAMES_MAP[elem.locale] || trimValueInBrackets(elem.local_name),
englishName: ENGLISH_NAMES_MAP[elem.locale] || trimValueInBrackets(elem.english_name),
progress: parseFloat(elem.translation_progress),
isReleased: elem.is_ready_to_publish,
};

View File

@ -4,8 +4,6 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage as Message } from 'react-intl';
import { LangMenu } from 'components/langMenu';
import styles from './footerMenu.scss';
import messages from './footerMenu.intl.json';
@ -13,7 +11,8 @@ class FooterMenu extends Component {
static displayName = 'FooterMenu';
static propTypes = {
createPopup: PropTypes.func.isRequired
createContactPopup: PropTypes.func.isRequired,
createLanguageSwitcherPopup: PropTypes.func.isRequired,
};
render() {
@ -27,23 +26,35 @@ class FooterMenu extends Component {
<Message {...messages.contactUs} />
</a>
<LangMenu />
<div className={styles.langTriggerContainer}>
<a href="#" className={styles.langTrigger} onClick={this.onLanguageSwitcher}>
<span className={styles.langTriggerIcon} />
<Message {...messages.siteLanguage} />
</a>
</div>
</div>
);
}
onContact = (event) => {
event.preventDefault();
this.props.createPopup();
this.props.createContactPopup();
};
onLanguageSwitcher = (event) => {
event.preventDefault();
this.props.createLanguageSwitcherPopup();
};
}
import { connect } from 'react-redux';
import ContactForm from 'components/contact/ContactForm';
import LanguageSwitcher from 'components/languageSwitcher/LanguageSwitcher';
import { create as createPopup } from 'components/ui/popup/actions';
// mark this component, as not pure, because it is stateless,
// but should be re-rendered, if current lang was changed
export default connect(null, {
createPopup: () => createPopup(ContactForm)
createContactPopup: () => createPopup(ContactForm),
createLanguageSwitcherPopup: () => createPopup(LanguageSwitcher),
}, null, {pure: false})(FooterMenu);

View File

@ -1,4 +1,5 @@
{
"rules": "Rules",
"contactUs": "Contact Us"
"contactUs": "Contact Us",
"siteLanguage": "Site language"
}

View File

@ -8,3 +8,16 @@
border-bottom-color: #666;
}
}
.langTriggerContainer {
text-align: center;
}
.langTriggerIcon {
composes: globe from 'components/ui/icons.scss';
position: relative;
bottom: 1px;
font-size: 11px;
margin-right: 3px;
}

View File

@ -1,168 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import { FormattedMessage as Message } from 'react-intl';
import styles from './langMenu.scss';
import messages from './langMenu.intl.json';
import LANGS from 'i18n/index.json';
class LangMenu extends Component {
static propTypes = {
showCurrentLang: PropTypes.bool,
toggleRef: PropTypes.func,
userLang: PropTypes.string,
changeLang: PropTypes.func
};
static defaultProps = {
toggleRef: () => {},
showCurrentLang: false
};
state = {
isActive: false
};
componentDidMount() {
document.addEventListener('click', this.onBodyClick);
this.props.toggleRef(this.toggle.bind(this));
}
componentWillUnmount() {
document.removeEventListener('click', this.onBodyClick);
this.props.toggleRef(null);
}
render() {
const {userLang: userLocale, showCurrentLang} = this.props;
const {isActive} = this.state;
return (
<div className={classNames(styles.container, {
[styles.withCurrentLang]: showCurrentLang
})}>
<div className={styles.menuContainer}>
<ul className={classNames(styles.menu, {
[styles.menuActive]: isActive
})}>
{Object.keys(LANGS).map((locale) => (
<li className={classNames(styles.menuItem, {
[styles.activeMenuItem]: locale === userLocale
})} onClick={this.onChangeLang(locale)} key={locale}
>
{this.renderLangLabel(locale, LANGS[locale])}
</li>
))}
<li className={styles.improveTranslatesLink}>
<a href="https://ely-translates.oneskyapp.com/collaboration/project?id=201323" target="_blank">
<Message {...messages.improveTranslations} />
</a>
</li>
</ul>
</div>
<div className={styles.triggerContainer} onClick={this.onToggle}>
<a className={styles.trigger} href="#">
{showCurrentLang
? this.renderLangLabel(userLocale, LANGS[userLocale]) : (
<span>
<span className={styles.triggerIcon} />
{' '}
<Message {...messages.siteLanguage} />
{' '}
<span className={isActive ? styles.triggerArrowBottom : styles.triggerArrowTop} />
</span>
)}
</a>
</div>
</div>
);
}
renderLangLabel(locale, localeData) {
const {name, progress, isReleased} = localeData;
let progressLabel;
if (progress !== 100) {
progressLabel = (
<span className={styles.langTranslateUnfinished}>
{`(${progress}%)`}
</span>
);
} else if (!isReleased) {
progressLabel = (
<span className={styles.langTranslateUnreviewed}>
{'*'}
</span>
);
}
return (
<span>
<span className={styles.langIco} style={{
backgroundImage: `url('${require(`icons/flag_${locale}.svg`)}')`
}} />
{this.formatLocaleName(locale) || name}
{progressLabel}
</span>
);
}
formatLocaleName(locale) {
switch (locale) {
case 'pt':
return 'Português (Br)';
default:
return null;
}
}
onChangeLang(lang) {
return (event) => {
event.preventDefault();
this.props.changeLang(lang);
this.setState({
isActive: false
});
};
}
onBodyClick = (event) => {
if (this.state.isActive) {
const el = ReactDOM.findDOMNode(this);
if (!el.contains(event.target) && el !== event.taget) {
event.preventDefault();
// add a small delay for the case someone have alredy called toggle
setTimeout(() => this.state.isActive && this.toggle(), 0);
}
}
};
onToggle = (event) => {
event.preventDefault();
this.toggle();
};
toggle = () => {
// add small delay to skip click event on body
setTimeout(() => this.setState({
isActive: !this.state.isActive
}), 0);
};
}
import { connect } from 'react-redux';
import { changeLang } from 'components/user/actions';
export default connect((state) => ({
userLang: state.user.lang
}), {
changeLang
})(LangMenu);

View File

@ -1,5 +0,0 @@
import LangMenu from './LangMenu';
export {
LangMenu
};

View File

@ -1,4 +0,0 @@
{
"siteLanguage": "Site language",
"improveTranslations": "Improve translations"
}

View File

@ -1,164 +0,0 @@
@import "~components/ui/colors.scss";
@import "~components/ui/fonts.scss";
.container {
position: relative;
}
.menuContainer {
position: absolute;
bottom: 100%;
left: 0;
right: 0;
display: inline-flex;
justify-content: center;
margin: 0 auto 10px;
perspective: 600px;
pointer-events: none;
}
.menu {
pointer-events: auto;
background: #fff;
border: 5px solid #ddd8ce;
border-left: 0;
border-right: 0;
text-align: left;
box-shadow: 0 0 1px rgba(#000, .2);
visibility: hidden;
opacity: 0;
transition: .3s cubic-bezier(0.075, 0.82, 0.165, 1); // easeOutCirc
transform: translateY(10px) rotateX(-17deg);
}
.menuActive {
visibility: visible;
opacity: 1;
transform: translateY(0) rotateX(0deg);
}
.withCurrentLang {
.triggerContainer {
text-align: left;
}
.menuContainer {
justify-content: flex-start;
}
}
.menuItem {
position: relative;
padding: 10px;
font-size: 13px;
border-bottom: 1px solid #eee;
cursor: pointer;
transition: .2s;
&:hover {
background: $whiteButtonLight;
color: #262626;
}
&:last-child {
border-bottom: none;
}
}
.activeMenuItem {
background: lighter($green)!important;
color: #fff!important;
font-weight: $font-weight-bold;
}
.langIco {
position: relative;
display: inline-block;
margin-right: 5px;
width: 20px;
height: 10px;
box-shadow: 0 0 1px rgba(#000, .2);
background: no-repeat;
background-size: cover;
}
.langTranslateProgress {
font-size: 9px;
position: relative;
font-family: $font-family-base;
color: #ccc;
}
.langTranslateUnfinished {
composes: langTranslateProgress;
top: -1px;
padding-left: 3px;
}
.langTranslateUnreviewed {
composes: langTranslateProgress;
top: -4px;
}
.improveTranslatesLink {
font-size: 11px;
text-align: center;
padding: 5px 10px;
a {
color: #9a9a9a;
border-bottom-color: #9a9a9a;
}
}
.trigger {
color: #666;
border-bottom: 1px dotted #666;
text-decoration: none;
transition: .25s;
&:hover {
border-bottom-color: #777;
color: #777;
}
}
.triggerContainer {
text-align: center;
}
.trigger {
font-size: 12px;
}
.triggerIcon {
composes: globe from 'components/ui/icons.scss';
position: relative;
bottom: 1px;
font-size: 11px;
}
.triggerArrow {
font-size: 8px;
transition: 0.2s;
}
.triggerArrowTop {
composes: triggerArrow;
composes: arrowTop from 'components/ui/icons.scss';
}
.triggerArrowBottom {
composes: triggerArrow;
composes: arrowBottom from 'components/ui/icons.scss';
// Докручиваем лишний раз, чтобы иконка крутилась по часовой стрелке
transform: rotate(360deg);
}

View File

@ -0,0 +1,197 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { FormattedMessage as Message } from 'react-intl';
import { requireLocaleFlag } from 'functions';
import LANGS from 'i18n/index.json';
import formStyles from 'components/ui/form/form.scss';
import popupStyles from 'components/ui/popup/popup.scss';
import icons from 'components/ui/icons.scss';
import styles from './languageSwitcher.scss';
import messages from './languageSwitcher.intl.json';
class LanguageSwitcher extends Component {
static displayName = 'LanguageSwitcher';
static propTypes = {
onClose: PropTypes.func,
userLang: PropTypes.string,
changeLang: PropTypes.func,
};
state = {
items: [],
filter: '',
};
static defaultProps = {
onClose() {}
};
componentWillMount() {
this.setState({items: LANGS});
}
render() {
const {userLang, onClose} = this.props;
const {items} = this.state;
return (
<div className={styles.languageSwitcher}>
<div className={popupStyles.popup}>
<div className={popupStyles.header}>
<h2 className={popupStyles.headerTitle}>
<Message {...messages.siteLanguage} />
</h2>
<span className={classNames(icons.close, popupStyles.close)} onClick={onClose} />
</div>
<div className={styles.languageSwitcherBody}>
<div className={styles.searchBox}>
<input
className={classNames(
formStyles.lightTextField,
formStyles.greenTextField
)}
placeholder={
<Message {...messages.startTyping}>
{(placeholder) => (
{placeholder}
)}
</Message>
}
onChange={this.onFilterUpdate()}
onKeyPress={this.onFilterKeyPress()}
/>
<span className={styles.searchIcon} />
</div>
<div className={styles.languagesList}>
{Object.keys(items).map((locale) => (
<li className={classNames(styles.languageItem, {
[styles.activeLanguageItem]: locale === userLang
})} onClick={this.onChangeLang(locale)} key={locale}
>
{this.renderLanguageItem(locale, items[locale])}
</li>
))}
</div>
<div className={styles.improveTranslates}>
<div className={styles.improveTranslatesIcon} />
<div className={styles.improveTranslatesContent}>
<div className={styles.improveTranslatesTitle}>
<Message {...messages.improveTranslates} />
</div>
<div className={styles.improveTranslatesText}>
<Message {...messages.improveTranslatesDescription} values={{
articleLink: (
<a href="#">
<Message {...messages.improveTranslatesArticleLink} />
</a>
)
}} />
</div>
</div>
</div>
</div>
</div>
</div>
);
}
renderLanguageItem(locale, localeData) {
const {name, progress, isReleased} = localeData;
let progressLabel;
if (progress !== 100) {
progressLabel = (
<Message {...messages.translationProgress} values={{
progress: `${progress}%`,
}} />
);
} else if (!isReleased) {
progressLabel = (
<Message {...messages.mayBeInaccurate} />
);
}
return (
<div className={styles.languageFlex}>
<div className={styles.languageIco} style={{
backgroundImage: `url('${requireLocaleFlag(locale)}')`
}} />
<div className={styles.languageCaptions}>
<div className={styles.languageName}>
{name}
</div>
<div className={styles.languageSubName}>
{localeData.englishName} {progressLabel ? '| ' : ''} {progressLabel}
</div>
</div>
<span className={styles.languageCircle} />
</div>
);
}
onChangeLang(lang) {
return (event) => {
event.preventDefault();
this.changeLang(lang);
};
}
changeLang(lang) {
this.props.changeLang(lang);
setTimeout(this.props.onClose, 300);
}
onFilterUpdate() {
return (event) => {
const value = event.target.value.trim().toLowerCase();
let items = LANGS;
if (value.length !== 0) {
items = Object.keys(items).reduce((prev, next) => {
if (items[next].englishName.toLowerCase().search(value) !== -1
|| items[next].name.toLowerCase().search(value) !== -1
) {
prev[next] = items[next];
}
return prev;
}, {});
}
this.setState({
items,
filter: value,
});
};
}
onFilterKeyPress() {
return (event) => {
if (event.key !== 'Enter' || this.state.filter === '') {
return;
}
const locales = Object.keys(this.state.items);
if (locales.length === 0) {
return;
}
this.changeLang(locales[0]);
};
};
}
import { connect } from 'react-redux';
import { changeLang } from 'components/user/actions';
export default connect((state) => ({
userLang: state.user.lang
}), {
changeLang
})(LanguageSwitcher);

View File

@ -0,0 +1,9 @@
{
"siteLanguage": "Site language",
"startTyping": "Start typing…",
"translationProgress": "{progress} translated",
"mayBeInaccurate": "May be inaccurate",
"improveTranslates": "Improve Ely.by translation",
"improveTranslatesDescription": "Ely.bys localization is a community effort. If you want to see Ely.by translated into another language, we'd love your help. To apply read {articleLink}.",
"improveTranslatesArticleLink": "this article"
}

View File

@ -0,0 +1,162 @@
@import '~components/ui/colors.scss';
@import '~components/ui/fonts.scss';
@import '~components/ui/popup/popup.scss';
.languageSwitcher {
composes: popupWrapper from 'components/ui/popup/popup.scss';
@include popupBounding(400px);
}
.languageSwitcherBody {
composes: body from 'components/ui/popup/popup.scss';
display: flex;
flex-direction: column;
max-height: 550px;
}
.searchBox {
position: relative;
margin-bottom: 20px;
}
.searchIcon {
composes: search from 'components/ui/icons.scss';
position: absolute;
top: 14px;
right: 12px;
font-size: 22px;
color: #EDEBE5;
pointer-events: none; // Иконка чисто декоративная, так что клик должен проходить сквозь неё
}
$languageListBorderStyle: 1px solid #eee;
.languagesList {
flex-grow: 1;
overflow-y: auto;
border-top: $languageListBorderStyle;
border-bottom: $languageListBorderStyle;
margin-bottom: 20px;
}
.languageItem {
padding: 10px;
border-top: $languageListBorderStyle;
font-family: $font-family-title;
transition: .25s;
cursor: pointer;
overflow: hidden;
&:first-child {
border-top: none;
}
&:hover {
background: $whiteButtonLight;
}
}
.languageFlex {
display: flex;
align-items: center;
}
.languageIco {
display: inline-block;
margin-right: 7px;
width: 40px;
height: 30px;
box-shadow: 0 0 1px rgba(#000, .2);
background: no-repeat;
background-size: cover;
}
.languageCaptions {
flex-grow: 1;
}
.languageName {
font-size: 15px;
margin-bottom: 2px;
}
.languageSubName {
font-size: 11px;
color: #CCC;
}
// Реализация радио кнопки. Когда у нас будет нормальный компонент радио кнопок, нужно будет перейти на него
.languageCircle {
composes: checkmark from 'components/ui/icons.scss';
position: relative;
box-sizing: border-box;
width: 22px;
height: 22px;
right: -32px;
font-size: 10px;
line-height: 18px;
text-align: center;
color: #fff;
border: 2px solid #DCD8CD;
border-radius: 50%;
transition: .5s cubic-bezier(0.19, 1, 0.22, 1);
&:before {
opacity: 0;
transition: opacity 0.3s;
}
.languageItem:hover & {
right: 0;
}
.activeLanguageItem & {
border-color: $green;
background: $green;
right: 0;
&:before {
opacity: 1;
}
}
}
.improveTranslates {
border: 1px solid #DEDEDE;
background: #F3F1ED;
padding: 10px;
display: flex;
flex-shrink: 0;
}
.improveTranslatesIcon {
composes: translate from 'components/ui/icons.scss';
color: lighter($blue);
font-size: 22px;
margin-right: 10px;
}
.improveTranslatesContent {
}
.improveTranslatesTitle {
font-family: $font-family-title;
font-size: 13px;
margin-bottom: 3px;
}
.improveTranslatesText {
font-size: 10px;
color: #9A9A9A;
line-height: 1.2;
}

View File

@ -1,11 +1,14 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl';
import { Link } from 'react-router-dom';
import Helmet from 'react-helmet';
import { requireLocaleFlag } from 'functions';
import LANGS from 'i18n/index.json';
import { userShape } from 'components/user/User';
import { LangMenu } from 'components/langMenu';
import ProfileField from './ProfileField';
import styles from './profile.scss';
@ -17,7 +20,8 @@ import RulesPage from 'pages/rules/RulesPage';
class Profile extends Component {
static displayName = 'Profile';
static propTypes = {
user: userShape
user: userShape,
createLanguageSwitcherPopup: PropTypes.func.isRequired,
};
render() {
@ -86,7 +90,14 @@ class Profile extends Component {
<ProfileField
label={<Message {...messages.siteLanguage} />}
value={<LangMenu showCurrentLang />}
value={
<span className={styles.language} onClick={this.onLanguageSwitcher.bind(this)}>
<span className={styles.languageIcon} style={{
backgroundImage: `url('${requireLocaleFlag(user.lang)}')`
}} />
{LANGS[user.lang].name}
</span>
}
/>
<ProfileField
@ -118,6 +129,10 @@ class Profile extends Component {
);
}
onLanguageSwitcher() {
this.props.createLanguageSwitcherPopup();
}
handleUUIDMouseOver() {
try {
const selection = window.getSelection();
@ -136,7 +151,11 @@ class Profile extends Component {
}
import { connect } from 'react-redux';
import LanguageSwitcher from 'components/languageSwitcher/LanguageSwitcher';
import { create as createPopup } from 'components/ui/popup/actions';
export default connect((state) => ({
user: state.user
}))(Profile);
user: state.user,
}), {
createLanguageSwitcherPopup: () => createPopup(LanguageSwitcher),
})(Profile);

View File

@ -68,6 +68,28 @@ $formColumnWidth: 416px;
flex-grow: 1;
}
.language {
color: #666;
border-bottom: 1px dotted #666;
text-decoration: none;
transition: .25s;
cursor: pointer;
}
.languageIcon {
$height: 13px;
position: relative;
top: 1px;
display: inline-block;
margin-right: 4px;
height: $height;
width: $height * 4 / 3;
box-shadow: 0 0 1px rgba(#000, .2);
background-size: cover;
}
.uuidValue {
composes: paramName;
composes: paramValue;

View File

@ -49,11 +49,6 @@
.textField {
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 50px;
width: 100%;

View File

@ -79,3 +79,24 @@ export function getJwtPayload(jwt: string): Object {
throw new Error('Can not decode jwt token');
}
}
const localeToCountryCode = {
en: 'gb',
be: 'by',
pt: 'br',
uk: 'ua',
vi: 'vn',
sl: 'si',
};
/**
* Возвращает для указанной локали её флаг с учётом всех нюансов загрузки флага
* и подбора соответствующего локали флага.
*
* @param {string} locale
* @return {*}
*/
export function requireLocaleFlag(locale: string) {
return require(`flag-icon-css/flags/4x3/${localeToCountryCode[locale] || locale}.svg`);
}

View File

@ -1,61 +1,73 @@
{
"be": {
"name": "Беларуская",
"englishName": "Belarusian",
"progress": 100,
"isReleased": true
},
"en": {
"name": "English",
"name": "English, UK",
"englishName": "English, UK",
"progress": 100,
"isReleased": true
},
"fr": {
"name": "Français",
"englishName": "French",
"progress": 89,
"isReleased": true
},
"id": {
"name": "Bahasa Indonesia",
"englishName": "Indonesian",
"progress": 100,
"isReleased": true
},
"lt": {
"name": "Lietuvių",
"englishName": "Lithuanian",
"progress": 96.9,
"isReleased": false
},
"pl": {
"name": "Polski",
"englishName": "Polish",
"progress": 85.5,
"isReleased": false
},
"pt": {
"name": "Português",
"name": "Português do Brasil",
"englishName": "Portuguese, Brazilian",
"progress": 100,
"isReleased": true
},
"ro": {
"name": "Română",
"englishName": "Romanian",
"progress": 85.5,
"isReleased": false
},
"ru": {
"name": "Русский",
"englishName": "Russian",
"progress": 100,
"isReleased": true
},
"sl": {
"name": "Slovenščina",
"englishName": "Slovenian",
"progress": 86,
"isReleased": false
},
"uk": {
"name": "Українська",
"englishName": "Ukrainian",
"progress": 89,
"isReleased": true
},
"vi": {
"name": "Tiếng Việt",
"englishName": "Vietnamese",
"progress": 96.9,
"isReleased": true
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="900" height="450" viewBox="0 0 1098 549">
<title>Flag of Belarus</title>
<rect fill="#C8313E" width="1098" height="549"/>
<rect y="366" fill="#4AA657" width="1098" height="183"/>
<rect fill="#FFF" width="122" height="549"/>
<g id="h">
<g id="q" fill="#C8313E" fill-rule="evenodd" transform="scale(5.304347826,9)">
<path d="M4,0h3v1h1v1h1v1h1v1h1v1h-1v1h-1v1h-1v1h-1v1h-1v1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h1v-1h1v-1h1v-1h1zM5,2h1v1h1v1h1v1h-1v1h-1v1h-1v-1h-1v-1h-1v-1h1v-1h1zM5,4h1v1h-1zM0,1h1v1h-1zM0,7h1v1h-1zM11,0h0.6v2h-.6zM11,7h.6v2h-.6zM2,9h1v1h1v1h1v1h-1v1h-1v1h-1v-1h-1v-1h-1v-1h1v-1h1zM2,11h1v1h-1zM8,9h1v1h1v1h1v1h-1v1h-1v1h-1v-1h-1v-1h-1v-1h1v-1h1zM8,11h1v1h-1zM0,15h1v1h-1zM11,14h.6v2h-.6z"/>
<path d="M0,18h1v-1h1v-1h1v-1h1v-1h1v-1h1v1h1v1h1v1h1v1h1v1h1v1h.6v4h-.6v1h-1v1h-1v1h-1v1h-1v1h-1v2.6h-2v-0.6h-1v-1h-1v-1h-1v-1h-1 v-3h1v1h1v1h1v1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h-1v-1h-1v-1h-3v1h2v1h-1v1h-1v1h-1v-1h-1v-1h-1v-1h-1zM0,22h1v1h-1zM11,25h.6v1h-.6zM9,27h1v1h1v1h.6v1.6h-.6v-.6h-1v-1h-1zM7,30h1v.6h-1z"/>
</g>
<use xlink:href="#q" transform="translate(122,0) scale(-1,1)"/>
</g>
<use xlink:href="#h" transform="translate(0,549) scale(1,-1)"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 30" width="1200" height="600">
<clipPath id="t">
<path d="M30,15 h30 v15 z v15 h-30 z h-30 v-15 z v-15 h30 z"/>
</clipPath>
<path d="M0,0 v30 h60 v-30 z" fill="#00247d"/>
<path d="M0,0 L60,30 M60,0 L0,30" stroke="#fff" stroke-width="6"/>
<path d="M0,0 L60,30 M60,0 L0,30" clip-path="url(#t)" stroke="#cf142b" stroke-width="4"/>
<path d="M30,0 v30 M0,15 h60" stroke="#fff" stroke-width="10"/>
<path d="M30,0 v30 M0,15 h60" stroke="#cf142b" stroke-width="6"/>
</svg>

Before

Width:  |  Height:  |  Size: 522 B

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 12 6">
<rect fill="#002395" width="4" height="6" x="0" />
<rect fill="#FFFFFF" width="4" height="6" x="4" />
<rect fill="#ED2939" width="4" height="6" x="8" />
</svg>

Before

Width:  |  Height:  |  Size: 297 B

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 4 2">
<rect fill="#FFF" width="4" height="2"/>
<rect fill="#CE1126" width="4" height="1"/>
</svg>

Before

Width:  |  Height:  |  Size: 224 B

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 12 6">
<rect fill="#ffb300" width="12" height="2" y="0" />
<rect fill="#007308" width="12" height="2" y="2" />
<rect fill="#bf0000" width="12" height="2" y="4" />
</svg>

Before

Width:  |  Height:  |  Size: 300 B

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 4 2">
<rect fill="#fff" width="4" height="1" />
<rect fill="#dc143c" width="4" height="1" y="1"/>
</svg>

Before

Width:  |  Height:  |  Size: 231 B

View File

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1200" height="600" viewBox="-2100 -1470 4200 2940">
<defs>
<path id="D" d="M -31.5,0 h 33 a 30 30 0 0 0 30,-30 v -10 a 30 30 0 0 0 -30,-30 H -31.5 z M -18.5,-13 h 19 a 19 19 0 0 0 19,-19 v -6 a 19 19 0 0 0 -19,-19 H -18.5 z" fill-rule="evenodd"/>
<path id="E" d="M 0,0 h 63 v -13 H 12 v -18 h 40 v -12 h -40 v -14 H 60 v -13 H 0 z" transform="translate(-31.5)"/>
<path id="e" d="M -26.25,0 h 52.5 v -12 h -40.5 v -16 h 33 v -12 h -33 v -11 H 25 v -12 H -26.25 z"/>
<g id="G">
<clipPath id="gcut">
<path d="M -31.5,0 v -70 h 63 v 70 z M 0,-47 v 12 h 31.5 v -12 z"/>
</clipPath>
<use xlink:href="#O" clip-path="url(#gcut)"/>
<rect x="5" y="-35" width="26.5" height="10"/>
<rect x="21.5" y="-35" width="10" height="35"/>
</g>
<path id="M" d="M -31.5,0 h 12 v -48 l 14,48 h 11 l 14,-48 V 0 h 12 V -70 h -17.5 l -14,48 l -14,-48 H -31.5 z"/>
<path id="O" d="M 0,0 a 31.5 35 0 0 0 0,-70 a 31.5 35 0 0 0 0,70 M 0,-13 a 18.5 22 0 0 0 0,-44 a 18.5 22 0 0 0 0,44" fill-rule="evenodd"/>
<path id="P" d="M -31.5,0 h 13 v -26 h 28 a 22 22 0 0 0 0,-44 h -40 z M -18.5,-39 h 27 a 9 9 0 0 0 0,-18 h -27 z" fill-rule="evenodd"/>
<g id="R">
<use xlink:href="#P"/>
<path d="M 28,0 c 0,-10 0,-32 -15,-32 h -19 c 22,0 22,22 22,32"/>
</g>
<path id="S" d="M -15.75,-22 C -15.75,-15 -9,-11.5 1,-11.5 C 11,-11.5 15.74,-14.75 15.75,-19.25 C 15.75,-33.5 -31,-24.5 -30.75,-49.5 C -30.5,-71 -6,-70 3,-70 C 12,-70 29,-66 28.75,-48.75 L 13.5,-48.75 C 13.5,-56.25 6.5,-59 -1.5,-59 C -9.25,-59 -14.75,-57.75 -14.75,-50.5 C -15,-38.75 31.5,-46.5 31.5,-21.75 C 31.5,-3.5 13.5,0 0,0 C -11.5,0 -31.55,-4.5 -31.5,-22 z"/>
<g id="star" fill="#fff">
<g id="c">
<path id="t" d="M 0,-1 v 1 h .5" transform="rotate(18 0,-1)"/>
<use xlink:href="#t" transform="scale(-1,1)"/>
</g>
<use xlink:href="#c" transform="rotate(72)"/>
<use xlink:href="#c" transform="rotate(-72)"/>
<use xlink:href="#c" transform="rotate(144)"/>
<use xlink:href="#c" transform="rotate(-144)"/>
</g>
<use id="star1" xlink:href="#star" transform="scale(31.5)"/>
<use id="star2" xlink:href="#star" transform="scale(26.25)"/>
<use id="star3" xlink:href="#star" transform="scale(21)"/>
<use id="star4" xlink:href="#star" transform="scale(15)"/>
<use id="star5" xlink:href="#star" transform="scale(10.5)"/>
</defs>
<rect x="-100%" y="-50%" width="200%" height="100%" fill="#009b3a"/>
<path d="M -1743,0 0,1113 1743,0 0,-1113 z" fill="#fedf00"/>
<circle r="735" fill="#002776"/>
<clipPath id="band">
<circle r="735"/>
</clipPath>
<path d="M -2205,1470 a 1785 1785 0 0 1 3570,0 h -105 a 1680 1680 0 1 0 -3360,0 z" clip-path="url(#band)" fill="#fff"/>
<g fill="#009b3a" transform="translate(-420,1470)">
<use xlink:href="#O" y="-1697.5" transform="rotate(-7)"/>
<use xlink:href="#R" y="-1697.5" transform="rotate(-4)"/>
<use xlink:href="#D" y="-1697.5" transform="rotate(-1)"/>
<use xlink:href="#E" y="-1697.5" transform="rotate(2)"/>
<use xlink:href="#M" y="-1697.5" transform="rotate(5)"/>
<use xlink:href="#e" y="-1697.5" transform="rotate(9.75)"/>
<use xlink:href="#P" y="-1697.5" transform="rotate(14.5)"/>
<use xlink:href="#R" y="-1697.5" transform="rotate(17.5)"/>
<use xlink:href="#O" y="-1697.5" transform="rotate(20.5)"/>
<use xlink:href="#G" y="-1697.5" transform="rotate(23.5)"/>
<use xlink:href="#R" y="-1697.5" transform="rotate(26.5)"/>
<use xlink:href="#E" y="-1697.5" transform="rotate(29.5)"/>
<use xlink:href="#S" y="-1697.5" transform="rotate(32.5)"/>
<use xlink:href="#S" y="-1697.5" transform="rotate(35.5)"/>
<use xlink:href="#O" y="-1697.5" transform="rotate(38.5)"/>
</g>
<use id="αCMi" xlink:href="#star1" x="-600" y="-132"/>
<use id="αCMa" xlink:href="#star1" x="-535" y="177"/>
<use id="βCMa" xlink:href="#star2" x="-625" y="243"/>
<use id="γCMa" xlink:href="#star4" x="-463" y="132"/>
<use id="δCMa" xlink:href="#star2" x="-382" y="250"/>
<use id="εCMa" xlink:href="#star3" x="-404" y="323"/>
<use id="αVir" xlink:href="#star1" x="228" y="-228"/>
<use id="αSco" xlink:href="#star1" x="515" y="258"/>
<use id="βSco" xlink:href="#star3" x="617" y="265"/>
<use id="εSco" xlink:href="#star2" x="545" y="323"/>
<use id="θSco" xlink:href="#star2" x="368" y="477"/>
<use id="ιSco" xlink:href="#star3" x="367" y="551"/>
<use id="κSco" xlink:href="#star3" x="441" y="419"/>
<use id="λSco" xlink:href="#star2" x="500" y="382"/>
<use id="μSco" xlink:href="#star3" x="365" y="405"/>
<use id="αHya" xlink:href="#star2" x="-280" y="30"/>
<use id="γHya" xlink:href="#star3" x="200" y="-37"/>
<use id="αCru" xlink:href="#star1" y="330"/>
<use id="βCru" xlink:href="#star2" x="85" y="184"/>
<use id="γCru" xlink:href="#star2" y="118"/>
<use id="δCru" xlink:href="#star3" x="-74" y="184"/>
<use id="εCru" xlink:href="#star4" x="-37" y="235"/>
<use id="αTrA" xlink:href="#star2" x="220" y="495"/>
<use id="βTrA" xlink:href="#star3" x="283" y="430"/>
<use id="γTrA" xlink:href="#star3" x="162" y="412"/>
<use id="αCar" xlink:href="#star1" x="-295" y="390"/>
<use id="σOct" xlink:href="#star5" y="575"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 12 6">
<rect fill="#002B7F" width="4" height="6" x="0" />
<rect fill="#FCD116" width="4" height="6" x="4" />
<rect fill="#CE1126" width="4" height="6" x="8" />
</svg>

Before

Width:  |  Height:  |  Size: 297 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" width="1200" height="600"><rect fill="#fff" width="12" height="3"/><rect fill="#d52b1e" y="3" width="12" height="3"/><rect fill="#0039a6" y="2" width="12" height="2"/></svg>

Before

Width:  |  Height:  |  Size: 271 B

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 6">
<rect width="12" fill="#ed1c24" height="6"/>
<rect width="12" fill="#005da4" height="4"/>
<rect width="12" fill="#fff" height="2"/>
<g transform="translate(2.2238 1) scale(.12937)">
<svg width="12" viewBox="-120 -190.223125 240 309.188274" height="15.459"><!-- R0 = 15*sqrt(349) ~ 280.223125 Py= 15*sqrt(285)-90 ~ 163.229145242 -->
<path d="m110.26-19.478l9.74-143.75a280.22 280.22 0 0 0 -240 0l9.74 143.75a155.61 155.61 0 0 0 110.26 138.45 155.61 155.61 0 0 0 110.26 -138.45" fill="#005da4"/>
<!-- 30*sqrt(81/4+1) , 30*sqrt(19)-30 -->
<path d="m-90 0a138.29 138.29 0 0 0 90 100.77 138.29 138.29 0 0 0 90 -100.77l-45-60-18 24-27-54-27 54-18-24-45 60" fill="#fff"/>
<g id="wave" fill="#005da4" transform="scale(5) translate(0 5.1962)">
<path d="m-17.196-2.1962a6 6 0 0 0 8.1962 2.1962 6 6 0 0 1 6 0 6 6 0 0 0 6 0 6 6 0 0 1 6 0 6 6 0 0 0 8.1962 -2.1962v1.732a6 6 0 0 1 -8.1962 2.1962 6 6 0 0 0 -6 0 6 6 0 0 1 -6 0 6 6 0 0 0 -6 0 6 6 0 0 1 -8.1962 -2.1962z"/>
</g>
<use xlink:href="#wave" transform="translate(0 17.321)"/>
<g id="s" transform="translate(0,-120) scale(2.25)">
<path stroke-width=".2" d="m0-5l1 3.2679 3.3301-0.7679-2.3301 2.5 2.3301 2.5-3.3301-0.7679-1 3.2679-1-3.2679-3.3301 0.7679 2.3301-2.5-2.3301-2.5 3.3301 0.7679z" fill="#fd0"/>
</g>
<use xlink:href="#s" transform="translate(-33.75,-45)"/>
<use xlink:href="#s" transform="translate(33.75,-45)"/>
<path d="m-111.58-167.05l9.96 146.99a146.95 146.95 0 0 0 101.62 129.95 146.95 146.95 0 0 0 101.62 -129.95l9.96-146.99a280.22 280.22 0 0 0 8.42 3.82l-9.74 143.75a155.61 155.61 0 0 1 -110.26 138.45 155.61 155.61 0 0 1 -110.26 -138.45l-9.74-143.75a280.22 280.22 0 0 0 8.42 -3.82" fill="#ed1c24"/>
</svg>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600">
<rect width="1200" height="600" fill="#005BBB"/>
<rect width="1200" height="300" y="300" fill="#FFD500"/>
</svg>

Before

Width:  |  Height:  |  Size: 180 B

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1200" height="600" viewBox="-15 -10 30 20">
<rect fill="#DA251d" x="-20" y="-15" width="40" height="30"/>
<g id="g" transform="translate(0,-6)">
<polyline id="g1" fill="#FF0" points="0,0 0,6 4,6" transform="rotate(18)"/>
<use xlink:href="#g1" transform="scale(-1,1)"/>
</g>
<g id="g2" transform="rotate(72)">
<use xlink:href="#g" />
<use xlink:href="#g" transform="rotate(72)"/>
</g>
<use xlink:href="#g2" transform="scale(-1,1)"/>
</svg>

Before

Width:  |  Height:  |  Size: 568 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.2" baseProfile="tiny" id="&#x421;&#x43B;&#x43E;&#x439;_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="17px" height="19px" viewBox="0 0 17 19" xml:space="preserve">
<path fill="#FFFFFF" d="M6.909,3.659c-2.346,0-4.25,1.903-4.25,4.25c0,2.347,1.903,4.248,4.25,4.248c2.347,0,4.249-1.9,4.249-4.248
C11.157,5.562,9.254,3.659,6.909,3.659z M16.831,16.617l-1.214,1.215c-0.222,0.223-0.586,0.223-0.809,0l-2.429-2.428
c-0.224-0.223-0.224-0.588,0-0.813l0.067-0.064l-1.144-1.141c-0.029-0.029-0.044-0.066-0.066-0.098
c-1.185,0.953-2.689,1.527-4.329,1.527C3.093,14.816,0,11.725,0,7.909S3.093,1,6.909,1s6.909,3.092,6.909,6.909
c0,1.641-0.573,3.144-1.528,4.328c0.031,0.021,0.068,0.039,0.1,0.068l1.14,1.141l0.066-0.066c0.223-0.223,0.587-0.223,0.811,0
l2.428,2.43C17.056,16.029,17.056,16.395,16.831,16.617z"/>
</svg>

After

Width:  |  Height:  |  Size: 875 B

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<title>translate</title>
<path d="M15.891 17.016h3.234l-1.641-4.359zM18.516 9.984l4.5 12h-2.016l-1.125-3h-4.734l-1.125 3h-2.016l4.5-12h2.016zM12.891 15.047l-0.797 2.063-3.094-3.094-5.016 4.969-1.406-1.406 5.109-5.016c-1.266-1.406-2.25-2.906-3-4.547h2.016c0.609 1.172 1.359 2.297 2.297 3.328 1.453-1.594 2.531-3.422 3.188-5.344h-11.203v-2.016h7.031v-1.969h1.969v1.969h7.031v2.016h-2.953c-0.75 2.344-1.969 4.594-3.703 6.516l-0.047 0.047z"></path>
</svg>

After

Width:  |  Height:  |  Size: 583 B