dynamic loading and like one animation, closes #1!

This commit is contained in:
flash 2020-10-30 13:43:48 +00:00
parent 0af2b7303a
commit 493ad2cb9b
6 changed files with 248 additions and 56 deletions

View file

@ -1,14 +1,15 @@
<?php
$quotes = isset($quotes) && is_array($quotes) ? $quotes : FM_FEET;
$baseUrl = empty($external) ? '' : '//' . $_SERVER['HTTP_HOST'];
if(empty($is_index)):
?>
</div>
<?php endif; if(empty($hide)): ?>
<div class="footer">
<div class="footer-text">&copy; flashwave 2010-<?=date('Y');?> - <?=($quotes[array_rand($quotes)]);?></div>
</div>
<?php if(isset($onload) && is_array($onload)): ?>
<script type="text/javascript">
window.fm = { onload: <?=json_encode($onload);?> };
</script>
<?php endif; ?>
<script src="<?=$baseUrl;?>/assets/2020v2.js" charset="utf-8" type="text/javascript"></script>
<?php if(isset($scripts) && is_array($scripts)) foreach($scripts as $script): ?>

View file

@ -2,6 +2,7 @@
$menu = isset($menu) && is_array($menu) ? $menu : FM_NAV;
$backgrounds = isset($backgrounds) && is_array($backgrounds) ? $backgrounds : FM_BGS;
$baseUrl = empty($external) ? '' : '//' . $_SERVER['HTTP_HOST'];
$showNowPlaying = !empty($is_index) || !empty($do_fullscreen_header);
?>
<!doctype html>
<html>
@ -16,38 +17,35 @@ $baseUrl = empty($external) ? '' : '//' . $_SERVER['HTTP_HOST'];
<link href="<?=$style;?>" type="text/css" rel="stylesheet"/>
<?php endforeach;?>
</head>
<body class="<?php if(isset($is_index)) { echo 'index';} if(isset($do_fullscreen_header)) { echo 'fullscreen-header';} ?>">
<body class="<?php if(isset($is_index)) { echo 'index ';} if(isset($do_fullscreen_header)) { echo 'fullscreen-header ';} if(isset($is_now_playing)) { echo 'now-playing ';} ?>">
<div class="header">
<div class="header-background">
<img src="<?=($backgrounds[array_rand($backgrounds)]);?>" alt=""/>
</div>
<div class="header-foreground"<?php if(isset($offset) && $offset > 0) echo " style=\"padding-bottom: {$offset}px\""; ?>>
<a class="header-logo" href="/">
<a class="header-logo" href="/" data-fm-dynload="">
<div class="header-flash">flash</div>
<div class="header-wave">wave</div>
</a>
<?php if(!empty($is_index) || !empty($do_fullscreen_header)): ?>
<div class="header-now-playing header-now-playing-hidden">
<div class="header-now-playing-icon" title="Now listening to...">
<a href="/now-listening"><div class="fmi fmi-music"></div></a>
<div class="header-right">
<div class="header-now-playing header-now-playing-hidden">
<div class="header-now-playing-icon" title="Now listening to...">
<a href="/now-listening" data-fm-dynload=""><div class="fmi fmi-music"></div></a>
</div>
<div class="header-now-playing-cover">
<img src="//now.flash.moe/resources/no-cover.png" alt=""/>
</div>
<div class="header-now-playing-details">
<div class="header-now-playing-title"><a href="#" target="_blank" rel="noopener"></a></div>
<div class="header-now-playing-artist"><a href="#" target="_blank" rel="noopener"></a></div>
</div>
</div>
<div class="header-now-playing-cover">
<img src="//now.flash.moe/resources/no-cover.png" alt=""/>
</div>
<div class="header-now-playing-details">
<div class="header-now-playing-title"><a href="#" target="_blank" rel="noopener"></a></div>
<div class="header-now-playing-artist"><a href="#" target="_blank" rel="noopener"></a></div>
</div>
</div>
<?php else: ?>
<div class="header-menu">
<div class="header-menu">
<?php foreach($menu as $link): ?>
<a href="<?=$link['link'];?>"><?=$link['title'];?></a>
<a href="<?=$link['link'];?>"<?php if($link['link'][0] === '/' && substr($link['link'], 0, 2) !== '//') { echo ' data-fm-dynload=""'; } ?>><?=$link['title'];?></a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
<?php if(empty($is_index) && empty($do_fullscreen_header)): ?>
<div class="container">
<?php endif; ?>

View file

@ -30,13 +30,14 @@ if($reqPath === '/now-listening') {
fm_component('header', [
'title' => 'flash.moe / now listening',
'do_fullscreen_header' => true,
'is_now_playing' => true,
'offset' => $offset,
]);
?>
<script>window.addEventListener('load', function() { window.fm.initIndex(10); });</script>
<?php
fm_component('footer', [
'hide' => true,
'onload' => [
['fm.initIndex', 10],
],
]);
return FM_HIT;
@ -88,11 +89,14 @@ if($reqPath === '/home') {
</div>
</form>
</div>
<script>window.addEventListener('load', function() { window.fm.initClock(); window.fm.initIndex(10); });</script>
<?php
fm_component('footer', [
'hide' => true,
'skip_analytics' => true,
'onload' => [
['fm.initClock'],
['fm.initIndex', 10],
],
]);
return FM_HIT;
@ -180,7 +184,7 @@ if($reqPath === '/') {
?>
<div class="index-menu">
<?php for($i = 1; $i < count(FM_NAV); ++$i): ?>
<a href="<?=(FM_NAV[$i]['link']);?>"><?=(FM_NAV[$i]['title']);?></a>
<a href="<?=(FM_NAV[$i]['link']);?>"<?php if(FM_NAV[$i]['link'][0] === '/' && substr(FM_NAV[$i]['link'], 0, 2) !== '//') { echo ' data-fm-dynload=""'; } ?>><?=(FM_NAV[$i]['title']);?></a>
<?php endfor; ?>
</div>
<div class="index-featured">
@ -267,10 +271,12 @@ foreach($projInfo as $proj):
</div>
</div>
</div>
<script>window.addEventListener('load', function() { window.fm.initIndex(); });</script>
<?php
fm_component('footer', [
'is_index' => true,
'onload' => [
['fm.initIndex'],
],
]);
return FM_HIT;

View file

@ -16,6 +16,10 @@ html {
scrollbar-color: #4a3650 #111;
}
.hidden {
display: none !important;
}
/* an attempt to replicate scrollbar-color for chromosome */
::-webkit-scrollbar {
width: 6px;
@ -46,6 +50,7 @@ body {
width: 100%;
height: 200px;
overflow: hidden;
transition: height .5s;
}
@media (max-width: 700px) {
.header { height: auto; }
@ -120,10 +125,21 @@ body {
background-image: linear-gradient(0deg, #281430 0%, #392540 50%, #4a3650 50%, #6c5871 100%);
-webkit-background-clip: text;
}
.header-right {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.header-menu {
display: flex;
justify-content: center;
flex: 0 0 auto;
margin-top: 10px;
}
.index .header-menu,
.fullscreen-header .header-menu,
.now-playing .header-menu {
display: none;
}
.header-menu a {
display: block;
@ -167,6 +183,11 @@ body {
}
.footer {}
.index .footer,
.fullscreen-header .footer,
.now-playing .footer {
display: none;
}
.footer-text {
opacity: .2;
font-size: .9em;

View file

@ -12,14 +12,43 @@ Date.prototype.getWeekYear = function() {
}
window.fm = (function() {
var fm = this;
this.container = document.querySelector('.container');
this.headerBackground = null;
this.originalHeaderBackground = null;
this.defaultCoverImage = 'https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png';
this.indexIsPlaying = false;
this.indexPlayingDefaultCover = false;
this.indexPlayingContainer = null;
this.indexPlayingCover = null;
this.indexPlayingTitle = null;
this.indexPlayingArtist = null;
this.indexLastNp = null;
this.indexPlayingInterval = null;
this.homeInterval = null;
this.callByName = function(name, args) {
var ref = window,
parent = null,
parts = name.split('.');
for(var i = 0; i < parts.length; ++i) {
parent = ref;
if(typeof ref[parts[i]] !== 'undefined')
ref = ref[parts[i]];
else return;
}
if(typeof ref !== 'function')
return;
return ref.apply(parent, args);
};
this.runFuncs = function(funcs) {
for(var i = 0; i < funcs.length; ++i)
fm.callByName(funcs[i][0], funcs[i].slice(1));
};
if(this.onload && Array.isArray(this.onload))
window.addEventListener('load', function() { fm.runFuncs(fm.onload); });
if(sessionStorage.getItem('header-bgs') === null
|| sessionStorage.getItem('header-bgs-loaded') < Date.now() - 86400000) {
@ -32,6 +61,83 @@ window.fm = (function() {
hXhr.send();
}
this.dynloadCurrent = function() {
return {
components: {
header: {
title: document.title,
is_index: document.body.classList.contains('index'),
do_fullscreen_header: document.body.classList.contains('fullscreen-header'),
is_now_playing: document.body.classList.contains('now-playing'),
},
footer: {
onload: this.onload || [],
}
},
raw_html: fm.container.innerHTML,
};
};
this.dynloadApply = function(state) {
if((state.components || {}).header) {
document.title = state.components.header.title || '';
document.body.classList[state.components.header.is_index ? 'add' : 'remove']('index');
document.body.classList[state.components.header.do_fullscreen_header ? 'add' : 'remove']('fullscreen-header');
document.body.classList[state.components.header.is_now_playing ? 'add' : 'remove']('now-playing');
}
if(typeof state.raw_html !== 'undefined')
this.container.innerHTML = state.raw_html;
if((state.components || {}).footer) {
this.runFuncs(state.components.footer.onload || []);
}
fm.dynloadInit();
fm.setRandomHeaderBackgroundIfNotPlaying();
};
this.dynloadInit = function(initial) {
if(initial) {
history.replaceState(this.dynloadCurrent(), document.title, location.toString());
window.addEventListener('popstate', function(ev) {
fm.dynloadApply(ev.state || {});
});
}
var dynload = document.querySelectorAll('[data-fm-dynload]');
for(var i = 0; i < dynload.length; ++i)
(function(dc){
dc.removeAttribute('data-fm-dynload');
dc.addEventListener('click', function(ev) {
ev.stopPropagation();
ev.preventDefault();
var xhr = new XMLHttpRequest;
xhr.onload = function() {
try {
var obj = JSON.parse(xhr.responseText);
} catch(ex) {}
if(!obj) {
location.assign(dc.href);
return;
}
var title = ((obj.components || {}).header || {}).title || '';
history.pushState(obj, title, dc.href);
fm.dynloadApply(obj);
};
xhr.onerror = function(ev) {
location.assign(dc.href);
};
xhr.open('GET', dc.href);
xhr.setRequestHeader('Accept', 'application/x-fdynload+json');
xhr.send();
}, true);
})(dynload[i]);
};
this.dynloadInit(true);
this.selectTextInElement = function(elem) {
// MSIE
if(document.body.createTextRange) {
@ -86,14 +192,16 @@ window.fm = (function() {
this.indexLastNp = info;
} else return;
this.indexIsPlaying = info.now_playing;
this.indexPlayingDefaultCover = !info.cover || info.cover === this.defaultCoverImage;
this.indexPlayingContainer.classList[info.now_playing ? 'remove' : 'add']('header-now-playing-hidden');
this.indexPlayingCover.alt = this.indexPlayingCover.src = (info.cover !== this.defaultCoverImage ? info.cover : '//now.flash.moe/resources/no-cover.png');
this.indexPlayingTitle.textContent = this.indexPlayingTitle.title = info.name;
this.indexPlayingTitle.href = info.url;
this.indexPlayingArtist.textContent = this.indexPlayingArtist.title = info.artist.name;
this.indexPlayingArtist.href = info.artist.url;
this.indexPlayingArtist.textContent = this.indexPlayingArtist.title = (info.artist || {}).name || '';
this.indexPlayingArtist.href = (info.artist || {}).url || '';
this.switchHeaderBackground(
info.now_playing && info.cover !== this.defaultCoverImage
info.now_playing && !this.indexPlayingDefaultCover
? this.indexPlayingCover.src
: this.originalHeaderBackground
);
@ -104,20 +212,27 @@ window.fm = (function() {
var set = JSON.parse(sessionStorage.getItem('header-bgs'));
if(!set)
return '/assets/errors/404.jpg';
return set[parseInt(Math.random() * set.length)];
return set[parseInt(Math.random() * set.length) - 1];
};
this.setRandomHeaderBackground = function() {
this.switchHeaderBackground(this.getRandomHeaderBackground());
};
this.setRandomHeaderBackgroundIfNotPlaying = function() {
if(!this.indexIsPlaying || this.indexPlayingDefaultCover)
this.setRandomHeaderBackground();
};
this.getCurrentHeaderBackground = function() {
return this.headerBackground.querySelector('img').src;
};
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground = function(url) {
if(this.getCurrentHeaderBackground() === url)
if(this.headerBackgroundIsChanging || this.getCurrentHeaderBackground() === url)
return;
this.headerBackgroundIsChanging = true;
var newImg = document.createElement('img'),
oldImg = this.headerBackground.querySelector('img');
newImg.alt = newImg.src = url;
@ -131,10 +246,12 @@ window.fm = (function() {
setTimeout(function() {
newImg.style.zIndex = null;
this.headerBackground.removeChild(oldImg);
this.headerBackgroundIsChanging = false;
}.bind(this), 500);
}.bind(this), 50);
}.bind(this);
newImg.onerror = function() {
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground(this.originalHeaderBackground);
}.bind(this);
};
@ -143,18 +260,29 @@ window.fm = (function() {
this.originalHeaderBackground = this.headerBackground.querySelector('img').src;
this.initIndex = function(npInterval) {
this.indexPlayingContainer = document.querySelector('.header-now-playing');
this.indexPlayingCover = window.fm.indexPlayingContainer.querySelector('.header-now-playing-cover img');
this.indexPlayingCover.onerror = function() {
this.indexPlayingCover.src = '//now.flash.moe/resources/no-cover.png';
}.bind(this);
this.indexPlayingTitle = window.fm.indexPlayingContainer.querySelector('.header-now-playing-title a');
this.indexPlayingArtist = window.fm.indexPlayingContainer.querySelector('.header-now-playing-artist a');
if(!this.indexPlayingContainer) {
this.indexPlayingContainer = document.querySelector('.header-now-playing');
this.indexPlayingCover = window.fm.indexPlayingContainer.querySelector('.header-now-playing-cover img');
this.indexPlayingCover.onerror = function() {
this.indexPlayingCover.src = '//now.flash.moe/resources/no-cover.png';
}.bind(this);
this.indexPlayingTitle = window.fm.indexPlayingContainer.querySelector('.header-now-playing-title a');
this.indexPlayingArtist = window.fm.indexPlayingContainer.querySelector('.header-now-playing-artist a');
}
if(this.indexPlayingInterval) {
clearInterval(this.indexPlayingInterval);
this.indexPlayingInterval = null;
}
this.updateIndexNowListening();
setInterval(this.updateIndexNowListening, (npInterval || 30) * 1000);
this.indexPlayingInterval = setInterval(this.updateIndexNowListening, (npInterval || 30) * 1000);
};
this.initClock = function() {
if(this.homeInterval)
return;
var digitalClock = document.querySelector('.php-time-digital'),
analogClock = document.querySelector('.php-time-analog'),
dateZone = document.querySelector('.php-time-date'),
@ -169,7 +297,13 @@ window.fm = (function() {
dateMonth = dateZone.querySelector('.php-date-month'),
dateYear = dateZone.querySelector('.php-date-year');
setInterval(function() {
this.homeInterval = setInterval(function() {
if(!document.body.contains(digitalClock)) {
clearInterval(this.homeInterval);
this.homeInterval = null;
return;
}
var time = new Date;
var dHour = time.getHours(),
@ -196,7 +330,7 @@ window.fm = (function() {
angHours.style.setProperty('--hand-rotation', (rHour * 360).toString() + 'deg');
angMinutes.style.setProperty('--hand-rotation', (rMin * 360).toString() + 'deg');
angSeconds.style.setProperty('--hand-rotation', (rSec * 360).toString() + 'deg');
}, 200);
}.bind(this), 200);
};
return this;

View file

@ -67,7 +67,17 @@ define('FM_ERRS' , [
],
]);
define('FM_DYNLOAD', filter_input(INPUT_SERVER, 'HTTP_ACCEPT') === 'application/x-fdynload+json');
function fm_component(string $_component_name, array $vars = []) {
if(FM_DYNLOAD) {
global $fmComponentVars;
if(!isset($fmComponentVars))
$fmComponentVars = [];
$fmComponentVars[$_component_name] = $vars;
return;
}
extract($vars);
require __DIR__ . '/../components/' . $_component_name . '.php';
}
@ -129,6 +139,9 @@ if($reqMethod == 'HEAD') {
$reqHead = true;
}
if(FM_DYNLOAD)
ob_start();
if(substr($reqPath, 0, 7) === '/error/') {
$statusCode = intval(substr($reqPath, 7, 3));
} else {
@ -138,24 +151,43 @@ if(substr($reqPath, 0, 7) === '/error/') {
if(($result & FM_HIT) === FM_HIT) {
if($statusCode >= 100 && $statusCode <= 999)
http_response_code($statusCode);
return;
else
$statusCode = 200;
break;
}
if(($result & FM_ERR) === FM_ERR)
break;
}
// Make sure we have a valid error code
if($statusCode < 100)
$statusCode = 404;
}
$errorInfo = FM_ERRS[$statusCode ?? 404] ?? FM_ERRS[404];
http_response_code($errorInfo['code']);
if($statusCode >= 400 && $statusCode <= 599 && ob_get_length() < 1) {
$errorInfo = FM_ERRS[$statusCode ?? 404] ?? FM_ERRS[404];
http_response_code($errorInfo['code']);
if(!$reqHead) {
fm_component('header', ['title' => $errorInfo['title']]);
if(!$reqHead) {
fm_component('header', ['title' => $errorInfo['title']]);
?>
<div class="http-error">
<h2 class="http-error-head"><?=$errorInfo['title'];?></h2>
<img src="<?=$errorInfo['image'];?>" alt="<?=$errorInfo['image'];?>" class="http-error-image"/>
<div class="http-error-desc"><?=$errorInfo['desc'];?></div>
</div>
<div class="http-error">
<h2 class="http-error-head"><?=$errorInfo['title'];?></h2>
<img src="<?=$errorInfo['image'];?>" alt="<?=$errorInfo['image'];?>" class="http-error-image"/>
<div class="http-error-desc"><?=$errorInfo['desc'];?></div>
</div>
<?php
fm_component('footer');
fm_component('footer');
}
}
if(FM_DYNLOAD) {
$contents = ob_get_contents();
ob_end_clean();
header('Content-Type: application/x-fdynload+json');
echo json_encode([
'components' => $fmComponentVars ?? [],
'raw_html' => $contents,
]);
}