Commit f6c8f20b authored by Eugen Rochko's avatar Eugen Rochko

Add covenant page

parent 5583f139
import React from 'react';
import {
BrowserRouter as Router,
Route
} from 'react-router-dom';
import PropTypes from 'prop-types';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import classNames from 'classnames';
import Home from './Home';
......@@ -11,6 +9,7 @@ import Imprint from './Imprint';
import BrowseApps from './BrowseApps';
import ScrollToTop from './ScrollToTop';
import Title from './Title';
import Covenant from './Covenant';
import { addLocaleData, IntlProvider } from 'react-intl';
import en from 'react-intl/locale-data/en';
......@@ -31,7 +30,25 @@ import nl from 'react-intl/locale-data/nl';
import cy from 'react-intl/locale-data/cy';
import sq from 'react-intl/locale-data/sq';
addLocaleData([...en, ...pl, ...cs, ...fr, ...es, ...ja, ...ko, ...de, ...pt, ...zh, ...ru, ...it, ...ar, ...tr, ...nl, ...cy, ...sq]);
addLocaleData([
...en,
...pl,
...cs,
...fr,
...es,
...ja,
...ko,
...de,
...pt,
...zh,
...ru,
...it,
...ar,
...tr,
...nl,
...cy,
...sq,
]);
const messages = require.context('./locales/', false, /\.json$/);
......@@ -46,6 +63,7 @@ const App = ({ usersLocale }) => (
<Route path='/sponsors' component={Sponsorship} />
<Route path='/imprint' component={Imprint} />
<Route path='/apps' component={BrowseApps} />
<Route path='/covenant' component={Covenant} />
<Title />
</div>
</ScrollToTop>
......@@ -53,4 +71,8 @@ const App = ({ usersLocale }) => (
</IntlProvider>
);
App.propTypes = {
usersLocale: PropTypes.string.isRequired,
};
export default App;
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
const Counter = ({ number, id, defaultMessage, intl }) => {
......@@ -12,4 +13,11 @@ const Counter = ({ number, id, defaultMessage, intl }) => {
);
};
Counter.propTypes = {
number: PropTypes.number.isRequired,
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
};
export default injectIntl(Counter);
import React from 'react';
import Navigation from './Navigation';
import Legal from './Legal';
const Covenant = () => (
<div className='browse-apps covenant'>
<Navigation />
<div className='container'>
<h1>Mastodon Server Covenant</h1>
<p className='lead'>All Mastodon servers we link to from our server picker commit to the following:</p>
<div className='covenant__terms'>
<p>1. <strong>Active moderation against racism, sexism, homophobia and transphobia</strong></p>
<p>Users must have the confidence that they are joining a safe space, free from white supremacy, anti-semitism and transphobia of other platforms.</p>
<hr />
<p>2. <strong>Daily backups</strong></p>
<p>It is important for users to have the confidence that a trip over the power cable or a rogue bit flip will not erase all of their data. Having a backup strategy is a basic necessity of providing a public service.</p>
<hr />
<p>3. <strong>At least one other person with emergency access to the server infrastructure</strong></p>
<p>Various circumstances can prevent the original owner of the Mastodon server from answering technical emergencies. For this reason, more than one person must have that capability.</p>
<hr />
<p>4. <strong>Commitment to give users at least 3 months of advance warning in case of shutting down</strong></p>
<p>Sometimes services shut down, it is the cycle of life. But users must have the confidence that their account will not disappear overnight, so that they have time to export their data and find another server.</p>
</div>
<p>If you are a server owner, and your server passes these requirements, you can send an e-mail to hello@joinmastodon.org with the subject "Server submission" to be listed on this website. Only servers that accept registrations (including approval-based registrations) are shown.</p>
<Legal />
</div>
</div>
);
export default Covenant;
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export default class Dropdown extends PureComponent {
static propTypes = {
label: PropTypes.node.isRequired,
value: PropTypes.string,
onChange: PropTypes.func,
options: PropTypes.arrayOf(PropTypes.shape({
value: PropTypes.string.isRequired,
label: PropTypes.node.isRequired,
})).isRequired,
asLinks: PropTypes.bool,
};
state = {
opened: false
};
......
......@@ -94,7 +94,10 @@ export default class Home extends PureComponent {
onCloseModal = () => {
this.setState({ open: false });
this.player.pauseVideo();
if (this.player) {
this.player.pauseVideo();
}
}
render () {
......
import React from 'react';
import PropTypes from 'prop-types';
import Dropdown from './Dropdown';
import flagEn from 'twemoji/2/svg/1f1ec-1f1e7.svg';
......@@ -41,7 +42,7 @@ const options = [
{ value: 'zh-TW', label: <span><img src={flagTw} className='emoji' alt='' /> 繁體中文(臺灣)</span> },
];
export default ({ value, onChange }) => (
const LanguageSelect = ({ value, onChange }) => (
<Dropdown
options={options}
value={value}
......@@ -49,3 +50,10 @@ export default ({ value, onChange }) => (
onChange={onChange}
/>
);
LanguageSelect.propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
};
export default LanguageSelect;
import React from 'react';
import PropTypes from 'prop-types';
import WizardRow from './WizardRow';
import WizardCard from './WizardCard';
import { FormattedHTMLMessage as FormattedMessage, injectIntl, defineMessages } from 'react-intl';
......@@ -24,6 +25,7 @@ const messages = defineMessages({
language: { id: 'wizard.filter.language', defaultMessage: 'Language: ' },
general: { id: 'wizard.filter.general', defaultMessage: 'General' },
all_languages: { id: 'wizard.filter.all_languages', defaultMessage: 'All languages' },
regional: { id: 'wizard.filter.regional', defaultMessage: 'Regional' },
});
const caretIcon = (
......@@ -34,6 +36,13 @@ const caretIcon = (
class Wizard extends React.PureComponent {
static propTypes = {
category: PropTypes.string.isRequired,
language: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
instances: PropTypes.arrayOf(PropTypes.object).isRequired,
};
componentDidMount () {
this.props.onMount();
}
......@@ -96,20 +105,21 @@ class Wizard extends React.PureComponent {
name="category"
options={[
{ value: 'general', text: intl.formatMessage(messages.general) },
{ value: 'regional', text: intl.formatMessage(messages.regional) },
{ value: 'art', text: intl.formatMessage(messages.art) },
{ value: 'music', text: intl.formatMessage(messages.music) },
{ value: 'books', text: intl.formatMessage(messages.books) },
{ value: 'journalism', text: intl.formatMessage(messages.journalism) },
{ value: 'activism', text: intl.formatMessage(messages.activism) },
{ value: 'lgbt', text: intl.formatMessage(messages.lgbt) },
{ value: 'poc', text: intl.formatMessage(messages.poc) },
{ value: 'sports', text: intl.formatMessage(messages.sports) },
//{ value: 'music', text: intl.formatMessage(messages.music) },
//{ value: 'books', text: intl.formatMessage(messages.books) },
//{ value: 'journalism', text: intl.formatMessage(messages.journalism) },
//{ value: 'activism', text: intl.formatMessage(messages.activism) },
//{ value: 'lgbt', text: intl.formatMessage(messages.lgbt) },
//{ value: 'poc', text: intl.formatMessage(messages.poc) },
//{ value: 'sports', text: intl.formatMessage(messages.sports) },
{ value: 'games', text: intl.formatMessage(messages.gaming) },
{ value: 'tech', text: intl.formatMessage(messages.tech) },
{ value: 'academia', text: intl.formatMessage(messages.academia) },
//{ value: 'academia', text: intl.formatMessage(messages.academia) },
{ value: 'adult', text: intl.formatMessage(messages.adult) },
{ value: 'humor', text: intl.formatMessage(messages.humor) },
{ value: 'furry', text: intl.formatMessage(messages.furry) },
//{ value: 'humor', text: intl.formatMessage(messages.humor) },
//{ value: 'furry', text: intl.formatMessage(messages.furry) },
]}
caretIcon={caretIcon}
selectedValue={category}
......
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
import Counter from './Counter';
......@@ -24,4 +25,15 @@ const WizardCard = ({ instance, intl }) => (
</div>
);
WizardCard.propTypes = {
instance: PropTypes.shape({
domain: PropTypes.string.isRequired,
total_users: PropTypes.number.isRequired,
description: PropTypes.string.isRequired,
proxied_thumbnail: PropTypes.string.isRequired,
}).isRequired,
intl: PropTypes.object.isRequired,
};
export default injectIntl(WizardCard);
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Counter from './Counter';
......@@ -53,4 +54,17 @@ const WizardRow = ({ instance, intl }) => {
);
};
WizardRow.propTypes = {
instance: PropTypes.shape({
domain: PropTypes.string.isRequired,
total_users: PropTypes.number.isRequired,
description: PropTypes.string.isRequired,
proxied_thumbnail: PropTypes.string.isRequired,
version: PropTypes.string.isRequired,
category: PropTypes.string.isRequired,
}).isRequired,
intl: PropTypes.object.isRequired,
};
export default injectIntl(WizardRow);
......@@ -8,10 +8,11 @@ export const FILTER_CATEGORY_CHANGE = 'FILTER_CATEGORY_CHANGE';
export function fetchInstances() {
return (dispatch, getState) => {
const { category, language } = getState().filter;
const params = {};
const params = {
category: category.split('-')[0],
};
if (category !== '') {
params.category = category.split('-')[0];
}
if (language !== '') {
params.language = language;
......
......@@ -16,3 +16,7 @@ render(
</Provider>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept();
}
//@import url('https://fonts.googleapis.com/css?family=Quando|Judson|Montserrat:400,600|Roboto:400,500,700');
//@import url('https://unpkg.com/ionicons@4.2.0/dist/css/ionicons.min.css');
@import 'fonts/fonts.css';
@import 'fonts/ionicons.min.css';
......@@ -15,3 +12,4 @@
@import 'scss/LanguageSelect.scss';
@import 'scss/Features.scss';
@import 'scss/BrowseApps.scss';
@import 'scss/Covenant.scss';
......@@ -5,12 +5,31 @@ import {
FILTER_LANGUAGE_CHANGE,
} from './actions';
const supportedLocales = ['en', 'fr', 'pl', 'cs', 'es', 'ja', 'ko', 'de','pt-BR', 'ar', 'tr', 'sq', 'nl-NL', 'cy', 'zh', 'zh-TW'];
const supportedLocales = [
'ar',
'cs',
'cy',
'de',
'en',
'es',
'fr',
'ja',
'ko',
'nl-NL',
'pl',
'pt-BR',
'sq',
'tr',
'zh',
'zh-TW',
];
const initialLocale = () => {
const lang = navigator.language.split('-')[0];
if (supportedLocales.indexOf(lang) !== -1) {
if (supportedLocales.indexOf(navigator.language) !== -1) {
return navigator.language;
} else if (supportedLocales.indexOf(lang) !== -1) {
return lang;
} else {
return 'en';
......@@ -24,15 +43,15 @@ const initialState = {
filter: {
category: '',
language: initialLocale(),
language: '',
},
};
const DUNBAR = Math.log(300);
const DUNBAR = Math.log(800);
const sortByDunbarsNumber = instances => instances.sort((a, b) => {
const aa = Math.abs(DUNBAR - Math.log(a.active_users));
const bb = Math.abs(DUNBAR - Math.log(b.active_users));
const aa = Math.abs(DUNBAR - Math.log(a.last_week_users));
const bb = Math.abs(DUNBAR - Math.log(b.last_week_users));
return aa > bb ? 1 : (aa < bb ? -1 : 0);
});
......
......@@ -22,7 +22,7 @@
clear: both;
height: 0;
border: 0;
border: 1px solid lighten($darkest, 8%);
border-top: 1px solid lighten($darkest, 8%);
margin: 20px 0;
}
......
@import './variables.scss';
.covenant__terms {
margin: 60px 0;
p {
font-size: 18px;
line-height: 30px;
margin-bottom: 20px;
}
p strong {
font-weight: 700;
color: $lightest;
}
}
......@@ -134,23 +134,6 @@
margin: 15px auto;
max-width: 800px;
.wizard-header {
display: flex;
border-bottom: 1px solid $darkest;
.wizard-column {
font-family: 'Montserrat', sans-serif;
font-weight: 500;
font-size: 14px;
color: $lighter;
border-right: 1px solid $darkest;
&:last-child {
border-right: 0;
}
}
}
&__row {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
......@@ -418,22 +401,14 @@
}
.wizard {
.wizard-row__thumbnail,
.wizard-row__meta {
.wizard-row__thumbnail {
display: none;
}
}
.wizard-row__details {
width: 100%;
}
.indicator-text {
margin-left: 4px;
.indicator {
display: none;
}
}
.wizard-row__name,
.wizard-row__description {
padding-left: 10px;
}
}
......@@ -462,14 +437,18 @@
margin-bottom: 0;
}
.wizard__row {
display: block;
.wizard-card {
margin-bottom: 20px;
}
}
.rrs,
.wizard-controls__label {
margin-bottom: 10px;
}
.wizard {
max-height: 50vh;
}
}
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment