7 Commits

Author SHA1 Message Date
Zoë Bijl 9ae713c083 [bugfix] make focus visible
Mastodon’s UI has been plagued with inaccessibility from the start. Removing the focus outline is one example of that. This is the start of fixing that. Removes all instances of `outline: 0 | none;`.

Next step is to add nicely styled focus outlines.
2025-10-10 01:07:35 +02:00
tobi 4b4a9f981f [chore] Update to yarn 4 (#90)
Update to yarn 4 and use `masto-fe-standalone-woodpecker-build` container for builds.

Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/90
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-10-09 16:13:26 +02:00
Zoë Bijl 3faabb8280 [docs] update AUTHORS.md (#89)
Removes Mastodon authors and replaces it with Sloth Flavour authors. Also adds a special thanks section to attribute the original project authors.

Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/89
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-09 15:02:45 +02:00
Zoë Bijl 5f9a92953f [docs] update changelog (#87)
Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/87
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-09 11:59:01 +02:00
Zoë Bijl 81445f0afd [build] upgrade to Prettier 3.6.2 (#86)
Upgrades Prettier to 3.6.2 and pins it there. Prettier [recommends pinning the version](https://prettier.io/docs/install#summary):

> Install an exact version of Prettier locally in your project. This makes sure that everyone in the project gets the exact same version of Prettier. Even a patch release of Prettier can result in slightly different formatting, so you wouldn’t want different team members using different versions and formatting each other’s changes back and forth.

---

Should probably merge after #85.

Co-authored-by: tobi <kipvandenbos@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/86
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-09 11:52:50 +02:00
Zoë Bijl adf075d19f [bugfix] Fix linter issues (#85)
- [x] .js
- [x] .json
- [x] .md
- [x] .scss
- [x] .yml

Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/85
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-09 11:11:42 +02:00
Zoë Bijl 8a26776492 [docs] Add changelog based on “Keep a Changelog” (#80)
Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/80
Co-authored-by: Zoë Bijl <code@moiety.me>
Co-committed-by: Zoë Bijl <code@moiety.me>
2025-10-09 11:10:00 +02:00
34 changed files with 18436 additions and 18443 deletions
+3
View File
@@ -55,6 +55,9 @@ npm-debug.log
yarn-error.log
yarn-debug.log
# Ignore yarn state file
.yarn/install-state.gz
# Ignore vagrant log files
*-cloudimg-console.log
-1
View File
@@ -1 +0,0 @@
20.8
+5 -5
View File
@@ -1,23 +1,23 @@
steps:
lint:
image: node:22-alpine
image: docker.io/superseriousbusiness/masto-fe-standalone-woodpecker-build:0.1.0
pull: true
# https://woodpecker-ci.org/docs/usage/volumes
volumes:
- /woodpecker/masto-fe-standalone/node_modules:/woodpecker/src/codeberg.org/superseriousbusiness/masto-fe-standalone/node_modules
- /woodpecker/masto-fe-standalone/.eslintcache:/woodpecker/src/codeberg.org/superseriousbusiness/masto-fe-standalone/.eslintcache
# https://woodpecker-ci.org/docs/administration/configuration/backends/docker#run-user
backend_options:
docker:
user: 1000:1000
# https://woodpecker-ci.org/docs/usage/workflow-syntax#commands
commands:
- yarn
- yarn lint:js
# https://woodpecker-ci.org/docs/usage/workflow-syntax#when---conditional-execution
when:
- event: pull_request
+1
View File
@@ -0,0 +1 @@
nodeLinker: node-modules
+15 -1884
View File
File diff suppressed because it is too large Load Diff
+69 -3198
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -4,7 +4,11 @@
## Dependencies
To work on the code decently, you should have Node and Yarn installed. To avoid fuckery, Node Version Manager is **highly recommended**: https://github.com/nvm-sh/nvm.
To work on the code, you must have Node installed.
To avoid fuckery, Node Version Manager is **highly recommended**: https://github.com/nvm-sh/nvm. You can then install the latest `lts` version of node with `nvm install --lts && nvm use --lts`.
You should install yarn as described [here](https://yarnpkg.com/getting-started/install) and/or [here](https://yarnpkg.com/migration/guide).
## Testing Locally
+1 -1
View File
@@ -1,5 +1,5 @@
### BUILDER IMAGE ###
FROM node:lts-alpine AS builder
FROM docker.io/superseriousbusiness/masto-fe-standalone-woodpecker-build:0.1.0 AS builder
# Prepare the build directory, copy
# relevant source + config files over.
@@ -21,17 +21,20 @@ export const fetchServer = () => (dispatch, getState) => {
dispatch(fetchServerRequest());
/* global data */
try {
api(getState)
.get('/api/v2/instance').then({ data })
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
dispatch(fetchServerSuccess(data));
.get('/api/v2/instance').then({ data }).catch(error => {
console.error(error);
});
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)));
}).catch(err => dispatch(fetchServerFail(err)));
}
};
@@ -24,9 +24,8 @@ import CharacterCounter from 'flavours/glitch/features/compose/components/charac
import UploadProgress from 'flavours/glitch/features/compose/components/upload_progress';
import { Tesseract as fetchTesseract } from 'flavours/glitch/features/ui/util/async-components';
import Video, { getPointerPosition } from 'flavours/glitch/features/video';
import { me } from 'flavours/glitch/initial_state';
import { me , maxMediaDescChars } 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';
@@ -52,7 +52,6 @@
}
@mixin search-input() {
outline: 0;
box-sizing: border-box;
width: 100%;
border: 0;
@@ -164,10 +164,6 @@ body {
button {
font-family: inherit;
cursor: pointer;
&:focus {
outline: none;
}
}
.app-holder {
@@ -178,7 +174,6 @@ button {
width: 100%;
align-items: center;
justify-content: center;
outline: 0 !important;
}
& > noscript {
@@ -250,7 +245,6 @@ button {
margin: 0;
line-height: inherit;
cursor: pointer;
outline: 0;
transition: color 300ms linear;
text-decoration: underline;
@@ -753,7 +753,6 @@
font-size: 14px;
resize: none;
border: 0;
outline: 0;
border-radius: 4px;
&::placeholder {
@@ -260,10 +260,6 @@ $ui-header-height: 55px;
background: lighten($ui-base-color, 11%);
}
&:focus {
outline: 0;
}
&--transparent {
background: transparent;
color: $ui-secondary-color;
@@ -350,7 +346,6 @@ $ui-header-height: 55px;
cursor: pointer;
position: relative;
z-index: 2;
outline: 0;
overflow: hidden;
& > button {
@@ -377,11 +372,6 @@ $ui-header-height: 55px;
text-shadow: 0 0 10px rgba($ui-highlight-color, 0.4);
}
}
&:focus,
&:active {
outline: 0;
}
}
.column {
@@ -743,10 +733,6 @@ $ui-header-height: 55px;
input {
width: 100%;
margin-bottom: 6px;
&:focus {
outline: 0;
}
}
}
@@ -786,16 +772,6 @@ $ui-header-height: 55px;
color: lighten($darker-text-color, 4%);
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@@ -50,7 +50,6 @@
border-radius: 4px;
padding: 10px;
width: 100%;
outline: 0;
color: $inverted-text-color;
background: $simple-background-color;
font-size: 14px;
@@ -61,9 +60,6 @@
color: $dark-text-color;
}
&:focus {
outline: 0;
}
@include single-column('screen and (max-width: 630px)') {
font-size: 16px;
}
@@ -220,7 +216,6 @@
padding: 10px 32px 0 10px;
width: 100%;
min-height: 100px;
outline: 0;
color: $inverted-text-color;
background: $simple-background-color;
font-size: 14px;
@@ -236,10 +231,6 @@
all: unset;
}
&:focus {
outline: 0;
}
@include single-column('screen and (max-width: 630px)') {
font-size: 16px;
}
@@ -670,7 +661,6 @@
&.active {
background: $ui-highlight-color;
color: $primary-text-color;
outline: 0;
.language-dropdown__dropdown__results__item__common-name {
color: $secondary-text-color;
@@ -77,7 +77,6 @@
&:focus,
&:hover {
outline: none;
background: lighten($ui-base-color, 3%);
transition: background 200ms ease-out;
}
@@ -76,14 +76,8 @@
padding-bottom: 2px;
padding-inline-start: 2px;
padding-inline-end: 5px;
outline: 0;
cursor: pointer;
&:active,
&:focus {
outline: 0 !important;
}
img {
filter: grayscale(100%);
opacity: 0.8;
@@ -123,16 +123,6 @@
border: 1px solid $ui-secondary-color;
border-radius: 4px;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&::-webkit-search-cancel-button {
display: none;
}
@@ -60,7 +60,6 @@
border-bottom: 1px $ui-secondary-color solid;
cursor: pointer;
text-decoration: none;
outline: none;
transition: background 0.3s;
box-sizing: border-box;
width: 100%;
@@ -454,10 +454,6 @@
height: 100% !important;
}
&:focus {
outline: 0;
}
.detailed-status & {
width: 100%;
height: 100%;
@@ -483,7 +479,6 @@
max-height: 100% !important;
width: 100% !important;
height: 100% !important;
outline: 0;
}
}
@@ -590,7 +585,6 @@
.player-button {
display: inline-block;
outline: 0;
flex: 0 0 auto;
background: transparent;
padding: 5px;
@@ -198,16 +198,6 @@
transition: none;
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&.inverted {
color: $lighter-text-color;
@@ -282,7 +272,6 @@
cursor: pointer;
padding: 0 3px;
white-space: nowrap;
outline: 0;
transition: all 100ms ease-in;
transition-property: background-color, color;
@@ -308,16 +297,6 @@
&.active {
color: $highlight-text-color;
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
}
body > [data-popper-placement] {
@@ -623,7 +602,6 @@ body > [data-popper-placement] {
&:hover,
&:active {
background: var(--dropdown-border-color);
outline: 0;
}
}
}
@@ -1038,7 +1016,6 @@ body > [data-popper-placement] {
background: transparent;
border: 0;
border-bottom: 2px solid $ui-primary-color;
outline: 0;
box-sizing: border-box;
display: block;
font-family: inherit;
@@ -1195,12 +1172,8 @@ button.icon-button.active i.fa-retweet {
align-items: center;
}
&:focus {
outline: 0 !important;
.ckbox {
box-shadow: 0 0 1px 1px $ui-highlight-color;
}
&:focus.ckbox {
box-shadow: 0 0 1px 1px $ui-highlight-color;
}
}
@@ -1523,7 +1496,6 @@ button.icon-button.active i.fa-retweet {
&:focus {
background: lighten($ui-base-color, 2%);
outline: 0;
}
&__avatar {
@@ -693,17 +693,12 @@
line-height: 22px;
resize: vertical;
border: 0;
outline: 0;
border-radius: 4px;
margin: 20px 0;
&::placeholder {
color: $dark-text-color;
}
&:focus {
outline: 0;
}
}
&__toggle {
@@ -821,7 +816,6 @@
font-family: inherit;
font-size: 14px;
resize: none;
outline: 0;
border-radius: 4px;
border: 1px solid $ui-secondary-color;
min-height: 100px;
@@ -1019,7 +1013,6 @@
color: $inverted-text-color;
display: inline-block;
width: auto;
outline: 0;
font-family: inherit;
background: $simple-background-color
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(darken($simple-background-color, 14%))}'/></svg>")
@@ -1128,7 +1121,6 @@
}
.embed-modal__html {
outline: 0;
box-sizing: border-box;
display: block;
width: 100%;
@@ -1142,16 +1134,6 @@
margin-bottom: 15px;
border-radius: 4px;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@@ -1377,10 +1359,6 @@ img.modal-warning {
&::placeholder {
color: lighten($darker-text-color, 4%);
}
&:focus {
outline: 0;
}
}
.button {
@@ -1477,7 +1455,6 @@ img.modal-warning {
overflow: hidden;
&:focus {
outline: 0;
background: darken($ui-base-color, 4%);
}
}
@@ -107,37 +107,17 @@
color: lighten($darker-text-color, 4%);
}
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
}
.search__icon {
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus {
outline: 0 !important;
}
.fa {
position: absolute;
top: 16px;
inset-inline-end: 10px;
display: inline-block;
opacity: 0;
transition: all 100ms linear;
transition-property: color, transform, opacity;
font-size: 18px;
@@ -57,10 +57,6 @@
padding-top: 5px;
clear: both;
&:focus {
outline: 0;
}
.emojione {
width: 20px;
height: 20px;
@@ -213,7 +209,6 @@
.focusable {
&:focus {
outline: 0;
background: lighten($ui-base-color, 4%);
&.status.status-direct {
@@ -27,7 +27,6 @@
align-items: center;
color: $primary-text-color;
text-decoration: none;
outline: 0;
padding: 12px 16px;
line-height: 32px;
font-weight: 500;
@@ -432,7 +432,6 @@ code {
color: $primary-text-color;
display: block;
width: 100%;
outline: 0;
font-family: inherit;
resize: vertical;
background: darken($ui-base-color, 10%);
@@ -535,7 +534,6 @@ code {
box-sizing: border-box;
cursor: pointer;
font-weight: 500;
outline: 0;
margin-bottom: 10px;
margin-inline-end: 10px;
@@ -581,7 +579,6 @@ code {
color: $primary-text-color;
display: block;
width: 100%;
outline: 0;
font-family: inherit;
resize: vertical;
background: darken($ui-base-color, 10%)
@@ -702,7 +699,6 @@ code {
}
.oauth-code {
outline: 0;
box-sizing: border-box;
display: block;
width: 100%;
@@ -714,16 +710,6 @@ code {
font-size: 14px;
margin: 0;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@@ -5,7 +5,7 @@
@import 'basics';
body {
font-family: ui-rounded, 'mastodon-font-sans-serif', sans-serif;
font-family: ui-rounded, mastodon-font-sans-serif, sans-serif;
font-size: 1rem;
line-height: 1.5;
}
@@ -88,7 +88,7 @@ button {
input[type='text'] {
display: block;
marhing: 0;
margin: 0;
padding: 15px;
border: 1px solid lighten(#282c37, 7%);
border-radius: 4px;
@@ -102,7 +102,7 @@ input[type='text'] {
}
.content {
padding: 20px 15px 20px;
padding: 20px 15px;
border-radius: 4px;
border: 1px solid lighten(#39404f, 7%);
color: #fff;
@@ -85,7 +85,6 @@
width: 100%;
font-size: 14px;
color: $inverted-text-color;
outline: 0;
font-family: inherit;
background: $simple-background-color;
border: 1px solid darken($simple-background-color, 14%);
@@ -139,16 +138,6 @@
border-color: $valid-value-color;
}
&::-moz-focus-inner {
outline: 0 !important;
border: 0;
}
&:focus,
&:active {
outline: 0 !important;
}
&.disabled {
border-color: $dark-text-color;
@@ -285,7 +274,6 @@
color: $inverted-text-color;
display: inline-block;
width: auto;
outline: 0;
font-family: inherit;
background: $simple-background-color
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(darken($simple-background-color, 14%))}'/></svg>")
@@ -96,7 +96,8 @@ $dismiss-overlay-width: 4rem;
:root {
--dropdown-border-color: #{lighten($ui-base-color, 12%)};
--dropdown-background-color: #{lighten($ui-base-color, 4%)};
--dropdown-shadow: 0 20px 25px -5px #{rgba($base-shadow-color, 0.25)},
--dropdown-shadow:
0 20px 25px -5px #{rgba($base-shadow-color, 0.25)},
0 8px 10px -6px #{rgba($base-shadow-color, 0.25)};
--modal-background-color: #{darken($ui-base-color, 4%)};
--modal-border-color: #{lighten($ui-base-color, 4%)};
+7 -4
View File
@@ -17,17 +17,20 @@ export const fetchServer = () => (dispatch, getState) => {
dispatch(fetchServerRequest());
/* global data */
try {
api(getState)
.get('/api/v2/instance').then({ data });
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
dispatch(fetchServerSuccess(data));
.get('/api/v2/instance').then({ data }).catch(error => {
console.error(error);
});
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)));
}).catch(err => dispatch(fetchServerFail(err)));
}
};
@@ -23,9 +23,8 @@ import Audio from 'mastodon/features/audio';
import CharacterCounter from 'mastodon/features/compose/components/character_counter';
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 { me , maxMediaDescChars } 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';
@@ -96,7 +96,8 @@ $font-monospace: 'mastodon-font-monospace' !default;
:root {
--dropdown-border-color: #{lighten($ui-base-color, 12%)};
--dropdown-background-color: #{lighten($ui-base-color, 4%)};
--dropdown-shadow: 0 20px 25px -5px #{rgba($base-shadow-color, 0.25)},
--dropdown-shadow:
0 20px 25px -5px #{rgba($base-shadow-color, 0.25)},
0 8px 10px -6px #{rgba($base-shadow-color, 0.25)};
--modal-background-color: #{darken($ui-base-color, 4%)};
--modal-border-color: #{lighten($ui-base-color, 4%)};
+3 -2
View File
@@ -208,7 +208,7 @@
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"lint-staged": "^13.2.2",
"prettier": "^3.0.0",
"prettier": "3.6.2",
"react-test-renderer": "^18.2.0",
"stylelint": "^15.10.1",
"stylelint-config-standard-scss": "^11.0.0",
@@ -230,5 +230,6 @@
"Capfile|Gemfile|*.{rb,ruby,ru,rake}": "bundle exec rubocop --force-exclusion -a",
"*.{js,jsx,ts,tsx}": "eslint --fix",
"*.{css,scss}": "stylelint --fix"
}
},
"packageManager": "yarn@4.10.3"
}
+18309 -13163
View File
File diff suppressed because it is too large Load Diff