base: Added /health route.
nfp_moe: Complete re-thinking of all loading. Smarter loading and lighter site. Better user experience among other things.
This commit is contained in:
parent
4b36820f09
commit
6565409e52
17 changed files with 1585 additions and 1008 deletions
|
@ -23,8 +23,12 @@ export default class ArticleRoutes {
|
|||
}
|
||||
|
||||
/** GET: /api/articles/[path] */
|
||||
async getArticle(ctx) {
|
||||
async getArticle(ctx, onlyReturn = false) {
|
||||
let res = await ctx.db.safeCallProc('article_get_single', [ctx.params.path])
|
||||
|
||||
if (onlyReturn) {
|
||||
return this.getArticle_resOutput(res)
|
||||
}
|
||||
|
||||
ctx.body = this.getArticle_resOutput(res)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class ServeHandler {
|
|||
}
|
||||
|
||||
let indexFile = fsSync.readFileSync(path.join(this.root, 'index.html'))
|
||||
this.template = dot.template(indexFile.toString(), { argName: ['headerDescription', 'headerImage', 'headerTitle', 'headerUrl', 'payloadData', 'payloadTree', 'version', 'nonce'] })
|
||||
this.template = dot.template(indexFile.toString(), { argName: ['headerDescription', 'headerImage', 'headerTitle', 'headerUrl', 'payloadData', 'payloadTree', 'version', 'nonce', 'type', 'banner'] })
|
||||
// console.log(indexFile.toString())
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import PageRoutes from './page/routes.mjs'
|
|||
import ArticleRoutes from './article/routes.mjs'
|
||||
import AuthenticationRoutes from './authentication/routes.mjs'
|
||||
import { authenticate } from './authentication/security.mjs'
|
||||
import StaticRoutes from './static_routes.mjs'
|
||||
|
||||
export default class Server {
|
||||
constructor(http, port, core, opts = {}) {
|
||||
|
@ -30,6 +31,7 @@ export default class Server {
|
|||
page: new PageRoutes(),
|
||||
article: new ArticleRoutes(),
|
||||
auth: new AuthenticationRoutes(),
|
||||
static: new StaticRoutes(),
|
||||
}
|
||||
|
||||
this.init()
|
||||
|
@ -54,6 +56,9 @@ export default class Server {
|
|||
ctx.db = pool
|
||||
})
|
||||
this.flaska.before(QueryHandler())
|
||||
|
||||
let healthChecks = 0
|
||||
let healthCollectLimit = 60 * 60 * 12
|
||||
|
||||
this.flaska.after(function(ctx) {
|
||||
let ended = new Date().getTime()
|
||||
|
@ -69,6 +74,18 @@ export default class Server {
|
|||
level = 'error'
|
||||
}
|
||||
|
||||
if (ctx.url === '/health') {
|
||||
healthChecks++
|
||||
if (healthChecks >= healthCollectLimit) {
|
||||
ctx.log[level]({
|
||||
duration: Math.round(ended),
|
||||
status: ctx.status,
|
||||
}, `<-- ${status}${ctx.method} ${ctx.url} {has happened ${healthChecks} times}`)
|
||||
healthChecks = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.log[level]({
|
||||
duration: requestTime,
|
||||
status: ctx.status,
|
||||
|
|
17
base/static_routes.mjs
Normal file
17
base/static_routes.mjs
Normal file
|
@ -0,0 +1,17 @@
|
|||
import config from './config.mjs'
|
||||
|
||||
export default class StaticRoutes {
|
||||
constructor(opts = {}) {
|
||||
Object.assign(this, { })
|
||||
}
|
||||
|
||||
register(server) {
|
||||
server.flaska.get('/health', this.health.bind(this))
|
||||
}
|
||||
|
||||
health(ctx) {
|
||||
ctx.body = {
|
||||
environment: config.get('NODE_ENV'),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ export function combineFilesWithArticles(articles, files) {
|
|||
}
|
||||
|
||||
export function parseFile(file) {
|
||||
file.url = 'https://cdn.nfp.is' + file.path
|
||||
file.path = 'https://cdn.nfp.is' + file.path
|
||||
file.magnet = null
|
||||
file.meta = JSON.parse(file.meta || '{}') || {}
|
||||
if (file.meta.torrent) {
|
||||
|
@ -27,6 +27,7 @@ export function parseFile(file) {
|
|||
+ '&dn=' + encodeURIComponent(file.meta.torrent.name)
|
||||
+ '&xt=urn:btih:' + file.meta.torrent.hash
|
||||
+ file.meta.torrent.announce.map(item => ('&tr=' + encodeURIComponent(item))).join('')
|
||||
file.meta.torrent = { name: file.meta.torrent.name, files: file.meta.torrent.files }
|
||||
}
|
||||
return file
|
||||
}
|
|
@ -1,8 +1,22 @@
|
|||
|
||||
import path from 'path'
|
||||
import Parent from '../base/serve.mjs'
|
||||
import fs from 'fs/promises'
|
||||
import dot from 'dot'
|
||||
|
||||
export default class ServeHandler extends Parent {
|
||||
traverseTree(set, tree) {
|
||||
for (let branch of tree) {
|
||||
if (branch.children && branch.children.length) {
|
||||
set.add(branch.id)
|
||||
this.traverseTree(set, branch.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async serveIndex(ctx) {
|
||||
let indexFile = await fs.readFile(path.join(this.root, 'index.html'))
|
||||
this.template = dot.template(indexFile.toString(), { argName: ['headerDescription', 'headerImage', 'headerTitle', 'headerUrl', 'payloadData', 'payloadTree', 'version', 'nonce', 'type', 'banner', 'media'] })
|
||||
|
||||
let payload = {
|
||||
headerDescription: 'Small fansubbing and scanlation group translating and encoding our favourite shows from Japan.',
|
||||
headerImage: this.frontend + '/assets/img/heart.png',
|
||||
|
@ -12,18 +26,39 @@ export default class ServeHandler extends Parent {
|
|||
payloadTree: null,
|
||||
version: this.version,
|
||||
nonce: ctx.state.nonce,
|
||||
type: 'page',
|
||||
banner: false,
|
||||
media: false,
|
||||
}
|
||||
|
||||
try {
|
||||
payload.payloadTree = JSON.stringify(await this.pageRoutes.getPageTree(ctx, true))
|
||||
let tree = await this.pageRoutes.getPageTree(ctx, true)
|
||||
let setOfBranches = new Set()
|
||||
this.traverseTree(setOfBranches, tree.tree)
|
||||
|
||||
payload.payloadTree = JSON.stringify(tree)
|
||||
if (ctx.url === '/' || (ctx.url.startsWith('/page/') && ctx.url.lastIndexOf('/') === 5)) {
|
||||
ctx.params.path = null
|
||||
if (ctx.url.lastIndexOf('/') === 5) {
|
||||
ctx.params.path = ctx.url.slice(ctx.url.lastIndexOf('/') + 1)
|
||||
}
|
||||
payload.payloadData = JSON.stringify(await this.pageRoutes.getPage(ctx, true))
|
||||
let data = await this.pageRoutes.getPage(ctx, true)
|
||||
if (!data.page) {
|
||||
payload.type = 'frontpage'
|
||||
}
|
||||
else if (setOfBranches.has(data.page.id)) {
|
||||
payload.type = 'page_with_children'
|
||||
}
|
||||
payload.media = data.page?.media_avif_preview || false
|
||||
payload.banner = data.featured?.banner_avif_preview || data.page?.banner_avif_preview || false
|
||||
payload.payloadData = JSON.stringify(data)
|
||||
} else if (ctx.url.startsWith('/article/') && ctx.url.lastIndexOf('/') === 8) {
|
||||
ctx.params.path = ctx.url.slice(ctx.url.lastIndexOf('/') + 1)
|
||||
let data = await this.articleRoutes.getArticle(ctx, true)
|
||||
payload.media = data.article?.media_avif_preview || false
|
||||
payload.payloadData = JSON.stringify(data)
|
||||
payload.type = 'article'
|
||||
}
|
||||
console.log('url', ctx.url)
|
||||
} catch (e) {
|
||||
ctx.log.error(e)
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ const Fileinfo = {
|
|||
m('a', {
|
||||
target: '_blank',
|
||||
rel: 'noopener',
|
||||
href: vnode.attrs.file.url,
|
||||
href: vnode.attrs.file.path,
|
||||
}, this.getDownloadName(vnode)),
|
||||
vnode.attrs.file.magnet
|
||||
? m('a', {
|
||||
|
|
|
@ -47,4 +47,4 @@ AVIF.onload = AVIF.onerror = function () {
|
|||
m.route(document.getElementById('main'), '/', allRoutes)
|
||||
m.mount(document.getElementById('footer'), Footer)
|
||||
}
|
||||
AVIF.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=';
|
||||
AVIF.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABcAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAABAA0ABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB9tZGF0EgAKCBgAPkgIaDQgMgkf8AAAQAAAr3A=';
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
const m = require('mithril')
|
||||
|
||||
export function generatePictureSource(item, cover) {
|
||||
if (!item || !item.media_alt_prefix) return null
|
||||
|
||||
|
@ -10,9 +12,56 @@ export function generatePictureSource(item, cover) {
|
|||
+ item.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
||||
+ item.media_alt_prefix + '_large.avif 1920w',
|
||||
cover: cover,
|
||||
preview: item.media_avif_preview,
|
||||
}
|
||||
}
|
||||
|
||||
let loadingImage = null
|
||||
let loader = null
|
||||
|
||||
function cancelLoader() {
|
||||
if (loader) {
|
||||
loader.src = ''
|
||||
}
|
||||
loader = null
|
||||
}
|
||||
|
||||
export function smartBanner(item) {
|
||||
if (!item) {
|
||||
if (loader) {
|
||||
cancelLoader()
|
||||
}
|
||||
loadingImage = null
|
||||
return null
|
||||
}
|
||||
|
||||
if (!item.preview) {
|
||||
loadingImage = null
|
||||
cancelLoader()
|
||||
return item.banner
|
||||
}
|
||||
if (loadingImage !== item.banner && loader) {
|
||||
cancelLoader()
|
||||
}
|
||||
if (loadingImage === item.banner && !loader) {
|
||||
return item.banner
|
||||
}
|
||||
if (loadingImage === item.banner) {
|
||||
return item.preview
|
||||
}
|
||||
|
||||
loadingImage = item.banner
|
||||
loader = new Image();
|
||||
|
||||
loader.src = item.banner;
|
||||
loader.onload = loader.onerror = function() {
|
||||
loader = null
|
||||
m.redraw()
|
||||
}
|
||||
|
||||
return item.preview
|
||||
}
|
||||
|
||||
export function getBannerImage(item, prefix) {
|
||||
if (!item || !item.banner_alt_prefix) return null
|
||||
|
||||
|
@ -20,7 +69,8 @@ export function getBannerImage(item, prefix) {
|
|||
path: prefix + item.path,
|
||||
name: item.name,
|
||||
original: item.banner_path,
|
||||
banner: item.banner_alt_prefix
|
||||
banner: item.banner_alt_prefix,
|
||||
preview: item.banner_avif_preview,
|
||||
}
|
||||
|
||||
var deviceWidth = window.innerWidth
|
||||
|
@ -47,23 +97,24 @@ export function getArticlePicture(pictureData, useRouteLink, path, altText, fall
|
|||
if (!pictureData) return fallback || null
|
||||
|
||||
return m(useRouteLink ? m.route.Link : 'a', {
|
||||
class: 'cover',
|
||||
class: 'cover ' + (pictureData.preview ? 'haspreview' : ''),
|
||||
rel: useRouteLink ? null : 'noopener',
|
||||
target: useRouteLink ? null : '_blank',
|
||||
href: path,
|
||||
},
|
||||
m('picture', [
|
||||
m('source', {
|
||||
srcset: pictureData.avif,
|
||||
sizes: pictureData.cover,
|
||||
type: 'image/avif',
|
||||
}),
|
||||
m('img', {
|
||||
srcset: pictureData.jpeg,
|
||||
sizes: pictureData.cover,
|
||||
alt: altText,
|
||||
src: pictureData.fallback,
|
||||
}),
|
||||
}, [
|
||||
pictureData.preview ? m('img', { src: pictureData.preview }) : null,
|
||||
m('picture', [
|
||||
m('source', {
|
||||
srcset: pictureData.avif,
|
||||
sizes: pictureData.cover,
|
||||
type: 'image/avif',
|
||||
}),
|
||||
m('img', {
|
||||
srcset: pictureData.jpeg,
|
||||
sizes: pictureData.cover,
|
||||
alt: altText,
|
||||
src: pictureData.fallback,
|
||||
}),
|
||||
])
|
||||
])
|
||||
)
|
||||
}
|
|
@ -21,7 +21,7 @@ const SiteArticle = {
|
|||
|
||||
if (window.__nfpdata) {
|
||||
this.path = m.route.param('id')
|
||||
this.data.article = window.__nfpdata
|
||||
this.data = window.__nfpdata
|
||||
window.__nfpdata = null
|
||||
this.afterData()
|
||||
} else {
|
||||
|
@ -83,7 +83,30 @@ const SiteArticle = {
|
|||
|
||||
return [
|
||||
this.loading
|
||||
? m('div.loading-spinner')
|
||||
? m('.inside.vertical', [
|
||||
m('div.actions', m('div.lb-link')),
|
||||
m('article.fullsize', [
|
||||
m('h2.title', m('div.lb-main.lb--long')),
|
||||
m('div.row', [
|
||||
m('div.cover', m('picture.lb.nobg')),
|
||||
m('div.description', [
|
||||
m('div.lb-main.lb--long'),
|
||||
m('div.lb-main'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main'),
|
||||
m('p', m.trust(' ')),
|
||||
m('fileinfo', [
|
||||
m('div.lb-main.lb--slim.lb--longest'),
|
||||
m('ul', [
|
||||
m('li', m('div.lb-main.lb--slim.lb--longest')),
|
||||
m('li', m('div.lb-main.lb--slim.lb--longest')),
|
||||
])
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
: null,
|
||||
!this.loading && this.error === 'Article not found'
|
||||
? NotFoundView.view()
|
||||
|
@ -96,7 +119,7 @@ const SiteArticle = {
|
|||
},
|
||||
}, 'Article error: ' + this.error + '. Click here to try again'))
|
||||
: null,
|
||||
(article
|
||||
(!this.loading && article
|
||||
? m('.inside.vertical', [
|
||||
m('div.actions', [
|
||||
'« ',
|
||||
|
@ -134,6 +157,7 @@ const SiteArticle = {
|
|||
}
|
||||
}}, m('div.loading-spinner'))
|
||||
: m('button.comments', {
|
||||
style: 'display: none',
|
||||
onclick: function() { window.LoadComments = true },
|
||||
}, 'Open comment discussion'),
|
||||
])
|
||||
|
|
|
@ -15,7 +15,7 @@ const SitePage = {
|
|||
oninit: function(vnode) {
|
||||
this.error = ''
|
||||
this.loading = false
|
||||
this.showLoading = null
|
||||
this.treePage = null
|
||||
this.data = {
|
||||
page: null,
|
||||
articles: [],
|
||||
|
@ -26,7 +26,6 @@ const SitePage = {
|
|||
this.children = []
|
||||
this.currentPage = Number(m.route.param('page')) || 1
|
||||
|
||||
console.log('test', window.__nfpdata)
|
||||
if (window.__nfpdata) {
|
||||
this.path = m.route.param('id')
|
||||
this.lastpage = this.currentPage
|
||||
|
@ -58,24 +57,13 @@ const SitePage = {
|
|||
this.lastpage = this.currentPage
|
||||
this.path = m.route.param('id')
|
||||
|
||||
if (this.showLoading) {
|
||||
clearTimeout(this.showLoading)
|
||||
}
|
||||
|
||||
if (this.data.page) {
|
||||
this.showLoading = setTimeout(() => {
|
||||
this.showLoading = null
|
||||
this.loading = true
|
||||
m.redraw()
|
||||
}, 300)
|
||||
} else {
|
||||
this.loading = true
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
if (this.path) {
|
||||
this.children = PageTree.TreeMap.get(this.path)
|
||||
this.children = this.children && this.children.children || []
|
||||
this.treePage = PageTree.TreeMap.get(this.path)
|
||||
this.children = this.treePage && this.treePage.children || []
|
||||
} else {
|
||||
this.treePage = { has_banner: true, has_media: true }
|
||||
this.children = PageTree.Tree
|
||||
}
|
||||
|
||||
|
@ -90,8 +78,6 @@ const SitePage = {
|
|||
this.error = err.message
|
||||
})
|
||||
.then(() => {
|
||||
clearTimeout(this.showLoading)
|
||||
this.showLoading = null
|
||||
this.loading = false
|
||||
m.redraw()
|
||||
})
|
||||
|
@ -111,8 +97,8 @@ const SitePage = {
|
|||
}
|
||||
|
||||
this.picture = media.generatePictureSource(this.data.page,
|
||||
'(max-width: 840px) calc(100vw - 82px), '
|
||||
+ '758px')
|
||||
'(max-width: 1280px) calc(100vw - 2rem), '
|
||||
+ '1248px')
|
||||
|
||||
if (this.lastpage !== 1) {
|
||||
document.title = 'Page ' + this.lastpage + ' - ' + title
|
||||
|
@ -128,107 +114,211 @@ const SitePage = {
|
|||
|
||||
return ([
|
||||
this.loading
|
||||
? m('div.loading-spinner')
|
||||
: null,
|
||||
!this.loading && this.error === 'Page not found'
|
||||
? NotFoundView.view()
|
||||
: null,
|
||||
!this.loading && this.error && this.error !== 'Page not found'
|
||||
? m('div.wrapper', m('div.error', {
|
||||
onclick: () => {
|
||||
this.error = ''
|
||||
this.fetchPage(vnode)
|
||||
},
|
||||
}, 'Page error: ' + this.error + '. Click here to try again'))
|
||||
: null,
|
||||
(featuredBanner
|
||||
? m(m.route.Link, {
|
||||
class: 'page-banner',
|
||||
href: featuredBanner.path,
|
||||
style: { 'background-image': 'url("' + featuredBanner.banner + '")' },
|
||||
},
|
||||
m('div.inside', m('div.page-banner-title', featuredBanner.name))
|
||||
)
|
||||
: null),
|
||||
(!featuredBanner && pageBanner
|
||||
? m('a.page-banner', {
|
||||
href: pageBanner.original,
|
||||
target: '_blank',
|
||||
style: { 'background-image': 'url("' + pageBanner.banner + '")' },
|
||||
},
|
||||
)
|
||||
: null),
|
||||
(page
|
||||
? m('.inside.vertical', [
|
||||
m('div.actions', [
|
||||
'« ',
|
||||
m(m.route.Link, {
|
||||
href: page.parent_path
|
||||
? '/page/' + page.parent_path
|
||||
: '/'
|
||||
}, page.parent_name || 'Home'),
|
||||
Authentication.currentUser
|
||||
? [
|
||||
m('div.filler'),
|
||||
'Actions:',
|
||||
m(m.route.Link, { href: '/admin/pages/' + page.id }, 'Edit page'),
|
||||
]
|
||||
: null,
|
||||
]),
|
||||
m('h2.title', page.name)
|
||||
])
|
||||
: null),
|
||||
(page || this.data.articles.length
|
||||
? m('.inside', [
|
||||
this.children.length
|
||||
? m('aside', { class: page ? '' : 'frontpage' }, [
|
||||
m('h5', page ? 'View ' + page.name + ':' : 'Categories'),
|
||||
this.children.map((page) => {
|
||||
return [
|
||||
m(m.route.Link, { class: 'root', href: '/page/' + page.path }, page.name),
|
||||
(page.children && page.children.length
|
||||
? m('ul', page.children.map(function(subpage) {
|
||||
return m('li', m(m.route.Link, { class: 'child', href: '/page/' + subpage.path }, subpage.name))
|
||||
}))
|
||||
: null),
|
||||
]
|
||||
}),
|
||||
!page
|
||||
? m('div.asuna.spritesheet')
|
||||
: null,
|
||||
? [
|
||||
this.treePage.has_banner
|
||||
? m('div.page-banner.lb')
|
||||
: null,
|
||||
this.path
|
||||
? m('div.inside.vertical', [
|
||||
m('div.actions', m('div.lb-link')),
|
||||
m('h2.title', m('div.lb-main.lb--long')),
|
||||
])
|
||||
: null,
|
||||
m('div.container', [
|
||||
(page
|
||||
? media.getArticlePicture(this.picture, false, page.media_path, 'Image for page ' + page.name)
|
||||
: null),
|
||||
(page && page.content
|
||||
? m('div.content', page.content.blocks.map(block => {
|
||||
return m(EditorBlock, { block: block })
|
||||
}))
|
||||
: null),
|
||||
(page && this.data.articles.length
|
||||
? [
|
||||
m('h5', 'Latest posts under ' + page.name + ':'),
|
||||
this.data.articles.map(function(article) {
|
||||
return m(Articleslim, { article: article })
|
||||
}),
|
||||
]
|
||||
: null),
|
||||
(!page && this.data.articles.length
|
||||
? this.data.articles.map(function(article) {
|
||||
return m(Article, { article: article })
|
||||
})
|
||||
: null),
|
||||
m(Paginator, {
|
||||
base: page ? '/page/' + page.path : '/',
|
||||
page: this.currentPage,
|
||||
perPage: ArticlesPerPage,
|
||||
total: this.data.total_articles,
|
||||
}),
|
||||
m('div.inside', [
|
||||
this.children.length
|
||||
? m('aside', [
|
||||
m('h5', m('div.lb-main')),
|
||||
m('div.lb-link'),
|
||||
m('ul', [
|
||||
m('li', m('div.lb-link')),
|
||||
m('li', m('div.lb-link')),
|
||||
m('li', m('div.lb-link')),
|
||||
]),
|
||||
m('div.lb-link'),
|
||||
m('ul', [
|
||||
m('li', m('div.lb-link')),
|
||||
m('li', m('div.lb-link')),
|
||||
m('li', m('div.lb-link')),
|
||||
]),
|
||||
])
|
||||
: null,
|
||||
!this.path
|
||||
? m('div.container', [
|
||||
m('article', [
|
||||
m('h2.title', m('div.lb-main.lb--long')),
|
||||
m('div.row', [
|
||||
m('div.lb-main.lb--imgmini'),
|
||||
m('div', [
|
||||
m('div', m.trust(' ')),
|
||||
m('div.lb-main.lb--long'),
|
||||
m('div.lb-main'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main'),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
m('article', [
|
||||
m('h2.title', m('div.lb-main.lb--long')),
|
||||
m('div.row', [
|
||||
m('div.lb-main.lb--imgmini'),
|
||||
m('div', [
|
||||
m('div', m.trust(' ')),
|
||||
m('div.lb-main.lb--long'),
|
||||
m('div.lb-main'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main.lb--medium'),
|
||||
m('div.lb-main'),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
: null,
|
||||
this.path
|
||||
? m('div.container', [
|
||||
this.treePage.has_media
|
||||
? m('div.cover', m('picture.lb.nobg'))
|
||||
: null,
|
||||
m('h5', m('div.lb-main.lb--long')),
|
||||
m('articleslim', [
|
||||
m('a.cover.nobg.lb'),
|
||||
m('div', [
|
||||
m('div', m('div.lb-link.lb--long')),
|
||||
m('div.lb-main.lb--longest.lb--slim'),
|
||||
]),
|
||||
]),
|
||||
m('articleslim', [
|
||||
m('a.cover.nobg.lb'),
|
||||
m('div', [
|
||||
m('div', m('div.lb-link.lb--long')),
|
||||
m('div.lb-main.lb--longest.lb--slim'),
|
||||
]),
|
||||
]),
|
||||
m('articleslim', [
|
||||
m('a.cover.nobg.lb'),
|
||||
m('div', [
|
||||
m('div', m('div.lb-link.lb--long')),
|
||||
m('div.lb-main.lb--longest.lb--slim'),
|
||||
]),
|
||||
]),
|
||||
m('articleslim', [
|
||||
m('a.cover.nobg.lb'),
|
||||
m('div', [
|
||||
m('div', m('div.lb-link.lb--long')),
|
||||
m('div.lb-main.lb--longest.lb--slim'),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
: null,
|
||||
]),
|
||||
])
|
||||
: null),
|
||||
]
|
||||
: [
|
||||
this.error === 'Page not found'
|
||||
? NotFoundView.view()
|
||||
: null,
|
||||
this.error && this.error !== 'Page not found'
|
||||
? m('div.wrapper', m('div.error', {
|
||||
onclick: () => {
|
||||
this.error = ''
|
||||
this.fetchPage(vnode)
|
||||
},
|
||||
}, 'Page error: ' + this.error + '. Click here to try again'))
|
||||
: null,
|
||||
(featuredBanner
|
||||
? m(m.route.Link, {
|
||||
class: 'page-banner',
|
||||
href: featuredBanner.path,
|
||||
style: { 'background-image': 'url("' + featuredBanner.preview + '")' },
|
||||
}, [
|
||||
m('div.page-banner-real', {
|
||||
style: { 'background-image': 'url("' + featuredBanner.banner + '")' },
|
||||
}, m('div.inside', m('div.page-banner-title', featuredBanner.name))),
|
||||
]
|
||||
)
|
||||
: null),
|
||||
(!featuredBanner && pageBanner
|
||||
? m('a.page-banner', {
|
||||
href: pageBanner.original,
|
||||
target: '_blank',
|
||||
style: { 'background-image': 'url("' + pageBanner.preview + '")' },
|
||||
},
|
||||
m('div.page-banner-real', {
|
||||
style: { 'background-image': 'url("' + pageBanner.banner + '")' },
|
||||
})
|
||||
)
|
||||
: null),
|
||||
(page
|
||||
? m('.inside.vertical', [
|
||||
m('div.actions', [
|
||||
'« ',
|
||||
m(m.route.Link, {
|
||||
href: page.parent_path
|
||||
? '/page/' + page.parent_path
|
||||
: '/'
|
||||
}, page.parent_name || 'Home'),
|
||||
Authentication.currentUser
|
||||
? [
|
||||
m('div.filler'),
|
||||
'Actions:',
|
||||
m(m.route.Link, { href: '/admin/pages/' + page.id }, 'Edit page'),
|
||||
]
|
||||
: null,
|
||||
]),
|
||||
m('h2.title', page.name)
|
||||
])
|
||||
: null),
|
||||
(page || this.data.articles.length
|
||||
? m('.inside', [
|
||||
this.children.length
|
||||
? m('aside', { class: page ? '' : 'frontpage' }, [
|
||||
m('h5', page ? 'View ' + page.name + ':' : 'Categories'),
|
||||
this.children.map((page) => {
|
||||
return [
|
||||
m(m.route.Link, { class: 'root', href: '/page/' + page.path }, page.name),
|
||||
(page.children && page.children.length
|
||||
? m('ul', page.children.map(function(subpage) {
|
||||
return m('li', m(m.route.Link, { class: 'child', href: '/page/' + subpage.path }, subpage.name))
|
||||
}))
|
||||
: null),
|
||||
]
|
||||
}),
|
||||
!page
|
||||
? m('div.asuna.spritesheet')
|
||||
: null,
|
||||
])
|
||||
: null,
|
||||
m('div.container', [
|
||||
(page
|
||||
? media.getArticlePicture(this.picture, false, page.media_path, 'Image for page ' + page.name)
|
||||
: null),
|
||||
(page && page.content
|
||||
? m('div.content', page.content.blocks.map(block => {
|
||||
return m(EditorBlock, { block: block })
|
||||
}))
|
||||
: null),
|
||||
(page && this.data.articles.length
|
||||
? [
|
||||
m('h5', 'Latest posts under ' + page.name + ':'),
|
||||
this.data.articles.map(function(article) {
|
||||
return m(Articleslim, { article: article })
|
||||
}),
|
||||
]
|
||||
: null),
|
||||
(!page && this.data.articles.length
|
||||
? this.data.articles.map(function(article) {
|
||||
return m(Article, { article: article })
|
||||
})
|
||||
: null),
|
||||
m(Paginator, {
|
||||
base: page ? '/page/' + page.path : '/',
|
||||
page: this.currentPage,
|
||||
perPage: ArticlesPerPage,
|
||||
total: this.data.total_articles,
|
||||
}),
|
||||
]),
|
||||
])
|
||||
: null),
|
||||
],
|
||||
])
|
||||
},
|
||||
}
|
||||
|
|
|
@ -306,6 +306,29 @@ dialogue button.cancel {
|
|||
min-height: 80px !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@keyframes spinner-loader {
|
||||
to {transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
.loading-spinner:after {
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
margin-left: -10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #ccc;
|
||||
border-top-color: #333;
|
||||
animation: spinner-loader .6s linear infinite;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== 3rd party =====================
|
||||
*/
|
||||
|
|
|
@ -1,858 +1,3 @@
|
|||
/*
|
||||
===================== Variables =====================
|
||||
*/
|
||||
:root {
|
||||
--content-max-width: 1280px;
|
||||
--primary-darker-bg: #002f6c;
|
||||
--primary-darker-fg: #fff;
|
||||
--primary-darker-fg-light: #999;
|
||||
--primary-darker-link: #ffad42;
|
||||
|
||||
--primary-bg: #3d77c7;
|
||||
--primary-fg: #fff;
|
||||
--primary-fg-light: #999;
|
||||
--primary-link: #f57c00;
|
||||
|
||||
--bg: #fff;
|
||||
--bg-content-alt: #eee;
|
||||
--color: #000;
|
||||
--light: #757575;
|
||||
--link: #bb4d00;
|
||||
--title-bg: #f57c00;
|
||||
--title-fg: #000;
|
||||
--seperator: #ccc;
|
||||
--content-bg: #fff;
|
||||
--content-border: 0px solid transparent;
|
||||
|
||||
--alt-bg: #ccc;
|
||||
--alt-inside-bg: #fff;
|
||||
--alt-inside-border: 1px solid #555;
|
||||
--alt-color: #555;
|
||||
|
||||
--footer-bg: #ccc;
|
||||
--footer-color: #000;
|
||||
--footer-seperator: #fff;
|
||||
--footer-link: #8F3C00;
|
||||
|
||||
--button-border: 1px solid #f57c00;
|
||||
--button-bg: #ffad42;
|
||||
--button-fg: #000;
|
||||
|
||||
--error-bg: red;
|
||||
--error-fg: white;
|
||||
}
|
||||
|
||||
.nightmode {
|
||||
--content-max-width: 1280px;
|
||||
--primary-darker-bg: #002f6c;
|
||||
--primary-darker-fg: #fff;
|
||||
--primary-darker-fg-light: #999;
|
||||
--primary-darker-link: #ffad42;
|
||||
|
||||
--primary-bg: #28518b;
|
||||
--primary-fg: #fff;
|
||||
--primary-fg-light: #999;
|
||||
--primary-link: #f57c00;
|
||||
|
||||
--bg: black;
|
||||
--bg-content-alt: #333;
|
||||
--color: #d7dadc;
|
||||
--light: #bbb;
|
||||
--link: #e05e00;
|
||||
--title-bg: #e05e00;
|
||||
--title-fg: #000;
|
||||
--title-sublink: #27159C;
|
||||
--seperator: #ccc;
|
||||
--content-bg: #1a1a1b;
|
||||
--content-border: 1px solid #343536;
|
||||
|
||||
--alt-bg: #000;
|
||||
--alt-inside-bg: #343536;
|
||||
--alt-inside-border: 1px solid #808080;
|
||||
--alt-color: #d7dadc;
|
||||
|
||||
--footer-bg: #343536;
|
||||
--footer-color: #d7dadc;
|
||||
--footer-seperator: #666;
|
||||
--footer-link: #fe791b;
|
||||
|
||||
--button-border: 1px solid #f57c00;
|
||||
--button-bg: #ffad42;
|
||||
--button-fg: #000;
|
||||
|
||||
--error-bg: red;
|
||||
--error-fg: white;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== Reset =====================
|
||||
*/
|
||||
|
||||
/* Box sizing rules */
|
||||
*, *::before, *::after { box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Remove default margin */
|
||||
body, h1, h2, h3, h4, p, figure, blockquote, dl, dd {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
text-rendering: optimizeSpeed;
|
||||
line-height: 1.5;
|
||||
font-size: 16px;
|
||||
font-family: 'Inter var', sans-serif;
|
||||
font-feature-settings: "slnt" 0deg, "case", "frac", "tnum", "ss02", "calt", "ccmp", "kern";
|
||||
background: var(--bg);
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
.italic { font-variation-settings: "slnt" 10deg; }
|
||||
|
||||
a {
|
||||
text-decoration-skip-ink: auto;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input, button, textarea, select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-play-state: paused !important;
|
||||
transition: none !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.488rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2.074rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.728rem;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.44rem;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
a, a:visited, button {
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=text],
|
||||
input[type=password],
|
||||
select {
|
||||
border: 1px solid var(--color);
|
||||
background: var(--bg);
|
||||
color: var(--color);
|
||||
border-radius: 0;
|
||||
padding: 0.25rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type=text]:hover,
|
||||
input[type=text]:active,
|
||||
input[type=password]:hover,
|
||||
input[type=password]:active,
|
||||
select:hover,
|
||||
select:active {
|
||||
border-color: var(--link);
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== Common =====================
|
||||
*/
|
||||
|
||||
.inside {
|
||||
width: 100%;
|
||||
max-width: var(--content-max-width);
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.inside.vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.error {
|
||||
background: var(--error-bg);
|
||||
color: var(--error-fg);
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background: var(--alt-bg);
|
||||
color: var(--alt-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - 200px);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.filler {
|
||||
flex: 2 1 auto;
|
||||
}
|
||||
|
||||
.wrapper .inside {
|
||||
flex-direction: column;
|
||||
color: var(--alt-color);
|
||||
background: var(--alt-inside-bg);
|
||||
border: var(--alt-inside-border);
|
||||
}
|
||||
|
||||
.wrapper .error {
|
||||
border: 1px solid var(--error-bg);
|
||||
color: var(--error-bg);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@keyframes spinner-loader {
|
||||
to {transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
.loading-spinner:after {
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
margin-left: -10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #ccc;
|
||||
border-top-color: #333;
|
||||
animation: spinner-loader .6s linear infinite;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.notfound {
|
||||
color: var(--light);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
main .inside {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================== Header =====================
|
||||
*/
|
||||
|
||||
header {
|
||||
background: var(--primary-darker-bg);
|
||||
color: var(--primary-darker-fg);
|
||||
}
|
||||
|
||||
header a,
|
||||
header a:visited,
|
||||
header button {
|
||||
color: var(--primary-darker-link);
|
||||
}
|
||||
|
||||
header p {
|
||||
color: var(--primary-darker-fg-light);
|
||||
}
|
||||
|
||||
header .title,
|
||||
header .title:visited {
|
||||
min-height: 100px;
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: 25px center no-repeat;
|
||||
background-size: auto 91px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
header .logo {
|
||||
background-position: -119px 0px;
|
||||
width: 81px;
|
||||
height: 100px;
|
||||
transform: scale(0.9);
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
header .title h1 {
|
||||
font-weight: 500;
|
||||
color: var(--primary-darker-fg);
|
||||
}
|
||||
|
||||
header aside {
|
||||
flex: 2 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
header aside a,
|
||||
header aside button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
header aside p button {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== Nav =====================
|
||||
*/
|
||||
|
||||
nav {
|
||||
background: var(--primary-bg);
|
||||
}
|
||||
|
||||
nav a, nav a:visited, nav .loading-spinner {
|
||||
flex: 2 0 auto;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
padding: 10px 10px 7px 10px;
|
||||
border-bottom: 3px solid var(--primary-bg);
|
||||
color: var(--primary-fg);
|
||||
}
|
||||
|
||||
nav a.active {
|
||||
border-bottom-color: var(--primary-link);
|
||||
}
|
||||
|
||||
nav .loading-spinner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
nav {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================== main =====================
|
||||
*/
|
||||
|
||||
main {
|
||||
min-height: calc(100vh - 390px);
|
||||
}
|
||||
|
||||
.page-banner {
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.page-banner-title {
|
||||
color: white;
|
||||
text-align: right;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1.6rem;
|
||||
flex: 2 1 auto;
|
||||
text-shadow: 0 0 .3em #000;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding: 0.5rem 1rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.actions a {
|
||||
margin-left: 0.375rem;
|
||||
}
|
||||
|
||||
main a,
|
||||
main a:visited {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
main h5 {
|
||||
padding: 0 0.5rem 0.5rem;
|
||||
margin: 0 0 0.75rem;
|
||||
border-bottom: 1px solid var(--seperator);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
main .loading-spinner {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
main h2.title,
|
||||
.main h2.title {
|
||||
font-size: 1.4rem;
|
||||
background: var(--title-bg);
|
||||
color: var(--title-fg);
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
padding: 0.375rem;
|
||||
line-height: 1.4rem;
|
||||
}
|
||||
|
||||
main .container {
|
||||
flex: 2 1 auto;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
main .cover picture img {
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
main button,
|
||||
main input[type=submit] {
|
||||
border: var(--button-border);
|
||||
background: #ffad42;
|
||||
color: #000;
|
||||
align-self: center;
|
||||
padding: 0.25rem 1rem;
|
||||
margin: 1rem 0 2rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
main .container {
|
||||
margin: 1rem 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************** aside ************** */
|
||||
|
||||
main aside {
|
||||
padding: 0.375rem 1rem 0.5rem;
|
||||
margin: 1rem;
|
||||
font-size: 0.875rem;
|
||||
flex: 0 0 250px;
|
||||
background: var(--content-bg);
|
||||
border: var(--content-border);
|
||||
}
|
||||
|
||||
main aside a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
main aside h5 {
|
||||
margin: 0 -0.5rem 0.25rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
main aside ul {
|
||||
margin: 0 0 0.5rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
main aside .asuna {
|
||||
margin-top: 2rem;
|
||||
width: 200px;
|
||||
height: 461px;
|
||||
background-position: 0 -150px;
|
||||
}
|
||||
|
||||
.nightmode main aside .asuna {
|
||||
background-position: -200px -150px;
|
||||
}
|
||||
|
||||
.daymode .day {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px){
|
||||
main aside {
|
||||
flex: 0 0 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
main aside {
|
||||
margin: 1rem 0.25rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main aside.frontpage {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ************** paginator ************** */
|
||||
|
||||
paginator {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
paginator a {
|
||||
color: var(--link);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
paginator a,
|
||||
paginator div {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
max-width: 80px;
|
||||
flex-grow: 2;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* ************** articleslim ************** */
|
||||
|
||||
articleslim {
|
||||
display: flex;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
articleslim p.description {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
articleslim .cover {
|
||||
flex: 0 0 124px;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
articleslim .cover picture img {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
articleslim a.nobg {
|
||||
height: 70px;
|
||||
background: var(--seperator);
|
||||
display: block;
|
||||
}
|
||||
|
||||
articleslim a.title {
|
||||
display: block;
|
||||
margin-bottom: 0.375rem;
|
||||
}
|
||||
|
||||
/* ************** article ************** */
|
||||
|
||||
article {
|
||||
background: var(--content-bg);
|
||||
border: var(--content-border);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
article .row {
|
||||
margin: 1rem 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
article .cover {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 1rem;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
article a.title {
|
||||
flex: 0 0 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
article .description {
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
article .meta {
|
||||
font-size: 0.625rem;
|
||||
line-height: 0.75rem;
|
||||
color: var(--light);
|
||||
font-weight: 500;
|
||||
padding: 1.25rem 0.25rem 0;
|
||||
}
|
||||
|
||||
article.fullsize .row {
|
||||
margin: 1rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
article.fullsize .cover {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px){
|
||||
article .row {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
article.fullsize .row {
|
||||
margin: 1rem 0.25rem;
|
||||
}
|
||||
|
||||
article .cover {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************** fileinfo ************** */
|
||||
|
||||
fileinfo {
|
||||
padding-left: 0.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--light);
|
||||
line-height: 1rem;
|
||||
font-size: 0.75rem;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
fileinfo.slim {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
fileinfo p span,
|
||||
fileinfo p a {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
fileinfo p a {
|
||||
font-weight: 550;
|
||||
padding-right: 0.25rem;
|
||||
border-right: 1px solid var(--seperator);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
fileinfo p span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
fileinfo .trimmed {
|
||||
padding: 0.25rem 0 0.25rem 1rem;
|
||||
}
|
||||
|
||||
fileinfo ul {
|
||||
margin: 0.5rem 0;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== login =====================
|
||||
*/
|
||||
|
||||
.login--first {
|
||||
flex: 0 0 170px;
|
||||
}
|
||||
|
||||
.login {
|
||||
align-items: center;
|
||||
font-size: 1rem;
|
||||
padding: 1rem 1rem 2rem;
|
||||
margin: 1rem;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.login .title {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 200;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login input,
|
||||
.login label {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.login input[type=submit] {
|
||||
min-width: 150px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.login--asuna {
|
||||
flex: 0 0 auto;
|
||||
width: 180px;
|
||||
height: 494px;
|
||||
background-position: -400px 0;
|
||||
}
|
||||
|
||||
.nightmode .login--asuna {
|
||||
background-position: -580px 0;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1000px){
|
||||
.login--first {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
.login {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.login--asuna {
|
||||
max-width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================== content =====================
|
||||
*/
|
||||
|
||||
.content :is(h1, h2, h3, h4, h5, ul, ol, blockquote, p) {
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
|
||||
.content :is(h1, h2, h3, h4, h5) {
|
||||
padding: 0 0.5rem 0.5rem;
|
||||
border-bottom: 1px solid var(--seperator);
|
||||
}
|
||||
|
||||
.content :is(blockquote, pre) {
|
||||
background: var(--bg-content-alt);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.content blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== footer =====================
|
||||
*/
|
||||
|
||||
footer {
|
||||
background: var(--footer-bg);
|
||||
color: var(--footer-color);
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
|
||||
footer .first {
|
||||
flex: 0 0 119px;
|
||||
}
|
||||
|
||||
footer .middle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 2 1 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
footer .asuna {
|
||||
flex: 0 0 119px;
|
||||
height: 150px;
|
||||
width: 119px;
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
|
||||
footer ul {
|
||||
margin: 0 0 0.25rem;
|
||||
padding: 0 0 0.25rem;
|
||||
border-bottom: 1px solid var(--footer-seperator);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
footer ul li {
|
||||
padding: 0 0.25rem;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: var(--footer-link);
|
||||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1000px){
|
||||
footer .first {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 639px){
|
||||
footer{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
footer .middle {
|
||||
padding: 0 0 2rem;
|
||||
}
|
||||
|
||||
footer .asuna {
|
||||
flex: 0 0 150px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================== 404 page =====================
|
||||
*/
|
||||
|
||||
.not_found {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.not_found .asuna {
|
||||
width: 120px;
|
||||
height: 444px;
|
||||
margin: 2rem 0 0rem;
|
||||
background-position: -760px 0;
|
||||
}
|
||||
|
||||
.nightmode .not_found .asuna {
|
||||
background-position: -880px 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===================== Large assets =====================
|
||||
|
|
1039
nfp_moe/public/assets/app_body.css
Normal file
1039
nfp_moe/public/assets/app_body.css
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3 KiB |
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue