A app/javascript/flavours/glitch/packs/login.js => app/javascript/flavours/glitch/packs/login.js +8 -0
@@ 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);
A app/javascript/flavours/glitch/styles/login.scss => app/javascript/flavours/glitch/styles/login.scss +118 -0
@@ 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;
+ }
+}<
\ No newline at end of file
M app/javascript/flavours/glitch/theme.yml => app/javascript/flavours/glitch/theme.yml +3 -0
@@ 16,6 16,9 @@ pack:
- flavours/glitch/async/getting_started
- flavours/glitch/async/home_timeline
- flavours/glitch/async/notifications
+ login:
+ filename: packs/login.js
+ stylesheet: true
mailer:
modal:
public: packs/public.jsx
M public/auth.js => public/auth.js +11 -3
@@ 30,7 30,9 @@ async function auth() {
const domain = matches[2];
if (!domain) {
- setMessage('Invalid instance', false);
+ setMessage('Invalid instance', true);
+ await new Promise(r => setTimeout(r, 2000));
+ setMessage('Authorize', false, false);
return;
}
localStorage.setItem('domain', domain);
@@ 92,7 94,6 @@ async function getToken(code, domain) {
formData.append('scope', 'read write follow push');
formData.append('redirect_uri', document.location.origin + document.location.pathname);
-
// eslint-disable-next-line promise/catch-or-return
return fetch(tokenUrl, {
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('btn').disabled = disabled;
+
+ if (!error) return;
+
+ const instance = document.getElementById('instance');
+ instance.setAttribute('aria-invalid', true);
+ instance.setAttribute('aria-describedby', 'message');
}
M public/login.html => public/login.html +40 -3
@@ 1,13 1,50 @@
<!DOCTYPE html>
<html lang="en">
+
<head>
<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>
-<input type="text" id="instance" placeholder="yourinstance.tld">
-<button onclick="auth()" id="btn">Log in</button>
-<span id="message"></span>
+ <div class="login-container">
+ <header>
+ <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>
+
</html>=
\ No newline at end of file