More development and UI fixes
This commit is contained in:
parent
71f157d393
commit
727af236ec
16 changed files with 586 additions and 179 deletions
|
@ -5,7 +5,7 @@ import PageRoutes from '../base/page/routes.mjs'
|
||||||
|
|
||||||
export default class Server extends Parent {
|
export default class Server extends Parent {
|
||||||
init() {
|
init() {
|
||||||
this.flaskaOptions.appendHeaders['Content-Security-Policy'] = `default-src 'self'; script-src 'self' talk.hyvor.com; style-src 'self' 'unsafe-inline'; img-src * data: blob:; font-src 'self' data:; object-src 'none'; iframe-src talk.hyvor.com` //; frame-ancestors 'none'`
|
this.flaskaOptions.appendHeaders['Content-Security-Policy'] = `default-src 'self'; script-src 'self' talk.hyvor.com; style-src 'self' 'unsafe-inline'; img-src * data: blob:; font-src 'self' data:; object-src 'none'; frame-src talk.hyvor.com` //; frame-ancestors 'none'`
|
||||||
}
|
}
|
||||||
|
|
||||||
addCustomRoutes() {
|
addCustomRoutes() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const EditPage = require('./editpage')
|
const EditPage = require('./site_editpage')
|
||||||
const AllPages = require('./site_pages')
|
const AllPages = require('./site_pages')
|
||||||
const AllArticles = require('./site_articles')
|
const AllArticles = require('./site_articles')
|
||||||
const EditArticle = require('./editarticle')
|
const EditArticle = require('./editarticle')
|
||||||
|
|
|
@ -30,33 +30,45 @@ const FileUpload = {
|
||||||
},
|
},
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
let media = vnode.attrs.media
|
let imageLink = this.preview && this.preview.preview || vnode.attrs.media
|
||||||
|
|
||||||
return m('fileupload', {
|
return m('fileupload', {
|
||||||
class: vnode.attrs.class || null,
|
class: (vnode.attrs.class || '') + ' '
|
||||||
|
+ (!imageLink ? 'empty' : '') + ' '
|
||||||
|
+ (vnode.attrs.useimg ? 'useimg' : ''),
|
||||||
}, [
|
}, [
|
||||||
this.preview || media
|
imageLink && vnode.attrs.useimg
|
||||||
? vnode.attrs.useimg
|
? m('img', { src: imageLink })
|
||||||
? [ m('img', { src: this.preview && this.preview.preview || media }), m('div.showicon')]
|
: null,
|
||||||
: m('a.display.inside', {
|
imageLink && !vnode.attrs.useimg
|
||||||
href: this.preview && this.preview.preview || media,
|
? m('a', {
|
||||||
style: {
|
href: imageLink,
|
||||||
'background-image': 'url("' + (this.preview && this.preview.preview || media) + '")',
|
style: {
|
||||||
},
|
'background-image': 'url("' + (imageLink) + '")',
|
||||||
}, m('div.showicon'))
|
'height': vnode.attrs.height + 'px'
|
||||||
: m('div.inside.showbordericon')
|
},
|
||||||
|
})
|
||||||
|
: null
|
||||||
,
|
,
|
||||||
|
!imageLink
|
||||||
|
? m('div.noimage', {
|
||||||
|
style: {
|
||||||
|
'padding-top': vnode.attrs.useimg ? '56.25%' : null,
|
||||||
|
'height': !vnode.attrs.useimg ? vnode.attrs.height + 'px' : null,
|
||||||
|
},
|
||||||
|
}, vnode.children)
|
||||||
|
: null,
|
||||||
m('input', {
|
m('input', {
|
||||||
accept: 'image/*',
|
accept: 'image/*',
|
||||||
type: 'file',
|
type: 'file',
|
||||||
onchange: this.fileChanged.bind(this, vnode),
|
onchange: this.fileChanged.bind(this, vnode),
|
||||||
}),
|
}),
|
||||||
media && vnode.attrs.ondelete
|
/*imageLink && vnode.attrs.ondelete
|
||||||
? m('button.remove', { onclick: vnode.attrs.ondelete })
|
? m('button.remove', { onclick: vnode.attrs.ondelete })
|
||||||
: null,
|
: null,
|
||||||
this.loading
|
this.loading
|
||||||
? m('div.loading-spinner')
|
? m('div.loading-spinner')
|
||||||
: null,
|
: null,*/
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,9 @@ const AdminArticles = {
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
return [
|
return [
|
||||||
m('div.wrapper.admin', [
|
m('div.admin', [
|
||||||
m('div.inside', [
|
m('div.inside.vertical', [
|
||||||
|
m('div.spacer'),
|
||||||
m('h2', 'All articles'),
|
m('h2', 'All articles'),
|
||||||
m('div.actions', [
|
m('div.actions', [
|
||||||
m('span', 'Actions:'),
|
m('span', 'Actions:'),
|
||||||
|
|
351
nfp_moe/app/admin/site_editpage.js
Normal file
351
nfp_moe/app/admin/site_editpage.js
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
const FileUpload = require('./fileupload')
|
||||||
|
const PageTree = require('../page_tree')
|
||||||
|
|
||||||
|
const api = require('../api')
|
||||||
|
const Editor = require('./editor')
|
||||||
|
|
||||||
|
const AdminEditPage = {
|
||||||
|
oninit: function(vnode) {
|
||||||
|
this.loading = false
|
||||||
|
this.showLoading = null
|
||||||
|
this.data = {
|
||||||
|
page: null,
|
||||||
|
}
|
||||||
|
this.pages = [{id: null, name: 'Frontpage'}]
|
||||||
|
this.pages = this.pages.concat(PageTree.getFlatTree())
|
||||||
|
|
||||||
|
this.newBanner = null
|
||||||
|
this.newMedia = null
|
||||||
|
this.editor = null
|
||||||
|
|
||||||
|
this.fetchPage(vnode)
|
||||||
|
},
|
||||||
|
|
||||||
|
onbeforeupdate: function(vnode) {
|
||||||
|
if (this.lastid !== m.route.param('id')) {
|
||||||
|
this.fetchPage(vnode)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchPage: function(vnode) {
|
||||||
|
this.lastid = m.route.param('id')
|
||||||
|
|
||||||
|
return this.requestPage(
|
||||||
|
api.sendRequest({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/api/auth/pages/' + (this.lastid === 'add' ? '0' : this.lastid),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
requestPage: function(data) {
|
||||||
|
this.error = ''
|
||||||
|
|
||||||
|
if (this.showLoading) {
|
||||||
|
clearTimeout(this.showLoading)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.data.page) {
|
||||||
|
this.showLoading = setTimeout(() => {
|
||||||
|
this.showLoading = null
|
||||||
|
this.loading = true
|
||||||
|
m.redraw()
|
||||||
|
}, 150)
|
||||||
|
} else {
|
||||||
|
this.loading = true
|
||||||
|
}
|
||||||
|
|
||||||
|
data
|
||||||
|
.then((result) => {
|
||||||
|
this.data = result
|
||||||
|
if (this.data.page.id) {
|
||||||
|
document.title = 'Editing: ' + this.data.page.name + ' - Admin NFP Moe'
|
||||||
|
this.editedPath = true
|
||||||
|
} else {
|
||||||
|
document.title = 'Create Page - Admin NFP Moe'
|
||||||
|
}
|
||||||
|
}, (err) => {
|
||||||
|
this.error = err.message
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
if (!this.data.page) {
|
||||||
|
this.data.page = {}
|
||||||
|
}
|
||||||
|
clearTimeout(this.showLoading)
|
||||||
|
this.showLoading = null
|
||||||
|
this.loading = false
|
||||||
|
m.redraw()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateValue: function(name, e) {
|
||||||
|
this.data.page[name] = e.currentTarget.value
|
||||||
|
if (name === 'path') {
|
||||||
|
this.editedPath = true
|
||||||
|
} else if (name === 'name' && !this.editedPath) {
|
||||||
|
this.data.page.path = this.data.page.name.toLowerCase().replace(/ /g, '-')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateParent: function(e) {
|
||||||
|
this.data.page.parent_id = Number(e.currentTarget.value) || null
|
||||||
|
},
|
||||||
|
|
||||||
|
mediaUploaded: function(type, file) {
|
||||||
|
if (type === 'banner') {
|
||||||
|
this.newBanner = file
|
||||||
|
} else {
|
||||||
|
this.newMedia = file
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mediaRemoved: function(type) {
|
||||||
|
this.data.page['remove_' + type] = true
|
||||||
|
this.data.page[type + '_prefix'] = null
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function(vnode, e) {
|
||||||
|
e.preventDefault()
|
||||||
|
if (!this.data.page.name) {
|
||||||
|
this.error = 'Name is missing'
|
||||||
|
} else if (!this.data.page.path) {
|
||||||
|
this.error = 'Path is missing'
|
||||||
|
} else {
|
||||||
|
this.error = ''
|
||||||
|
}
|
||||||
|
if (this.error) return
|
||||||
|
|
||||||
|
let formData = new FormData()
|
||||||
|
if (this.newBanner) {
|
||||||
|
formData.append('banner', this.newBanner.file)
|
||||||
|
}
|
||||||
|
if (this.newMedia) {
|
||||||
|
formData.append('media', this.newMedia.file)
|
||||||
|
}
|
||||||
|
if (this.data.page.id) {
|
||||||
|
formData.append('id', this.data.page.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.append('name', this.data.page.name)
|
||||||
|
formData.append('parent_id', this.data.page.parent_id || null)
|
||||||
|
formData.append('path', this.data.page.path)
|
||||||
|
formData.append('remove_banner', this.data.page.remove_banner ? true : false)
|
||||||
|
formData.append('remove_media', this.data.page.remove_media ? true : false)
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
this.requestPage(
|
||||||
|
this.editor.save()
|
||||||
|
.then(body => {
|
||||||
|
formData.append('content', JSON.stringify(body))
|
||||||
|
|
||||||
|
return api.sendRequest({
|
||||||
|
method: 'PUT',
|
||||||
|
url: '/api/auth/pages/' + (this.lastid === 'add' ? '0' : this.lastid),
|
||||||
|
body: formData,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (!data.page.id) {
|
||||||
|
throw new Error('Something went wrong with saving, try again later')
|
||||||
|
} else if (this.lastid === 'add') {
|
||||||
|
this.lastid = data.page.id.toString()
|
||||||
|
m.route.set('/admin/pages/' + data.page.id)
|
||||||
|
}
|
||||||
|
return PageTree.refreshTree().then(() => {
|
||||||
|
this.pages = [{id: null, name: 'Frontpage'}]
|
||||||
|
this.pages = this.pages.concat(PageTree.getFlatTree())
|
||||||
|
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
view: function(vnode) {
|
||||||
|
let page = this.data.page
|
||||||
|
let bannerImage = page && page.banner_alt_prefix
|
||||||
|
? page.banner_alt_prefix + '_large.avif'
|
||||||
|
: null
|
||||||
|
let mediaImage = page && page.media_alt_prefix
|
||||||
|
? page.media_alt_prefix + '_large.avif'
|
||||||
|
: null
|
||||||
|
|
||||||
|
return [
|
||||||
|
m('div.admin', [
|
||||||
|
!this.loading
|
||||||
|
? m(FileUpload, {
|
||||||
|
class: 'banner',
|
||||||
|
height: 150,
|
||||||
|
onfile: this.mediaUploaded.bind(this, 'banner'),
|
||||||
|
ondelete: this.mediaRemoved.bind(this, 'banner'),
|
||||||
|
media: bannerImage,
|
||||||
|
}, 'Click to upload banner image')
|
||||||
|
: null,
|
||||||
|
m('div.inside.vertical', {
|
||||||
|
onsubmit: this.save.bind(this, vnode),
|
||||||
|
}, [
|
||||||
|
m('div.page-goback', [
|
||||||
|
'« ',
|
||||||
|
m(m.route.Link, { href: '/admin/pages' }, 'Pages')
|
||||||
|
]),
|
||||||
|
m('h2', this.lastid === 'add' ? 'Create page' : 'Edit ' + (page && page.name || '(untitled)')),
|
||||||
|
page
|
||||||
|
? m('div.actions', [
|
||||||
|
m('span', 'Actions:'),
|
||||||
|
m(m.route.Link, { href: '/page/' + page.path }, 'View page'),
|
||||||
|
])
|
||||||
|
: null,
|
||||||
|
m('div.error', {
|
||||||
|
hidden: !this.error,
|
||||||
|
onclick: function() { vnode.state.error = '' },
|
||||||
|
}, this.error),
|
||||||
|
this.loading
|
||||||
|
? m('div.loading-spinner')
|
||||||
|
: [
|
||||||
|
m(FileUpload, {
|
||||||
|
class: 'cover',
|
||||||
|
useimg: true,
|
||||||
|
onfile: this.mediaUploaded.bind(this, 'media'),
|
||||||
|
ondelete: this.mediaRemoved.bind(this, 'media'),
|
||||||
|
media: mediaImage,
|
||||||
|
}, 'Click to upload page image'),
|
||||||
|
m('form', [
|
||||||
|
m('label', 'Parent'),
|
||||||
|
m('select', {
|
||||||
|
onchange: this.updateParent.bind(this),
|
||||||
|
}, this.pages.filter(item => !page || item.id !== page.id).map((item) => {
|
||||||
|
return m('option', {
|
||||||
|
value: item.id || 0,
|
||||||
|
selected: item.id === page.parent_id
|
||||||
|
}, item.name)
|
||||||
|
})),
|
||||||
|
m('div.input-row', [
|
||||||
|
m('div', [
|
||||||
|
m('label', 'Name'),
|
||||||
|
m('input', {
|
||||||
|
type: 'text',
|
||||||
|
value: page.name,
|
||||||
|
oninput: this.updateValue.bind(this, 'name'),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
m('div', [
|
||||||
|
m('label', 'Path'),
|
||||||
|
m('input', {
|
||||||
|
type: 'text',
|
||||||
|
value: page.path,
|
||||||
|
oninput: this.updateValue.bind(this, 'path'),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
m('label', 'Description'),
|
||||||
|
m(Editor, {
|
||||||
|
oncreate: (subnode) => {
|
||||||
|
this.editor = subnode.state.editor
|
||||||
|
},
|
||||||
|
contentdata: page.content,
|
||||||
|
}),
|
||||||
|
m('input', {
|
||||||
|
hidden: !page.name || !page.path,
|
||||||
|
type: 'submit',
|
||||||
|
value: 'Save',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
/*
|
||||||
|
this.loading && !this.data.page
|
||||||
|
? m('div.admin-spinner.loading-spinner')
|
||||||
|
: null,
|
||||||
|
this.data.page
|
||||||
|
? m('div.admin-wrapper', [
|
||||||
|
this.loading
|
||||||
|
? m('div.loading-spinner')
|
||||||
|
: null,
|
||||||
|
m('div.admin-actions', this.data.page.id
|
||||||
|
? [
|
||||||
|
m('span', 'Actions:'),
|
||||||
|
m(m.route.Link, { href: '/page/' + this.data.page.path }, 'View page'),
|
||||||
|
]
|
||||||
|
: null),
|
||||||
|
m('article.editarticle', [
|
||||||
|
m('header', m('h1',
|
||||||
|
(this.data.page.id ? 'Edit ' : 'Create Page ') + (this.data.page.name || '(untitled)')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
m('div.error', {
|
||||||
|
hidden: !this.error,
|
||||||
|
onclick: () => { vnode.state.error = '' },
|
||||||
|
}, this.error),
|
||||||
|
m(FileUpload, {
|
||||||
|
height: 300,
|
||||||
|
onfile: this.mediaUploaded.bind(this, 'banner'),
|
||||||
|
ondelete: this.mediaRemoved.bind(this, 'banner'),
|
||||||
|
media: bannerImage,
|
||||||
|
}),
|
||||||
|
m(FileUpload, {
|
||||||
|
class: 'cover',
|
||||||
|
useimg: true,
|
||||||
|
onfile: this.mediaUploaded.bind(this, 'media'),
|
||||||
|
ondelete: this.mediaRemoved.bind(this, 'media'),
|
||||||
|
media: mediaImage,
|
||||||
|
}),
|
||||||
|
m('form.editarticle.content', {
|
||||||
|
onsubmit: this.save.bind(this, vnode),
|
||||||
|
}, [
|
||||||
|
m('label', 'Parent'),
|
||||||
|
m('select', {
|
||||||
|
onchange: this.updateParent.bind(this),
|
||||||
|
}, this.pages.filter(item => !this.data.page || item.id !== this.data.page.id).map((item) => {
|
||||||
|
return m('option', {
|
||||||
|
value: item.id || 0,
|
||||||
|
selected: item.id === this.data.page.parent_id
|
||||||
|
}, item.name)
|
||||||
|
})),
|
||||||
|
m('div.input-row', [
|
||||||
|
m('div.input-group', [
|
||||||
|
m('label', 'Name'),
|
||||||
|
m('input', {
|
||||||
|
type: 'text',
|
||||||
|
value: this.data.page.name,
|
||||||
|
oninput: this.updateValue.bind(this, 'name'),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
m('div.input-group', [
|
||||||
|
m('label', 'Path'),
|
||||||
|
m('input', {
|
||||||
|
type: 'text',
|
||||||
|
value: this.data.page.path,
|
||||||
|
oninput: this.updateValue.bind(this, 'path'),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
m('label', 'Description'),
|
||||||
|
m(Editor, {
|
||||||
|
oncreate: (subnode) => {
|
||||||
|
this.editor = subnode.state.editor
|
||||||
|
},
|
||||||
|
contentdata: this.data.page.content,
|
||||||
|
}),
|
||||||
|
m('div', {
|
||||||
|
hidden: !this.data.page.name || !this.data.page.path
|
||||||
|
}, [
|
||||||
|
m('input', {
|
||||||
|
type: 'submit',
|
||||||
|
value: 'Save',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
: m('div.error', {
|
||||||
|
hidden: !this.error,
|
||||||
|
onclick: () => { this.fetchPage(vnode) },
|
||||||
|
}, this.error),,*/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AdminEditPage
|
|
@ -68,8 +68,9 @@ const AdminPages = {
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
return [
|
return [
|
||||||
m('div.wrapper.admin', [
|
m('div.admin', [
|
||||||
m('div.inside', [
|
m('div.inside.vertical', [
|
||||||
|
m('div.spacer'),
|
||||||
m('h2', 'All pages'),
|
m('h2', 'All pages'),
|
||||||
m('div.actions', [
|
m('div.actions', [
|
||||||
m('span', 'Actions:'),
|
m('span', 'Actions:'),
|
||||||
|
@ -80,7 +81,7 @@ const AdminPages = {
|
||||||
onclick: function() { vnode.state.error = '' },
|
onclick: function() { vnode.state.error = '' },
|
||||||
}, this.error),
|
}, this.error),
|
||||||
this.loading
|
this.loading
|
||||||
? m('div.loading-spinner.full')
|
? m('div.loading-spinner')
|
||||||
: m('table', [
|
: m('table', [
|
||||||
m('thead',
|
m('thead',
|
||||||
m('tr', [
|
m('tr', [
|
||||||
|
|
|
@ -68,7 +68,9 @@ if (Authentication.currentUser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Loader = {
|
const Loader = {
|
||||||
view: function() { return m('div.loading-spinner') },
|
view: function() {
|
||||||
|
return m('div.wrapper', m('div.loading-spinner'))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const AdminResolver = {
|
const AdminResolver = {
|
||||||
onmatch: function(args, requestedPath) {
|
onmatch: function(args, requestedPath) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const Fileinfo = require('./fileinfo')
|
const Fileinfo = require('./fileinfo')
|
||||||
const EditorBlock = require('./editorblock')
|
const EditorBlock = require('./editorblock')
|
||||||
|
const media = require('./media')
|
||||||
|
|
||||||
const Article = {
|
const Article = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
|
@ -13,29 +14,17 @@ const Article = {
|
||||||
if (this.lastId !== article.id) {
|
if (this.lastId !== article.id) {
|
||||||
this.lastId = article.id
|
this.lastId = article.id
|
||||||
|
|
||||||
if (article.media_alt_prefix) {
|
let pictureCover = '(max-width: 639px) calc(100vw - 40px), '
|
||||||
this.pictureFallback = article.media_alt_prefix + '_small.jpg'
|
+ '(max-width: 1000px) 300px, '
|
||||||
this.pictureJpeg = article.media_alt_prefix + '_small.jpg' + ' 720w, '
|
+ '400px'
|
||||||
+ article.media_alt_prefix + '_medium.jpg' + ' 1300w, '
|
if (vnode.attrs.full) {
|
||||||
+ article.media_alt_prefix + '_large.jpg 1920w'
|
pictureCover = '(max-width: 1280) calc(100vw - 2rem), '
|
||||||
this.pictureAvif = article.media_alt_prefix + '_small.avif' + ' 720w, '
|
+ '1248px'
|
||||||
+ article.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
|
||||||
+ article.media_alt_prefix + '_large.avif 1920w'
|
|
||||||
|
|
||||||
if (vnode.attrs.full) {
|
|
||||||
this.pictureCover = '(max-width: 1280) calc(100vw - 2rem), '
|
|
||||||
+ '1248px'
|
|
||||||
} else {
|
|
||||||
this.pictureCover = '(max-width: 639px) calc(100vw - 40px), '
|
|
||||||
+ '(max-width: 1000px) 300px, '
|
|
||||||
+ '400px'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.pictureFallback = null
|
|
||||||
this.pictureJpeg = null
|
|
||||||
this.pictureAvif = null
|
|
||||||
this.pictureCover = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.pictureData = media.generatePictureSource(
|
||||||
|
article,
|
||||||
|
pictureCover)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -51,27 +40,12 @@ const Article = {
|
||||||
m('h2', article.name)
|
m('h2', article.name)
|
||||||
),
|
),
|
||||||
m('div.row', [
|
m('div.row', [
|
||||||
this.pictureFallback
|
media.getArticlePicture(
|
||||||
? m(vnode.attrs.full ? 'a' : m.route.Link, {
|
this.pictureData,
|
||||||
class: 'cover',
|
!vnode.attrs.full,
|
||||||
target: vnode.attrs.full ? '_blank' : '',
|
vnode.attrs.full ? article.media_path : '/article/' + article.path,
|
||||||
href: vnode.attrs.full ? article.media_path : '/article/' + article.path,
|
'Image for news item ' + article.name,
|
||||||
},
|
),
|
||||||
m('picture', [
|
|
||||||
m('source', {
|
|
||||||
srcset: this.pictureAvif,
|
|
||||||
sizes: this.pictureCover,
|
|
||||||
type: 'image/avif',
|
|
||||||
}),
|
|
||||||
m('img', {
|
|
||||||
srcset: this.pictureJpeg,
|
|
||||||
sizes: this.pictureCover,
|
|
||||||
alt: 'Image for news item ' + article.name,
|
|
||||||
src: this.pictureFallback,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
m('div', [
|
m('div', [
|
||||||
m('div.description',
|
m('div.description',
|
||||||
article.content.blocks.map(block => {
|
article.content.blocks.map(block => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const Fileinfo = require('./fileinfo')
|
const Fileinfo = require('./fileinfo')
|
||||||
|
const media = require('./media')
|
||||||
|
|
||||||
const Articleslim = {
|
const Articleslim = {
|
||||||
oninit: function(vnode) {
|
oninit: function(vnode) {
|
||||||
|
@ -35,23 +36,10 @@ const Articleslim = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (article.media_alt_prefix) {
|
this.pictureData = media.generatePictureSource(
|
||||||
this.pictureFallback = article.media_alt_prefix + '_small.jpg'
|
article,
|
||||||
this.pictureJpeg = article.media_alt_prefix + '_small.jpg' + ' 720w, '
|
'(max-width: 440px) calc(100vw - 40px), '
|
||||||
+ article.media_alt_prefix + '_medium.jpg' + ' 1300w, '
|
+ '124px')
|
||||||
+ article.media_alt_prefix + '_large.jpg 1920w'
|
|
||||||
this.pictureAvif = article.media_alt_prefix + '_small.avif' + ' 720w, '
|
|
||||||
+ article.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
|
||||||
+ article.media_alt_prefix + '_large.avif 1920w'
|
|
||||||
|
|
||||||
this.pictureCover = '(max-width: 440px) calc(100vw - 40px), '
|
|
||||||
+ '124px'
|
|
||||||
} else {
|
|
||||||
this.pictureFallback = null
|
|
||||||
this.pictureJpeg = null
|
|
||||||
this.pictureAvif = null
|
|
||||||
this.pictureCover = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -59,26 +47,13 @@ const Articleslim = {
|
||||||
let article = vnode.attrs.article
|
let article = vnode.attrs.article
|
||||||
|
|
||||||
return m('articleslim', [
|
return m('articleslim', [
|
||||||
this.pictureFallback
|
media.getArticlePicture(
|
||||||
? m(m.route.Link, {
|
this.pictureData,
|
||||||
class: 'cover',
|
true,
|
||||||
href: '/article/' + article.path,
|
'/article/' + article.path,
|
||||||
},
|
'Image for news item ' + article.name,
|
||||||
m('picture', [
|
m('a.cover.nobg')
|
||||||
m('source', {
|
),
|
||||||
srcset: this.pictureAvif,
|
|
||||||
sizes: this.pictureCover,
|
|
||||||
type: 'image/avif',
|
|
||||||
}),
|
|
||||||
m('img', {
|
|
||||||
srcset: this.pictureJpeg,
|
|
||||||
sizes: this.pictureCover,
|
|
||||||
alt: 'Image for news item ' + article.name,
|
|
||||||
src: this.pictureFallback,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
: m('a.cover.nobg'),
|
|
||||||
m('div', [
|
m('div', [
|
||||||
m(m.route.Link,
|
m(m.route.Link,
|
||||||
{ class: 'title', href: '/article/' + article.path },
|
{ class: 'title', href: '/article/' + article.path },
|
||||||
|
|
|
@ -7,7 +7,6 @@ const Authentication = {
|
||||||
authListeners: [],
|
authListeners: [],
|
||||||
|
|
||||||
updateToken: function(token) {
|
updateToken: function(token) {
|
||||||
console.log('updateToken', 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]))
|
||||||
|
@ -18,8 +17,6 @@ const Authentication = {
|
||||||
},
|
},
|
||||||
|
|
||||||
clearToken: function() {
|
clearToken: function() {
|
||||||
var err = new Error()
|
|
||||||
console.log('clearing', err.stack)
|
|
||||||
Authentication.currentUser = null
|
Authentication.currentUser = null
|
||||||
localStorage.removeItem(storageName)
|
localStorage.removeItem(storageName)
|
||||||
Authentication.isAdmin = false
|
Authentication.isAdmin = false
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
export function generateSource(item, cover) {
|
export function generatePictureSource(item, cover) {
|
||||||
if (!item) return
|
if (!item || !item.media_alt_prefix) return null
|
||||||
|
|
||||||
if (item.media_alt_prefix) {
|
return {
|
||||||
item.pictureFallback = item.media_alt_prefix + '_small.jpg'
|
fallback: item.media_alt_prefix + '_small.jpg',
|
||||||
item.pictureJpeg = item.media_alt_prefix + '_small.jpg' + ' 720w, '
|
jpeg: item.media_alt_prefix + '_small.jpg' + ' 720w, '
|
||||||
+ item.media_alt_prefix + '_medium.jpg' + ' 1300w, '
|
+ item.media_alt_prefix + '_medium.jpg' + ' 1300w, '
|
||||||
+ item.media_alt_prefix + '_large.jpg 1920w'
|
+ item.media_alt_prefix + '_large.jpg 1920w',
|
||||||
item.pictureAvif = item.media_alt_prefix + '_small.avif' + ' 720w, '
|
avif: item.media_alt_prefix + '_small.avif' + ' 720w, '
|
||||||
+ item.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
+ item.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
||||||
+ item.media_alt_prefix + '_large.avif 1920w'
|
+ item.media_alt_prefix + '_large.avif 1920w',
|
||||||
|
cover: cover,
|
||||||
item.pictureCover = cover
|
|
||||||
} else {
|
|
||||||
item.pictureFallback = null
|
|
||||||
item.pictureJpeg = null
|
|
||||||
item.pictureAvif = null
|
|
||||||
item.pictureCover = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,4 +41,29 @@ export function getBannerImage(item, prefix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getArticlePicture(pictureData, useRouteLink, path, altText, fallback) {
|
||||||
|
if (!pictureData) return fallback || null
|
||||||
|
|
||||||
|
return m(useRouteLink ? m.route.Link : 'a', {
|
||||||
|
class: 'cover',
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
}
|
}
|
|
@ -59,24 +59,6 @@ const SiteArticle = {
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.data = result
|
this.data = result
|
||||||
|
|
||||||
if (this.data.article.media_alt_prefix) {
|
|
||||||
this.data.article.pictureFallback = this.data.article.media_alt_prefix + '_small.jpg'
|
|
||||||
this.data.article.pictureJpeg = this.data.article.media_alt_prefix + '_small.jpg' + ' 720w, '
|
|
||||||
+ this.data.article.media_alt_prefix + '_medium.jpg' + ' 1300w, '
|
|
||||||
+ this.data.article.media_alt_prefix + '_large.jpg 1920w'
|
|
||||||
this.data.article.pictureAvif = this.data.article.media_alt_prefix + '_small.avif' + ' 720w, '
|
|
||||||
+ this.data.article.media_alt_prefix + '_medium.avif' + ' 1300w, '
|
|
||||||
+ this.data.article.media_alt_prefix + '_large.avif 1920w'
|
|
||||||
|
|
||||||
this.data.article.pictureCover = '(max-width: 840px) calc(100vw - 82px), '
|
|
||||||
+ '758px'
|
|
||||||
} else {
|
|
||||||
this.data.article.pictureFallback = null
|
|
||||||
this.data.article.pictureJpeg = null
|
|
||||||
this.data.article.pictureAvif = null
|
|
||||||
this.data.article.pictureCover = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.data.article) {
|
if (!this.data.article) {
|
||||||
this.error = 'Article not found'
|
this.error = 'Article not found'
|
||||||
}
|
}
|
||||||
|
@ -93,7 +75,6 @@ const SiteArticle = {
|
||||||
|
|
||||||
view: function(vnode) {
|
view: function(vnode) {
|
||||||
let article = this.data.article
|
let article = this.data.article
|
||||||
let banner = media.getBannerImage(article, '/article/')
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
this.loading
|
this.loading
|
||||||
|
@ -107,14 +88,6 @@ const SiteArticle = {
|
||||||
},
|
},
|
||||||
}, 'Page error: ' + this.error + '. Click here to try again'))
|
}, 'Page error: ' + this.error + '. Click here to try again'))
|
||||||
: null,
|
: null,
|
||||||
/*(banner
|
|
||||||
? m('a.page-banner', {
|
|
||||||
href: banner.original,
|
|
||||||
target: '_blank',
|
|
||||||
style: { 'background-image': 'url("' + banner.banner + '")' },
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: null),*/
|
|
||||||
(article
|
(article
|
||||||
? m('.inside.vertical', [
|
? m('.inside.vertical', [
|
||||||
m('div.page-goback', ['« ', m(m.route.Link, {
|
m('div.page-goback', ['« ', m(m.route.Link, {
|
||||||
|
@ -143,7 +116,7 @@ const SiteArticle = {
|
||||||
hyvor_talk.reload()
|
hyvor_talk.reload()
|
||||||
}
|
}
|
||||||
}}, m('div.loading-spinner'))
|
}}, m('div.loading-spinner'))
|
||||||
: m('button', {
|
: m('button.comments', {
|
||||||
onclick: function() { window.LoadComments = true },
|
onclick: function() { window.LoadComments = true },
|
||||||
}, 'Open comment discussion'),
|
}, 'Open comment discussion'),
|
||||||
])
|
])
|
||||||
|
|
|
@ -20,6 +20,7 @@ const SitePage = {
|
||||||
total_articles: 0,
|
total_articles: 0,
|
||||||
featured: null,
|
featured: null,
|
||||||
}
|
}
|
||||||
|
this.picture = null
|
||||||
this.children = []
|
this.children = []
|
||||||
this.currentPage = Number(m.route.param('page')) || 1
|
this.currentPage = Number(m.route.param('page')) || 1
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ const SitePage = {
|
||||||
title = 'NFP Moe - Anime/Manga translation group'
|
title = 'NFP Moe - Anime/Manga translation group'
|
||||||
}
|
}
|
||||||
|
|
||||||
media.generateSource(this.data.page,
|
this.picture = media.generatePictureSource(this.data.page,
|
||||||
'(max-width: 840px) calc(100vw - 82px), '
|
'(max-width: 840px) calc(100vw - 82px), '
|
||||||
+ '758px')
|
+ '758px')
|
||||||
|
|
||||||
|
@ -111,8 +112,6 @@ const SitePage = {
|
||||||
let page = this.data.page
|
let page = this.data.page
|
||||||
let featuredBanner = media.getBannerImage(this.data.featured, '/article/')
|
let featuredBanner = media.getBannerImage(this.data.featured, '/article/')
|
||||||
let pageBanner = media.getBannerImage(this.data.page, '/page/')
|
let pageBanner = media.getBannerImage(this.data.page, '/page/')
|
||||||
let paginatorMaxPath = Math.floor(this.data.total_articles / ArticlesPerPage) + 1
|
|
||||||
let paginatorPrefix = page ? '/page/' + page.path : '/'
|
|
||||||
|
|
||||||
return ([
|
return ([
|
||||||
this.loading
|
this.loading
|
||||||
|
@ -171,25 +170,8 @@ const SitePage = {
|
||||||
])
|
])
|
||||||
: null,
|
: null,
|
||||||
m('div.container', [
|
m('div.container', [
|
||||||
(page && page.pictureFallback
|
(page
|
||||||
? m('a.cover', {
|
? media.getArticlePicture(this.picture, false, page.media_path, 'Image for page ' + page.name)
|
||||||
rel: 'noopener',
|
|
||||||
href: page.media_path,
|
|
||||||
}, [
|
|
||||||
m('picture', [
|
|
||||||
m('source', {
|
|
||||||
srcset: page.pictureAvif,
|
|
||||||
sizes: page.pictureCover,
|
|
||||||
type: 'image/avif',
|
|
||||||
}),
|
|
||||||
m('img', {
|
|
||||||
srcset: page.pictureJpeg,
|
|
||||||
sizes: page.pictureCover,
|
|
||||||
alt: 'Image for news item ' + page.name,
|
|
||||||
src: page.pictureFallback,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
: null),
|
: null),
|
||||||
(page && page.content
|
(page && page.content
|
||||||
? page.content.blocks.map(block => {
|
? page.content.blocks.map(block => {
|
||||||
|
|
Binary file not shown.
|
@ -2,6 +2,8 @@
|
||||||
===================== Variables =====================
|
===================== Variables =====================
|
||||||
*/
|
*/
|
||||||
:root {
|
:root {
|
||||||
|
--admin-bg: hsl(213.9, 100%, 95%);
|
||||||
|
--admin-color: #000;
|
||||||
--admin-table-border: #01579b;
|
--admin-table-border: #01579b;
|
||||||
--admin-table-header-bg: #3D77C7;
|
--admin-table-header-bg: #3D77C7;
|
||||||
--admin-table-header-fg: #fff;
|
--admin-table-header-fg: #fff;
|
||||||
|
@ -11,12 +13,32 @@
|
||||||
===================== main =====================
|
===================== main =====================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
[hidden] { display: none !important; }
|
||||||
|
|
||||||
|
.admin {
|
||||||
|
background: var(--admin-bg);
|
||||||
|
color: var(--admin-color);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: calc(100vh - 200px);
|
||||||
|
}
|
||||||
|
|
||||||
.admin .inside {
|
.admin .inside {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin table {
|
.admin .spacer {
|
||||||
margin: 1rem;
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin .loading-spinner {
|
||||||
|
position: relative;
|
||||||
|
left: unset;
|
||||||
|
top: unset;
|
||||||
|
min-height: 300px;
|
||||||
|
height: calc(100vh - 300px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin table {
|
.admin table {
|
||||||
|
@ -24,6 +46,7 @@
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin table thead th,
|
.admin table thead th,
|
||||||
|
@ -47,6 +70,7 @@
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin table td.right,
|
.admin table td.right,
|
||||||
|
@ -55,7 +79,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin .actions {
|
.admin .actions {
|
||||||
margin: 0.5rem 1rem 0;
|
margin: 0.5rem 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
|
@ -64,3 +88,89 @@
|
||||||
.admin .actions a {
|
.admin .actions a {
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin form {
|
||||||
|
margin: 1rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin form input[type=text],
|
||||||
|
.admin form select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin .input-row {
|
||||||
|
display: flex;
|
||||||
|
margin-right: -1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin .input-row > * {
|
||||||
|
margin-right: 1rem;
|
||||||
|
flex: 2 1 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************** fileupload ************** */
|
||||||
|
|
||||||
|
fileupload {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload.banner {
|
||||||
|
margin: 0 0 -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload.empty {
|
||||||
|
border: 3px solid var(--seperator);
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload.empty.useimg {
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload a {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload .noimage {
|
||||||
|
color: var(--seperator);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fileupload input {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
opacity: 0.01;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
text-indent: -9999px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================== 3rd party =====================
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ce-block__content,
|
||||||
|
.ce-toolbar__content { max-width:calc(100% - 120px) !important; }
|
||||||
|
.cdx-block { max-width: 100% !important; }
|
||||||
|
|
||||||
|
.codex-editor {
|
||||||
|
border: 1px solid var(--color);
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.codex-editor:hover,
|
||||||
|
.codex-editor:active {
|
||||||
|
border-color: var(--link);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue