Big Optimisations and such
This commit is contained in:
parent
4f529e22dd
commit
eaf2edd6c3
46 changed files with 842 additions and 395 deletions
|
@ -16,6 +16,9 @@ jobs:
|
||||||
command: apk update && apk upgrade && apk add --no-cache bash git openssh
|
command: apk update && apk upgrade && apk add --no-cache bash git openssh
|
||||||
- checkout
|
- checkout
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
|
- run:
|
||||||
|
name: Replace version in config
|
||||||
|
command: sed -i .org "s/circleci_version_number/${CIRCLE_BUILD_NUM}/g" config/config.default.json
|
||||||
- run:
|
- run:
|
||||||
name: Build docker image
|
name: Build docker image
|
||||||
command: docker build -t ${di}:build_${CIRCLE_BUILD_NUM} -t ${di}:${CIRCLE_SHA1} -t ${di}:${dtag} .
|
command: docker build -t ${di}:build_${CIRCLE_BUILD_NUM} -t ${di}:${CIRCLE_SHA1} -t ${di}:${dtag} .
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"FroalaEditor": "readonly",
|
"FroalaEditor": "readonly",
|
||||||
"gapi": "readonly"
|
"gapi": "readonly",
|
||||||
|
"m": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"env": {
|
"env": {
|
||||||
|
|
|
@ -76,6 +76,17 @@ const Article = bookshelf.createModel({
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getFrontpageArticles() {
|
||||||
|
return this.query(qb => {
|
||||||
|
qb.orderBy('updated_at', 'DESC')
|
||||||
|
})
|
||||||
|
.fetchPage({
|
||||||
|
pageSize: 10,
|
||||||
|
page: 1,
|
||||||
|
withRelated: ['files', 'media', 'banner'],
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Article
|
export default Article
|
||||||
|
|
|
@ -44,7 +44,7 @@ const Media = bookshelf.createModel({
|
||||||
},
|
},
|
||||||
|
|
||||||
url() {
|
url() {
|
||||||
return `${Media.baseUrl}${this.get('large_image')}`
|
return `${Media.baseUrl}${this.get('medium_image')}`
|
||||||
},
|
},
|
||||||
|
|
||||||
thumb() {
|
thumb() {
|
||||||
|
|
|
@ -61,6 +61,12 @@ const Page = bookshelf.createModel({
|
||||||
})
|
})
|
||||||
.fetch({ require, withRelated, ctx })
|
.fetch({ require, withRelated, ctx })
|
||||||
},
|
},
|
||||||
|
getTree() {
|
||||||
|
return this.query(qb => {
|
||||||
|
qb.where({ parent_id: null })
|
||||||
|
qb.select(['id', 'name', 'path'])
|
||||||
|
}).fetchAll({ withRelated: ['children'] })
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Page
|
export default Page
|
||||||
|
|
|
@ -1,5 +1,82 @@
|
||||||
|
import { readFileSync } from 'fs'
|
||||||
import send from 'koa-send'
|
import send from 'koa-send'
|
||||||
|
import dot from 'dot'
|
||||||
import defaults from './defaults.mjs'
|
import defaults from './defaults.mjs'
|
||||||
|
import config from './config.mjs'
|
||||||
|
import Page from './page/model.mjs'
|
||||||
|
import Article from './article/model.mjs'
|
||||||
|
|
||||||
|
const body = readFileSync('./public/index.html').toString()
|
||||||
|
const bodyTemplate = dot.template(body)
|
||||||
|
|
||||||
|
async function sendIndex(ctx, path) {
|
||||||
|
let tree = null
|
||||||
|
let data = null
|
||||||
|
let links = null
|
||||||
|
try {
|
||||||
|
tree = (await Page.getTree()).toJSON()
|
||||||
|
tree.forEach(item => (
|
||||||
|
item.children = item.children.map(x => (
|
||||||
|
{ id: x.id, name: x.name, path: x.path }
|
||||||
|
))
|
||||||
|
))
|
||||||
|
if (path === '/') {
|
||||||
|
data = await Article.getFrontpageArticles()
|
||||||
|
|
||||||
|
if (data.pagination.rowCount > 10) {
|
||||||
|
links = {
|
||||||
|
current: { title: 'Page 1' },
|
||||||
|
next: { page: 2, title: 'Next' },
|
||||||
|
last: { page: Math.ceil(data.pagination.rowCount / 10), title: 'Last' },
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
links = {
|
||||||
|
current: { title: 'Page 1' },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = data.toJSON().map(x => ({
|
||||||
|
id: x.id,
|
||||||
|
created_at: x.created_at,
|
||||||
|
path: x.path,
|
||||||
|
description: x.description,
|
||||||
|
name: x.name,
|
||||||
|
media: x.media && ({
|
||||||
|
medium_url: x.media.medium_url,
|
||||||
|
small_url: x.media.small_url,
|
||||||
|
}) || null,
|
||||||
|
banner: x.banner && ({
|
||||||
|
large_url: x.banner.large_url,
|
||||||
|
medium_url: x.banner.medium_url,
|
||||||
|
small_url: x.banner.small_url,
|
||||||
|
}) || null,
|
||||||
|
files: x.files && x.files.map(f => ({
|
||||||
|
filename: f.filename,
|
||||||
|
url: f.url,
|
||||||
|
magnet: f.magnet,
|
||||||
|
meta: f.meta.torrent && ({
|
||||||
|
torrent: {
|
||||||
|
files: f.meta.torrent.files.map(tf => ({
|
||||||
|
name: tf.name,
|
||||||
|
size: tf.size,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}) || {},
|
||||||
|
})) || [],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ctx.log.error(e)
|
||||||
|
}
|
||||||
|
ctx.body = bodyTemplate({
|
||||||
|
v: config.get('CIRCLECI_VERSION'),
|
||||||
|
tree: JSON.stringify(tree),
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
links: JSON.stringify(links),
|
||||||
|
})
|
||||||
|
ctx.set('Content-Length', Buffer.byteLength(ctx.body))
|
||||||
|
ctx.set('Cache-Control', 'max-age=0')
|
||||||
|
ctx.set('Content-Type', 'text/html; charset=utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
export function serve(docRoot, pathname, options = {}) {
|
export function serve(docRoot, pathname, options = {}) {
|
||||||
options.root = docRoot
|
options.root = docRoot
|
||||||
|
@ -22,9 +99,14 @@ export function serve(docRoot, pathname, options = {}) {
|
||||||
opts = defaults({ maxage: 2592000 * 1000 }, opts)
|
opts = defaults({ maxage: 2592000 * 1000 }, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filepath === '/index.html') {
|
||||||
|
return sendIndex(ctx, '/')
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
return send(ctx, '/index.html', options)
|
return sendIndex(ctx)
|
||||||
|
// return send(ctx, '/index.html', options)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
15
app/admin.js
Normal file
15
app/admin.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
const EditPage = require('./admin/editpage')
|
||||||
|
const AdminPages = require('./admin/pages')
|
||||||
|
const AdminArticles = require('./admin/articles')
|
||||||
|
const EditArticle = require('./admin/editarticle')
|
||||||
|
const AdminStaffList = require('./admin/stafflist')
|
||||||
|
const EditStaff = require('./admin/editstaff')
|
||||||
|
|
||||||
|
window.addAdminRoutes = [
|
||||||
|
['/admin/pages', AdminPages],
|
||||||
|
['/admin/pages/:key', EditPage],
|
||||||
|
['/admin/articles', AdminArticles],
|
||||||
|
['/admin/articles/:id', EditArticle],
|
||||||
|
['/admin/staff', AdminStaffList],
|
||||||
|
['/admin/staff/:id', EditStaff],
|
||||||
|
]
|
79
app/admin.scss
Normal file
79
app/admin.scss
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
@import './_common';
|
||||||
|
|
||||||
|
.error {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: $secondary-dark-bg;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bordercolor: $primary-bg;
|
||||||
|
$headcolor: $primary-light-bg;
|
||||||
|
$headtext: $primary-light-fg;
|
||||||
|
|
||||||
|
.admin-wrapper table {
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
margin: 10px;
|
||||||
|
border: solid 1px $bordercolor;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
background-color: $headcolor;
|
||||||
|
border: solid 1px $bordercolor;
|
||||||
|
color: $headtext;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
tbody td {
|
||||||
|
text-align: left;
|
||||||
|
border: solid 1px $bordercolor;
|
||||||
|
color: $table-fg;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
a,
|
||||||
|
a:visited,
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: $secondary-dark-bg;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: $secondary-dark-bg;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid $secondary-dark-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.right,
|
||||||
|
th.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #00000099;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import 'admin/admin';
|
||||||
|
@import 'widgets/admin';
|
||||||
|
|
||||||
|
.darkmodeon {
|
||||||
|
.maincontainer .admin-wrapper {
|
||||||
|
color: $main-fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: $dark_secondary-dark-bg;
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,21 +38,3 @@
|
||||||
@import 'pages';
|
@import 'pages';
|
||||||
@import 'articles';
|
@import 'articles';
|
||||||
@import 'staff';
|
@import 'staff';
|
||||||
|
|
||||||
.darkmodeon {
|
|
||||||
.admin-wrapper {
|
|
||||||
background: $dark_primary-bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-actions {
|
|
||||||
background: $dark_primary-bg;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: $dark_primary-fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $dark_secondary-light-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const { getAllArticlesPagination, removeArticle } = require('../api/article')
|
const { getAllArticlesPagination, removeArticle } = require('../api/article')
|
||||||
const { fetchPage } = require('../api/pagination')
|
const { fetchPage } = require('../api/pagination')
|
||||||
const Dialogue = require('../widgets/dialogue')
|
const Dialogue = require('../widgets/dialogue')
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Authentication = require('../authentication')
|
const Authentication = require('../authentication')
|
||||||
const FileUpload = require('../widgets/fileupload')
|
const FileUpload = require('../widgets/fileupload')
|
||||||
const Froala = require('./froala')
|
const Froala = require('./froala')
|
||||||
|
@ -120,6 +118,9 @@ const EditArticle = {
|
||||||
if (this.error) return
|
if (this.error) return
|
||||||
|
|
||||||
this.article.description = vnode.state.froala && vnode.state.froala.html.get() || this.article.description
|
this.article.description = vnode.state.froala && vnode.state.froala.html.get() || this.article.description
|
||||||
|
if (this.article.description) {
|
||||||
|
this.article.description = this.article.description.replace(/<p[^>]+data-f-id="pbf"[^>]+>[^>]+>[^>]+>[^>]+>/, '')
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Authentication = require('../authentication')
|
const Authentication = require('../authentication')
|
||||||
const FileUpload = require('../widgets/fileupload')
|
const FileUpload = require('../widgets/fileupload')
|
||||||
const Froala = require('./froala')
|
const Froala = require('./froala')
|
||||||
|
@ -98,6 +96,9 @@ const EditPage = {
|
||||||
if (this.error) return
|
if (this.error) return
|
||||||
|
|
||||||
this.page.description = vnode.state.froala ? vnode.state.froala.html.get() : this.page.description
|
this.page.description = vnode.state.froala ? vnode.state.froala.html.get() : this.page.description
|
||||||
|
if (this.page.description) {
|
||||||
|
this.page.description = this.page.description.replace(/<p[^>]+data-f-id="pbf"[^>]+>[^>]+>[^>]+>[^>]+>/, '')
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const { createStaff, updateStaff, getStaff } = require('../api/staff')
|
const { createStaff, updateStaff, getStaff } = require('../api/staff')
|
||||||
|
|
||||||
const EditStaff = {
|
const EditStaff = {
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Authentication = require('../authentication')
|
|
||||||
const { getAllPages, removePage } = require('../api/page')
|
const { getAllPages, removePage } = require('../api/page')
|
||||||
const Dialogue = require('../widgets/dialogue')
|
const Dialogue = require('../widgets/dialogue')
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const { getAllStaff, removeStaff } = require('../api/staff')
|
const { getAllStaff, removeStaff } = require('../api/staff')
|
||||||
const Dialogue = require('../widgets/dialogue')
|
const Dialogue = require('../widgets/dialogue')
|
||||||
const Pages = require('../widgets/pages')
|
const Pages = require('../widgets/pages')
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
const Authentication = require('../authentication')
|
const Authentication = require('../authentication')
|
||||||
|
|
||||||
exports.sendRequest = function(options, isPagination) {
|
exports.sendRequest = function(options, isPagination) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
const { sendRequest } = require('./common')
|
const { sendRequest } = require('./common')
|
||||||
|
|
||||||
exports.uploadMedia = function(file) {
|
exports.uploadMedia = function(file) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const { sendRequest } = require('./common')
|
const { sendRequest } = require('./common')
|
||||||
|
|
||||||
const Tree = []
|
const Tree = window.__nfptree || []
|
||||||
|
|
||||||
exports.Tree = Tree
|
exports.Tree = Tree
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ exports.createPage = function(body) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTree = function(body) {
|
exports.getTree = function() {
|
||||||
return sendRequest({
|
return sendRequest({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/pages?tree=true&includes=children&fields=id,name,path,children(id,name,path)',
|
url: '/api/pages?tree=true&includes=children&fields=id,name,path,children(id,name,path)',
|
||||||
|
|
120
app/app.scss
120
app/app.scss
File diff suppressed because one or more lines are too long
|
@ -54,6 +54,7 @@ const Article = {
|
||||||
m('.fr-view', [
|
m('.fr-view', [
|
||||||
this.article.media
|
this.article.media
|
||||||
? m('a.cover', {
|
? m('a.cover', {
|
||||||
|
rel: 'noopener',
|
||||||
href: this.article.media.url,
|
href: this.article.media.url,
|
||||||
}, m('img', { src: this.article.media.medium_url, alt: 'Cover image for ' + this.article.name }))
|
}, m('img', { src: this.article.media.medium_url, alt: 'Cover image for ' + this.article.name }))
|
||||||
: null,
|
: null,
|
||||||
|
|
|
@ -1,30 +1,35 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const storageName = 'logintoken'
|
const storageName = 'logintoken'
|
||||||
const loadingListeners = []
|
|
||||||
|
|
||||||
window.googleLoaded = function() {
|
|
||||||
Authentication.loadedGoogle = true
|
|
||||||
while (Authentication.loadingListeners.length) {
|
|
||||||
Authentication.loadingListeners.pop()()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Authentication = {
|
const Authentication = {
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
|
isAdmin: false,
|
||||||
loadedGoogle: false,
|
loadedGoogle: false,
|
||||||
loadingGoogle: false,
|
loadingGoogle: false,
|
||||||
loadingListeners: [],
|
loadingListeners: [],
|
||||||
|
authListeners: [],
|
||||||
|
|
||||||
updateToken: function(token) {
|
updateToken: function(token) {
|
||||||
if (!token) return Authentication.clearToken()
|
if (!token) return Authentication.clearToken()
|
||||||
localStorage.setItem(storageName, token)
|
localStorage.setItem(storageName, token)
|
||||||
Authentication.currentUser = JSON.parse(atob(token.split('.')[1]))
|
Authentication.currentUser = JSON.parse(atob(token.split('.')[1]))
|
||||||
|
|
||||||
|
if (Authentication.authListeners.length) {
|
||||||
|
Authentication.authListeners.forEach(function(x) { x(Authentication.currentUser) })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clearToken: function() {
|
clearToken: function() {
|
||||||
Authentication.currentUser = null
|
Authentication.currentUser = null
|
||||||
localStorage.removeItem(storageName)
|
localStorage.removeItem(storageName)
|
||||||
|
Authentication.isAdmin = false
|
||||||
|
},
|
||||||
|
|
||||||
|
addEvent: function(event) {
|
||||||
|
Authentication.authListeners.push(event)
|
||||||
|
},
|
||||||
|
|
||||||
|
setAdmin: function(item) {
|
||||||
|
Authentication.isAdmin = item
|
||||||
},
|
},
|
||||||
|
|
||||||
createGoogleScript: function() {
|
createGoogleScript: function() {
|
||||||
|
@ -50,6 +55,15 @@ const Authentication = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!window.googleLoaded) {
|
||||||
|
window.googleLoaded = function() {
|
||||||
|
Authentication.loadedGoogle = true
|
||||||
|
while (Authentication.loadingListeners.length) {
|
||||||
|
Authentication.loadingListeners.pop()()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Authentication.updateToken(localStorage.getItem(storageName))
|
Authentication.updateToken(localStorage.getItem(storageName))
|
||||||
|
|
||||||
module.exports = Authentication
|
module.exports = Authentication
|
||||||
|
|
|
@ -10,7 +10,7 @@ const Darkmode = {
|
||||||
Darkmode.darkIsOn = true
|
Darkmode.darkIsOn = true
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem(storageName)
|
localStorage.removeItem(storageName)
|
||||||
document.body.className = ''
|
document.body.className = 'daymode'
|
||||||
Darkmode.darkIsOn = false
|
Darkmode.darkIsOn = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const m = require('mithril')
|
const m = require('mithril')
|
||||||
const { Tree } = require('../api/page')
|
const { Tree } = require('../api/page')
|
||||||
const Authentication = require('../authentication')
|
const Authentication = require('../authentication')
|
||||||
const Darkmode = require('../darkmode')
|
|
||||||
|
|
||||||
const Footer = {
|
const Footer = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
|
@ -9,11 +8,6 @@ const Footer = {
|
||||||
},
|
},
|
||||||
|
|
||||||
view: function() {
|
view: function() {
|
||||||
var pixelRatio = window.devicePixelRatio || 1
|
|
||||||
var darkPrefix = ''
|
|
||||||
if (Darkmode.darkIsOn) {
|
|
||||||
darkPrefix = 'dark_'
|
|
||||||
}
|
|
||||||
return [
|
return [
|
||||||
m('div.sitemap', [
|
m('div.sitemap', [
|
||||||
m('div', 'Sitemap'),
|
m('div', 'Sitemap'),
|
||||||
|
@ -31,16 +25,15 @@ const Footer = {
|
||||||
!Authentication.currentUser
|
!Authentication.currentUser
|
||||||
? m(m.route.Link, { class: 'root', href: '/login' }, 'Login')
|
? m(m.route.Link, { class: 'root', href: '/login' }, 'Login')
|
||||||
: null,
|
: null,
|
||||||
m('div.meta', ['©'
|
m('div.meta', [
|
||||||
|
'©'
|
||||||
+ this.year
|
+ this.year
|
||||||
+ ' NFP Encodes - nfp@nfp.moe - ',
|
+ ' NFP Encodes - nfp@nfp.moe - ',
|
||||||
m('a', { href: 'https://www.iubenda.com/privacy-policy/31076050', target: '_blank' }, 'Privacy Policy'),
|
m('a', { rel: 'noopener', href: 'https://www.iubenda.com/privacy-policy/31076050', target: '_blank' }, 'Privacy Policy'),
|
||||||
' (Fuck EU)',
|
' (Fuck EU)',
|
||||||
])
|
|
||||||
]),
|
]),
|
||||||
m('div.footer-logo', { style: {
|
]),
|
||||||
'background-image': pixelRatio > 1 ? 'url("/assets/img/' + darkPrefix + 'tsun.jpg")' : 'url("/assets/img/' + darkPrefix + 'tsun_small.jpg")'
|
m('div.footer-logo'),
|
||||||
} }),
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,3 +73,35 @@ footer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.daymode footer .footer-logo {
|
||||||
|
background-image: url("/assets/img/tsun_small.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmodeon footer .footer-logo {
|
||||||
|
background-image: url("/assets/img/dark_tsun_small.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
@media
|
||||||
|
only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||||
|
only screen and ( min--moz-device-pixel-ratio: 2),
|
||||||
|
only screen and ( -o-min-device-pixel-ratio: 2/1),
|
||||||
|
only screen and ( min-device-pixel-ratio: 2),
|
||||||
|
only screen and ( min-resolution: 192dpi),
|
||||||
|
only screen and ( min-resolution: 2dppx) {
|
||||||
|
.daymode .footer-logo {
|
||||||
|
background-image: url("/assets/img/tsun.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmodeon .footer-logo {
|
||||||
|
background-image: url("/assets/img/dark_tsun.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (pointer:coarse) {
|
||||||
|
footer .sitemap a.root,
|
||||||
|
footer .sitemap a.child {
|
||||||
|
// padding: 10px 10px;
|
||||||
|
// display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
208
app/froala.scss
Normal file
208
app/froala.scss
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
.fr-view {
|
||||||
|
word-wrap: break-word;
|
||||||
|
|
||||||
|
.clearfix::after {
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6, p, dl, ol, ul {
|
||||||
|
margin: 0 0 1em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: solid 2px $main-fg;
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
color: $main-fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-by-clipping {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
border: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-rounded,
|
||||||
|
.fr-img-caption.fr-rounded img {
|
||||||
|
border-radius: 10px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
-webkit-border-radius: 10px;
|
||||||
|
-moz-background-clip: padding;
|
||||||
|
-webkit-background-clip: padding-box;
|
||||||
|
background-clip: padding-box
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-bordered,
|
||||||
|
.fr-img-caption.fr-bordered img {
|
||||||
|
border: solid 5px #CCC
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-bordered {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr-img-caption.fr-bordered img {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-emoticon {
|
||||||
|
font-weight: normal;
|
||||||
|
font-family: "Apple Color Emoji", "Segoe UI Emoji", "NotoColorEmoji", "Segoe UI Symbol", "Android Emoji", "EmojiSymbols";
|
||||||
|
display: inline;
|
||||||
|
line-height: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dib {
|
||||||
|
margin: 5px auto;
|
||||||
|
display: block;
|
||||||
|
float: none;
|
||||||
|
vertical-align: top
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dib.fr-fil {
|
||||||
|
margin-left: 0;
|
||||||
|
text-align: left
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dib.fr-fir {
|
||||||
|
margin-right: 0;
|
||||||
|
text-align: right
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dii {
|
||||||
|
display: inline-block;
|
||||||
|
float: none;
|
||||||
|
vertical-align: bottom;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
max-width: calc(100% - (2 * 5px))
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dii.fr-fil {
|
||||||
|
float: left;
|
||||||
|
margin: 5px 5px 5px 0;
|
||||||
|
max-width: calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
img.fr-dii.fr-fir {
|
||||||
|
float: right;
|
||||||
|
margin: 5px 0 5px 5px;
|
||||||
|
max-width: calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption {
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dib {
|
||||||
|
margin: 5px auto;
|
||||||
|
display: block;
|
||||||
|
float: none;
|
||||||
|
vertical-align: top
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dib.fr-fil {
|
||||||
|
margin-left: 0;
|
||||||
|
text-align: left
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dib.fr-fir {
|
||||||
|
margin-right: 0;
|
||||||
|
text-align: right
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dii {
|
||||||
|
display: inline-block;
|
||||||
|
float: none;
|
||||||
|
vertical-align: bottom;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
max-width: calc(100% - (2 * 5px))
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dii.fr-fil {
|
||||||
|
float: left;
|
||||||
|
margin: 5px 5px 5px 0;
|
||||||
|
max-width: calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fr-img-caption.fr-dii.fr-fir {
|
||||||
|
float: right;
|
||||||
|
margin: 5px 0 5px 5px;
|
||||||
|
max-width: calc(100% - 5px)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.fr-strong {
|
||||||
|
font-weight: 700
|
||||||
|
}
|
||||||
|
|
||||||
|
a.fr-green {
|
||||||
|
color: green
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr-img-caption {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr-img-caption .fr-img-wrap {
|
||||||
|
padding: 0;
|
||||||
|
display: inline-block;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr-img-caption .fr-img-wrap img {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr-img-caption .fr-img-wrap>span {
|
||||||
|
margin: auto;
|
||||||
|
display: block;
|
||||||
|
padding: 5px 5px 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: initial;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-opacity: 0.9;
|
||||||
|
-moz-opacity: 0.9;
|
||||||
|
opacity: 0.9;
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||||
|
width: 100%;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
a { color: $secondary-dark-bg; }
|
||||||
|
dt { font-weight: bold; }
|
||||||
|
ol { list-style-type: decimal; padding-left: 40px; }
|
||||||
|
ul { list-style-type: disc; padding-left: 40px; }
|
||||||
|
h1 { font-size: 1.8em; font-weight: bold; }
|
||||||
|
h2 { font-size: 1.6em; font-weight: bold; }
|
||||||
|
h3 { font-size: 1.4em; font-weight: bold; }
|
||||||
|
h4 { font-size: 1.2em; font-weight: bold; }
|
||||||
|
h5 { font-size: 1.0em; font-weight: bold; }
|
||||||
|
h6 { font-size: 0.8em; font-weight: bold; }
|
||||||
|
hr { width: 100%; }
|
||||||
|
strong { font-weight: 700 }
|
||||||
|
|
||||||
|
}
|
|
@ -5,15 +5,25 @@ const { getAllArticlesPagination } = require('../api/article')
|
||||||
const { fetchPage } = require('../api/pagination')
|
const { fetchPage } = require('../api/pagination')
|
||||||
const Pages = require('../widgets/pages')
|
const Pages = require('../widgets/pages')
|
||||||
const Newsitem = require('../widgets/newsitem')
|
const Newsitem = require('../widgets/newsitem')
|
||||||
const Darkmode = require('../darkmode')
|
|
||||||
|
|
||||||
module.exports = {
|
const Frontpage = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
this.error = ''
|
this.error = ''
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.featured = null
|
this.featured = null
|
||||||
this.links = null
|
this.links = null
|
||||||
|
|
||||||
|
if (window.__nfpdata
|
||||||
|
&& window.__nfplinks) {
|
||||||
|
this.links = window.__nfplinks
|
||||||
|
this.articles = window.__nfpdata
|
||||||
|
this.lastpage = '1'
|
||||||
|
window.__nfpdata = null
|
||||||
|
window.__nfplinks = null
|
||||||
|
Frontpage.processFeatured(vnode, this.articles)
|
||||||
|
} else {
|
||||||
this.fetchArticles(vnode)
|
this.fetchArticles(vnode)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onupdate: function(vnode) {
|
onupdate: function(vnode) {
|
||||||
|
@ -30,19 +40,14 @@ module.exports = {
|
||||||
this.lastpage = m.route.param('page') || '1'
|
this.lastpage = m.route.param('page') || '1'
|
||||||
|
|
||||||
return fetchPage(getAllArticlesPagination({
|
return fetchPage(getAllArticlesPagination({
|
||||||
per_page: 10,
|
per_page: 2,
|
||||||
page: this.lastpage,
|
page: this.lastpage,
|
||||||
includes: ['parent', 'files', 'media', 'banner'],
|
includes: ['parent', 'files', 'media', 'banner'],
|
||||||
}))
|
}))
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
vnode.state.articles = result.data
|
vnode.state.articles = result.data
|
||||||
vnode.state.links = result.links
|
vnode.state.links = result.links
|
||||||
|
Frontpage.processFeatured(vnode, result.data)
|
||||||
for (var i = result.data.length - 1; i >= 0; i--) {
|
|
||||||
if (result.data[i].banner) {
|
|
||||||
vnode.state.featured = result.data[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
vnode.state.error = err.message
|
vnode.state.error = err.message
|
||||||
|
@ -53,19 +58,18 @@ module.exports = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
processFeatured: function(vnode, data) {
|
||||||
|
for (var i = data.length - 1; i >= 0; i--) {
|
||||||
|
if (data[i].banner) {
|
||||||
|
vnode.state.featured = data[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
var deviceWidth = window.innerWidth
|
var deviceWidth = window.innerWidth
|
||||||
|
|
||||||
var bannerPath = ''
|
var bannerPath = ''
|
||||||
var asuna_side = ''
|
|
||||||
|
|
||||||
if (deviceWidth > 800) {
|
|
||||||
if (Darkmode.darkIsOn) {
|
|
||||||
asuna_side = '/assets/img/dark_asuna_frontpage.jpg'
|
|
||||||
} else {
|
|
||||||
asuna_side = '/assets/img/asuna_frontpage.jpg'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.featured && this.featured.banner) {
|
if (this.featured && this.featured.banner) {
|
||||||
var pixelRatio = window.devicePixelRatio || 1
|
var pixelRatio = window.devicePixelRatio || 1
|
||||||
|
@ -75,12 +79,12 @@ module.exports = {
|
||||||
|| (deviceWidth < 600 && pixelRatio > 1)) {
|
|| (deviceWidth < 600 && pixelRatio > 1)) {
|
||||||
bannerPath = this.featured.banner.medium_url
|
bannerPath = this.featured.banner.medium_url
|
||||||
} else {
|
} else {
|
||||||
bannerPath = this.featured.banner.url
|
bannerPath = this.featured.banner.large_url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(this.featured && this.featured.banner
|
(bannerPath
|
||||||
? m('a.frontpage-banner', {
|
? m('a.frontpage-banner', {
|
||||||
href: '/article/' + this.featured.path,
|
href: '/article/' + this.featured.path,
|
||||||
style: { 'background-image': 'url("' + bannerPath + '")' },
|
style: { 'background-image': 'url("' + bannerPath + '")' },
|
||||||
|
@ -103,7 +107,7 @@ module.exports = {
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
asuna_side ? m('img', { src: asuna_side, alt: 'Asuna standing tall welcomes you' }) : null,
|
m('div.asunaside'),
|
||||||
]),
|
]),
|
||||||
m('.frontpage-news', [
|
m('.frontpage-news', [
|
||||||
(this.loading
|
(this.loading
|
||||||
|
@ -121,3 +125,5 @@ module.exports = {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = Frontpage
|
||||||
|
|
|
@ -38,10 +38,6 @@ frontpage {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
img {
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories {
|
.categories {
|
||||||
padding: 10px 10px 20px;
|
padding: 10px 10px 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -89,6 +85,10 @@ frontpage {
|
||||||
newsitem {
|
newsitem {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asunaside {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1000px){
|
@media screen and (max-width: 1000px){
|
||||||
|
@ -113,6 +113,26 @@ frontpage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 800px){
|
||||||
|
frontpage .asunaside {
|
||||||
|
display: block;
|
||||||
|
width: 200px;
|
||||||
|
height: 480px;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top left;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.daymode frontpage .asunaside {
|
||||||
|
background-image: url("/assets/img/asuna_frontpage.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkmodeon frontpage .asunaside {
|
||||||
|
background-image: url("/assets/img/dark_asuna_frontpage.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 480px){
|
@media screen and (max-width: 480px){
|
||||||
.frontpage-banner {
|
.frontpage-banner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
70
app/index.js
70
app/index.js
|
@ -1,4 +1,5 @@
|
||||||
const m = require('mithril')
|
const m = require('mithril')
|
||||||
|
window.m = m
|
||||||
|
|
||||||
m.route.prefix = ''
|
m.route.prefix = ''
|
||||||
|
|
||||||
|
@ -7,31 +8,72 @@ const Footer = require('./footer/footer')
|
||||||
const Frontpage = require('./frontpage/frontpage')
|
const Frontpage = require('./frontpage/frontpage')
|
||||||
const Login = require('./login/login')
|
const Login = require('./login/login')
|
||||||
const Logout = require('./login/logout')
|
const Logout = require('./login/logout')
|
||||||
const EditPage = require('./admin/editpage')
|
|
||||||
const Page = require('./pages/page')
|
const Page = require('./pages/page')
|
||||||
const Article = require('./article/article')
|
const Article = require('./article/article')
|
||||||
const AdminPages = require('./admin/pages')
|
const Authentication = require('./authentication')
|
||||||
const AdminArticles = require('./admin/articles')
|
|
||||||
const EditArticle = require('./admin/editarticle')
|
|
||||||
const AdminStaffList = require('./admin/stafflist')
|
|
||||||
const EditStaff = require('./admin/editstaff')
|
|
||||||
|
|
||||||
const menuRoot = document.getElementById('nav')
|
const menuRoot = document.getElementById('nav')
|
||||||
const mainRoot = document.getElementById('main')
|
const mainRoot = document.getElementById('main')
|
||||||
const footerRoot = document.getElementById('footer')
|
const footerRoot = document.getElementById('footer')
|
||||||
|
|
||||||
m.route(mainRoot, '/', {
|
const allRoutes = {
|
||||||
'/': Frontpage,
|
'/': Frontpage,
|
||||||
'/login': Login,
|
'/login': Login,
|
||||||
'/logout': Logout,
|
'/logout': Logout,
|
||||||
'/page/:id': Page,
|
'/page/:id': Page,
|
||||||
'/article/:id': Article,
|
'/article/:id': Article,
|
||||||
'/admin/pages': AdminPages,
|
}
|
||||||
'/admin/pages/:key': EditPage,
|
|
||||||
'/admin/articles': AdminArticles,
|
m.route(mainRoot, '/', allRoutes)
|
||||||
'/admin/articles/:id': EditArticle,
|
|
||||||
'/admin/staff': AdminStaffList,
|
|
||||||
'/admin/staff/:id': EditStaff,
|
|
||||||
})
|
|
||||||
m.mount(menuRoot, Menu)
|
m.mount(menuRoot, Menu)
|
||||||
m.mount(footerRoot, Footer)
|
m.mount(footerRoot, Footer)
|
||||||
|
|
||||||
|
let loadingAdmin = false
|
||||||
|
let loadedAdmin = false
|
||||||
|
let loaded = 0
|
||||||
|
|
||||||
|
const onLoaded = function() {
|
||||||
|
loaded++
|
||||||
|
if (loaded < 2) return
|
||||||
|
|
||||||
|
if (window.addAdminRoutes) {
|
||||||
|
window.addAdminRoutes.forEach(function (item) {
|
||||||
|
allRoutes[item[0]] = item[1]
|
||||||
|
})
|
||||||
|
m.route(mainRoot, '/', allRoutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication.setAdmin(Authentication.currentUser && Authentication.currentUser.level >= 10)
|
||||||
|
loadedAdmin = true
|
||||||
|
m.redraw()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadAdmin = function(user) {
|
||||||
|
if (loadingAdmin) {
|
||||||
|
if (loadedAdmin) {
|
||||||
|
Authentication.setAdmin(user && user.level >= 10)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!user || user.level < 10) return
|
||||||
|
|
||||||
|
loadingAdmin = true
|
||||||
|
|
||||||
|
let element = document.createElement('link')
|
||||||
|
element.setAttribute('rel', 'stylesheet')
|
||||||
|
element.setAttribute('type', 'text/css')
|
||||||
|
element.setAttribute('href', '/assets/admin.css')
|
||||||
|
element.onload = onLoaded
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(element)
|
||||||
|
|
||||||
|
element = document.createElement('script')
|
||||||
|
element.setAttribute('type', 'text/javascript')
|
||||||
|
element.setAttribute('src', '/assets/admin.js')
|
||||||
|
element.onload = onLoaded
|
||||||
|
document.body.appendChild(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication.addEvent(loadAdmin)
|
||||||
|
if (Authentication.currentUser) {
|
||||||
|
loadAdmin(Authentication.currentUser)
|
||||||
|
}
|
||||||
|
|
|
@ -18,11 +18,13 @@ const Menu = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
Menu.onbeforeupdate()
|
Menu.onbeforeupdate()
|
||||||
|
|
||||||
|
if (Tree.length) return
|
||||||
|
|
||||||
Menu.loading = true
|
Menu.loading = true
|
||||||
|
|
||||||
getTree()
|
getTree()
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
Tree.splice(0, Tree.Length)
|
Tree.splice(0, Tree.length)
|
||||||
Tree.push.apply(Tree, results)
|
Tree.push.apply(Tree, results)
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
|
@ -35,13 +37,10 @@ const Menu = {
|
||||||
},
|
},
|
||||||
|
|
||||||
view: function() {
|
view: function() {
|
||||||
var pixelRatio = window.devicePixelRatio || 1
|
|
||||||
return [
|
return [
|
||||||
m('div.top', [
|
m('div.top', [
|
||||||
m(m.route.Link,
|
m(m.route.Link,
|
||||||
{ href: '/', class: 'logo', style: {
|
{ href: '/', class: 'logo' },
|
||||||
'background-image': pixelRatio > 1 ? 'url("/assets/img/logo.jpg")' : 'url("/assets/img/logo_small.jpg")'
|
|
||||||
} },
|
|
||||||
m('h2', 'NFP Moe')
|
m('h2', 'NFP Moe')
|
||||||
),
|
),
|
||||||
m('aside', Authentication.currentUser ? [
|
m('aside', Authentication.currentUser ? [
|
||||||
|
@ -51,16 +50,16 @@ const Menu = {
|
||||||
(Darkmode.darkIsOn
|
(Darkmode.darkIsOn
|
||||||
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
|
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
|
||||||
: m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, true) }, 'Night mode')
|
: m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, true) }, 'Night mode')
|
||||||
)
|
),
|
||||||
]),
|
]),
|
||||||
(Authentication.currentUser.level >= 10
|
(Authentication.isAdmin
|
||||||
? m('div.adminlinks', [
|
? m('div.adminlinks', [
|
||||||
m(m.route.Link, { href: '/admin/articles/add' }, 'Create article'),
|
m(m.route.Link, { href: '/admin/articles/add' }, 'Create article'),
|
||||||
m(m.route.Link, { href: '/admin/articles' }, 'Articles'),
|
m(m.route.Link, { href: '/admin/articles' }, 'Articles'),
|
||||||
m(m.route.Link, { href: '/admin/pages' }, 'Pages'),
|
m(m.route.Link, { href: '/admin/pages' }, 'Pages'),
|
||||||
m(m.route.Link, { hidden: Authentication.currentUser.level < 100, href: '/admin/staff' }, 'Staff'),
|
m(m.route.Link, { hidden: Authentication.currentUser.level < 100, href: '/admin/staff' }, 'Staff'),
|
||||||
])
|
])
|
||||||
: null
|
: (Authentication.currentUser.level > 10 ? m('div.loading-spinner') : null)
|
||||||
),
|
),
|
||||||
] : (Darkmode.darkIsOn
|
] : (Darkmode.darkIsOn
|
||||||
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
|
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
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 {
|
||||||
|
@ -74,6 +75,11 @@
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +127,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media
|
||||||
|
only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||||
|
only screen and ( min--moz-device-pixel-ratio: 2),
|
||||||
|
only screen and ( -o-min-device-pixel-ratio: 2/1),
|
||||||
|
only screen and ( min-device-pixel-ratio: 2),
|
||||||
|
only screen and ( min-resolution: 192dpi),
|
||||||
|
only screen and ( min-resolution: 2dppx) {
|
||||||
|
#nav .top a.logo {
|
||||||
|
background-image: url("/assets/img/logo.jpg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.darkmodeon {
|
.darkmodeon {
|
||||||
#nav {
|
#nav {
|
||||||
.top {
|
.top {
|
||||||
|
|
133
app/widgets/admin.scss
Normal file
133
app/widgets/admin.scss
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
fileupload {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: stretch;
|
||||||
|
|
||||||
|
.showicon,
|
||||||
|
.showbordericon,
|
||||||
|
.display {
|
||||||
|
flex-grow: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showbordericon {
|
||||||
|
border: 3px solid $title-fg;
|
||||||
|
border-style: dashed;
|
||||||
|
background-image: url('./img/upload.svg');
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showicon {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-image: url('./img/upload.svg');
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 600px;
|
||||||
|
width: 100%;
|
||||||
|
align-self: center;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display {
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: #33333388;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
opacity: 0.01;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
text-indent: -9999px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
border: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 60px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-image: url('./img/delete.svg');
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-color: transparent;
|
||||||
|
background-size: contain;
|
||||||
|
z-index: 3;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue {
|
||||||
|
background: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
max-width: 500px;
|
||||||
|
color: $main-fg;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
background: $secondary-dark-bg;
|
||||||
|
color: $secondary-dark-fg;
|
||||||
|
font-size: 1.5em;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: 1px solid $secondary-dark-bg;
|
||||||
|
background: transparent;
|
||||||
|
color: $secondary-dark-bg;
|
||||||
|
padding: 5px 15px;
|
||||||
|
min-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.alert {
|
||||||
|
border-color: red;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.cancel {
|
||||||
|
border-color: #999;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,137 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
fileupload {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: stretch;
|
|
||||||
|
|
||||||
.showicon,
|
|
||||||
.showbordericon,
|
|
||||||
.display {
|
|
||||||
flex-grow: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.showbordericon {
|
|
||||||
border: 3px solid $title-fg;
|
|
||||||
border-style: dashed;
|
|
||||||
background-image: url('./img/upload.svg');
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.showicon {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
background-image: url('./img/upload.svg');
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 600px;
|
|
||||||
width: 100%;
|
|
||||||
align-self: center;
|
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.display {
|
|
||||||
background-size: cover;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: #33333388;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
opacity: 0.01;
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
text-indent: -9999px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remove {
|
|
||||||
border: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 60px;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
background-image: url('./img/delete.svg');
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-color: transparent;
|
|
||||||
background-size: contain;
|
|
||||||
z-index: 3;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogue {
|
|
||||||
background: white;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
width: calc(100% - 40px);
|
|
||||||
max-width: 500px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
background: $secondary-dark-bg;
|
|
||||||
color: $secondary-dark-fg;
|
|
||||||
font-size: 1.5em;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border: 1px solid $secondary-dark-bg;
|
|
||||||
background: transparent;
|
|
||||||
color: $secondary-dark-bg;
|
|
||||||
padding: 5px 15px;
|
|
||||||
min-width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.alert {
|
|
||||||
border-color: red;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.cancel {
|
|
||||||
border-color: #999;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newsentry {
|
newsentry {
|
||||||
display: flex;
|
display: flex;
|
||||||
color: $meta-fg;
|
color: $meta-fg;
|
||||||
|
@ -275,6 +142,10 @@ newsitem {
|
||||||
flex: 2 1 auto;
|
flex: 2 1 auto;
|
||||||
padding: 0 5px 5px;
|
padding: 0 5px 5px;
|
||||||
|
|
||||||
|
&.extrapadding {
|
||||||
|
padding: 0 15px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
|
@ -342,28 +213,14 @@ pages {
|
||||||
.newsitemcontent {
|
.newsitemcontent {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entrycontent.extrapadding {
|
||||||
|
padding: 0 5px 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.darkmodeon {
|
.darkmodeon {
|
||||||
fileupload {
|
|
||||||
.showbordericon {
|
|
||||||
border: 3px solid $dark_title-fg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogue {
|
|
||||||
h2 {
|
|
||||||
background: $dark_secondary-dark-bg;
|
|
||||||
color: $dark_secondary-dark-fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border: 1px solid $dark_secondary-dark-bg;
|
|
||||||
color: $dark_secondary-dark-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newsentry {
|
newsentry {
|
||||||
color: $dark_meta-fg;
|
color: $dark_meta-fg;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Dialogue = {
|
const Dialogue = {
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
return m('div.floating-container', {
|
return m('div.floating-container', {
|
||||||
|
@ -10,7 +8,7 @@ const Dialogue = {
|
||||||
m('div.buttons', [
|
m('div.buttons', [
|
||||||
m('button', { class: vnode.attrs.yesclass || '', onclick: vnode.attrs.onyes }, vnode.attrs.yes),
|
m('button', { class: vnode.attrs.yesclass || '', onclick: vnode.attrs.onyes }, vnode.attrs.yes),
|
||||||
m('button', { class: vnode.attrs.noclass || '', onclick: vnode.attrs.onno }, vnode.attrs.no),
|
m('button', { class: vnode.attrs.noclass || '', onclick: vnode.attrs.onno }, vnode.attrs.no),
|
||||||
])
|
]),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Fileinfo = {
|
const Fileinfo = {
|
||||||
getPrefix(vnode) {
|
getPrefix(vnode) {
|
||||||
if (!vnode.attrs.file.filename.endsWith('.torrent')) {
|
if (!vnode.attrs.file.filename.endsWith('.torrent')) {
|
||||||
|
@ -49,6 +47,7 @@ const Fileinfo = {
|
||||||
m('span.prefix', this.getPrefix(vnode) + ':'),
|
m('span.prefix', this.getPrefix(vnode) + ':'),
|
||||||
m('a', {
|
m('a', {
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
|
rel: 'noopener',
|
||||||
href: vnode.attrs.file.url,
|
href: vnode.attrs.file.url,
|
||||||
}, this.getDownloadName(vnode)),
|
}, this.getDownloadName(vnode)),
|
||||||
vnode.attrs.file.magnet
|
vnode.attrs.file.magnet
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
const { uploadMedia } = require('../api/media')
|
const { uploadMedia } = require('../api/media')
|
||||||
|
|
||||||
const FileUpload = {
|
const FileUpload = {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
const Fileinfo = require('./fileinfo')
|
const Fileinfo = require('./fileinfo')
|
||||||
|
|
||||||
const Newsentry = {
|
const Newsentry = {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
const Fileinfo = require('./fileinfo')
|
const Fileinfo = require('./fileinfo')
|
||||||
|
|
||||||
const Newsitem = {
|
const Newsitem = {
|
||||||
|
@ -14,8 +13,10 @@ const Newsitem = {
|
||||||
? m('a.cover', {
|
? m('a.cover', {
|
||||||
href: '/article/' + vnode.attrs.path,
|
href: '/article/' + vnode.attrs.path,
|
||||||
}, m('img', { alt: 'Image for news item ' + vnode.attrs.name, src: pixelRatio > 1 ? vnode.attrs.media.medium_url : vnode.attrs.media.small_url }))
|
}, m('img', { alt: 'Image for news item ' + vnode.attrs.name, src: pixelRatio > 1 ? vnode.attrs.media.medium_url : vnode.attrs.media.small_url }))
|
||||||
: m('a.cover.nobg'),
|
: null,
|
||||||
m('div.entrycontent', [
|
m('div.entrycontent', {
|
||||||
|
class: vnode.attrs.media ? '' : 'extrapadding',
|
||||||
|
}, [
|
||||||
(vnode.attrs.description
|
(vnode.attrs.description
|
||||||
? m('.fr-view', m.trust(vnode.attrs.description))
|
? m('.fr-view', m.trust(vnode.attrs.description))
|
||||||
: null),
|
: null),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const m = require('mithril')
|
|
||||||
|
|
||||||
const Pages = {
|
const Pages = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
this.onpage = vnode.attrs.onpage || function() {}
|
this.onpage = vnode.attrs.onpage || function() {}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"port": 4030,
|
"port": 4030,
|
||||||
"host": "0.0.0.0"
|
"host": "0.0.0.0"
|
||||||
},
|
},
|
||||||
|
"CIRCLECI_VERSION": "circleci_version_number",
|
||||||
"knex": {
|
"knex": {
|
||||||
"client": "pg",
|
"client": "pg",
|
||||||
"connection": {
|
"connection": {
|
||||||
|
|
49
config/config.default.json.org
Normal file
49
config/config.default.json.org
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"NODE_ENV": "development",
|
||||||
|
"server": {
|
||||||
|
"port": 4030,
|
||||||
|
"host": "0.0.0.0"
|
||||||
|
},
|
||||||
|
"CIRCLECI_VERSION": "circleci_version_number",
|
||||||
|
"knex": {
|
||||||
|
"client": "pg",
|
||||||
|
"connection": {
|
||||||
|
"host" : "127.0.0.1",
|
||||||
|
"user" : "postgres",
|
||||||
|
"password" : "postgres",
|
||||||
|
"database" : "nfpmoe"
|
||||||
|
},
|
||||||
|
"connectionslave": null,
|
||||||
|
"migrations": {
|
||||||
|
},
|
||||||
|
"acquireConnectionTimeout": 10000
|
||||||
|
},
|
||||||
|
"bunyan": {
|
||||||
|
"name": "nfpmoe",
|
||||||
|
"streams": [{
|
||||||
|
"stream": "process.stdout",
|
||||||
|
"level": "debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"frontend": {
|
||||||
|
"url": "http://localhost:8080"
|
||||||
|
},
|
||||||
|
"jwt": {
|
||||||
|
"secret": "this-is-my-secret",
|
||||||
|
"options": {
|
||||||
|
"expiresIn": 604800
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"googleid": "1076074914074-3no1difo1jq3dfug3glfb25pn1t8idud.apps.googleusercontent.com",
|
||||||
|
"sessionsecret": "this-is-session-secret-lol",
|
||||||
|
"bcrypt": 5,
|
||||||
|
"fileSize": 524288000,
|
||||||
|
"upload": {
|
||||||
|
"baseurl": "http://192.168.42.14",
|
||||||
|
"port": "2111",
|
||||||
|
"host": "storage01.nfp.is",
|
||||||
|
"name": "nfpmoe-dev",
|
||||||
|
"secret": "nfpmoe-dev"
|
||||||
|
}
|
||||||
|
}
|
11
package.json
11
package.json
|
@ -19,13 +19,15 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"start": "node --experimental-modules index.mjs",
|
"start": "node --experimental-modules index.mjs",
|
||||||
"build": "sass -s compressed app/app.scss public/assets/app.css && browserify -p tinyify --no-commondir -o public/assets/app.js app/index.js",
|
"build": "sass -s compressed app/app.scss public/assets/app.css && sass -s compressed app/admin.scss public/assets/admin.css && browserify -p tinyify --no-commondir -o public/assets/app.js app/index.js && browserify -p tinyify --no-commondir -o public/assets/admin.js app/admin.js",
|
||||||
"build:check": "browserify -o public/assets/app.js app/index.js",
|
"build:check": "browserify -o public/assets/app.js app/index.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"watch:api": "nodemon --experimental-modules index.mjs | bunyan",
|
"watch:api": "nodemon --experimental-modules index.mjs | bunyan",
|
||||||
"watch:app": "watchify -g envify -d app/index.js -o public/assets/app.js",
|
"watch:app:admin": "watchify -g envify -d app/admin.js -o public/assets/admin.js",
|
||||||
"watch:sass": "sass --watch app/app.scss public/assets/app.css",
|
"watch:app:public": "watchify -g envify -d app/index.js -o public/assets/app.js",
|
||||||
"dev": "run-p watch:api watch:app watch:sass",
|
"watch:sass:public": "sass --watch app/app.scss public/assets/app.css",
|
||||||
|
"watch:sass:admin": "sass --watch app/admin.scss public/assets/admin.css",
|
||||||
|
"dev": "run-p watch:api watch:app:public watch:app:admin watch:sass:public watch:sass:admin",
|
||||||
"prod": "npm run build && npm start",
|
"prod": "npm run build && npm start",
|
||||||
"docker": "docker run -it --rm --name nfp_moe -e knex__connection__host -e NODE_ENV -p 4030:4030 -v \"$PWD\":/usr/src/app -w /usr/src/app node",
|
"docker": "docker run -it --rm --name nfp_moe -e knex__connection__host -e NODE_ENV -p 4030:4030 -v \"$PWD\":/usr/src/app -w /usr/src/app node",
|
||||||
"docker:install": "npm run docker -- npm install",
|
"docker:install": "npm run docker -- npm install",
|
||||||
|
@ -47,6 +49,7 @@
|
||||||
"bcrypt": "^3.0.0",
|
"bcrypt": "^3.0.0",
|
||||||
"bookshelf": "^0.15.1",
|
"bookshelf": "^0.15.1",
|
||||||
"bunyan-lite": "^1.0.1",
|
"bunyan-lite": "^1.0.1",
|
||||||
|
"dot": "^1.1.2",
|
||||||
"format-link-header": "^2.1.0",
|
"format-link-header": "^2.1.0",
|
||||||
"googleapis": "^42.0.0",
|
"googleapis": "^42.0.0",
|
||||||
"http-errors": "^1.7.2",
|
"http-errors": "^1.7.2",
|
||||||
|
|
1
public/assets/admin.css
Normal file
1
public/assets/admin.css
Normal file
File diff suppressed because one or more lines are too long
1
public/assets/admin.css.map
Normal file
1
public/assets/admin.css.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sourceRoot":"","sources":["../../app/admin.scss","../../app/_common.scss","../../app/admin/admin.scss","../../app/admin/pages.scss","../../app/admin/articles.scss","../../app/admin/staff.scss","../../app/widgets/admin.scss"],"names":[],"mappings":"AAEA,OACE,eACA,MCSkB,QDRlB,iBACA,oBAOF,qBACE,wBACA,YACA,yBACA,yBACA,iBACA,eAEA,8BACE,iBClBe,QDmBf,yBACA,MCnBe,KDoBf,aACA,gBAEF,8BACE,gBACA,yBACA,MCfO,KDgBP,aAEF,mFAGE,qBACA,MCzBgB,QD0BhB,iBAGF,4BACE,MC9BgB,QD+BhB,uBACA,yBAGF,4DAEE,iBAIJ,oBACE,eACA,MACA,SACA,OACA,QACA,qBACA,aACA,sBACA,uBACA,mBE/DF,eACE,YACA,aACA,sBACA,WDJW,QCKX,oBAGF,eACE,WDTW,QCUX,aACA,uBACA,gBAEA,oBACE,MDdS,KCeT,aACA,eACA,iBAGF,iBACE,aACA,qBACA,MDdiB,QCejB,eACA,iBAIJ,4CAGE,2BCjCF,iBACE,kBACA,gBACA,iBAEA,wBACE,aACA,WFCW,QECX,2BACE,MFDS,KEIX,0BACE,eACA,qBACA,iBACA,MFNe,KEUnB,4BACE,gBAEA,oCACE,aAIJ,kCACE,kBACA,gBAEA,2CACE,0BAIJ,sBACE,oBAEA,+BACE,aAGF,uCACE,aACA,kBAIJ,oBACE,mBAGF,kCACE,YACA,YACA,kBAIJ,mBACE,cC/DF,oBACE,kBACA,gBACA,iBAEA,2BACE,aACA,WHCW,QGCX,8BACE,MHDS,KGIX,6BACE,eACA,qBACA,iBACA,MHNe,KGUnB,+BACE,gBAEA,uCACE,aAIJ,qCACE,kBACA,gBAGF,yBACE,oBAEA,kCACE,aAGF,0CACE,aACA,kBAIJ,uBACE,mBAGF,qCACE,YACA,YACA,kBAEA,0CACE,WAIJ,gCACE,kBACA,aACA,cACA,gBACA,YACA,yBACA,WH1DiB,QG2DjB,MH1DiB,KG2DjB,kBAEA,sCACE,kBACA,MACA,OACA,QACA,SACA,YACA,WACA,eACA,oBACA,UAIJ,0BACE,oBACA,WACA,aACA,sBACA,oBACA,gBAEA,6BACE,gBACA,iBACA,kBACA,mBACA,6BAKN,sBACE,cCzGF,kBACE,kBACA,gBACA,iBAEA,yBACE,aACA,WJCW,QICX,4BACE,MJDS,KIIX,2BACE,eACA,qBACA,iBACA,MJNe,KIUnB,uBACE,oBAEA,gCACE,aAGF,wCACE,aACA,kBAIJ,qBACE,mBAGF,mCACE,YACA,YACA,kBAEA,wCACE,WC5CN,WACE,kBACA,aACA,oBACA,sBACA,wBAEA,oEAGE,YAGF,2BACE,sBACA,oBACA,yCACA,2BACA,4BACA,qBAGF,qBACE,kBACA,QACA,UACA,WACA,YACA,yCACA,2BACA,4BACA,wBAGF,eACE,gBACA,WACA,kBACA,iBAGF,oBACE,sBACA,4BACA,2BAGF,4BACE,kBACA,MACA,OACA,QACA,SACA,qBACA,WAGF,iBACE,kBACA,MACA,OACA,QACA,SACA,YACA,WACA,eACA,oBACA,UAGF,mBACE,YACA,kBACA,QACA,WACA,WACA,YACA,yCACA,2BACA,4BACA,6BACA,wBACA,UACA,aACA,eAIJ,SACE,gBACA,aACA,sBACA,kBACA,wBACA,gBACA,MLvEQ,KKyER,YACE,WLtFgB,QKuFhB,MLtFgB,KKuFhB,gBACA,aAGF,WACE,aAGF,kBACE,aACA,6BACA,aAGF,gBACE,yBACA,uBACA,MLzGgB,QK0GhB,iBACA,gBAGF,sBACE,iBACA,UAGF,uBACE,kBACA,WN3DF,0CACE,MC/CM,KDkDR,mBACE,MC7BqB","file":"admin.css"}
|
1
public/assets/admin.js
Normal file
1
public/assets/admin.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -6,20 +6,22 @@
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" href="/assets/img/favicon.png">
|
||||||
<link rel="Stylesheet" href="/assets/app.css?v=4" type="text/css" />
|
<link rel="Stylesheet" href="/assets/app.css?v={{=it.v}}" type="text/css" />
|
||||||
|
<link rel="preconnect" href="https://cdn-nfp.global.ssl.fastly.net" />
|
||||||
<meta name="google-signin-client_id" content="1076074914074-3no1difo1jq3dfug3glfb25pn1t8idud.apps.googleusercontent.com">
|
<meta name="google-signin-client_id" content="1076074914074-3no1difo1jq3dfug3glfb25pn1t8idud.apps.googleusercontent.com">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="daymode">
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
if (localStorage.getItem('darkmode')) {
|
if (localStorage.getItem('darkmode')) {document.body.className = 'darkmodeon';}
|
||||||
document.body.className = 'darkmodeon'
|
window.__nfptree = {{=it.tree}};
|
||||||
}
|
window.__nfpdata = {{=it.data}};
|
||||||
|
window.__nfplinks = {{=it.links}};
|
||||||
</script>
|
</script>
|
||||||
<div class="maincontainer">
|
<div class="maincontainer">
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
<main id="main"></main>
|
<main id="main"></main>
|
||||||
<footer id="footer"></footer>
|
<footer id="footer"></footer>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="/assets/app.js?v=4"></script>
|
<script type="text/javascript" src="/assets/app.js?v={{=it.v}}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue