From 065e7fbfddf67bddad15b979b99460cb252d048a Mon Sep 17 00:00:00 2001 From: rob Date: Fri, 22 Jul 2022 16:00:23 -0400 Subject: [PATCH] brought announcements in from Soapbox/Venue --- app/controllers/admin.js | 1 + app/controllers/admin/announcement.js | 109 ++++++++++++++++ app/controllers/announcement.js | 66 ++++++++++ app/controllers/home.js | 11 +- app/models/announcement.js | 23 ++++ app/models/chat-message.js | 2 +- app/models/email-log.js | 2 +- app/models/user.js | 1 + app/services/announcement.js | 119 ++++++++++++++++++ app/services/core-node.js | 27 ++-- app/services/user.js | 15 +++ app/views/admin/announcement/editor.pug | 50 ++++++++ app/views/admin/announcement/index.pug | 28 +++++ app/views/admin/components/menu.pug | 6 + .../announcement/components/announcement.pug | 12 ++ app/views/announcement/index.pug | 16 +++ app/views/components/page-sidebar.pug | 11 +- app/views/components/section-title.pug | 2 +- app/views/index.pug | 30 ++--- app/views/layouts/main-sidebar.pug | 1 + client/less/site/content.less | 8 ++ client/less/site/section.less | 6 + client/less/site/sidebar.less | 8 ++ client/less/site/uikit-theme.dtp-dark.less | 4 + client/less/site/uikit-theme.dtp-light.less | 4 + client/less/style.common.less | 3 + 26 files changed, 534 insertions(+), 31 deletions(-) create mode 100644 app/controllers/admin/announcement.js create mode 100644 app/controllers/announcement.js create mode 100644 app/models/announcement.js create mode 100644 app/services/announcement.js create mode 100644 app/views/admin/announcement/editor.pug create mode 100644 app/views/admin/announcement/index.pug create mode 100644 app/views/announcement/components/announcement.pug create mode 100644 app/views/announcement/index.pug create mode 100644 client/less/site/content.less create mode 100644 client/less/site/section.less create mode 100644 client/less/site/sidebar.less diff --git a/app/controllers/admin.js b/app/controllers/admin.js index f8ae0db..0cdec58 100644 --- a/app/controllers/admin.js +++ b/app/controllers/admin.js @@ -42,6 +42,7 @@ class AdminController extends SiteController { }), ); + router.use('/announcement', await this.loadChild(path.join(__dirname, 'admin', 'announcement'))); router.use('/content-report', await this.loadChild(path.join(__dirname, 'admin', 'content-report'))); router.use('/core-node', await this.loadChild(path.join(__dirname, 'admin', 'core-node'))); router.use('/core-user', await this.loadChild(path.join(__dirname, 'admin', 'core-user'))); diff --git a/app/controllers/admin/announcement.js b/app/controllers/admin/announcement.js new file mode 100644 index 0000000..ebdf4f1 --- /dev/null +++ b/app/controllers/admin/announcement.js @@ -0,0 +1,109 @@ +// admin/announcement.js +// Copyright (C) 2022 DTP Technologies, LLC +// License: Apache-2.0 + +'use strict'; + +const express = require('express'); + +const { SiteController } = require('../../../lib/site-lib'); + +class AnnouncementAdminController extends SiteController { + + constructor (dtp) { + super(dtp, module.exports); + } + + async start ( ) { + const router = express.Router(); + router.use(async (req, res, next) => { + res.locals.currentView = 'admin'; + res.locals.adminView = 'announcement'; + return next(); + }); + + router.param('announcementId', this.populateAnnouncementId.bind(this)); + + router.post('/:announcementId', this.postUpdateAnnouncement.bind(this)); + router.post('/', this.postCreateAnnouncement.bind(this)); + + router.get('/create', this.getAnnouncementEditor.bind(this)); + router.get('/:announcementId', this.getAnnouncementEditor.bind(this)); + + router.get('/', this.getHomeView.bind(this)); + + router.delete('/:announcementId', this.deleteAnnouncement.bind(this)); + + return router; + } + + async populateAnnouncementId (req, res, next, announcementId) { + const { announcement: announcementService } = this.dtp.services; + try { + res.locals.announcement = await announcementService.getById(announcementId); + return next(); + } catch (error) { + return next(error); + } + } + + async postUpdateAnnouncement (req, res, next) { + const { announcement: announcementService } = this.dtp.services; + try { + await announcementService.update(res.locals.announcement, req.body); + res.redirect('/admin/announcement'); + } catch (error) { + return next(error); + } + } + + async postCreateAnnouncement (req, res, next) { + const { announcement: announcementService } = this.dtp.services; + try { + await announcementService.create(req.body); + res.redirect('/admin/announcement'); + } catch (error) { + return next(error); + } + } + + async getAnnouncementEditor (req, res) { + res.render('admin/announcement/editor'); + } + + async getHomeView (req, res, next) { + const { announcement: announcementService } = this.dtp.services; + try { + res.locals.pagination = this.getPaginationParameters(req, 20); + res.locals.announcements = await announcementService.getAnnouncements(res.locals.pagination); + res.render('admin/announcement/index'); + } catch (error) { + return next(error); + } + } + + async deleteAnnouncement (req, res) { + const { announcement: announcementService } = this.dtp.services; + try { + const displayList = this.createDisplayList('delete-announcement'); + await announcementService.remove(res.locals.announcement); + displayList.reloadView(); + res.status(200).json({ success: true, displayList }); + } catch (error) { + this.log.error('failed to delete announcement', { error }); + res.status(error.statusCode || 500).json({ + success: false, + message: error.message, + }); + } + } +} + +module.exports = { + name: 'announcement', + slug: 'announcement', + create: async (dtp) => { + let controller = new AnnouncementAdminController(dtp); + return controller; + }, +}; \ No newline at end of file diff --git a/app/controllers/announcement.js b/app/controllers/announcement.js new file mode 100644 index 0000000..269291b --- /dev/null +++ b/app/controllers/announcement.js @@ -0,0 +1,66 @@ +// announcement.js +// Copyright (C) 2022 DTP Technologies, LLC +// License: Apache-2.0 + +'use strict'; + +const express = require('express'); + +const { SiteController, SiteError } = require('../../lib/site-lib'); + +class AnnouncementController extends SiteController { + + constructor (dtp) { + super(dtp, module.exports); + } + + async start ( ) { + const router = express.Router(); + this.dtp.app.use('/announcement', router); + + router.param('announcementId', this.populateAnnouncementId.bind(this)); + + router.get('/:announcementId', this.getAnnouncementView.bind(this)); + router.get('/', this.getHome.bind(this)); + + return router; + } + + async populateAnnouncementId (req, res, next, announcementId) { + const { announcement: announcementService } = this.dtp.services; + try { + res.locals.announcement = await announcementService.getById(announcementId); + if (!res.locals.announcement) { + this.log.error('announcement not found', { announcementId }); + return next(new SiteError(404, 'Announcement not found')); + } + return next(); + } catch (error) { + return next(error); + } + } + + async getAnnouncementView (req, res) { + res.render('announcement/view'); + } + + async getHome (req, res, next) { + const { announcement: announcementService } = this.dtp.services; + try { + res.locals.pagination = this.getPaginationParameters(req, 10); + res.locals.announcements = await announcementService.getAnnouncements(res.locals.pagination); + res.render('announcement/index'); + } catch (error) { + return next(error); + } + } +} + +module.exports = { + slug: 'announcement', + name: 'announcement', + create: async (dtp) => { + let controller = new AnnouncementController(dtp); + return controller; + }, +}; \ No newline at end of file diff --git a/app/controllers/home.js b/app/controllers/home.js index 0397923..fa355c6 100644 --- a/app/controllers/home.js +++ b/app/controllers/home.js @@ -62,8 +62,15 @@ class HomeController extends SiteController { res.render('policy/view'); } - async getHome (req, res) { - res.render('index'); + async getHome (req, res, next) { + const { announcement: announcementService } = this.dtp.services; + try { + res.locals.announcements = await announcementService.getLatest(req.user); + res.render('index'); + } catch (error) { + this.log.error('failed to render home view', { error }); + return next(error); + } } } diff --git a/app/models/announcement.js b/app/models/announcement.js new file mode 100644 index 0000000..6481078 --- /dev/null +++ b/app/models/announcement.js @@ -0,0 +1,23 @@ +// announcement.js +// Copyright (C) 2022 DTP Technologies, LLC +// License: Apache-2.0 + +'use strict'; + +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const AnnouncementSchema = new Schema({ + created: { type: Date, default: Date.now, required: true, index: -1, expires: '21d' }, + title: { + icon: { + class: { type: String, default: 'fa-bullhorn', required: true }, + color: { type: String, default: '#ffffff', required: true }, + }, + content: { type: String, required: true }, + }, + content: { type: String, required: true }, +}); + +module.exports = mongoose.model('Announcement', AnnouncementSchema); \ No newline at end of file diff --git a/app/models/chat-message.js b/app/models/chat-message.js index 2a3f47b..0a691fd 100644 --- a/app/models/chat-message.js +++ b/app/models/chat-message.js @@ -1,6 +1,6 @@ // chat-message.js // Copyright (C) 2022 DTP Technologies, LLC -// License Apache-2.0 +// License: Apache-2.0 'use strict'; diff --git a/app/models/email-log.js b/app/models/email-log.js index 2131e25..b15fdec 100644 --- a/app/models/email-log.js +++ b/app/models/email-log.js @@ -1,6 +1,6 @@ // email-log.js // Copyright (C) 2022 DTP Technologies, LLC -// All Rights Reserved +// License: Apache-2.0 'use strict'; diff --git a/app/models/user.js b/app/models/user.js index b7d68ae..e71b1fc 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -39,6 +39,7 @@ const UserSchema = new Schema({ optIn: { type: UserOptInSchema, required: true, select: false }, theme: { type: String, enum: DTP_THEME_LIST, default: 'dtp-light', required: true }, stats: { type: ResourceStats, default: ResourceStatsDefaults, required: true }, + lastAnnouncement: { type: Date }, }); module.exports = mongoose.model('User', UserSchema); \ No newline at end of file diff --git a/app/services/announcement.js b/app/services/announcement.js new file mode 100644 index 0000000..de78d5b --- /dev/null +++ b/app/services/announcement.js @@ -0,0 +1,119 @@ +// announcement.js +// Copyright (C) 2022 DTP Technologies, LLC +// All Rights Reserved + +'use strict'; + +const mongoose = require('mongoose'); +const Announcement = mongoose.model('Announcement'); + +const { SiteService } = require('../../lib/site-lib'); + +class AnnouncementService extends SiteService { + + constructor (dtp) { + super(dtp, module.exports); + } + + async create (announcementDefinition) { + const NOW = new Date(); + const { coreNode: coreNodeService } = this.dtp.services; + + const announcement = new Announcement(); + announcement.created = NOW; + announcement.title = { + icon: { + class: announcementDefinition.titleIconClass, + color: announcementDefinition.titleIconColor, + }, + content: announcementDefinition.titleContent, + }; + announcement.content = announcementDefinition.content.trim(); + + await announcement.save(); + + /* + * Broadcast the Announcement to your DTP Constellation. + */ + const announcementHref = coreNodeService.getLocalUrl(`/announcement/${announcement._id}`); + await coreNodeService.sendKaleidoscopeEvent({ + action: 'announcement', + label: announcement.title.content, + content: announcement.content, + href: announcementHref, + }); + + return announcement.toObject(); + } + + async update (announcement, announcementDefinition) { + await Announcement.updateOne( + { _id: announcement._id }, + { + $set: { + title: { + icon: { + class: announcementDefinition.titleIconClass, + color: announcementDefinition.titleIconColor, + }, + content: announcementDefinition.titleContent, + }, + content: announcementDefinition.content.trim(), + }, + }, + ); + } + + async getLatest (user) { + const { user: userService } = this.dtp.services; + let announcements = [ ]; + + if (user) { + const search = { }; + if (user.lastAnnouncement) { + search.created = { $gt: user.lastAnnouncement }; + } + announcements = await Announcement + .find(search) + .sort({ created: -1 }) + .limit(1) + .lean(); + if (announcements && (announcements.length > 0)) { + await userService.setLastAnnouncement(user, announcements[0]); + } + } else { + announcements = await Announcement + .find() + .sort({ created: -1 }) + .limit(1) + .lean(); + } + + return announcements; + } + + async getById (announcementId) { + const announcement = await Announcement.findById(announcementId); + return announcement; + } + + async getAnnouncements (pagination) { + const announcements = await Announcement + .find() + .sort({ created: -1 }) + .skip(pagination.skip) + .limit(pagination.cpp) + .lean(); + return announcements; + } + + async remove (announcement) { + await Announcement.deleteOne({ _id: announcement._id }); + } +} + +module.exports = { + slug: 'announcement', + name: 'announcement', + create: (dtp) => { return new AnnouncementService(dtp); }, +}; \ No newline at end of file diff --git a/app/services/core-node.js b/app/services/core-node.js index e12cd84..7235d27 100644 --- a/app/services/core-node.js +++ b/app/services/core-node.js @@ -276,24 +276,27 @@ class CoreNodeService extends SiteService { return { connectedCount, pendingCount, potentialReach }; } - async sendKaleidoscopeEvent (emitter, event) { + async sendKaleidoscopeEvent (event) { const CORE_SCHEME = this.getCoreRequestScheme(); const { pkg } = this.dtp; const { site } = this.dtp.config; - let emitterUrl = emitter.coreUserId ? `/user/core/${emitter._id}` : `/user/${emitter._id}`; event.source = Object.assign({ pkg: { name: pkg.name, version: pkg.version }, site, - emitter: { - emitterType: emitter.type, - emitterId: emitter._id.toString(), - displayName: emitter.displayName, - username: emitter.username, - href: `${CORE_SCHEME}://${site.domain}${emitterUrl}`, - }, }, event.source); + if (event.emitter) { + let emitterUrl = event.emitter.coreUserId ? `/user/core/${event.emitter._id}` : `/user/${event.emitter._id}`; + event.source.emitter = { + emitterType: event.emitter.type, + emitterId: event.emitter._id.toString(), + displayName: event.emitter.displayName, + username: event.emitter.username, + href: `${CORE_SCHEME}://${site.domain}${emitterUrl}`, + }; + } + const request = { tokenized: false, method: 'POST', @@ -339,6 +342,12 @@ class CoreNodeService extends SiteService { return `${coreScheme}://${core.address.host}:${core.address.port}${requestUrl}`; } + getLocalUrl (url) { + const CORE_SCHEME = this.getCoreRequestScheme(); + const { site } = this.dtp.config; + return `${CORE_SCHEME}://${site.domain}${url}`; + } + async sendRequest (core, request) { try { const req = new CoreNodeRequest(); diff --git a/app/services/user.js b/app/services/user.js index 2e5f4b8..9b7a8af 100644 --- a/app/services/user.js +++ b/app/services/user.js @@ -637,6 +637,21 @@ class UserService extends SiteService { { upsert: true }, ); } + + /** + * Updates the `lastAnnouncement` field of a User to the `created` date of the + * specified announcement (for tracking last-seen announcements). + * @param {User} user The user being updated + * @param {Announcement} announcement The announcement being seen by the User + */ + async setLastAnnouncement (user, announcement) { + await User.updateOne( + { _id: user._id }, + { + $set: { lastAnnouncement: announcement.created }, + }, + ); + } } module.exports = { diff --git a/app/views/admin/announcement/editor.pug b/app/views/admin/announcement/editor.pug new file mode 100644 index 0000000..a3c8cf3 --- /dev/null +++ b/app/views/admin/announcement/editor.pug @@ -0,0 +1,50 @@ +extends ../layouts/main +block content + + - var formActionUrl = announcement ? `/admin/announcement/${announcement._id}` : '/admin/announcement'; + + form(method="POST", action= formActionUrl).uk-form + .uk-card.uk-card-default.uk-card-small + .uk-card-header + h1 Announcement Editor + + .uk-card-body + div(uk-grid) + .uk-width-1-2 + .uk-margin + label(for="icon-class").uk-form-label Icon Class + input( + id="icon-class", + name="titleIconClass", + type="text", + placeholder="Enter FontAwesome icon class", + value= announcement ? announcement.title.icon.class : 'fa-bullhorn', + ).uk-input + .uk-text-small + a(href="https://fontawesome.com/v5/search", target="_blank") Search icons + + .uk-width-1-2 + .uk-margin + label(for="icon-color").uk-form-label Icon Color + input( + id="icon-color", + name="titleIconColor", + type="color", + value= announcement ? announcement.title.icon.color : '#ff0013', + ).uk-input + + .uk-margin + label(for="title").uk-form-label Title + input( + id="title", + name="titleContent", + type="text", + placeholder="Enter announcement title", value= announcement ? announcement.title.content : undefined, + ).uk-input + + .uk-margin + label(for="content").uk-form-label Announcement Body + textarea(id="content", name="content", rows="4", placeholder="Enter announcement").uk-textarea= announcement ? announcement.content : undefined + + .uk-card-footer + button(type="submit").uk-button.dtp-button-primary= announcement ? 'Update Announcement' : 'Create Announcement' \ No newline at end of file diff --git a/app/views/admin/announcement/index.pug b/app/views/admin/announcement/index.pug new file mode 100644 index 0000000..0e421ca --- /dev/null +++ b/app/views/admin/announcement/index.pug @@ -0,0 +1,28 @@ +extends ../layouts/main +block content + + div(uk-grid).uk-grid-small + .uk-width-expand + h1 Announcements + .uk-width-auto + a(href="/admin/announcement/create").uk-button.dtp-button-primary + span + i.fas.fa-plus + span.uk-margin-small-left Create + + if Array.isArray(announcements) && (announcements.length > 0) + ul.uk-list.uk-list-divider + each announcement in announcements + li + div(uk-grid).uk-grid-small.uk-flex-middle + .uk-width-expand + a(href=`/admin/announcement/${announcement._id}`) + span + i(class=`fas ${announcement.title.icon.class}`) + span.uk-margin-small-left= announcement.title.content + .uk-width-auto + button(type="button", data-announcement-id= announcement._id, onclick="return dtp.adminApp.deleteAnnouncement(event);").uk-button.dtp-button-danger + span + i.fas.fa-trash + else + div There are no announcements. \ No newline at end of file diff --git a/app/views/admin/components/menu.pug b/app/views/admin/components/menu.pug index 3bb8f02..7dd7641 100644 --- a/app/views/admin/components/menu.pug +++ b/app/views/admin/components/menu.pug @@ -15,6 +15,12 @@ ul(uk-nav).uk-nav-default li.uk-nav-divider + li(class={ 'uk-active': (adminView === 'announcement') }) + a(href="/admin/announcement") + span.nav-item-icon + i.fas.fa-bullhorn + span.uk-margin-small-left Announcements + li(class={ 'uk-active': (adminView === 'user') }) a(href="/admin/user") span.nav-item-icon diff --git a/app/views/announcement/components/announcement.pug b/app/views/announcement/components/announcement.pug new file mode 100644 index 0000000..91a5625 --- /dev/null +++ b/app/views/announcement/components/announcement.pug @@ -0,0 +1,12 @@ +mixin renderAnnouncement (announcement) + .uk-card.uk-card-default.uk-card-small + .uk-card-header + h1.uk-card-title + span + i(class=`fas ${announcement.title.icon.class}`, style=`color: ${announcement.title.icon.color}`) + span.uk-margin-small-left= announcement.title.content + .uk-card-body!= marked.parse(announcement.content, { renderer: marked.Renderer() }) + .uk-card-footer + .uk-text-small.uk-text-muted.uk-flex.uk-flex-between + div= moment(announcement.created).format('MMM DD, YYYY') + div= moment(announcement.created).format('hh:mm a') \ No newline at end of file diff --git a/app/views/announcement/index.pug b/app/views/announcement/index.pug new file mode 100644 index 0000000..a693ee9 --- /dev/null +++ b/app/views/announcement/index.pug @@ -0,0 +1,16 @@ +extends ../layouts/main +block content + + include components/announcement + + section.uk-section.uk-section-default.uk-section-small + .uk-container + h1 #{site.name} Announcements + + if Array.isArray(announcements) && (announcements.length > 0) + ul.uk-list.uk-list-divider + each announcement in announcements + li + +renderAnnouncement(announcement) + else + div There are no announcements. \ No newline at end of file diff --git a/app/views/components/page-sidebar.pug b/app/views/components/page-sidebar.pug index 54ab4fa..9100676 100644 --- a/app/views/components/page-sidebar.pug +++ b/app/views/components/page-sidebar.pug @@ -1,6 +1,13 @@ +include ../announcement/components/announcement + mixin renderPageSidebar ( ) - //- Gab TV 3 Most Recent Episodes - .uk-margin + if Array.isArray(announcements) && (announcements.length > 0) + ul.uk-list.uk-margin + each announcement in announcements + li + +renderAnnouncement(announcement) + + .sidebar-widget.uk-margin +renderSectionTitle('Widget', { label: 'Sample URL', title: 'Sample URL Title', diff --git a/app/views/components/section-title.pug b/app/views/components/section-title.pug index 9ed6b2e..b4ea873 100644 --- a/app/views/components/section-title.pug +++ b/app/views/components/section-title.pug @@ -2,7 +2,7 @@ mixin renderSectionTitle (title, barButton) .dtp-border-bottom div(uk-grid).uk-grid-small.uk-flex-middle .uk-width-expand - h3.uk-heading-bullet.uk-margin-small= title + h4.uk-heading-bullet.uk-margin-small= title if barButton .uk-width-auto a(href= barButton.url, title= barButton.title).uk-button.uk-button-link.uk-button-small= barButton.label \ No newline at end of file diff --git a/app/views/index.pug b/app/views/index.pug index 0d48921..cc161cf 100644 --- a/app/views/index.pug +++ b/app/views/index.pug @@ -1,22 +1,22 @@ extends layouts/main-sidebar block content - p - img(src="/img/the-bobs.jpg", alt="The Bobs have questions").responsive + img(src="/img/the-bobs.jpg", alt="The Bobs have questions").responsive - h1 Sample DTP Web Application - p This application doesn't actually do anything. The Bobs would have questions. + .content-block + h1 Sample DTP Web Application + p This application doesn't actually do anything. The Bobs would have questions. - if user - h2 Current User - pre= JSON.stringify(user, null, 2) + if user + h2 Current User + pre= JSON.stringify(user, null, 2) - if session - h2 Session - pre= JSON.stringify(session, null, 2) - - h2 Site Configuration - pre= JSON.stringify(config, null, 2) + if session + h2 Session + pre= JSON.stringify(session, null, 2) - h2 Package Information - pre= JSON.stringify(pkg, null, 2) \ No newline at end of file + h2 Site Configuration + pre= JSON.stringify(config, null, 2) + + h2 Package Information + pre= JSON.stringify(pkg, null, 2) \ No newline at end of file diff --git a/app/views/layouts/main-sidebar.pug b/app/views/layouts/main-sidebar.pug index 1c647cb..644073e 100644 --- a/app/views/layouts/main-sidebar.pug +++ b/app/views/layouts/main-sidebar.pug @@ -6,6 +6,7 @@ block content-container div(uk-grid)#dtp-content-grid div(class="uk-width-1-1 uk-width-2-3@m") block content + div(class="uk-width-1-1 uk-width-1-3@m") block content-sidebar +renderPageSidebar() \ No newline at end of file diff --git a/client/less/site/content.less b/client/less/site/content.less new file mode 100644 index 0000000..f4f99ce --- /dev/null +++ b/client/less/site/content.less @@ -0,0 +1,8 @@ +.content-block { + padding: @global-gutter; + background-color: @content-background-color; + + :last-child { + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/client/less/site/section.less b/client/less/site/section.less new file mode 100644 index 0000000..f7332e3 --- /dev/null +++ b/client/less/site/section.less @@ -0,0 +1,6 @@ +section.uk-section { + + &.uk-section-default { + background-color: @page-background-color; + } +} \ No newline at end of file diff --git a/client/less/site/sidebar.less b/client/less/site/sidebar.less new file mode 100644 index 0000000..591aa2c --- /dev/null +++ b/client/less/site/sidebar.less @@ -0,0 +1,8 @@ +.sidebar-widget { + display: block; + padding: @global-gutter; + background-color: @content-background-color; + border: solid 1px @content-border-color; + border-radius: 6px; + overflow: hidden; +} \ No newline at end of file diff --git a/client/less/site/uikit-theme.dtp-dark.less b/client/less/site/uikit-theme.dtp-dark.less index 0e96eb5..7ef0aef 100644 --- a/client/less/site/uikit-theme.dtp-dark.less +++ b/client/less/site/uikit-theme.dtp-dark.less @@ -2,6 +2,10 @@ // Colors // +@page-background-color: #000000; +@content-background-color: #2a2a2a; +@content-border-color: #4a4a4a; + @site-brand-color: #ff0013; @button-label-color: #e8e8e8; @button-label-hover: #2a2a2a; diff --git a/client/less/site/uikit-theme.dtp-light.less b/client/less/site/uikit-theme.dtp-light.less index a737de8..af69641 100644 --- a/client/less/site/uikit-theme.dtp-light.less +++ b/client/less/site/uikit-theme.dtp-light.less @@ -2,6 +2,10 @@ // Colors // +@page-background-color: #e8e8e8; +@content-background-color: #ffffff; +@content-border-color: #a8a8a8; + @site-brand-color: #ff0013; @button-label-color: #2a2a2a; @button-label-hover: #ffffff; diff --git a/client/less/style.common.less b/client/less/style.common.less index 4d9c527..2dc2d9e 100644 --- a/client/less/style.common.less +++ b/client/less/style.common.less @@ -9,10 +9,13 @@ @import "site/image.less"; @import "site/nav.less"; +@import "site/content.less"; @import "site/core-node.less"; @import "site/dashboard.less"; @import "site/site.less"; @import "site/form.less"; @import "site/button.less"; +@import "site/sidebar.less"; +@import "site/section.less"; @import "site/chat.less"; \ No newline at end of file