~cytrogen/masto-fe

370a666d27638530fbf51007d1defc2f883a0b62 — vyxen 1 year, 6 days ago 0f77cb5
[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>
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