Add avif support
This commit is contained in:
parent
44bcbe2647
commit
5645572bb6
16 changed files with 99 additions and 50 deletions
|
@ -24,10 +24,14 @@ export function serve(docRoot, pathname, options = {}) {
|
||||||
|| filepath.endsWith('.png')
|
|| filepath.endsWith('.png')
|
||||||
|| filepath.endsWith('.js')
|
|| filepath.endsWith('.js')
|
||||||
|| filepath.endsWith('.css')
|
|| filepath.endsWith('.css')
|
||||||
|
|| filepath.endsWith('.avif')
|
||||||
|| filepath.endsWith('.svg')) {
|
|| filepath.endsWith('.svg')) {
|
||||||
if (filepath.indexOf('admin') === -1) {
|
if (filepath.indexOf('admin') === -1) {
|
||||||
opts = defaults({ maxage: 2592000 * 1000 }, opts)
|
opts = defaults({ maxage: 2592000 * 1000 }, opts)
|
||||||
}
|
}
|
||||||
|
if (filepath.endsWith('.avif')) {
|
||||||
|
ctx.type = 'image/avif'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filepath === '/index.html') {
|
if (filepath === '/index.html') {
|
||||||
|
@ -48,6 +52,7 @@ export function serve(docRoot, pathname, options = {}) {
|
||||||
|
|
||||||
return send(ctx, filepath, opts).catch((er) => {
|
return send(ctx, filepath, opts).catch((er) => {
|
||||||
if (er.code === 'ENOENT' && er.status === 404) {
|
if (er.code === 'ENOENT' && er.status === 404) {
|
||||||
|
ctx.type = null
|
||||||
return serveIndex(ctx, filepath)
|
return serveIndex(ctx, filepath)
|
||||||
// return send(ctx, '/index.html', options)
|
// return send(ctx, '/index.html', options)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,10 +50,9 @@ const Article = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onupdate: function(vnode) {
|
onbeforeupdate: function(vnode) {
|
||||||
if (this.path !== m.route.param('id')) {
|
if (this.path !== m.route.param('id')) {
|
||||||
this.fetchArticle(vnode)
|
this.fetchArticle(vnode)
|
||||||
m.redraw()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,11 @@ const Darkmode = {
|
||||||
setDarkMode: function(setOn) {
|
setDarkMode: function(setOn) {
|
||||||
if (setOn) {
|
if (setOn) {
|
||||||
localStorage.setItem(storageName, true)
|
localStorage.setItem(storageName, true)
|
||||||
document.body.className = 'darkmodeon'
|
document.body.className = 'darkmodeon' + ' ' + (window.supportsavif ? 'avifsupport' : 'jpegonly')
|
||||||
Darkmode.darkIsOn = true
|
Darkmode.darkIsOn = true
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem(storageName)
|
localStorage.removeItem(storageName)
|
||||||
document.body.className = 'daymode'
|
document.body.className = 'daymode' + ' ' + (window.supportsavif ? 'avifsupport' : 'jpegonly')
|
||||||
Darkmode.darkIsOn = false
|
Darkmode.darkIsOn = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -87,14 +87,18 @@ footer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.daymode footer .footer-logo {
|
.daymode.jpegonly footer .footer-logo {
|
||||||
background-image: url("/assets/img/tsun_small.jpg");
|
background-image: url("/assets/img/tsun_small.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.darkmodeon footer .footer-logo {
|
.darkmodeon.jpegonly footer .footer-logo {
|
||||||
background-image: url("/assets/img/dark_tsun_small.jpg");
|
background-image: url("/assets/img/dark_tsun_small.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avifsupport footer .footer-logo {
|
||||||
|
background-image: url("/assets/img/tsun.avif");
|
||||||
|
}
|
||||||
|
|
||||||
@media
|
@media
|
||||||
only screen and (-webkit-min-device-pixel-ratio: 2),
|
only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||||
only screen and ( min--moz-device-pixel-ratio: 2),
|
only screen and ( min--moz-device-pixel-ratio: 2),
|
||||||
|
@ -102,11 +106,11 @@ only screen and ( -o-min-device-pixel-ratio: 2/1),
|
||||||
only screen and ( min-device-pixel-ratio: 2),
|
only screen and ( min-device-pixel-ratio: 2),
|
||||||
only screen and ( min-resolution: 192dpi),
|
only screen and ( min-resolution: 192dpi),
|
||||||
only screen and ( min-resolution: 2dppx) {
|
only screen and ( min-resolution: 2dppx) {
|
||||||
.daymode .footer-logo {
|
.daymode.jpegonly .footer-logo {
|
||||||
background-image: url("/assets/img/tsun.jpg");
|
background-image: url("/assets/img/tsun.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.darkmodeon .footer-logo {
|
.darkmodeon.jpegonly .footer-logo {
|
||||||
background-image: url("/assets/img/dark_tsun.jpg");
|
background-image: url("/assets/img/dark_tsun.jpg");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,8 @@ const Frontpage = {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(bannerPath
|
(bannerPath
|
||||||
? m('a.frontpage-banner', {
|
? m(m.route.Link, {
|
||||||
|
class: 'frontpage-banner',
|
||||||
href: '/article/' + this.featured.path,
|
href: '/article/' + this.featured.path,
|
||||||
style: { 'background-image': 'url("' + bannerPath + '")' },
|
style: { 'background-image': 'url("' + bannerPath + '")' },
|
||||||
},
|
},
|
||||||
|
@ -131,7 +132,9 @@ const Frontpage = {
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
m('div.asunaside'),
|
m('div.asunaside', {
|
||||||
|
class: window.supportsavif ? 'avif' : 'jpeg'
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
m('.frontpage-news', [
|
m('.frontpage-news', [
|
||||||
(this.loading
|
(this.loading
|
||||||
|
|
|
@ -137,13 +137,19 @@ frontpage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.daymode frontpage .asunaside {
|
.daymode.jpegonly frontpage .asunaside {
|
||||||
background-image: url("/assets/img/asuna_frontpage.jpg");
|
background-image: url("/assets/img/asuna_frontpage.jpg");
|
||||||
}
|
}
|
||||||
|
.daymode.avifsupport frontpage .asunaside {
|
||||||
|
background-image: url("/assets/img/asuna_frontpage.avif");
|
||||||
|
}
|
||||||
|
|
||||||
.darkmodeon frontpage .asunaside {
|
.darkmodeon.jpegonly frontpage .asunaside {
|
||||||
background-image: url("/assets/img/dark_asuna_frontpage.jpg");
|
background-image: url("/assets/img/dark_asuna_frontpage.jpg");
|
||||||
}
|
}
|
||||||
|
.darkmodeon.avifsupport frontpage .asunaside {
|
||||||
|
background-image: url("/assets/img/dark_asuna_frontpage.avif");
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 480px){
|
@media screen and (max-width: 480px){
|
||||||
.frontpage-banner {
|
.frontpage-banner {
|
||||||
|
|
21
app/index.js
21
app/index.js
|
@ -3,15 +3,6 @@ require('./polyfill')
|
||||||
const m = require('mithril')
|
const m = require('mithril')
|
||||||
window.m = m
|
window.m = m
|
||||||
|
|
||||||
/*
|
|
||||||
* imgsupport.js from leechy/imgsupport
|
|
||||||
*/
|
|
||||||
const AVIF = new Image();
|
|
||||||
AVIF.onload = AVIF.onerror = function () {
|
|
||||||
window.supportsavif = (AVIF.height === 2)
|
|
||||||
}
|
|
||||||
AVIF.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=';
|
|
||||||
|
|
||||||
m.route.setOrig = m.route.set
|
m.route.setOrig = m.route.set
|
||||||
m.route.set = function(path, data, options){
|
m.route.set = function(path, data, options){
|
||||||
m.route.setOrig(path, data, options)
|
m.route.setOrig(path, data, options)
|
||||||
|
@ -119,6 +110,18 @@ const allRoutes = {
|
||||||
'/admin/:path/:id': AdminResolver,
|
'/admin/:path/:id': AdminResolver,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait until we finish checking avif support, some views render immediately and will ask for this immediately before the callback gets called.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* imgsupport.js from leechy/imgsupport
|
||||||
|
*/
|
||||||
|
const AVIF = new Image();
|
||||||
|
AVIF.onload = AVIF.onerror = function () {
|
||||||
|
window.supportsavif = (AVIF.height === 2)
|
||||||
|
document.body.className = document.body.className + ' ' + (window.supportsavif ? 'avifsupport' : 'jpegonly')
|
||||||
|
|
||||||
m.route(mainRoot, '/', allRoutes)
|
m.route(mainRoot, '/', allRoutes)
|
||||||
m.mount(menuRoot, Menu)
|
m.mount(menuRoot, Menu)
|
||||||
m.mount(footerRoot, Footer)
|
m.mount(footerRoot, Footer)
|
||||||
|
}
|
||||||
|
AVIF.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=';
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
color: $primary-dark-fg;
|
color: $primary-dark-fg;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-image: url("/assets/img/logo_small.jpg");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
|
@ -127,6 +126,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avifsupport #nav .top a.logo {
|
||||||
|
background-image: url("/assets/img/logo.avif");
|
||||||
|
}
|
||||||
|
|
||||||
|
.jpegonly #nav .top a.logo {
|
||||||
|
background-image: url("/assets/img/logo_small.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
@media
|
@media
|
||||||
only screen and (-webkit-min-device-pixel-ratio: 2),
|
only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||||
only screen and ( min--moz-device-pixel-ratio: 2),
|
only screen and ( min--moz-device-pixel-ratio: 2),
|
||||||
|
@ -134,7 +141,7 @@ only screen and ( -o-min-device-pixel-ratio: 2/1),
|
||||||
only screen and ( min-device-pixel-ratio: 2),
|
only screen and ( min-device-pixel-ratio: 2),
|
||||||
only screen and ( min-resolution: 192dpi),
|
only screen and ( min-resolution: 192dpi),
|
||||||
only screen and ( min-resolution: 2dppx) {
|
only screen and ( min-resolution: 2dppx) {
|
||||||
#nav .top a.logo {
|
.jpegonly #nav .top a.logo {
|
||||||
background-image: url("/assets/img/logo.jpg");
|
background-image: url("/assets/img/logo.jpg");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,11 @@ const Page = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onupdate: function(vnode) {
|
onbeforeupdate: function(vnode) {
|
||||||
if (this.path !== m.route.param('id')) {
|
if (this.path !== m.route.param('id')) {
|
||||||
this.fetchPage(vnode)
|
this.fetchPage(vnode)
|
||||||
m.redraw()
|
|
||||||
} else if (m.route.param('page') && m.route.param('page') !== this.lastpage) {
|
} else if (m.route.param('page') && m.route.param('page') !== this.lastpage) {
|
||||||
this.fetchArticles(vnode)
|
this.fetchArticles(vnode)
|
||||||
m.redraw()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -146,9 +146,9 @@ newsitem {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
img {
|
picture {
|
||||||
max-height: 360px;
|
max-height: 400px;
|
||||||
max-width: 360px;
|
max-width: 400px;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ pages {
|
||||||
newsitem a.cover {
|
newsitem a.cover {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
||||||
img {
|
picture {
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ pages {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
img {
|
picture {
|
||||||
max-height: unset;
|
max-height: unset;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -25,9 +25,15 @@ const Newsentry = {
|
||||||
}
|
}
|
||||||
return m('newsentry', [
|
return m('newsentry', [
|
||||||
imagePath
|
imagePath
|
||||||
? m('a.cover', {
|
? m(m.route.Link, {
|
||||||
|
class: 'cover',
|
||||||
href: '/article/' + vnode.attrs.path,
|
href: '/article/' + vnode.attrs.path,
|
||||||
}, m('img', { src: imagePath, alt: 'Article image for ' + vnode.attrs.name }))
|
}, m('picture', [
|
||||||
|
m('source', { srcset:
|
||||||
|
vnode.attrs.media.small_url + ''
|
||||||
|
}),
|
||||||
|
m('img', { src: imagePath, alt: 'Article image for ' + vnode.attrs.name }),
|
||||||
|
]))
|
||||||
: m('a.cover.nobg'),
|
: m('a.cover.nobg'),
|
||||||
m('div.entrycontent', [
|
m('div.entrycontent', [
|
||||||
m('div.title', [
|
m('div.title', [
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
const Fileinfo = require('./fileinfo')
|
const Fileinfo = require('./fileinfo')
|
||||||
|
|
||||||
const Newsitem = {
|
const Newsitem = {
|
||||||
|
oninit: function(vnode) {
|
||||||
|
this.srcsetJpeg = vnode.attrs.media.small_url + ' 500w, '
|
||||||
|
+ vnode.attrs.media.medium_url + ' 800w '
|
||||||
|
if (vnode.attrs.media.small_url_avif) {
|
||||||
|
this.srcsetAvif = vnode.attrs.media.small_url_avif + ' 500w, '
|
||||||
|
+ vnode.attrs.media.medium_url_avif + ' 800w '
|
||||||
|
} else {
|
||||||
|
this.srcsetAvif = null
|
||||||
|
}
|
||||||
|
this.coverSizes = '(max-width: 639px) calc(100vw - 40px), '
|
||||||
|
+ '(max-width: 1000px) 300px, '
|
||||||
|
+ '400px'
|
||||||
|
},
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
var pixelRatio = window.devicePixelRatio || 1
|
|
||||||
var jpegImage = pixelRatio > 1 ? vnode.attrs.media.medium_url : vnode.attrs.media.small_url
|
|
||||||
var avifImage = pixelRatio > 1 ? vnode.attrs.media.medium_url_avif : vnode.attrs.media.small_url_avif
|
|
||||||
return m('newsitem', [
|
return m('newsitem', [
|
||||||
m(m.route.Link,
|
m(m.route.Link,
|
||||||
{ href: '/article/' + vnode.attrs.path, class: 'title' },
|
{ href: '/article/' + vnode.attrs.path, class: 'title' },
|
||||||
|
@ -12,16 +23,23 @@ const Newsitem = {
|
||||||
),
|
),
|
||||||
m('div.newsitemcontent', [
|
m('div.newsitemcontent', [
|
||||||
vnode.attrs.media
|
vnode.attrs.media
|
||||||
? m('a.cover', {
|
? m(m.route.Link, {
|
||||||
|
class: 'cover',
|
||||||
href: '/article/' + vnode.attrs.path,
|
href: '/article/' + vnode.attrs.path,
|
||||||
},
|
},
|
||||||
m('picture', [
|
m('picture', [
|
||||||
avifImage ? m('source', {
|
this.srcsetAvif ? m('source', {
|
||||||
srcset: avifImage,
|
srcset: this.srcsetAvif,
|
||||||
|
sizes: this.coverSizes,
|
||||||
type: 'image/avif',
|
type: 'image/avif',
|
||||||
}) : null,
|
}) : null,
|
||||||
m('img', { alt: 'Image for news item ' + vnode.attrs.name, src: jpegImage })
|
m('img', {
|
||||||
]))
|
srcset: this.srcsetJpeg,
|
||||||
|
sizes: this.coverSizes,
|
||||||
|
alt: 'Image for news item ' + vnode.attrs.name,
|
||||||
|
src: vnode.attrs.media.small_url }),
|
||||||
|
])
|
||||||
|
)
|
||||||
: null,
|
: null,
|
||||||
m('div.entrycontent', {
|
m('div.entrycontent', {
|
||||||
class: vnode.attrs.media ? '' : 'extrapadding',
|
class: vnode.attrs.media ? '' : 'extrapadding',
|
||||||
|
|
BIN
public/assets/img/asuna_frontpage.avif
Normal file
BIN
public/assets/img/asuna_frontpage.avif
Normal file
Binary file not shown.
BIN
public/assets/img/dark_asuna_frontpage.avif
Normal file
BIN
public/assets/img/dark_asuna_frontpage.avif
Normal file
Binary file not shown.
BIN
public/assets/img/logo.avif
Normal file
BIN
public/assets/img/logo.avif
Normal file
Binary file not shown.
BIN
public/assets/img/tsun.avif
Normal file
BIN
public/assets/img/tsun.avif
Normal file
Binary file not shown.
Loading…
Reference in a new issue