Styled landing, Bluesky and Fedi redirect pages.
This commit is contained in:
parent
7e75a71bd2
commit
b6f5a4e0cc
24 changed files with 406 additions and 132 deletions
assets
common.js
misuzu.css
redir-bsky.js
redir-fedi.js
redirects.css
redirects.js
|
@ -18,10 +18,13 @@ const MszLoadingIcon = function() {
|
|||
let tsLastUpdate;
|
||||
let counter = 0;
|
||||
let playing = false;
|
||||
let delay = 50;
|
||||
let playResolve;
|
||||
let pauseResolve;
|
||||
|
||||
const update = tsCurrent => {
|
||||
try {
|
||||
if(tsLastUpdate !== undefined && (tsCurrent - tsLastUpdate) < 50)
|
||||
if(tsLastUpdate !== undefined && (tsCurrent - tsLastUpdate) < delay)
|
||||
return;
|
||||
tsLastUpdate = tsCurrent;
|
||||
|
||||
|
@ -30,29 +33,94 @@ const MszLoadingIcon = function() {
|
|||
|
||||
++counter;
|
||||
} finally {
|
||||
if(playResolve)
|
||||
try {
|
||||
playResolve();
|
||||
} finally {
|
||||
playResolve = undefined;
|
||||
playing = true;
|
||||
}
|
||||
|
||||
if(pauseResolve)
|
||||
try {
|
||||
pauseResolve();
|
||||
} finally {
|
||||
pauseResolve = undefined;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
if(playing)
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
};
|
||||
|
||||
const play = () => {
|
||||
if(playing)
|
||||
return;
|
||||
playing = true;
|
||||
requestAnimationFrame(update);
|
||||
return new Promise(resolve => {
|
||||
if(playing || playResolve) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
playResolve = resolve;
|
||||
requestAnimationFrame(update);
|
||||
});
|
||||
};
|
||||
const pause = () => {
|
||||
return new Promise(resolve => {
|
||||
if(!playing || pauseResolve) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
pauseResolve = resolve;
|
||||
});
|
||||
};
|
||||
const stop = async () => {
|
||||
await pause();
|
||||
counter = 0;
|
||||
};
|
||||
const restart = async () => {
|
||||
await stop();
|
||||
await play();
|
||||
};
|
||||
const reverse = () => {
|
||||
blocks.reverse();
|
||||
};
|
||||
const setBlock = (num, state=null) => {
|
||||
element.children[num].classList.toggle('msz-loading-icon-block-hidden', !state);
|
||||
};
|
||||
const batsu = () => {
|
||||
setBlock(0, true);setBlock(1, false);setBlock(2, true);
|
||||
setBlock(3, false);setBlock(4, true);setBlock(5, false);
|
||||
setBlock(6, true);setBlock(7, false);setBlock(8, true);
|
||||
};
|
||||
const maru = () => {
|
||||
setBlock(0, true);setBlock(1, true);setBlock(2, true);
|
||||
setBlock(3, true);setBlock(4, false);setBlock(5, true);
|
||||
setBlock(6, true);setBlock(7, true);setBlock(8, true);
|
||||
};
|
||||
const pause = () => { playing = false; };
|
||||
const stop = () => { pause(); counter = 0; };
|
||||
const restart = () => { stop(); play(); };
|
||||
|
||||
return {
|
||||
get element() { return element; },
|
||||
get playing() { return playing; },
|
||||
get delay() { return delay; },
|
||||
set delay(value) {
|
||||
if(typeof value !== 'number')
|
||||
value = parseFloat(value);
|
||||
if(isNaN(value) || !isFinite(value))
|
||||
return;
|
||||
if(value < 0)
|
||||
value = Math.abs(value);
|
||||
delay = value;
|
||||
},
|
||||
|
||||
play: play,
|
||||
pause: pause,
|
||||
stop: stop,
|
||||
restart: restart,
|
||||
play,
|
||||
pause,
|
||||
stop,
|
||||
restart,
|
||||
reverse,
|
||||
batsu,
|
||||
maru,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
mask-image: linear-gradient(0deg, transparent 10%, var(--background-colour) 100%);
|
||||
-webkit-mask-image: linear-gradient(0deg, transparent 10%, var(--background-colour) 100%);
|
||||
background: var(--background-pattern);
|
||||
background-color: var(--accent-colour);
|
||||
background-blend-mode: multiply;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
(async () => {
|
||||
const status = document.querySelector('.js-status');
|
||||
status.textContent = 'Looking up DID...';
|
||||
|
||||
let did = null;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${location.protocol}//${BSKY_HANDLE}/.well-known/atproto-did`);
|
||||
did = await response.text();
|
||||
} catch(ex) {
|
||||
status.style.color = 'red';
|
||||
status.textContent = `Could not find DID! ${ex}`;
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof did !== 'string' || !did.startsWith('did:')) {
|
||||
status.style.color = 'red';
|
||||
status.textContent = 'Look up result was not a valid DID.';
|
||||
return;
|
||||
}
|
||||
|
||||
const url = BSKY_FORMAT.replace('%s', did);
|
||||
status.textContent = `Redirecting to ${url}...`;
|
||||
location.replace(url);
|
||||
})();
|
|
@ -1,39 +0,0 @@
|
|||
(async () => {
|
||||
const status = document.querySelector('.js-status');
|
||||
status.textContent = 'Looking up Fediverse profile...';
|
||||
|
||||
let url = null;
|
||||
try {
|
||||
const response = await fetch(`${location.protocol}//${FEDI_INSTANCE}/.well-known/webfinger?format=json&resource=acct:${FEDI_USERNAME}@${FEDI_INSTANCE}`);
|
||||
const webfinger = await response.json();
|
||||
|
||||
if(typeof webfinger === 'object') {
|
||||
if(Array.isArray(webfinger.links))
|
||||
for(const link of webfinger.links)
|
||||
if(typeof link === 'object' && link.rel === 'http://webfinger.net/rel/profile-page' && typeof link.href === 'string') {
|
||||
url = link.href;
|
||||
break;
|
||||
}
|
||||
|
||||
if(typeof url !== 'string' && Array.isArray(webfinger.aliases))
|
||||
for(const alias of webfinger.aliases)
|
||||
if(typeof alias === 'string') {
|
||||
url = alias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(ex) {
|
||||
status.style.color = 'red';
|
||||
status.textContent = `Could not complete Webfinger lookup! ${ex}`;
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof url !== 'string' || (!url.startsWith('https://') && !url.startsWith('http://'))) {
|
||||
status.style.color = 'red';
|
||||
status.textContent = 'Could not find an acceptable profile URL.';
|
||||
return;
|
||||
}
|
||||
|
||||
status.textContent = `Redirecting to ${url}...`;
|
||||
location.replace(url);
|
||||
})();
|
42
assets/redirects.css/landing.css
Normal file
42
assets/redirects.css/landing.css
Normal file
|
@ -0,0 +1,42 @@
|
|||
.redir-landing {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.redir-landing-content {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
background: #191919;
|
||||
box-shadow: 0 1px 2px #0009;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.redir-landing-body {
|
||||
text-align: center;
|
||||
}
|
||||
.redir-landing-body p {
|
||||
margin: .5em;
|
||||
}
|
||||
|
||||
.redir-landing-footer {
|
||||
font-size: .8em;
|
||||
line-height: 1.4em;
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.redir-landing-logo {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-color: #fff;
|
||||
mask: url('/images/flashii.svg') no-repeat center;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
margin: 10px;
|
||||
font-size: 0;
|
||||
}
|
54
assets/redirects.css/main.css
Normal file
54
assets/redirects.css/main.css
Normal file
|
@ -0,0 +1,54 @@
|
|||
:root {
|
||||
--accent-colour: #8559a5;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #111;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 25px;
|
||||
font-family: var(--font-regular);
|
||||
overflow-y: scroll;
|
||||
position: static;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1e90ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:visited {
|
||||
color: #6B4F80;
|
||||
}
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.redir-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
mask-image: linear-gradient(315deg, #000f 0, #0000 40%);
|
||||
background: url('/images/clouds.png');
|
||||
background-color: var(--accent-colour);
|
||||
background-blend-mode: multiply;
|
||||
}
|
||||
|
||||
.redir-foreground {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@include landing.css;
|
||||
@include social.css;
|
26
assets/redirects.css/social.css
Normal file
26
assets/redirects.css/social.css
Normal file
|
@ -0,0 +1,26 @@
|
|||
.redir-social {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.redir-social-content {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
background: #191919;
|
||||
box-shadow: 0 1px 2px #0009;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.redir-social-body {
|
||||
text-align: center;
|
||||
}
|
||||
.redir-social-body p {
|
||||
margin: .5em;
|
||||
line-height: 1.4em;
|
||||
}
|
32
assets/redirects.js/bsky.jsx
Normal file
32
assets/redirects.js/bsky.jsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
const MszRedirectsBsky = async () => {
|
||||
const loading = new MszLoading({ element: '.js-loading', size: 2, inline: true });
|
||||
|
||||
const statusBig = document.querySelector('.js-status-big');
|
||||
const statusSmall = document.querySelector('.js-status-small');
|
||||
const setStatusSmall = body => {
|
||||
$removeChildren(statusSmall);
|
||||
$appendChild(statusSmall, body);
|
||||
};
|
||||
|
||||
setStatusSmall(<>Resolving ATProto DID for @{BSKY_HANDLE}...</>);
|
||||
|
||||
try {
|
||||
const { body } = await $xhr.get(`${location.protocol}//${BSKY_HANDLE}/.well-known/atproto-did`);
|
||||
if(typeof body !== 'string' || !body.startsWith('did:'))
|
||||
throw new Error('Was unable to resolve the given handle.');
|
||||
|
||||
const url = BSKY_FORMAT.replace('%s', body);
|
||||
setStatusSmall(<>Redirecting to <a href={url} rel="noopener">{url}</a>...</>);
|
||||
location.replace(url);
|
||||
} catch(ex) {
|
||||
await loading.icon.stop();
|
||||
loading.icon.batsu();
|
||||
|
||||
let errorText = ex.toString();
|
||||
if(errorText.startsWith('['))
|
||||
errorText = 'Something went wrong.';
|
||||
|
||||
statusBig.textContent = 'Profile not found!';
|
||||
setStatusSmall(<span style="color: red">{errorText}</span>);
|
||||
}
|
||||
};
|
49
assets/redirects.js/fedi.jsx
Normal file
49
assets/redirects.js/fedi.jsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
const MszRedirectsFedi = async () => {
|
||||
const loading = new MszLoading({ element: '.js-loading', size: 2, inline: true });
|
||||
|
||||
const statusBig = document.querySelector('.js-status-big');
|
||||
const statusSmall = document.querySelector('.js-status-small');
|
||||
const setStatusSmall = body => {
|
||||
$removeChildren(statusSmall);
|
||||
$appendChild(statusSmall, body);
|
||||
};
|
||||
|
||||
setStatusSmall(<>Resolving Webfinger resource for @{FEDI_USERNAME}@{FEDI_INSTANCE}...</>);
|
||||
|
||||
try {
|
||||
const { body } = await $xhr.get(`${location.protocol}//${FEDI_INSTANCE}/.well-known/webfinger?format=json&resource=acct:${FEDI_USERNAME}@${FEDI_INSTANCE}`, { type: 'json' });
|
||||
|
||||
let url;
|
||||
if(typeof body === 'object') {
|
||||
if(Array.isArray(body.links))
|
||||
for(const link of body.links)
|
||||
if(typeof link === 'object' && link.rel === 'http://webfinger.net/rel/profile-page' && typeof link.href === 'string') {
|
||||
url = link.href;
|
||||
break;
|
||||
}
|
||||
|
||||
if(typeof url !== 'string' && Array.isArray(body.aliases))
|
||||
for(const alias of body.aliases)
|
||||
if(typeof alias === 'string') {
|
||||
url = alias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof url !== 'string' || (!url.startsWith('https://') && !url.startsWith('http://')))
|
||||
throw new Error('Unable to resolve profile URL for given handle.');
|
||||
|
||||
setStatusSmall(<>Redirecting to <a href={url} rel="noopener">{url}</a>...</>);
|
||||
location.replace(url);
|
||||
} catch(ex) {
|
||||
await loading.icon.stop();
|
||||
loading.icon.batsu();
|
||||
|
||||
let errorText = ex.toString();
|
||||
if(errorText.startsWith('['))
|
||||
errorText = 'Something went wrong.';
|
||||
|
||||
statusBig.textContent = 'Profile not found!';
|
||||
setStatusSmall(<span style="color: red">{errorText}</span>);
|
||||
}
|
||||
};
|
9
assets/redirects.js/main.js
Normal file
9
assets/redirects.js/main.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include bsky.jsx
|
||||
#include fedi.jsx
|
||||
|
||||
(() => {
|
||||
if(location.pathname === '/bsky' || location.pathname.startsWith('/bsky/'))
|
||||
MszRedirectsBsky();
|
||||
if(location.pathname === '/fedi' || location.pathname.startsWith('/fedi/'))
|
||||
MszRedirectsFedi();
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue