Adjustments to welcome and login pages

This commit is contained in:
Lim Chee Aun 2023-12-10 19:16:34 +08:00
parent 7dd0b0a4fb
commit 433d8b3bcc
5 changed files with 148 additions and 125 deletions

View file

@ -242,6 +242,15 @@ button,
:is(button, .button).plain4:not(:disabled, .disabled):is(:hover, :focus) { :is(button, .button).plain4:not(:disabled, .disabled):is(:hover, :focus) {
color: var(--text-color); color: var(--text-color);
} }
:is(button, .button).plain5 {
background-color: transparent;
color: var(--link-color);
text-decoration: underline;
text-decoration-color: var(--link-faded-color);
}
:is(button, .button).plain5:not(:disabled, .disabled):is(:hover, :focus) {
text-decoration: underline;
}
:is(button, .button).light { :is(button, .button).light {
background-color: var(--bg-faded-color); background-color: var(--bg-faded-color);
color: var(--text-color); color: var(--text-color);

View file

@ -30,7 +30,7 @@
#instances-suggestions { #instances-suggestions {
margin: 0.2em 0 0; margin: 0.2em 0 0;
padding: 0; padding: 0 0 0 1.2em;
list-style: none; list-style: none;
width: 90vw; width: 90vw;
max-width: 40em; max-width: 40em;

View file

@ -3,6 +3,8 @@ import './login.css';
import { useEffect, useRef, useState } from 'preact/hooks'; import { useEffect, useRef, useState } from 'preact/hooks';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import logo from '../assets/logo.svg';
import Link from '../components/link'; import Link from '../components/link';
import Loader from '../components/loader'; import Loader from '../components/loader';
import instancesListURL from '../data/instances.json?url'; import instancesListURL from '../data/instances.json?url';
@ -42,6 +44,7 @@ function Login() {
// }, []); // }, []);
const submitInstance = (instanceURL) => { const submitInstance = (instanceURL) => {
if (!instanceURL) return;
store.local.set('instanceURL', instanceURL); store.local.set('instanceURL', instanceURL);
(async () => { (async () => {
@ -72,23 +75,18 @@ function Login() {
})(); })();
}; };
const onSubmit = (e) => { const cleanInstanceText = instanceText
e.preventDefault(); ? instanceText
const { elements } = e.target; .replace(/^https?:\/\//, '') // Remove protocol from instance URL
let instanceURL = elements.instanceURL.value.toLowerCase(); .replace(/\/+$/, '') // Remove trailing slash
// Remove protocol from instance URL .replace(/^@?[^@]+@/, '') // Remove @?acct@
instanceURL = instanceURL.replace(/^https?:\/\//, '').replace(/\/+$/, ''); .trim()
// Remove @acct@ or acct@ from instance URL : null;
instanceURL = instanceURL.replace(/^@?[^@]+@/, ''); const instanceTextLooksLikeDomain =
if (!/\./.test(instanceURL)) { /[^\s\r\n\t\/\\]+\.[^\s\r\n\t\/\\]+/.test(cleanInstanceText) &&
instanceURL = instancesList.find((instance) => !/[\s\/\\@]/.test(cleanInstanceText);
instance.includes(instanceURL),
);
}
submitInstance(instanceURL);
};
const instancesSuggestions = instanceText const instancesSuggestions = cleanInstanceText
? instancesList ? instancesList
.filter((instance) => instance.includes(instanceText)) .filter((instance) => instance.includes(instanceText))
.sort((a, b) => { .sort((a, b) => {
@ -106,10 +104,39 @@ function Login() {
.slice(0, 10) .slice(0, 10)
: []; : [];
const selectedInstanceText = instanceTextLooksLikeDomain
? cleanInstanceText
: instancesSuggestions?.length
? instancesSuggestions[0]
: instanceText
? instancesList.find((instance) => instance.includes(instanceText))
: null;
const onSubmit = (e) => {
e.preventDefault();
// const { elements } = e.target;
// let instanceURL = elements.instanceURL.value.toLowerCase();
// // Remove protocol from instance URL
// instanceURL = instanceURL.replace(/^https?:\/\//, '').replace(/\/+$/, '');
// // Remove @acct@ or acct@ from instance URL
// instanceURL = instanceURL.replace(/^@?[^@]+@/, '');
// if (!/\./.test(instanceURL)) {
// instanceURL = instancesList.find((instance) =>
// instance.includes(instanceURL),
// );
// }
// submitInstance(instanceURL);
submitInstance(selectedInstanceText);
};
return ( return (
<main id="login" style={{ textAlign: 'center' }}> <main id="login" style={{ textAlign: 'center' }}>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<h1>Log in</h1> <h1>
<img src={logo} alt="" width="80" height="80" />
<br />
Log in
</h1>
<label> <label>
<p>Instance</p> <p>Instance</p>
<input <input
@ -132,11 +159,11 @@ function Login() {
/> />
{instancesSuggestions?.length > 0 ? ( {instancesSuggestions?.length > 0 ? (
<ul id="instances-suggestions"> <ul id="instances-suggestions">
{instancesSuggestions.map((instance) => ( {instancesSuggestions.map((instance, i) => (
<li> <li>
<button <button
type="button" type="button"
class="plain4" class="plain5"
onClick={() => { onClick={() => {
submitInstance(instance); submitInstance(instance);
}} }}
@ -147,7 +174,7 @@ function Login() {
))} ))}
</ul> </ul>
) : ( ) : (
<div id="instances-eg">e.g. &ldquo;mastodon.social&rsquo;</div> <div id="instances-eg">e.g. &ldquo;mastodon.social&rdquo;</div>
)} )}
{/* <datalist id="instances-list"> {/* <datalist id="instances-list">
{instancesList.map((instance) => ( {instancesList.map((instance) => (
@ -161,8 +188,14 @@ function Login() {
</p> </p>
)} )}
<div> <div>
<button class="large" disabled={uiState === 'loading'}> <button
Log in disabled={
uiState === 'loading' || !instanceText || !selectedInstanceText
}
>
{selectedInstanceText
? `Continue with ${selectedInstanceText}`
: 'Continue'}
</button>{' '} </button>{' '}
</div> </div>
<Loader hidden={uiState !== 'loading'} /> <Loader hidden={uiState !== 'loading'} />

View file

@ -1,15 +1,3 @@
@keyframes shine2 {
0% {
left: -100%;
}
20% {
left: 100%;
}
100% {
left: 100%;
}
}
#welcome { #welcome {
text-align: center; text-align: center;
background-image: radial-gradient( background-image: radial-gradient(
@ -35,45 +23,23 @@
flex-direction: column; flex-direction: column;
} }
.hero-content {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
h1 { h1 {
display: flex;
flex-direction: column;
align-items: center;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 5em; font-size: 5em;
line-height: 1; line-height: 1;
letter-spacing: -1px; letter-spacing: -1px;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative; position: relative;
mix-blend-mode: multiply;
@media (prefers-color-scheme: dark) {
mix-blend-mode: normal;
}
&:before {
content: '';
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
background-image: linear-gradient(
100deg,
rgba(255, 255, 255, 0) 30%,
rgba(255, 255, 255, 0.4),
rgba(255, 255, 255, 0) 70%
);
top: 0;
left: -100%;
pointer-events: none;
animation: shine2 5s ease-in-out 1s infinite;
@media (prefers-color-scheme: dark) {
content: none;
}
}
img { img {
filter: drop-shadow(-1px -1px var(--bg-blur-color)) filter: drop-shadow(-1px -1px var(--bg-blur-color))
@ -99,6 +65,10 @@
font-size: 1.4em; font-size: 1.4em;
text-wrap: balance; text-wrap: balance;
opacity: 0.7; opacity: 0.7;
& ~ p {
margin-top: 0;
}
} }
.hero-container > p { .hero-container > p {
@ -148,25 +118,34 @@
} }
@media (width > 40em) { @media (width > 40em) {
display: grid; /* display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr auto;
height: 100vh; height: 100vh;
height: 100svh; height: 100svh; */
width: 100%;
.hero-container { .hero-container {
height: auto; height: auto;
max-height: none;
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 50%;
align-items: flex-end;
> * {
max-width: 40em;
width: 100%;
}
} }
#why-container { #why-container {
padding: 32px; padding: 32px 32px 32px 8px;
overflow: auto; margin-left: 50%;
mask-image: linear-gradient(to top, transparent 16px, black 64px);
}
footer { /* overflow: auto;
grid-row: 2; mask-image: linear-gradient(to top, transparent 16px, black 64px); */
grid-column: 1 / span 2;
} }
} }

View file

@ -17,29 +17,58 @@ function Welcome() {
return ( return (
<main id="welcome"> <main id="welcome">
<div class="hero-container"> <div class="hero-container">
<h1> <div class="hero-content">
<img <h1>
src={logo} <img
alt="" src={logo}
width="200" alt=""
height="200" width="160"
style={{ height="160"
aspectRatio: '1/1', style={{
marginBlockEnd: -16, aspectRatio: '1/1',
}} marginBlockEnd: -16,
/> }}
<img src={logoText} alt="Phanpy" width="250" /> />
</h1> <img src={logoText} alt="Phanpy" width="200" />
</h1>
<p class="desc">A minimalistic opinionated Mastodon web client.</p>
<p>
<Link to="/login" class="button">
Log in with Mastodon
</Link>
</p>
<p class="insignificant">
<small>
Connect your existing Mastodon/Fediverse account.
<br />
Your credentials are not stored on this server.
</small>
</p>
</div>
<p> <p>
<big> <a href="https://github.com/cheeaun/phanpy" target="_blank">
<b> Built
<Link to="/login" class="button"> </a>{' '}
Log in by{' '}
</Link> <a
</b> href="https://mastodon.social/@cheeaun"
</big> target="_blank"
onClick={(e) => {
e.preventDefault();
states.showAccount = 'cheeaun@mastodon.social';
}}
>
@cheeaun
</a>
.{' '}
<a
href="https://github.com/cheeaun/phanpy/blob/main/PRIVACY.MD"
target="_blank"
>
Privacy Policy
</a>
.
</p> </p>
<p class="desc">A minimalistic opinionated Mastodon web client.</p>
</div> </div>
<div id="why-container"> <div id="why-container">
<div class="sections"> <div class="sections">
@ -98,33 +127,6 @@ function Welcome() {
</section> </section>
</div> </div>
</div> </div>
<footer>
<hr />
<p>
<a href="https://github.com/cheeaun/phanpy" target="_blank">
Built
</a>{' '}
by{' '}
<a
href="https://mastodon.social/@cheeaun"
target="_blank"
onClick={(e) => {
e.preventDefault();
states.showAccount = 'cheeaun@mastodon.social';
}}
>
@cheeaun
</a>
.{' '}
<a
href="https://github.com/cheeaun/phanpy/blob/main/PRIVACY.MD"
target="_blank"
>
Privacy Policy
</a>
.
</p>
</footer>
</main> </main>
); );
} }