Implemented dark mode and frontpage sidebar

This commit is contained in:
Jonatan Nilsson 2019-09-23 18:37:02 +00:00
parent 7c74375caf
commit 61f61fad85
33 changed files with 623 additions and 42 deletions

View file

@ -40,7 +40,7 @@ const Media = bookshelf.createModel({
},
link() {
return `${Media.baseUrl}${this.get('large_image')}`
return `${Media.baseUrl}${this.get('org_image')}`
},
url() {

View file

@ -17,6 +17,9 @@ export default class Resizer {
fit: sharp.fit.inside,
withoutEnlargement: true,
})
.jpeg({
quality: 80,
})
.toFile(output)
.then(() => output)
}
@ -29,6 +32,20 @@ export default class Resizer {
fit: sharp.fit.inside,
withoutEnlargement: true,
})
.jpeg({
quality: 80,
})
.toFile(output)
.then(() => output)
}
createLarge(input) {
let output = this.Media.getSubUrl(input, 'large')
return this.sharp(input)
.jpeg({
quality: 80,
})
.toFile(output)
.then(() => output)
}

View file

@ -21,13 +21,15 @@ export default class MediaRoutes {
let smallPath = await this.resize.createSmall(result.path)
let mediumPath = await this.resize.createMedium(result.path)
let largePath = await this.resize.createLarge(result.path)
let token = this.jwt.signDirect({ site: config.get('upload:name') }, config.get('upload:secret'))
let [large, small, medium] = await Promise.all([
let [org, small, medium, large] = await Promise.all([
this.uploadFile(token, result.path),
this.uploadFile(token, smallPath),
this.uploadFile(token, mediumPath),
this.uploadFile(token, largePath),
])
ctx.body = await this.Media.create({
@ -36,6 +38,7 @@ export default class MediaRoutes {
small_image: small.path,
medium_image: medium.path,
large_image: large.path,
org_image: org.path,
size: result.size,
staff_id: ctx.state.user.id,
})

View file

@ -1,9 +1,11 @@
import send from 'koa-send'
import defaults from './defaults'
export function serve(docRoot, pathname, options = {}) {
options.root = docRoot
return (ctx, next) => {
let opts = defaults({}, options)
if (ctx.request.method === 'OPTIONS') return
let filepath = ctx.path.replace(pathname, '')
@ -12,7 +14,15 @@ export function serve(docRoot, pathname, options = {}) {
filepath = '/index.html'
}
return send(ctx, filepath, options).catch((er) => {
if (filepath.endsWith('.jpg')
|| filepath.endsWith('.png')
|| filepath.endsWith('.js')
|| filepath.endsWith('.css')
|| filepath.endsWith('.svg')) {
opts = defaults({ maxage: 2592000 * 1000 }, opts)
}
return send(ctx, filepath, opts).catch((er) => {
if (er.code === 'ENOENT' && er.status === 404) {
return send(ctx, '/index.html', options)
}

View file

@ -1,6 +1,8 @@
$primary-bg: #01579b;
$primary-fg: white;
$primary-light-bg: #3D77C7; /*#4f83cc;*/
$primary-fg-url: #FFC7C7;
$primary-light-bg: #3D77C7; // #4f83cc;
$primary-light-fg: white;
$primary-dark-bg: #002f6c;
$primary-dark-fg: white;
@ -12,7 +14,53 @@ $secondary-light-fg: black;
$secondary-dark-bg: #bb4d00;
$secondary-dark-fg: white;
$table-fg: #333;
$border: #ccc;
$border-fg: black;
$border-fg-url: #8f3c00;
$title-fg: #555;
$meta-fg: #757575; /* #999 */
$meta-fg: #757575; // #999
$meta-light-fg: #999999;
$main-bg: white;
$main-fg: black;
$input-bg: white;
$input-border: #333;
$input-fg: black;
$newsitem-bg: transparent;
$newsitem-border: none;
/* Dark theme */
$dark_primary-bg: #013b68;
$dark_primary-fg: white;
$dark_primary-fg-url: #FFC7C7;
$dark_primary-light-bg: #28518B;
$dark_primary-light-fg: white;
$dark_primary-dark-bg: #002f6c;
$dark_primary-dark-fg: white;
$dark_secondary-bg: #e05e00;
$dark_secondary-fg: black;
$dark_secondary-light-bg: #ffad42;
$dark_secondary-light-fg: black;
$dark_secondary-dark-bg: #e05e00;
$dark_secondary-dark-fg: white;
$dark_table-fg: #333;
$dark_border: #343536;
$dark_border-fg: #d7dadc;;
$dark_border-fg-url: #e05e00;
$dark_title-fg: #808080;
$dark_meta-fg: #d7dadc;
$dark_meta-light-fg: #999999;
$dark_main-bg: black;
$dark_main-fg: #d7dadc;
$dark_input-bg: #272729;
$dark_input-border: #343536;
$dark_input-fg: white;
$dark_newsitem-bg: #1a1a1b;
$dark_newsitem-border: 1px solid #343536;

View file

@ -38,3 +38,21 @@
@import 'pages';
@import 'articles';
@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;
}
}
}

View file

@ -21,6 +21,10 @@ body {
font-family: Arial, Helvetica, sans-serif;
}
button {
font-family: Arial, Helvetica, sans-serif;
}
ol, ul {
list-style: none;
}
@ -51,6 +55,8 @@ img {
}
.maincontainer {
background: $main-bg;
color: $main-fg;
width: 100%;
min-height: 100vh;
display: flex;
@ -133,9 +139,9 @@ form {
font-size: 1em;
padding: 0.5em;
margin: 0 0 0.5em;
background: white;
border: 1px solid #333;
color: black;
background: $input-bg;
border: 1px solid $input-border;
color: $input-fg;
outline: none;
&:hover,
@ -203,7 +209,7 @@ table {
tbody td {
text-align: left;
border: solid 1px $bordercolor;
color: #333;
color: $table-fg;
padding: 10px;
}
a,
@ -247,3 +253,91 @@ table {
@import 'pages/page';
@import 'article/article';
@import 'frontpage/frontpage';
.darkmodeon {
.maincontainer {
background: $dark_main-bg;
color: $dark_main-fg;
}
.error {
color: $dark_secondary-dark-bg;
}
article {
header {
h1 {
color: $dark_title-fg;
}
span {
color: $dark_meta-fg;
}
}
.content {
h5 {
color: $dark_title-fg;
}
}
}
form {
input[type=text],
input[type=password],
select,
textarea {
background: $dark_input-bg;
border: 1px solid $dark_input-border;
color: $dark_input-fg;
&:hover,
&:focus {
border-color: $dark_secondary-bg;
}
}
input[type=submit] {
border: 1px solid $dark_secondary-bg;
background: $dark_secondary-light-bg;
color: $dark_secondary-light-fg;
&:hover {
background: $dark_secondary-dark-bg;
color: $dark_secondary-dark-fg;
}
}
}
.fr-view {
a { color: $dark_secondary-dark-bg; }
}
$dark_bordercolor: $dark_primary-bg;
$dark_headcolor: $dark_primary-light-bg;
$dark_headtext: $dark_primary-light-fg;
table {
border: solid 1px $dark_bordercolor;
thead th {
background-color: $dark_headcolor;
border: solid 1px $dark_bordercolor;
color: $dark_headtext;
}
tbody td {
border: solid 1px $dark_bordercolor;
color: $dark_table-fg;
}
a,
a:visited,
a:hover {
color: $dark_secondary-dark-bg;
}
button {
color: $dark_secondary-dark-bg;
border: 1px solid $dark_secondary-dark-bg;
}
}
}

View file

@ -1,10 +1,10 @@
article.article {
background: white;
padding: 0 0 40px;
padding: 0;
header {
text-align: center;
margin: 20px;
margin: 20px 20px 0;
padding: 10px;
background: $secondary-bg;
width: 100%;
@ -26,11 +26,14 @@ article.article {
.fr-view {
margin: 0 20px;
padding: 0 20px;
padding: 20px 20px 60px;
width: calc(100% - 40px);
max-width: 800px;
flex: 2 0 0;
align-self: center;
background: $newsitem-bg;
border-right: 1px solid #343536;
border-left: 1px solid #343536;
a.cover img {
margin-bottom: 30px;
@ -41,3 +44,19 @@ article.article {
}
}
}
.darkmodeon {
article.article {
header {
background: $dark_secondary-bg;
h1 {
color: $dark_secondary-fg;
}
}
.fr-view {
background: $dark_newsitem-bg;
}
}
}

25
app/darkmode.js Normal file
View file

@ -0,0 +1,25 @@
const storageName = 'darkmode'
const Darkmode = {
darkIsOn: false,
setDarkMode: function(setOn) {
if (setOn) {
localStorage.setItem(storageName, true)
document.body.className = 'darkmodeon'
Darkmode.darkIsOn = true
} else {
localStorage.removeItem(storageName)
document.body.className = ''
Darkmode.darkIsOn = false
}
},
isOn: function() {
return Darkmode.darkIsOn
},
}
Darkmode.darkIsOn = localStorage.getItem(storageName)
module.exports = Darkmode

View file

@ -1,6 +1,7 @@
const m = require('mithril')
const { Tree } = require('../api/page')
const Authentication = require('../authentication')
const Darkmode = require('../darkmode')
const Footer = {
oninit: function(vnode) {
@ -8,7 +9,11 @@ const Footer = {
},
view: function() {
console.log(Tree)
var pixelRatio = window.devicePixelRatio || 1
var darkPrefix = ''
if (Darkmode.darkIsOn) {
darkPrefix = 'dark_'
}
return [
m('div.sitemap', [
m('div', 'Sitemap'),
@ -33,7 +38,9 @@ const Footer = {
' (Fuck EU)',
])
]),
m('div.footer-logo'),
m('div.footer-logo', { style: {
'background-image': pixelRatio > 1 ? 'url("/assets/img/' + darkPrefix + 'tsun.jpg")' : 'url("/assets/img/' + darkPrefix + 'tsun_small.jpg")'
} }),
]
},
}

View file

@ -5,6 +5,7 @@ footer {
display: flex;
padding: 20px;
background: $border;
color: $border-fg;
.sitemap {
display: flex;
@ -17,7 +18,7 @@ footer {
a {
text-decoration: none;
color: #8f3c00;
color: $border-fg-url;
}
a.root {
@ -40,7 +41,7 @@ footer {
}
.footer-logo {
background: url('./img/tsun.png') center no-repeat transparent;
background: center no-repeat transparent;
background-size: contain;
width: 119px;
height: 150px;
@ -58,3 +59,17 @@ footer {
a { margin: 0 3px; }
}
}
.darkmodeon {
footer {
border-top: 1px solid $dark_border;
background: $dark_border;
color: $dark_border-fg;
.sitemap {
a {
color: $dark_border-fg-url;
}
}
}
}

View file

@ -1,9 +1,11 @@
const m = require('mithril')
const { Tree } = require('../api/page')
const { getAllArticlesPagination } = require('../api/article')
const { fetchPage } = require('../api/pagination')
const Pages = require('../widgets/pages')
const Newsitem = require('../widgets/newsitem')
const Darkmode = require('../darkmode')
module.exports = {
oninit: function(vnode) {
@ -52,9 +54,20 @@ module.exports = {
},
view: function(vnode) {
var deviceWidth = window.innerWidth
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) {
var deviceWidth = window.innerWidth
var pixelRatio = window.devicePixelRatio || 1
if (deviceWidth < 400 && pixelRatio <= 1) {
bannerPath = this.featured.banner.small_url
@ -76,16 +89,34 @@ module.exports = {
)
: null),
m('frontpage', [
(this.loading
? m('div.loading-spinner')
: null),
this.articles.map(function(article) {
return m(Newsitem, article)
}),
m(Pages, {
base: '/',
links: this.links,
}),
m('aside.sidebar', [
m('div.categories', [
m('h4', 'Categories'),
Tree.map(function(page) {
return [
m(m.route.Link, { class: 'root', href: '/page/' + page.path }, page.name),
(page.children.length
? m('ul', page.children.map(function(subpage) {
return m('li', m(m.route.Link, { class: 'child', href: '/page/' + subpage.path }, subpage.name))
}))
: null),
]
}),
]),
asuna_side ? m('img', { src: asuna_side, alt: 'Asuna standing tall welcomes you' }) : null,
]),
m('.frontpage-news', [
(this.loading
? m('div.loading-spinner')
: null),
this.articles.map(function(article) {
return m(Newsitem, article)
}),
m(Pages, {
base: '/',
links: this.links,
}),
]),
]),
]
},

View file

@ -1,5 +1,5 @@
.frontpage-banner {
background-color: #999999;
background-color: $meta-light-fg;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
@ -20,14 +20,68 @@
frontpage {
display: flex;
flex-direction: column;
align-self: center;
margin: 0 20px;
padding: 0 20px 40px;
width: calc(100% - 40px);
max-width: 1000px;
max-width: 1200px;
flex: 2 0 0;
.frontpage-news {
display: flex;
flex-direction: column;
}
aside.sidebar {
width: 250px;
flex: 0 0 250px;
align-self: flex-start;
margin-right: 20px;
display: flex;
flex-direction: column;
img {
align-self: center;
}
.categories {
padding: 10px 10px 20px;
margin-bottom: 20px;
background: $newsitem-bg;
border: $newsitem-border;
}
h4 {
font-size: 14px;
padding: 0 5px 5px;
font-weight: bold;
margin: 0 0 10px;
border-bottom: 1px solid $border;
}
ul {
margin: 0;
padding: 0;
li {
padding-left: 10px;
list-style-type: disc;
list-style-position: inside;
a {
display: inline-block;
}
}
}
a {
padding: 5px 5px 0px;
display: block;
text-decoration: none;
color: $secondary-dark-bg;
font-size: 14px;
font-weight: bold;
}
}
.loading-spinner {
height: 100px;
}
@ -37,6 +91,28 @@ frontpage {
}
}
@media screen and (max-width: 1000px){
frontpage aside.sidebar {
width: 200px;
flex: 0 0 200px;
}
}
@media screen and (max-width: 800px){
frontpage {
flex-direction: column;
}
frontpage aside.sidebar {
width: auto;
flex: 0 0 auto;
align-self: stretch;
margin: 20px 0 30px;
border-bottom: 1px solid $border;
order: 2;
}
}
@media screen and (max-width: 480px){
.frontpage-banner {
width: 100%;
@ -48,3 +124,26 @@ frontpage {
width: 100%;
}
}
.darkmodeon {
.frontpage-banner {
background-color: $dark_meta-light-fg;
}
frontpage {
aside.sidebar {
.categories {
background: $dark_newsitem-bg;
border: $dark_newsitem-border;
}
h4 {
border-bottom: 1px solid $dark_border;
}
a {
color: $dark_secondary-dark-bg;
}
}
}
}

View file

@ -21,7 +21,8 @@ article.login {
text-align: center;
flex-grow: 0;
border: 1px solid $title-fg;
background: white;
background: $main-bg;
color: $main-fg;
align-self: center;
.content {
@ -45,3 +46,15 @@ article.login {
margin-bottom: 20px;
}
}
.darkmodeon {
.login-wrapper {
background: $dark_border;
}
article.login {
border: 1px solid $dark_title-fg;
background: $dark_main-bg;
color: $dark_main-fg;
}
}

View file

@ -1,5 +1,6 @@
const m = require('mithril')
const Authentication = require('../authentication')
const Darkmode = require('../darkmode')
const { Tree, getTree } = require('../api/page')
const Menu = {
@ -34,16 +35,23 @@ const Menu = {
},
view: function() {
var pixelRatio = window.devicePixelRatio || 1
return [
m('div.top', [
m(m.route.Link,
{ href: '/', class: 'logo' },
{ href: '/', class: 'logo', style: {
'background-image': pixelRatio > 1 ? 'url("/assets/img/logo.jpg")' : 'url("/assets/img/logo_small.jpg")'
} },
m('h2', 'NFP Moe')
),
m('aside', Authentication.currentUser ? [
m('p', [
'Welcome ' + Authentication.currentUser.email,
m(m.route.Link, { href: '/logout' }, 'Logout'),
(Darkmode.darkIsOn
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
: m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, true) }, 'Night mode')
)
]),
(Authentication.currentUser.level >= 10
? m('div.adminlinks', [
@ -54,7 +62,11 @@ const Menu = {
])
: null
),
] : null),
] : (Darkmode.darkIsOn
? m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, false) }, 'Day mode')
: m('button.dark', { onclick: Darkmode.setDarkMode.bind(Darkmode, true) }, 'Night mode')
)
),
]),
m('nav', [
m(m.route.Link, {

View file

@ -11,8 +11,17 @@
height: 100px;
display: flex;
button.dark {
background: transparent;
color: $secondary-light-bg;
border: none;
cursor: pointer;
font-weight: bold;
}
a.logo {
background: url('./img/logo.png') 25px center no-repeat transparent;
background: 25px center no-repeat transparent;
background-size: auto 91px;
padding-left: 120px;
display: flex;
color: $primary-dark-fg;
@ -39,6 +48,10 @@
a {
margin-left: 5px;
}
button {
font-size: 0.8em;
}
}
a, a:visited {
@ -103,7 +116,48 @@
background: $primary-bg;
text-align: center;
padding: 10px;
color: #FFC7C7;
color: $primary-fg-url;
font-weight: bold;
}
}
.darkmodeon {
#nav {
.top {
background: $dark_primary-dark-bg;
color: $dark_primary-dark-fg;
a.logo {
color: $dark_primary-dark-fg;
}
aside {
p {
color: $dark_meta-light-fg;
}
a, a:visited {
color: $dark_secondary-light-bg;
}
}
}
nav {
background: $dark_primary-light-bg;
color: $dark_primary-light-fg;
a, a:visited {
color: $dark_primary-light-fg;
&.active {
border-bottom: 3px solid $dark_secondary-bg;
}
}
}
.menuerror {
background: $dark_primary-bg;
color: $dark_primary-fg-url;
}
}
}

View file

@ -1,10 +1,9 @@
article.page {
background: white;
padding: 0 0 40px;
padding-bottom: 0;
header {
text-align: center;
margin: 20px;
margin: 20px 20px 0;
padding: 10px;
background: $secondary-bg;
width: 100%;
@ -71,6 +70,11 @@ article.page {
flex-direction: column;
align-items: center;
height: auto;
padding: 20px 0;
background: $newsitem-bg;
border-right: $newsitem-border;
border-left: $newsitem-border;
&.multi {
align-self: center;
@ -186,3 +190,44 @@ aside.news {
}
}
}
.darkmodeon {
article.page {
header {
background: $dark_secondary-bg;
h1 {
color: $dark_secondary-fg;
}
}
.container {
background: $dark_newsitem-bg;
border-right: $dark_newsitem-border;
border-left: $dark_newsitem-border;
}
aside.sidebar {
h4 {
border-bottom: 1px solid $dark_border;
}
a {
color: $dark_secondary-dark-bg;
}
}
}
aside.news {
&.single {
& > h4 {
border-bottom: 1px solid $dark_border;
}
}
}
@media screen and (max-width: 639px){
article.page aside.sidebar {
border-bottom: 1px solid $dark_border;
}
}
}

View file

@ -233,6 +233,8 @@ newsitem {
display: flex;
flex-direction: column;
font-size: 15px;
background: $newsitem-bg;
border: $newsitem-border;
.title {
text-decoration: none;
@ -342,3 +344,66 @@ pages {
}
}
}
.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 {
color: $dark_meta-fg;
.title {
a {
color: $dark_secondary-dark-bg;
}
}
.entrymeta {
color: $dark_meta-fg;
}
}
fileinfo {
.filetitle {
a {
color: $dark_secondary-dark-bg;
border-right: 1px solid $dark_border;
}
}
}
newsitem {
background: $dark_newsitem-bg;
border: $dark_newsitem-border;
.title {
background: $dark_secondary-bg;
color: $dark_secondary-fg;
}
.entrymeta {
color: $dark_meta-fg;
}
}
pages {
a {
color: $dark_secondary-dark-bg;
}
}
}

View file

@ -29,6 +29,7 @@ exports.up = function up(knex, Promise) {
table.text('small_image')
table.text('medium_image')
table.text('large_image')
table.text('org_image')
table.integer('size')
table.integer('staff_id')
.references('staff.id')

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
public/assets/img/heart.psd Normal file

Binary file not shown.

BIN
public/assets/img/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
public/assets/img/tsun.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View file

@ -10,6 +10,11 @@
<meta name="google-signin-client_id" content="1076074914074-3no1difo1jq3dfug3glfb25pn1t8idud.apps.googleusercontent.com">
</head>
<body>
<script type="text/javascript">
if (localStorage.getItem('darkmode')) {
document.body.className = 'darkmodeon'
}
</script>
<div class="maincontainer">
<div id="nav"></div>
<main id="main"></main>