commit
19da64a787
|
@ -261,7 +261,11 @@ function App() {
|
|||
if (code) {
|
||||
console.log({ code });
|
||||
// Clear the code from the URL
|
||||
window.history.replaceState({}, document.title, location.pathname || '/');
|
||||
window.history.replaceState(
|
||||
{},
|
||||
document.title,
|
||||
window.location.pathname || '/',
|
||||
);
|
||||
|
||||
const clientID = store.session.get('clientID');
|
||||
const clientSecret = store.session.get('clientSecret');
|
||||
|
|
|
@ -74,6 +74,7 @@ export default memo(function BackgroundService({ isLoggedIn }) {
|
|||
}
|
||||
states.notificationsShowNew = true;
|
||||
}
|
||||
console.log('💥 Streaming notification loop STOPPED');
|
||||
} catch (e) {
|
||||
hasStreaming = false;
|
||||
console.error(e);
|
||||
|
|
|
@ -108,7 +108,7 @@ function countableText(inputText) {
|
|||
// https://github.com/mastodon/mastodon/blob/c03bd2a238741a012aa4b98dc4902d6cf948ab63/app/models/account.rb#L69
|
||||
const USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i;
|
||||
const MENTION_RE = new RegExp(
|
||||
`(^|[^=\\/\\w])(@${USERNAME_RE.source}(?:@[\\p{L}\\w.-]+[\\w]+)?)`,
|
||||
`(^|[^=\\/\\w.])(@${USERNAME_RE.source}(?:@[\\p{L}\\w.-]+[\\w]+)?)`,
|
||||
'uig',
|
||||
);
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ function Media({
|
|||
}}
|
||||
onError={(e) => {
|
||||
const { src } = e.target;
|
||||
if (src === mediaURL) {
|
||||
if (src === mediaURL && mediaURL !== remoteMediaURL) {
|
||||
e.target.src = remoteMediaURL;
|
||||
}
|
||||
}}
|
||||
|
@ -307,7 +307,7 @@ function Media({
|
|||
}}
|
||||
onError={(e) => {
|
||||
const { src } = e.target;
|
||||
if (src === mediaURL) {
|
||||
if (src === mediaURL && mediaURL !== remoteMediaURL) {
|
||||
e.target.src = remoteMediaURL;
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -688,6 +688,13 @@
|
|||
margin-inline: -16px;
|
||||
max-width: calc(100% + 16px + 16px) !important;
|
||||
|
||||
figure:before {
|
||||
content: '';
|
||||
display: block;
|
||||
/* padding (16px) - gap (4px) */
|
||||
flex-basis: calc(16px - 4px);
|
||||
}
|
||||
|
||||
figure figcaption {
|
||||
padding-inline: 16px !important;
|
||||
}
|
||||
|
@ -712,8 +719,19 @@
|
|||
/* height: 200px; */
|
||||
max-height: max(200px, 40vh);
|
||||
}
|
||||
.status.medium .content ~ * .media-container:is(.media-eq2, .media-gt2),
|
||||
.status.medium .content ~ .media-container:is(.media-eq2, .media-gt2) {
|
||||
.status.medium
|
||||
.content
|
||||
~ *
|
||||
.media-container:not(.status-card .media-container):is(
|
||||
.media-eq2,
|
||||
.media-gt2
|
||||
),
|
||||
.status.medium
|
||||
.content
|
||||
~ .media-container:not(.status-card .media-container):is(
|
||||
.media-eq2,
|
||||
.media-gt2
|
||||
) {
|
||||
/* 50px = avatar size */
|
||||
margin-left: calc(-1 * ((50px / 2)));
|
||||
/*
|
||||
|
|
|
@ -242,6 +242,15 @@ button,
|
|||
:is(button, .button).plain4:not(:disabled, .disabled):is(:hover, :focus) {
|
||||
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 {
|
||||
background-color: var(--bg-faded-color);
|
||||
color: var(--text-color);
|
||||
|
|
|
@ -95,6 +95,7 @@ function Following({ title, path, id, ...props }) {
|
|||
if (s) s._deleted = true;
|
||||
}
|
||||
}
|
||||
console.log('💥 Streaming user loop STOPPED');
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#instances-suggestions {
|
||||
margin: 0.2em 0 0;
|
||||
padding: 0;
|
||||
padding: 0 0 0 1.2em;
|
||||
list-style: none;
|
||||
width: 90vw;
|
||||
max-width: 40em;
|
||||
|
|
|
@ -3,6 +3,8 @@ import './login.css';
|
|||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import logo from '../assets/logo.svg';
|
||||
|
||||
import Link from '../components/link';
|
||||
import Loader from '../components/loader';
|
||||
import instancesListURL from '../data/instances.json?url';
|
||||
|
@ -42,6 +44,7 @@ function Login() {
|
|||
// }, []);
|
||||
|
||||
const submitInstance = (instanceURL) => {
|
||||
if (!instanceURL) return;
|
||||
store.local.set('instanceURL', instanceURL);
|
||||
|
||||
(async () => {
|
||||
|
@ -72,23 +75,18 @@ function Login() {
|
|||
})();
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
const cleanInstanceText = instanceText
|
||||
? instanceText
|
||||
.replace(/^https?:\/\//, '') // Remove protocol from instance URL
|
||||
.replace(/\/+$/, '') // Remove trailing slash
|
||||
.replace(/^@?[^@]+@/, '') // Remove @?acct@
|
||||
.trim()
|
||||
: null;
|
||||
const instanceTextLooksLikeDomain =
|
||||
/[^\s\r\n\t\/\\]+\.[^\s\r\n\t\/\\]+/.test(cleanInstanceText) &&
|
||||
!/[\s\/\\@]/.test(cleanInstanceText);
|
||||
|
||||
const instancesSuggestions = instanceText
|
||||
const instancesSuggestions = cleanInstanceText
|
||||
? instancesList
|
||||
.filter((instance) => instance.includes(instanceText))
|
||||
.sort((a, b) => {
|
||||
|
@ -106,10 +104,39 @@ function Login() {
|
|||
.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 (
|
||||
<main id="login" style={{ textAlign: 'center' }}>
|
||||
<form onSubmit={onSubmit}>
|
||||
<h1>Log in</h1>
|
||||
<h1>
|
||||
<img src={logo} alt="" width="80" height="80" />
|
||||
<br />
|
||||
Log in
|
||||
</h1>
|
||||
<label>
|
||||
<p>Instance</p>
|
||||
<input
|
||||
|
@ -132,11 +159,11 @@ function Login() {
|
|||
/>
|
||||
{instancesSuggestions?.length > 0 ? (
|
||||
<ul id="instances-suggestions">
|
||||
{instancesSuggestions.map((instance) => (
|
||||
{instancesSuggestions.map((instance, i) => (
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="plain4"
|
||||
class="plain5"
|
||||
onClick={() => {
|
||||
submitInstance(instance);
|
||||
}}
|
||||
|
@ -147,7 +174,7 @@ function Login() {
|
|||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<div id="instances-eg">e.g. “mastodon.social’</div>
|
||||
<div id="instances-eg">e.g. “mastodon.social”</div>
|
||||
)}
|
||||
{/* <datalist id="instances-list">
|
||||
{instancesList.map((instance) => (
|
||||
|
@ -161,8 +188,14 @@ function Login() {
|
|||
</p>
|
||||
)}
|
||||
<div>
|
||||
<button class="large" disabled={uiState === 'loading'}>
|
||||
Log in
|
||||
<button
|
||||
disabled={
|
||||
uiState === 'loading' || !instanceText || !selectedInstanceText
|
||||
}
|
||||
>
|
||||
{selectedInstanceText
|
||||
? `Continue with ${selectedInstanceText}`
|
||||
: 'Continue'}
|
||||
</button>{' '}
|
||||
</div>
|
||||
<Loader hidden={uiState !== 'loading'} />
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
|
||||
#settings-container section select {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#settings-container .radio-group {
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
@keyframes shine2 {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
20% {
|
||||
left: 100%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#welcome {
|
||||
text-align: center;
|
||||
background-image: radial-gradient(
|
||||
|
@ -35,45 +23,23 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 5em;
|
||||
line-height: 1;
|
||||
letter-spacing: -1px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
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 {
|
||||
filter: drop-shadow(-1px -1px var(--bg-blur-color))
|
||||
|
@ -99,6 +65,10 @@
|
|||
font-size: 1.4em;
|
||||
text-wrap: balance;
|
||||
opacity: 0.7;
|
||||
|
||||
& ~ p {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-container > p {
|
||||
|
@ -148,25 +118,34 @@
|
|||
}
|
||||
|
||||
@media (width > 40em) {
|
||||
display: grid;
|
||||
/* display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
height: 100vh;
|
||||
height: 100svh;
|
||||
height: 100svh; */
|
||||
width: 100%;
|
||||
|
||||
.hero-container {
|
||||
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 {
|
||||
padding: 32px;
|
||||
overflow: auto;
|
||||
mask-image: linear-gradient(to top, transparent 16px, black 64px);
|
||||
}
|
||||
padding: 32px 32px 32px 8px;
|
||||
margin-left: 50%;
|
||||
|
||||
footer {
|
||||
grid-row: 2;
|
||||
grid-column: 1 / span 2;
|
||||
/* overflow: auto;
|
||||
mask-image: linear-gradient(to top, transparent 16px, black 64px); */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,29 +17,58 @@ function Welcome() {
|
|||
return (
|
||||
<main id="welcome">
|
||||
<div class="hero-container">
|
||||
<div class="hero-content">
|
||||
<h1>
|
||||
<img
|
||||
src={logo}
|
||||
alt=""
|
||||
width="200"
|
||||
height="200"
|
||||
width="160"
|
||||
height="160"
|
||||
style={{
|
||||
aspectRatio: '1/1',
|
||||
marginBlockEnd: -16,
|
||||
}}
|
||||
/>
|
||||
<img src={logoText} alt="Phanpy" width="250" />
|
||||
<img src={logoText} alt="Phanpy" width="200" />
|
||||
</h1>
|
||||
<p>
|
||||
<big>
|
||||
<b>
|
||||
<Link to="/login" class="button">
|
||||
Log in
|
||||
</Link>
|
||||
</b>
|
||||
</big>
|
||||
</p>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
<div id="why-container">
|
||||
<div class="sections">
|
||||
|
@ -98,33 +127,6 @@ function Welcome() {
|
|||
</section>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue