From 240e008a8720df5374f85357efd71ac242f2e613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 18 Oct 2017 16:35:53 +0200 Subject: [PATCH] feat(editors): add editorial features aka the configurable edit link --- app.js | 46 +++++++++++++++++++++-------- routes/settings.js | 17 +++++------ views/course.pug | 2 ++ views/landingPage.pug | 9 ++++-- views/mixins/_editorialFeatures.pug | 13 ++++++++ views/mixins/_lesson.pug | 32 ++++++++++---------- views/mixins/_moduleCopy.pug | 3 +- views/settings.pug | 22 +++++++++----- 8 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 views/mixins/_editorialFeatures.pug diff --git a/app.js b/app.js index be11e27..5cd245d 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,6 @@ require('dotenv').config({ path: 'variables.env' }) const express = require('express') -const url = require('url') +const querystring = require('querystring') const path = require('path') const helpers = require('./helpers') // const favicon = require('serve-favicon') @@ -34,21 +34,34 @@ app.use(breadcrumb()) // Pass our application state and custom helpers to all our templates app.use(async function (req, res, next) { - // Inject custom helpers - res.locals.helpers = helpers - - // Express query string - const qs = url.parse(req.url).query - res.locals.queryString = qs ? `?${qs}` : '' - res.locals.query = req.query - res.locals.currentPath = req.path - // Allow setting of API credentials via query parameters - let settings = req.cookies.theExampleAppSettings + let settings = { + space: process.env.CF_SPACE, + cda: process.env.CF_ACCESS_TOKEN, + cpa: process.env.CF_PREVIEW_ACCESS_TOKEN, + editorialFeatures: false, + ...req.cookies.theExampleAppSettings + } const { space_id, preview_access_token, delivery_access_token } = req.query if (space_id && preview_access_token && delivery_access_token) { // eslint-disable-line camelcase - settings = {space: space_id, cda: delivery_access_token, cpa: preview_access_token} + settings = { + ...settings, + space: space_id, + cda: delivery_access_token, + cpa: preview_access_token + } + res.cookie('theExampleAppSettings', settings, { maxAge: 900000, httpOnly: true }) + } + + // Allow enabling of editorial features via query parameters + const { enable_editorial_features } = req.query + if (enable_editorial_features !== undefined) { // eslint-disable-line camelcase + delete req.query.enable_editorial_features + settings = { + ...settings, + editorialFeatures: true + } res.cookie('theExampleAppSettings', settings, { maxAge: 900000, httpOnly: true }) } @@ -86,6 +99,15 @@ app.use(async function (req, res, next) { res.locals.currentLocale = defaultLocale } + // Inject custom helpers + res.locals.helpers = helpers + + // Make query string available in templates + const qs = querystring.stringify(req.query) + res.locals.queryString = qs ? `?${qs}` : '' + res.locals.query = req.query + res.locals.currentPath = req.path + next() }) diff --git a/routes/settings.js b/routes/settings.js index aa55cae..d4a9491 100644 --- a/routes/settings.js +++ b/routes/settings.js @@ -25,13 +25,7 @@ async function renderSettings (res, opts) { /* GET settings page. */ router.get('/', catchErrors(async function (req, res, next) { - const cookie = req.cookies.theExampleAppSettings - const settings = cookie || { - space: process.env.CF_SPACE, - cda: process.env.CF_ACCESS_TOKEN, - cpa: process.env.CF_PREVIEW_ACCESS_TOKEN - } - + const { settings } = res.locals await renderSettings(res, { settings }) @@ -40,8 +34,13 @@ router.get('/', catchErrors(async function (req, res, next) { /* POST settings page. */ router.post('/', catchErrors(async function (req, res, next) { const errorList = [] - const { space, cda, cpa } = req.body - const settings = {space, cda, cpa} + const { space, cda, cpa, editorialFeatures } = req.body + const settings = { + space, + cda, + cpa, + editorialFeatures: !!editorialFeatures + } // Validate required fields. if (!space) { diff --git a/views/course.pug b/views/course.pug index c26168c..000cf6c 100644 --- a/views/course.pug +++ b/views/course.pug @@ -1,6 +1,7 @@ extends layout include mixins/_breadcrumb +include mixins/_editorialFeatures include mixins/_lesson block content @@ -25,6 +26,7 @@ block content else .course h1.course__title= course.fields.title + +editorialFeatures(course) .course__overview h3.course__overview-title Overview if course.fields.duration diff --git a/views/landingPage.pug b/views/landingPage.pug index 4273bd4..cb2f9f3 100644 --- a/views/landingPage.pug +++ b/views/landingPage.pug @@ -1,15 +1,18 @@ extends layout include mixins/_breadcrumb +include mixins/_editorialFeatures include mixins/_moduleCopy include mixins/_moduleHeroImage include mixins/_moduleHighlightedCourse block content + if currentPath !== '/' + .layout-centered + +breadcrumb + .layout-centered + +editorialFeatures(landingPage) .modules-container - if currentPath !== '/' - .layout-centered - +breadcrumb each module in landingPage.fields.contentModules case module.sys.contentType.sys.id when 'layoutCopy' diff --git a/views/mixins/_editorialFeatures.pug b/views/mixins/_editorialFeatures.pug new file mode 100644 index 0000000..2129206 --- /dev/null +++ b/views/mixins/_editorialFeatures.pug @@ -0,0 +1,13 @@ +mixin editorialFeatures(entry) + if settings.editorialFeatures + .editorial-features + .editorial-features__item + a.editorial-features__text( + href=`https://app.contentful.com/spaces/${settings.space}/entries/${entry.sys.id}` + target='_blank' + rel='noopener' + ) Edit in the web app + .editorial-features__hint-wrapper + svg.editorial-features__hint-icon + use(xlink:href='/icons/icons.svg#info') + .editorial-features__hint-message Edit this entry in our web app. You have to be logged in and have access to the connected space to use this feature. diff --git a/views/mixins/_lesson.pug b/views/mixins/_lesson.pug index 6cf7572..2a174c0 100644 --- a/views/mixins/_lesson.pug +++ b/views/mixins/_lesson.pug @@ -1,3 +1,4 @@ +include _editorialFeatures include _lessonModuleCodeSnippet include _lessonModuleCopy include _lessonModuleImage @@ -5,23 +6,24 @@ include _lessonModuleImage mixin lesson(lesson, course, nextLesson) .lesson h1.lesson__title #{lesson.fields.title} - div.lesson__short-description !{helpers.markdown(lesson.fields.description)} + +editorialFeatures(lesson) if lesson.fields.image img.lesson__image(src=`${lesson.fields.image.fields.file.url}` alt=`${lesson.fields.image.fields.title}`) - each module in lesson.fields.modules - if module.sys.contentType - case module.sys.contentType.sys.id - when 'lessonCodeSnippets' - +lessonModuleCodeSnippet(module) - when 'lessonCopy' - +lessonModuleCopy(module) - when 'lessonModuleImage' - +lessonImage(module) - else - h2 ️️⚠️ Invalid lesson module - p - span Could not determine type of - strong #{module.sys.id} + .lesson__modules + each module in lesson.fields.modules + if module.sys.contentType + case module.sys.contentType.sys.id + when 'lessonCodeSnippets' + +lessonModuleCodeSnippet(module) + when 'lessonCopy' + +lessonModuleCopy(module) + when 'lessonModuleImage' + +lessonImage(module) + else + h2 ️️⚠️ Invalid lesson module + p + span Could not determine type of + strong #{module.sys.id} if nextLesson a.lesson__cta.cta(href=`/courses/${course.fields.slug}/lessons/${nextLesson.fields.slug}${queryString}`) View next lesson diff --git a/views/mixins/_moduleCopy.pug b/views/mixins/_moduleCopy.pug index aaddb8b..7e36425 100644 --- a/views/mixins/_moduleCopy.pug +++ b/views/mixins/_moduleCopy.pug @@ -3,7 +3,8 @@ mixin moduleCopy(module) .module div(class=`module-copy${style}`) div(class=`module-copy__first${style}`) - h1(class=`module-copy__headline${style}`) #{module.fields.headline} + if module.fields.headline + h1(class=`module-copy__headline${style}`) #{module.fields.headline} div(class=`module-copy__copy${style}`) !{helpers.markdown(module.fields.copy)} div(class=`module-copy__second${style}`) if module.fields.ctaTitle && module.fields.ctaLink diff --git a/views/settings.pug b/views/settings.pug index b1e507f..9190ecd 100644 --- a/views/settings.pug +++ b/views/settings.pug @@ -39,23 +39,24 @@ block content form(action=`/settings` method="POST" class="form") .form-item - label(for="space") Space ID - input(type="text" name="space" value=settings.space) + label(for="input-space") Space ID + input(type="text" name="space" id="input-space" value=settings.space) if 'space' in errors +renderErrors(errors.space) .form-item__help-text The Space ID is a unique identifier for your space. .form-item - label(for="cda") Content Delivery API - access token - input(type="text" name="cda" value=settings.cda) + label(for="input-cda") Content Delivery API - access token + input(type="text" name="cda" id="input-cda" value=settings.cda) if 'cda' in errors +renderErrors(errors.cda) .form-item__help-text | View published content using this API.  a(href='https://www.contentful.com/developers/docs/references/content-delivery-api/' target='_blank' rel='noopener') Content Delivery API. + .form-item - label(for="cpa") Content Preview API - access token - input(type="text" name="cpa" value=settings.cpa) + label(for="input-cpa") Content Preview API - access token + input(type="text" name="cpa" id="input-cpa" value=settings.cpa) if 'cpa' in errors +renderErrors(errors.cpa) .form-item__help-text @@ -63,4 +64,11 @@ block content a(href='https://www.contentful.com/developers/docs/references/content-preview-api/' target='_blank' rel='noopener') Content Preview API. .form-item - input.cta(type="submit" value="Load settings") + input(type="checkbox" name="editorialFeatures" id="input-editorial-features" checked=settings.editorialFeatures) + label(for="input-editorial-features") Enable editorial features + if 'cpa' in errors + +renderErrors(errors.cpa) + .form-item__help-text Enable to display an edit link and other contextual helpers for authors. You need to have access to the connected space to make this work. + + .form-item + input.cta(type="submit" value="Save settings")