More development and UI fixes

master
Jonatan Nilsson 2022-08-08 07:22:41 +00:00
parent 71f157d393
commit 727af236ec
16 changed files with 586 additions and 179 deletions

View File

@ -5,7 +5,7 @@ import PageRoutes from '../base/page/routes.mjs'
export default class Server extends Parent {
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() {

View File

@ -1,4 +1,4 @@
const EditPage = require('./editpage')
const EditPage = require('./site_editpage')
const AllPages = require('./site_pages')
const AllArticles = require('./site_articles')
const EditArticle = require('./editarticle')

View File

@ -30,33 +30,45 @@ const FileUpload = {
},
view: function(vnode) {
let media = vnode.attrs.media
let imageLink = this.preview && this.preview.preview || vnode.attrs.media
return m('fileupload', {
class: vnode.attrs.class || null,
class: (vnode.attrs.class || '') + ' '
+ (!imageLink ? 'empty' : '') + ' '
+ (vnode.attrs.useimg ? 'useimg' : ''),
}, [
this.preview || media
? vnode.attrs.useimg
? [ m('img', { src: this.preview && this.preview.preview || media }), m('div.showicon')]
: m('a.display.inside', {
href: this.preview && this.preview.preview || media,
style: {
'background-image': 'url("' + (this.preview && this.preview.preview || media) + '")',
},
}, m('div.showicon'))
: m('div.inside.showbordericon')
imageLink && vnode.attrs.useimg
? m('img', { src: imageLink })
: null,
imageLink && !vnode.attrs.useimg
? m('a', {
href: imageLink,
style: {
'background-image': 'url("' + (imageLink) + '")',
'height': vnode.attrs.height + 'px'
},
})
: 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', {
accept: 'image/*',
type: 'file',
onchange: this.fileChanged.bind(this, vnode),
}),
media && vnode.attrs.ondelete
/*imageLink && vnode.attrs.ondelete
? m('button.remove', { onclick: vnode.attrs.ondelete })
: null,
this.loading
? m('div.loading-spinner')
: null,
: null,*/
])
},
}

View File

@ -111,8 +111,9 @@ const AdminArticles = {
view: function(vnode) {
return [
m('div.wrapper.admin', [
m('div.inside', [
m('div.admin', [
m('div.inside.vertical', [
m('div.spacer'),
m('h2', 'All articles'),
m('div.actions', [
m('span', 'Actions:'),

View 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

View File

@ -68,8 +68,9 @@ const AdminPages = {
view: function(vnode) {
return [
m('div.wrapper.admin', [
m('div.inside', [
m('div.admin', [
m('div.inside.vertical', [
m('div.spacer'),
m('h2', 'All pages'),
m('div.actions', [
m('span', 'Actions:'),
@ -80,7 +81,7 @@ const AdminPages = {
onclick: function() { vnode.state.error = '' },
}, this.error),
this.loading
? m('div.loading-spinner.full')
? m('div.loading-spinner')
: m('table', [
m('thead',
m('tr', [

View File

@ -68,7 +68,9 @@ if (Authentication.currentUser) {
}
const Loader = {
view: function() { return m('div.loading-spinner') },
view: function() {
return m('div.wrapper', m('div.loading-spinner'))
},
}
const AdminResolver = {
onmatch: function(args, requestedPath) {

View File

@ -1,5 +1,6 @@
const Fileinfo = require('./fileinfo')
const EditorBlock = require('./editorblock')
const media = require('./media')
const Article = {
oninit: function(vnode) {
@ -13,29 +14,17 @@ const Article = {
if (this.lastId !== article.id) {
this.lastId = article.id
if (article.media_alt_prefix) {
this.pictureFallback = article.media_alt_prefix + '_small.jpg'
this.pictureJpeg = article.media_alt_prefix + '_small.jpg' + ' 720w, '
+ article.media_alt_prefix + '_medium.jpg' + ' 1300w, '
+ 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'
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
let pictureCover = '(max-width: 639px) calc(100vw - 40px), '
+ '(max-width: 1000px) 300px, '
+ '400px'
if (vnode.attrs.full) {
pictureCover = '(max-width: 1280) calc(100vw - 2rem), '
+ '1248px'
}
this.pictureData = media.generatePictureSource(
article,
pictureCover)
}
},
@ -51,27 +40,12 @@ const Article = {
m('h2', article.name)
),
m('div.row', [
this.pictureFallback
? m(vnode.attrs.full ? 'a' : m.route.Link, {
class: 'cover',
target: vnode.attrs.full ? '_blank' : '',
href: vnode.attrs.full ? article.media_path : '/article/' + article.path,
},
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,
media.getArticlePicture(
this.pictureData,
!vnode.attrs.full,
vnode.attrs.full ? article.media_path : '/article/' + article.path,
'Image for news item ' + article.name,
),
m('div', [
m('div.description',
article.content.blocks.map(block => {

View File

@ -1,4 +1,5 @@
const Fileinfo = require('./fileinfo')
const media = require('./media')
const Articleslim = {
oninit: function(vnode) {
@ -35,23 +36,10 @@ const Articleslim = {
}
}
if (article.media_alt_prefix) {
this.pictureFallback = article.media_alt_prefix + '_small.jpg'
this.pictureJpeg = article.media_alt_prefix + '_small.jpg' + ' 720w, '
+ article.media_alt_prefix + '_medium.jpg' + ' 1300w, '
+ 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
}
this.pictureData = media.generatePictureSource(
article,
'(max-width: 440px) calc(100vw - 40px), '
+ '124px')
}
},
@ -59,26 +47,13 @@ const Articleslim = {
let article = vnode.attrs.article
return m('articleslim', [
this.pictureFallback
? m(m.route.Link, {
class: 'cover',
href: '/article/' + article.path,
},
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,
}),
])
)
: m('a.cover.nobg'),
media.getArticlePicture(
this.pictureData,
true,
'/article/' + article.path,
'Image for news item ' + article.name,
m('a.cover.nobg')
),
m('div', [
m(m.route.Link,
{ class: 'title', href: '/article/' + article.path },

View File

@ -7,7 +7,6 @@ const Authentication = {
authListeners: [],
updateToken: function(token) {
console.log('updateToken', token)
if (!token) return Authentication.clearToken()
localStorage.setItem(storageName, token)
Authentication.currentUser = JSON.parse(atob(token.split('.')[1]))
@ -18,8 +17,6 @@ const Authentication = {
},
clearToken: function() {
var err = new Error()
console.log('clearing', err.stack)
Authentication.currentUser = null
localStorage.removeItem(storageName)
Authentication.isAdmin = false

View File

@ -1,21 +1,15 @@
export function generateSource(item, cover) {
if (!item) return
export function generatePictureSource(item, cover) {
if (!item || !item.media_alt_prefix) return null
if (item.media_alt_prefix) {
item.pictureFallback = item.media_alt_prefix + '_small.jpg'
item.pictureJpeg = item.media_alt_prefix + '_small.jpg' + ' 720w, '
+ item.media_alt_prefix + '_medium.jpg' + ' 1300w, '
+ item.media_alt_prefix + '_large.jpg 1920w'
item.pictureAvif = item.media_alt_prefix + '_small.avif' + ' 720w, '
+ item.media_alt_prefix + '_medium.avif' + ' 1300w, '
+ item.media_alt_prefix + '_large.avif 1920w'
item.pictureCover = cover
} else {
item.pictureFallback = null
item.pictureJpeg = null
item.pictureAvif = null
item.pictureCover = null
return {
fallback: item.media_alt_prefix + '_small.jpg',
jpeg: item.media_alt_prefix + '_small.jpg' + ' 720w, '
+ item.media_alt_prefix + '_medium.jpg' + ' 1300w, '
+ item.media_alt_prefix + '_large.jpg 1920w',
avif: item.media_alt_prefix + '_small.avif' + ' 720w, '
+ item.media_alt_prefix + '_medium.avif' + ' 1300w, '
+ item.media_alt_prefix + '_large.avif 1920w',
cover: cover,
}
}
@ -47,4 +41,29 @@ export function getBannerImage(item, prefix) {
}
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,
}),
])
)
}

View File

@ -59,24 +59,6 @@ const SiteArticle = {
.then((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) {
this.error = 'Article not found'
}
@ -93,7 +75,6 @@ const SiteArticle = {
view: function(vnode) {
let article = this.data.article
let banner = media.getBannerImage(article, '/article/')
return [
this.loading
@ -107,14 +88,6 @@ const SiteArticle = {
},
}, 'Page error: ' + this.error + '. Click here to try again'))
: null,
/*(banner
? m('a.page-banner', {
href: banner.original,
target: '_blank',
style: { 'background-image': 'url("' + banner.banner + '")' },
},
)
: null),*/
(article
? m('.inside.vertical', [
m('div.page-goback', ['« ', m(m.route.Link, {
@ -143,7 +116,7 @@ const SiteArticle = {
hyvor_talk.reload()
}
}}, m('div.loading-spinner'))
: m('button', {
: m('button.comments', {
onclick: function() { window.LoadComments = true },
}, 'Open comment discussion'),
])

View File

@ -20,6 +20,7 @@ const SitePage = {
total_articles: 0,
featured: null,
}
this.picture = null
this.children = []
this.currentPage = Number(m.route.param('page')) || 1
@ -87,7 +88,7 @@ const SitePage = {
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), '
+ '758px')
@ -111,8 +112,6 @@ const SitePage = {
let page = this.data.page
let featuredBanner = media.getBannerImage(this.data.featured, '/article/')
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 ([
this.loading
@ -171,25 +170,8 @@ const SitePage = {
])
: null,
m('div.container', [
(page && page.pictureFallback
? m('a.cover', {
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,
}),
]),
])
(page
? media.getArticlePicture(this.picture, false, page.media_path, 'Image for page ' + page.name)
: null),
(page && page.content
? page.content.blocks.map(block => {

View File

@ -2,6 +2,8 @@
===================== Variables =====================
*/
:root {
--admin-bg: hsl(213.9, 100%, 95%);
--admin-color: #000;
--admin-table-border: #01579b;
--admin-table-header-bg: #3D77C7;
--admin-table-header-fg: #fff;
@ -11,12 +13,32 @@
===================== 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 {
padding-bottom: 1rem;
}
.admin table {
margin: 1rem;
.admin .spacer {
height: 40px;
}
.admin .loading-spinner {
position: relative;
left: unset;
top: unset;
min-height: 300px;
height: calc(100vh - 300px);
}
.admin table {
@ -24,6 +46,7 @@
border-collapse: collapse;
border-spacing: 0;
font-size: 0.75em;
margin-bottom: 1rem;
}
.admin table thead th,
@ -47,6 +70,7 @@
background: transparent;
border-color: transparent;
padding: 0;
margin: 0;
}
.admin table td.right,
@ -55,7 +79,7 @@
}
.admin .actions {
margin: 0.5rem 1rem 0;
margin: 0.5rem 0;
display: flex;
justify-content: flex-end;
font-size: 0.875rem;
@ -64,3 +88,89 @@
.admin .actions a {
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