Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1a4aafabf | |||
| a011c5addf | |||
| d7d013609c | |||
| e36d764aaa | |||
| c6eb0b1927 | |||
| 4edb2f2b2c | |||
| 110c8fb8cc | |||
| 6d0b964e2b | |||
| 60792ec753 | |||
| e5869dc945 | |||
| f61625f4bd | |||
| 02106153ec | |||
| 8eba3f59f8 |
@@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*.scss]
|
||||
indent_size = 2
|
||||
|
||||
[login.scss]
|
||||
indent_size = 4
|
||||
+9
-2
@@ -8,7 +8,14 @@ To work on the code decently, you should have Node and Yarn installed. To avoid
|
||||
|
||||
## Testing Locally
|
||||
|
||||
You can fairly easily test builds of Masto-FE locally by using Docker and the GoToSocial testrig.
|
||||
If you want to run Masto-FE in dev mode:
|
||||
|
||||
- install the project: `yarn install`
|
||||
- start the dev server: `yarn dev`
|
||||
|
||||
You should now be able to connect on http://localhost:3035. Changes will automatically compile.
|
||||
|
||||
You can also fairly easily test builds of Masto-FE locally by using Docker and the GoToSocial testrig.
|
||||
|
||||
### Build GoToSocial + launch the GtS testrig
|
||||
|
||||
@@ -37,7 +44,7 @@ Leave the testrig running.
|
||||
|
||||
### Build Masto-FE + run it locally
|
||||
|
||||
Now in a *separate* terminal window, get back to the Masto-FE directory, and do a Docker build (this might take a bit of time):
|
||||
Now in a _separate_ terminal window, get back to the Masto-FE directory, and do a Docker build (this might take a bit of time):
|
||||
|
||||
```bash
|
||||
docker build -t superseriousbusiness/masto-fe-standalone:latest .
|
||||
|
||||
@@ -40,7 +40,7 @@ Serve all the stuff in `public` behind an nginx or whatever you want! See the in
|
||||
|
||||
### Docker (definitely the easiest way)
|
||||
|
||||
The Docker container is based on Nginx, and serves over port 3000. Just deploy it and listen on that port, preferably with a reverse proxy at some point (Traefik? Caddy? Another Nginx perhaps?) handling https.
|
||||
The Docker container is based on Nginx, and serves over port 80. Just deploy it and listen on that port, preferably with a reverse proxy at some point (Traefik? Caddy? Another Nginx perhaps?) handling https.
|
||||
|
||||
## Testing locally, linting, etc
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expandSpoilers, disableSwiping } from 'flavours/glitch/initial_state';
|
||||
import { disableSwiping } from 'flavours/glitch/initial_state';
|
||||
|
||||
import { openModal } from './modal';
|
||||
|
||||
@@ -7,18 +7,9 @@ export const LOCAL_SETTING_DELETE = 'LOCAL_SETTING_DELETE';
|
||||
|
||||
export function checkDeprecatedLocalSettings() {
|
||||
return (dispatch, getState) => {
|
||||
const local_auto_unfold = getState().getIn(['local_settings', 'content_warnings', 'auto_unfold']);
|
||||
const local_swipe_to_change_columns = getState().getIn(['local_settings', 'swipe_to_change_columns']);
|
||||
let changed_settings = [];
|
||||
|
||||
if (local_auto_unfold !== null && local_auto_unfold !== undefined) {
|
||||
if (local_auto_unfold === expandSpoilers) {
|
||||
dispatch(deleteLocalSetting(['content_warnings', 'auto_unfold']));
|
||||
} else {
|
||||
changed_settings.push('user_setting_expand_spoilers');
|
||||
}
|
||||
}
|
||||
|
||||
if (local_swipe_to_change_columns !== null && local_swipe_to_change_columns !== undefined) {
|
||||
if (local_swipe_to_change_columns === !disableSwiping) {
|
||||
dispatch(deleteLocalSetting(['swipe_to_change_columns']));
|
||||
|
||||
@@ -21,11 +21,18 @@ export const fetchServer = () => (dispatch, getState) => {
|
||||
|
||||
dispatch(fetchServerRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v2/instance').then(({ data }) => {
|
||||
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
try {
|
||||
api(getState)
|
||||
.get('/api/v2/instance').then({ data })
|
||||
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
} catch (e) {
|
||||
api(getState)
|
||||
.get('/api/v1/instance').then(({ data }) => {
|
||||
if (data.contact_account) dispatch(importFetchedAccount(data.contact_account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
}).catch(err => dispatch(fetchServerFail(err)));
|
||||
}
|
||||
};
|
||||
|
||||
const fetchServerRequest = () => ({
|
||||
|
||||
@@ -8,9 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
|
||||
// Our imports
|
||||
import { expandSpoilers } from 'flavours/glitch/initial_state';
|
||||
|
||||
import DeprecatedLocalSettingsPageItem from './deprecated_item';
|
||||
import LocalSettingsPageItem from './item';
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
@@ -308,35 +305,21 @@ class LocalSettingsPage extends PureComponent {
|
||||
</LocalSettingsPageItem>
|
||||
<section>
|
||||
<h2><FormattedMessage id='settings.content_warnings_unfold_opts' defaultMessage='Auto-unfolding options' /></h2>
|
||||
<DeprecatedLocalSettingsPageItem
|
||||
<LocalSettingsPageItem
|
||||
settings={settings}
|
||||
item={['content_warnings', 'auto_unfold']}
|
||||
onChange={onChange}
|
||||
id='mastodon-settings--content_warnings-auto_unfold'
|
||||
value={expandSpoilers}
|
||||
>
|
||||
<FormattedMessage id='settings.enable_content_warnings_auto_unfold' defaultMessage='Automatically unfold content-warnings' />
|
||||
<span className='hint'>
|
||||
<FormattedMessage
|
||||
id='settings.deprecated_setting'
|
||||
defaultMessage="This setting is now controlled from Mastodon's {settings_page_link}"
|
||||
values={{
|
||||
settings_page_link: (
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='settings.shared_settings_link'
|
||||
defaultMessage='user preferences'
|
||||
/>
|
||||
</span>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</DeprecatedLocalSettingsPageItem>
|
||||
</LocalSettingsPageItem>
|
||||
<LocalSettingsPageItem
|
||||
settings={settings}
|
||||
item={['content_warnings', 'filter']}
|
||||
id='mastodon-settings--content_warnings-auto_unfold'
|
||||
onChange={onChange}
|
||||
dependsOn={[['content_warnings', 'auto_unfold']]}
|
||||
placeholder={intl.formatMessage(messages.regexp)}
|
||||
disabled={!expandSpoilers}
|
||||
>
|
||||
<FormattedMessage id='settings.content_warnings_filter' defaultMessage='Content warnings to not automatically unfold:' />
|
||||
</LocalSettingsPageItem>
|
||||
|
||||
@@ -55,6 +55,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||
singleColumn: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
openSettings: PropTypes.func,
|
||||
onLogout: PropTypes.func,
|
||||
};
|
||||
|
||||
// Corresponds to (max-width: $no-gap-breakpoint + 285px - 1px) in SCSS
|
||||
@@ -139,7 +140,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { columns, children, singleColumn, openSettings } = this.props;
|
||||
const { columns, children, singleColumn, openSettings, onLogout } = this.props;
|
||||
const { renderComposePanel } = this.state;
|
||||
|
||||
if (singleColumn) {
|
||||
@@ -158,7 +159,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||
|
||||
<div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'>
|
||||
<div className='columns-area__panels__pane__inner'>
|
||||
<NavigationPanel onOpenSettings={openSettings} />
|
||||
<NavigationPanel onOpenSettings={openSettings} onLogout={onLogout} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,6 @@ import illustration from 'flavours/glitch/images/logo_warn_glitch.svg';
|
||||
|
||||
const messages = defineMessages({
|
||||
discardChanges: { id: 'confirmations.deprecated_settings.confirm', defaultMessage: 'Use Mastodon preferences' },
|
||||
user_setting_expand_spoilers: { id: 'settings.enable_content_warnings_auto_unfold', defaultMessage: 'Automatically unfold content-warnings' },
|
||||
user_setting_disable_swiping: { id: 'settings.swipe_to_change_columns', defaultMessage: 'Allow swiping to change columns (Mobile only)' },
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import { Tesseract as fetchTesseract } from 'flavours/glitch/features/ui/util/as
|
||||
import Video, { getPointerPosition } from 'flavours/glitch/features/video';
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
import { assetHost } from 'flavours/glitch/utils/config';
|
||||
import { maxMediaDescChars } from 'flavours/glitch/initial_state';
|
||||
|
||||
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
|
||||
|
||||
@@ -367,10 +368,10 @@ class FocalPointModal extends ImmutablePureComponent {
|
||||
|
||||
<div className='setting-text__toolbar'>
|
||||
<button disabled={detecting || media.get('type') !== 'image' || is_changing_upload} className='link-button' onClick={this.handleTextDetection}><FormattedMessage id='upload_modal.detect_text' defaultMessage='Detect text from picture' /></button>
|
||||
<CharacterCounter max={1500} text={detecting ? '' : description} />
|
||||
<CharacterCounter max={maxMediaDescChars} text={detecting ? '' : description} />
|
||||
</div>
|
||||
|
||||
<Button disabled={!dirty || detecting || isUploadingThumbnail || length(description) > 1500 || is_changing_upload} text={intl.formatMessage(is_changing_upload ? messages.applying : messages.apply)} onClick={this.handleSubmit} />
|
||||
<Button disabled={!dirty || detecting || isUploadingThumbnail || length(description) > maxMediaDescChars || is_changing_upload} text={intl.formatMessage(is_changing_upload ? messages.applying : messages.apply)} onClick={this.handleSubmit} />
|
||||
</div>
|
||||
|
||||
<div className='focal-point-modal__content'>
|
||||
|
||||
@@ -30,6 +30,7 @@ const messages = defineMessages({
|
||||
advancedInterface: { id: 'navigation_bar.advanced_interface', defaultMessage: 'Open in advanced web interface' },
|
||||
openedInClassicInterface: { id: 'navigation_bar.opened_in_classic_interface', defaultMessage: 'Posts, accounts, and other specific pages are opened by default in the classic web interface.' },
|
||||
app_settings: { id: 'navigation_bar.app_settings', defaultMessage: 'App settings' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Log out' },
|
||||
});
|
||||
|
||||
class NavigationPanel extends Component {
|
||||
@@ -42,6 +43,7 @@ class NavigationPanel extends Component {
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
onOpenSettings: PropTypes.func,
|
||||
onLogout: PropTypes.func,
|
||||
};
|
||||
|
||||
isFirehoseActive = (match, location) => {
|
||||
@@ -49,7 +51,7 @@ class NavigationPanel extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { intl, onOpenSettings } = this.props;
|
||||
const { intl, onOpenSettings, onLogout } = this.props;
|
||||
const { signedIn, disabledAccountId } = this.context.identity;
|
||||
|
||||
return (
|
||||
@@ -104,6 +106,7 @@ class NavigationPanel extends Component {
|
||||
<hr />
|
||||
|
||||
<ColumnLink transparent onClick={onOpenSettings} icon='cogs' text={intl.formatMessage(messages.app_settings)} />
|
||||
<ColumnLink transparent onClick={onLogout} icon='sign-out' text={intl.formatMessage(messages.logout)} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -112,6 +115,7 @@ class NavigationPanel extends Component {
|
||||
<ColumnLink transparent to='/about' icon='ellipsis-h' text={intl.formatMessage(messages.about)} />
|
||||
</div>
|
||||
|
||||
|
||||
<NavigationPortal />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { logOut } from 'flavours/glitch/utils/log_out';
|
||||
|
||||
import ColumnsArea from '../components/columns_area';
|
||||
|
||||
const messages = defineMessages({
|
||||
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
|
||||
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
openSettings (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -17,6 +25,17 @@ const mapDispatchToProps = dispatch => ({
|
||||
modalProps: {},
|
||||
}));
|
||||
},
|
||||
onLogout () {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.logoutMessage),
|
||||
confirm: intl.formatMessage(messages.logoutConfirm),
|
||||
closeWhenConfirm: false,
|
||||
onConfirm: () => logOut(),
|
||||
},
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(ColumnsArea);
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(ColumnsArea));
|
||||
|
||||
@@ -149,7 +149,9 @@ class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) {
|
||||
this.node.handleChildrenContentChange();
|
||||
if (this.node && this.node.handleChildrenContentChange === 'function') {
|
||||
this.node.handleChildrenContentChange();
|
||||
}
|
||||
}
|
||||
|
||||
if (prevProps.singleColumn !== this.props.singleColumn) {
|
||||
|
||||
@@ -104,6 +104,7 @@ export const hasMultiColumnPath = initialPath === '/'
|
||||
* @property {object} local_settings
|
||||
* @property {number} max_toot_chars
|
||||
* @property {number} max_media_attachments
|
||||
* @property {number} max_media_desc_chars
|
||||
* @property {number} poll_limits
|
||||
*/
|
||||
|
||||
@@ -167,6 +168,7 @@ export const sso_redirect = getMeta('sso_redirect');
|
||||
// Glitch-soc-specific settings
|
||||
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
|
||||
export const maxMediaAttachments = (initialState && initialState.max_media_attachments) || 4;
|
||||
export const maxMediaDescChars = (initialState && initialState.max_media_desc_chars) || 1500;
|
||||
export const favouriteModal = getMeta('favourite_modal');
|
||||
export const pollLimits = (initialState && initialState.poll_limits);
|
||||
export const defaultContentType = getMeta('default_content_type');
|
||||
|
||||
@@ -23,6 +23,7 @@ const initialState = ImmutableMap({
|
||||
tag_misleading_links: true,
|
||||
rewrite_mentions: 'no',
|
||||
content_warnings : ImmutableMap({
|
||||
auto_unfold : false,
|
||||
filter : null,
|
||||
media_outside: true,
|
||||
shared_state : true,
|
||||
|
||||
@@ -5,88 +5,76 @@
|
||||
@import 'basics';
|
||||
|
||||
body {
|
||||
height: 100vh;
|
||||
|
||||
a {
|
||||
color: #89caff;
|
||||
}
|
||||
font-family: ui-rounded, 'mastodon-font-sans-serif', sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
max-width: 30rem;
|
||||
--login-row-gap: 10px;
|
||||
|
||||
display: grid;
|
||||
row-gap: var(--login-row-gap);
|
||||
margin: 50px auto;
|
||||
padding: 1rem;
|
||||
margin: auto;
|
||||
max-width: 30rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mascot {
|
||||
height: 10rem;
|
||||
img {
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
row-gap: var(--login-row-gap);
|
||||
}
|
||||
|
||||
.login {
|
||||
display: flex;
|
||||
position: relative;
|
||||
column-gap: 10px;
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
line-height: 33px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.instance {
|
||||
background: #282c37;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
color: #9baec8;
|
||||
display: block;
|
||||
label {
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
line-height: 18px;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
padding: 15px;
|
||||
padding-inline-end: 30px;
|
||||
width: 100%;
|
||||
color: $primary-text-color;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
font-weight: 500;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
column-gap: .5rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #66befe;
|
||||
border: 0 none;
|
||||
form {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
grid-template-columns: 1fr min-content;
|
||||
}
|
||||
|
||||
:focus-visible,
|
||||
button:focus-visible {
|
||||
outline: 2px solid #66befe;
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 7px 10px;
|
||||
border: 1px solid lighten(#66befe, 7%);
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
color: #2a2b2f;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0;
|
||||
line-height: 22px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: 500;
|
||||
padding: 7px 10px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
flex-basis: auto;
|
||||
background-color: #66befe;
|
||||
|
||||
&:hover {
|
||||
background-color: #89caff;
|
||||
@@ -98,21 +86,35 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: #444b5d;
|
||||
input[type='text'] {
|
||||
display: block;
|
||||
marhing: 0;
|
||||
padding: 15px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
border: 1px solid lighten(#282c37, 7%);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: .75rem;
|
||||
box-sizing: border-box;
|
||||
box-shadow: none;
|
||||
color: #9baec8;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: 18px;
|
||||
background: #282c37;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 20px 15px 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid lighten(#39404f, 7%);
|
||||
color: #fff;
|
||||
background-color: #39404f;
|
||||
}
|
||||
|
||||
.link-footer {
|
||||
padding: 10px;
|
||||
padding-inline: 10px;
|
||||
color: #97a8b4;
|
||||
font-size: 0.875rem;
|
||||
|
||||
p, a {
|
||||
color: #97A8B4;
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { expandSpoilers } from 'flavours/glitch/initial_state';
|
||||
|
||||
function _autoUnfoldCW(spoiler_text, skip_unfold_regex) {
|
||||
if (!expandSpoilers)
|
||||
function _autoUnfoldCW(spoiler_text, settings) {
|
||||
if (!settings.getIn(['content_warnings', 'auto_unfold']))
|
||||
return false;
|
||||
|
||||
const skip_unfold_regex = settings.getIn(['content_warnings', 'filter']);
|
||||
|
||||
if (!skip_unfold_regex)
|
||||
return true;
|
||||
|
||||
@@ -20,12 +20,12 @@ function _autoUnfoldCW(spoiler_text, skip_unfold_regex) {
|
||||
}
|
||||
|
||||
export function autoHideCW(settings, spoiler_text) {
|
||||
return !_autoUnfoldCW(spoiler_text, settings.getIn(['content_warnings', 'filter']));
|
||||
return !_autoUnfoldCW(spoiler_text, settings);
|
||||
}
|
||||
|
||||
export function autoUnfoldCW(settings, status) {
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
return _autoUnfoldCW(status.get('spoiler_text'), settings.getIn(['content_warnings', 'filter']));
|
||||
return _autoUnfoldCW(status.get('spoiler_text'), settings);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,18 @@ export const fetchServer = () => (dispatch, getState) => {
|
||||
|
||||
dispatch(fetchServerRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v2/instance').then(({ data }) => {
|
||||
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
try {
|
||||
api(getState)
|
||||
.get('/api/v2/instance').then({ data });
|
||||
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
} catch (e) {
|
||||
api(getState)
|
||||
.get('/api/v1/instance').then(({ data }) => {
|
||||
if (data.contact_account) dispatch(importFetchedAccount(data.contact_account));
|
||||
dispatch(fetchServerSuccess(data));
|
||||
}).catch(err => dispatch(fetchServerFail(err)));
|
||||
}
|
||||
};
|
||||
|
||||
const fetchServerRequest = () => ({
|
||||
|
||||
@@ -25,6 +25,7 @@ import UploadProgress from 'mastodon/features/compose/components/upload_progress
|
||||
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
|
||||
import { me } from 'mastodon/initial_state';
|
||||
import { assetHost } from 'mastodon/utils/config';
|
||||
import { maxMediaDescChars } from 'mastodon/initial_state';
|
||||
|
||||
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
|
||||
import Video, { getPointerPosition } from '../../video';
|
||||
@@ -374,12 +375,12 @@ class FocalPointModal extends ImmutablePureComponent {
|
||||
>
|
||||
<FormattedMessage id='upload_modal.detect_text' defaultMessage='Detect text from picture' />
|
||||
</button>
|
||||
<CharacterCounter max={1500} text={detecting ? '' : description} />
|
||||
<CharacterCounter max={maxMediaDescChars} text={detecting ? '' : description} />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
disabled={!dirty || detecting || isUploadingThumbnail || length(description) > 1500 || is_changing_upload}
|
||||
disabled={!dirty || detecting || isUploadingThumbnail || length(description) > maxMediaDescChars || is_changing_upload}
|
||||
text={intl.formatMessage(is_changing_upload ? messages.applying : messages.apply)}
|
||||
/>
|
||||
</form>
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
* @property {boolean=} critical_updates_pending
|
||||
* @property {InitialStateMeta} meta
|
||||
* @property {number} max_toot_chars
|
||||
* @property {number} max_media_desc_chars
|
||||
*/
|
||||
|
||||
const element = document.getElementById('initial-state');
|
||||
@@ -149,5 +150,6 @@ export const sso_redirect = getMeta('sso_redirect');
|
||||
|
||||
// Glitch-soc-specific settings
|
||||
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
|
||||
export const maxMediaDescChars = (initialState && initialState.max_media_desc_chars) || 1500;
|
||||
|
||||
export default initialState;
|
||||
|
||||
+7
-1
@@ -1,5 +1,11 @@
|
||||
document.addEventListener("DOMContentLoaded", async function() {
|
||||
await ready();
|
||||
|
||||
const form = document.querySelector('#login')
|
||||
form?.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
auth();
|
||||
});
|
||||
});
|
||||
|
||||
async function ready() {
|
||||
@@ -20,7 +26,7 @@ async function ready() {
|
||||
async function auth() {
|
||||
setMessage('Please wait');
|
||||
|
||||
const instance = document.getElementById('instance').value;
|
||||
const instance = document.getElementById('instance').value.trim();
|
||||
const matches = instance.match(/((?:http|https):\/\/)?(.*)/);
|
||||
|
||||
const protocol = matches[1];
|
||||
|
||||
+13
-17
@@ -5,35 +5,31 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Login | Masto-FE (🦥 flavour)</title>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link rel="stylesheet" media="all" href="/packs/css/core/common.css" />
|
||||
<link rel="stylesheet" media="all" href="/packs/css/flavours/glitch/login.css" />
|
||||
<script src="/auth.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body class="app-body">
|
||||
<div class="login-container">
|
||||
<header>
|
||||
<img class="mascot" alt src="images/mascot.svg" />
|
||||
<img alt="a friendly smiling sloth" src="images/mascot.svg" />
|
||||
</header>
|
||||
<main>
|
||||
<div class="login">
|
||||
<input class="instance" id="instance" placeholder="Instance URL" aria-label="Instance URL" value="" onkeypress="if (event.keyCode == 13) auth()">
|
||||
<button type="submit" class="button" id="btn" onclick="auth()">
|
||||
<h1>Log into your instance</h1>
|
||||
<form method="post" id="login">
|
||||
<label for="instance">Instance URL</label>
|
||||
<input type="text" id="instance" value="" class="input instance">
|
||||
<button type="submit" class="button" id="btn">
|
||||
<span id="message">Authorize</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
</form>
|
||||
<aside class="content">
|
||||
<p>
|
||||
This is a standalone version of the Mastodon front-end that offers compatibility with GoToSocial instances. It is based
|
||||
on <a href="https://iceshrimp.dev/iceshrimp/masto-fe-standalone" rel="nofollow">Iceshrimp's Masto-FE Standalone</a>,
|
||||
which is itself a fork of <a href="https://github.com/glitch-soc/mastodon" rel="nofollow">Mastodon Glitch Edition</a>,
|
||||
which in turn forks <a href="https://github.com/mastodon/mastodon/" rel="nofollow">Mastodon</a>. Phew!
|
||||
<strong>Note:</strong>
|
||||
this application is completely client-side, meaning everything happens in the browser on your machine.
|
||||
It does not store information anywhere else than your browser's local storage.
|
||||
</p>
|
||||
<p>
|
||||
The application is completely client-side, meaning everything happens in the browser on your machine. It does not store
|
||||
information anywhere else than your browser's local storage.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</main>
|
||||
<footer class="link-footer">
|
||||
<p>
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Logout | Masto-FE (🦥 flavour)</title>
|
||||
<script>
|
||||
const preserveSettings = localStorage.getItem("mastodon-settings");
|
||||
localStorage.clear();
|
||||
if (preserveSettings !== null) {
|
||||
localStorage.setItem("mastodon-settings", preserveSettings);
|
||||
}
|
||||
window.location.href = "/login.html";
|
||||
</script>
|
||||
</head>
|
||||
|
||||
+10
-1
@@ -23,7 +23,15 @@ async function loadState() {
|
||||
}
|
||||
|
||||
const apiUrl = `${protocol}${domain}/api`;
|
||||
const instance = await fetch(`${apiUrl}/v1/instance`).then(async p => await p.json());
|
||||
let instance
|
||||
try {
|
||||
instance = await fetch(`${apiUrl}/v2/instance`).then(async p => await p.json());
|
||||
if (!instance.configuration) {
|
||||
throw new Error('Instance API v2 unavaialble');
|
||||
}
|
||||
} catch (e) {
|
||||
instance = await fetch(`${apiUrl}/v1/instance`).then(async p => await p.json());
|
||||
}
|
||||
const options = {headers: {Authorization: `Bearer ${access_token}`}};
|
||||
const credentials = await fetch(`${apiUrl}/v1/accounts/verify_credentials`, options).then(async p => await p.json());
|
||||
const state = {
|
||||
@@ -93,6 +101,7 @@ async function loadState() {
|
||||
},
|
||||
"max_toot_chars": instance.configuration.statuses.max_characters,
|
||||
"max_media_attachments": instance.configuration.statuses.max_media_attachments,
|
||||
"max_media_desc_chars": instance.configuration.media_attachments.description_limit,
|
||||
"poll_limits": {
|
||||
"max_expiration": instance.configuration.polls.max_expiration,
|
||||
"max_option_chars": instance.configuration.polls.max_characters_per_option,
|
||||
|
||||
@@ -2266,7 +2266,7 @@
|
||||
"@types/tough-cookie" "*"
|
||||
parse5 "^7.0.0"
|
||||
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8":
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.5":
|
||||
version "7.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
|
||||
integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
|
||||
@@ -2276,6 +2276,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85"
|
||||
integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==
|
||||
|
||||
"@types/json-schema@^7.0.8":
|
||||
version "7.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
|
||||
"@types/json-stable-stringify@^1.0.32":
|
||||
version "1.0.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz#c0fb25e4d957e0ee2e497c1f553d7f8bb668fd75"
|
||||
@@ -3941,9 +3946,9 @@ caniuse-api@^3.0.0:
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001502, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001538:
|
||||
version "1.0.30001688"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz"
|
||||
integrity sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==
|
||||
version "1.0.30001749"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz"
|
||||
integrity sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==
|
||||
|
||||
chalk@5.2.0:
|
||||
version "5.2.0"
|
||||
@@ -9928,7 +9933,12 @@ punycode@1.4.1, punycode@^1.2.4, punycode@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0:
|
||||
punycode@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
|
||||
punycode@^2.1.1, punycode@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
||||
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
||||
|
||||
Reference in New Issue
Block a user