[feature] Nicer login.html page, with cute styling + link to source code (#19)

Fixes #9

- Cute styling, combination of Mastodon and GTS
- Short description of the project
- Error and status messages (temporarily) appear in disabled button with correct ARIA attributes
- Sufficient contrast (WCAG AAA)

Let me know if using `login.scss` both as an index file and for adding custom styling is okay. I figured this might be preferred over creating an extra folder and file.

Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/19
Co-authored-by: vyxen <vyxen@tutamail.com>
Co-committed-by: vyxen <vyxen@tutamail.com>
This commit is contained in:
vyxen
2025-04-03 11:07:34 +00:00
committed by tobi
parent 0f77cb593c
commit 370a666d27
5 changed files with 180 additions and 6 deletions

View File

@@ -0,0 +1,8 @@
import 'packs/public-path';
import { start } from '@rails/ujs';
import 'flavours/glitch/styles/login.scss';
start();
// This ensures that webpack compiles our images.
require.context('../images', true);

View File

@@ -0,0 +1,118 @@
@import 'variables';
@import 'styles/fonts/roboto';
@import 'styles/fonts/roboto-mono';
@import 'reset';
@import 'basics';
body {
height: 100vh;
a {
color: #89caff;
}
}
.login-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
max-width: 30rem;
padding: 1rem;
margin: auto;
box-sizing: border-box;
}
header {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.mascot {
height: 10rem;
}
main {
display: flex;
position: relative;
flex-direction: column;
row-gap: 10px;
}
.login {
display: flex;
position: relative;
column-gap: 10px;
}
.instance {
background: #282c37;
border: 0;
border-radius: 4px;
box-shadow: none;
box-sizing: border-box;
color: #9baec8;
display: block;
font-family: inherit;
font-size: 16px;
line-height: 18px;
margin: 0;
outline: 0;
padding: 15px;
padding-inline-end: 30px;
width: 100%;
}
.button {
display: flex;
column-gap: .5rem;
align-items: center;
justify-content: center;
background-color: #66befe;
border: 0 none;
border-radius: 4px;
box-sizing: border-box;
color: #2a2b2f;
cursor: pointer;
font-size: 16px;
letter-spacing: 0;
line-height: 22px;
font-family: inherit;
font-weight: 500;
padding: 7px 10px;
position: relative;
text-align: center;
text-decoration: none;
white-space: nowrap;
flex-basis: auto;
&:hover {
background-color: #89caff;
}
&:disabled {
background-color: #9baec8;
cursor: default;
}
}
.content {
background-color: #444b5d;
padding: 15px;
font-size: 1rem;
line-height: 1.5rem;
border-radius: 4px;
display: flex;
flex-direction: column;
row-gap: .75rem;
}
.link-footer {
padding: 10px;
p, a {
color: #97A8B4;
}
}

View File

@@ -16,6 +16,9 @@ pack:
- flavours/glitch/async/getting_started - flavours/glitch/async/getting_started
- flavours/glitch/async/home_timeline - flavours/glitch/async/home_timeline
- flavours/glitch/async/notifications - flavours/glitch/async/notifications
login:
filename: packs/login.js
stylesheet: true
mailer: mailer:
modal: modal:
public: packs/public.jsx public: packs/public.jsx

View File

@@ -30,7 +30,9 @@ async function auth() {
const domain = matches[2]; const domain = matches[2];
if (!domain) { if (!domain) {
setMessage('Invalid instance', false); setMessage('Invalid instance', true);
await new Promise(r => setTimeout(r, 2000));
setMessage('Authorize', false, false);
return; return;
} }
localStorage.setItem('domain', domain); localStorage.setItem('domain', domain);
@@ -92,7 +94,6 @@ async function getToken(code, domain) {
formData.append('scope', 'read write follow push'); formData.append('scope', 'read write follow push');
formData.append('redirect_uri', document.location.origin + document.location.pathname); formData.append('redirect_uri', document.location.origin + document.location.pathname);
// eslint-disable-next-line promise/catch-or-return // eslint-disable-next-line promise/catch-or-return
return fetch(tokenUrl, { return fetch(tokenUrl, {
method: 'POST', method: 'POST',
@@ -108,7 +109,14 @@ async function getToken(code, domain) {
}); });
} }
function setMessage(message, disabled = true) { function setMessage(message, error = false, disabled = true) {
document.getElementById('message').setAttribute('role', 'status');
document.getElementById('message').textContent = message; document.getElementById('message').textContent = message;
document.getElementById('btn').disabled = disabled; document.getElementById('btn').disabled = disabled;
if (!error) return;
const instance = document.getElementById('instance');
instance.setAttribute('aria-invalid', true);
instance.setAttribute('aria-describedby', 'message');
} }

View File

@@ -1,13 +1,50 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Login | Masto-FE (🦥 flavour)</title> <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> <script src="/auth.js"></script>
</head> </head>
<body> <body>
<input type="text" id="instance" placeholder="yourinstance.tld"> <div class="login-container">
<button onclick="auth()" id="btn">Log in</button> <header>
<span id="message"></span> <img class="mascot" alt 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()">
<span id="message">Authorize</span>
</button>
</div>
<div 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!
</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>
</main>
<footer class="link-footer">
<p>
<strong>Masto-FE (🦥 flavour)</strong>
<span aria-hidden="true"> · </span>
<a href="https://codeberg.org/superseriousbusiness/masto-fe-standalone" rel="noopener noreferrer" target="_blank">
Source code
</a>
</p>
</footer>
</div>
</body> </body>
</html> </html>