From 5072eddcc1eb7fcb3749a61fe2e83f4e1c36c557 Mon Sep 17 00:00:00 2001 From: George Cushen Date: Wed, 3 Feb 2021 20:32:25 +0000 Subject: [PATCH] feat: add Wowchemy CMS module --- wowchemy-cms/README.md | 28 + wowchemy-cms/config.yaml | 16 + wowchemy-cms/go.mod | 3 + wowchemy-cms/static/admin/index.html | 15 + .../templates/single.wowchemycms_config.yml | 521 ++++++++++++++++++ wowchemy/assets/js/wowchemy-init.js | 11 + wowchemy/layouts/partials/site_head.html | 3 +- wowchemy/layouts/partials/site_js.html | 16 - 8 files changed, 596 insertions(+), 17 deletions(-) create mode 100644 wowchemy-cms/README.md create mode 100644 wowchemy-cms/config.yaml create mode 100644 wowchemy-cms/go.mod create mode 100644 wowchemy-cms/static/admin/index.html create mode 100644 wowchemy-cms/templates/single.wowchemycms_config.yml diff --git a/wowchemy-cms/README.md b/wowchemy-cms/README.md new file mode 100644 index 00000000..6d5ff5cb --- /dev/null +++ b/wowchemy-cms/README.md @@ -0,0 +1,28 @@ +# Wowchemy CMS + +A Content Management System (CMS) for the [Wowchemy](https://wowchemy.com) website builder. + +Built upon the open source [Netlify CMS](https://www.netlifycms.org/) and [Netlify Identity](https://docs.netlify.com/visitor-access/identity/#enable-identity-in-the-ui) projects. + +## Install + +1. Install the Hugo Module by adding the following to the bottom of your `config/_default/config.toml`: + + ```toml + [module] + # Any existing modules here... + [[module.imports]] + path = "github.com/wowchemy/wowchemy-hugo-modules/wowchemy-cms" + [[module.imports]] + path = "github.com/wowchemy/wowchemy-hugo-modules/wowchemy" + ``` + +2. Create a `content/admin/index.md` file containing: + +```yaml +--- +type: wowchemycms +outputs: + - wowchemycms_config +--- +``` diff --git a/wowchemy-cms/config.yaml b/wowchemy-cms/config.yaml new file mode 100644 index 00000000..1099d5f0 --- /dev/null +++ b/wowchemy-cms/config.yaml @@ -0,0 +1,16 @@ +module: + mounts: + - source: static + target: static + - source: templates + target: layouts/wowchemycms +outputFormats: + wowchemycms_config: + baseName: config + isPlainText: true + mediatype: application/yaml + notAlternative: false +mediaTypes: + application/yaml: + suffixes: + - yml diff --git a/wowchemy-cms/go.mod b/wowchemy-cms/go.mod new file mode 100644 index 00000000..73993a61 --- /dev/null +++ b/wowchemy-cms/go.mod @@ -0,0 +1,3 @@ +module github.com/wowchemy/wowchemy-hugo-modules/wowchemy-cms + +go 1.15 diff --git a/wowchemy-cms/static/admin/index.html b/wowchemy-cms/static/admin/index.html new file mode 100644 index 00000000..196ab598 --- /dev/null +++ b/wowchemy-cms/static/admin/index.html @@ -0,0 +1,15 @@ + + + + + + + Wowchemy Content Manager + + + + + + + + diff --git a/wowchemy-cms/templates/single.wowchemycms_config.yml b/wowchemy-cms/templates/single.wowchemycms_config.yml new file mode 100644 index 00000000..42e28782 --- /dev/null +++ b/wowchemy-cms/templates/single.wowchemycms_config.yml @@ -0,0 +1,521 @@ +backend: + name: git-gateway + branch: main + squash_merges: true +media_folder: 'static/media' +public_folder: '/media' +collections: + - name: home + label: "Homepage" + folder: 'content/home' + path: '{{slug}}' + # When specifying a path on a folder collection, media_folder defaults to an empty string, so make it explicit. + media_folder: '/static/media' + public_folder: '' + summary: "{{filename}}: {{title}}" + identifier_field: "widget_id" + create: true + fields: + - {label: "Widget Type (https://wowchemy.com/docs/page-builder/)", name: "widget", widget: "string", required: true} + - {label: 'Your reference for this widget (e.g. recent-posts)', name: 'widget_id', widget: 'string', default: 'my-widget-123'} + - {label: "Headless?", name: "headless", widget: "hidden", default: true} + - label: "Widget position" + name: "weight" + widget: "number" + default: 10 + value_type: "int" + min: 0 + max: 1001 + step: 10 + - {label: "Title", name: "title", widget: "string", required: false} + - {label: "Subtitle", name: "subtitle", widget: "string", required: false} + - label: "Enabled?" + name: "active" + required: false + widget: "boolean" + default: true + - label: "Widget Style" + name: "design" + widget: "object" + required: false + fields: + - {label: "Columns (options: `1` or `2`)", name: "columns", widget: "string", default: "2", required: false} + - label: "Background" + name: "background" + widget: "object" + required: false + fields: + - {label: 'Solid color', name: 'color', widget: 'color', enableAlpha: true, allowInput: true, required: false} + - {label: 'Gradient start', name: 'gradient_start', widget: 'color', enableAlpha: true, allowInput: true, required: false} + - {label: 'Gradient end', name: 'gradient_end', widget: 'color', enableAlpha: true, allowInput: true, required: false} + - label: "Use a light text color?" + name: "text_color_light" + required: false + widget: "boolean" + default: false + - label: "Image" + name: "image" + widget: "image" + required: false + # When specifying a path on a folder collection, media_folder defaults to an empty string, so make it explicit. + media_folder: '/static/media' + public_folder: '' + media_library: + config: + multiple: false + - label: "Darken the image? (0 is transparent & 1 is opaque)" + name: "image_darken" + widget: "number" + default: 0.0 + value_type: "float" + min: 0.0 + max: 1.0 + step: 0.1 + required: false + - {label: "Body", name: "body", widget: "markdown", required: false} + - name: authors + label: Authors + label_singular: Author + folder: 'content/authors' + path: '{{slug}}/_index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - {label: "Display name (such as your full name)", name: "title", widget: "string"} + - {label: "Position or tagline (such as Professor of AI)", name: "role", widget: "string", required: false} + - label: "Avatar (upload an image named `avatar.jpg/png`)" + name: "avatar_filename" + widget: "image" + default: "avatar" + required: false + media_library: + config: + multiple: false + - {label: "Short biography (shown in author boxes)", name: "bio", widget: "string", required: false} + - {label: "Full biography (shown in About widget)", name: "body", widget: "markdown", required: false} + - label: "Interests (shown in About widget)" + name: "interests" + required: false + widget: "list" + - label: Social links + name: social + required: false + widget: list + fields: + - {label: Link, name: link, widget: string} + - label: Icon pack + name: icon_pack + widget: select + multiple: false + options: + - {label: "None", value: ""} + - {label: "Solid", value: "fas"} + - {label: "Regular", value: "far"} + - {label: "Brand", value: "fab"} + - {label: "Academic", value: "ai"} + - {label: Icon (see https://wowchemy.com/docs/page-builder/#icons), name: icon, widget: string} + - {label: Label (tooltip), name: label, widget: string, required: false} + - label: Display in About widget and... + name: display + widget: object + fields: + - label: "Header (main menu)" + name: "header" + widget: "boolean" + default: false + required: false + - label: "Organizations you belong to or are affiliated with (shown in About widget)" + name: "organizations" + required: false + widget: list + fields: + - {label: Organization, name: name, widget: string, required: true} + - {label: Link, name: url, widget: string, required: false} + - label: "Education" + name: "education" + required: false + widget: object + fields: + - label: "Courses" + name: "courses" + required: false + widget: list + fields: + - {label: Course, name: course, widget: string, required: true} + - {label: Institution, name: institution, widget: string, required: true} + - {label: Year, name: year, widget: number, value_type: int, required: false} + - {label: "Email (to use a Gravatar.com avatar)", name: "email", widget: "string", required: false} + - label: "Super user (is this the primary site user?)" + name: "superuser" + widget: "boolean" + default: false + - label: "User groups (only for organization websites)" + name: "user_groups" + required: false + widget: "list" + - name: posts + label: Posts + label_singular: Post + folder: 'content/post' + path: '{{slug}}/index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - {label: "Title", name: "title", widget: "string"} + - {label: "Subtitle", name: "subtitle", widget: "string", required: false} + - {label: "Body", name: "body", widget: "markdown"} + - {label: "Publish this page on", name: "date", widget: "datetime"} + - {label: "Summary", name: "summary", widget: "markdown", required: false} + - label: "Draft" + name: "draft" + widget: "boolean" + default: false + required: false + - label: "Featured" + name: "featured" + widget: "boolean" + default: false + required: false + - label: "Authors" + name: "authors" + required: false + widget: "list" + - label: "Tags" + name: "tags" + required: false + widget: "list" + - label: "Categories" + name: "categories" + required: false + widget: "list" + - label: "Projects" + name: "projects" + required: false + widget: "list" + - label: "Featured Image" + name: "image" + required: false + widget: object + fields: + - label: "Upload an image named `featured.jpg/png`" + name: "filename" + widget: "image" + default: "featured" + required: false + media_library: + config: + multiple: false + - {label: Caption, name: caption, widget: string, required: false} + - {label: Description for screen readers, name: alt_text, widget: string, required: false} + - {label: "Where's the focal point in the image? Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.", name: focal_point, widget: string, required: false, default: "Smart"} + - {label: Thumbnail Only?, name: preview_only, widget: boolean, default: false, required: false} + - name: projects + label: Projects + label_singular: Project + folder: 'content/project' + path: '{{slug}}/index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - {label: "Title", name: "title", widget: "string"} + - {label: "Subtitle", name: "subtitle", widget: "string", required: false} + - {label: "Body", name: "body", widget: "markdown", required: false} + - {label: "Publish this page on", name: "date", widget: "datetime"} + - {label: "Summary", name: "summary", widget: "markdown", required: false} + - label: "Draft" + name: "draft" + widget: "boolean" + default: false + required: false + - label: "Featured" + name: "featured" + widget: "boolean" + default: false + required: false + - label: "Authors" + name: "authors" + required: false + widget: "list" + - label: "Tags" + name: "tags" + required: false + widget: "list" + - label: "Categories" + name: "categories" + required: false + widget: "list" + - {label: "External link (optional - replaces link to project page)", name: "external_link", widget: "string"} + - label: Links + name: links + required: false + widget: list + fields: + - {label: Link, name: url, widget: string} + - {label: Link text, name: name, widget: string, required: false} + - label: Icon pack + name: icon_pack + widget: select + multiple: false + required: false + options: + - {label: "None", value: ""} + - {label: "Solid", value: "fas"} + - {label: "Regular", value: "far"} + - {label: "Brand", value: "fab"} + - {label: "Academic", value: "ai"} + - {label: "Icon (see https://wowchemy.com/docs/page-builder/#icons)", name: icon, widget: string, required: false} + - label: "Featured Image" + name: "image" + required: false + widget: object + fields: + - label: "Upload an image named `featured.jpg/png`" + name: "filename" + widget: "image" + default: "featured" + required: false + media_library: + config: + multiple: false + - {label: Caption, name: caption, widget: string, required: false} + - {label: Description for screen readers, name: alt_text, widget: string, required: false} + - {label: "Where's the focal point in the image? Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.", name: focal_point, widget: string, required: false, default: "Smart"} + - {label: Thumbnail Only?, name: preview_only, widget: boolean, default: false, required: false} + - name: events + label: Events + label_singular: Event + folder: 'content/event' + path: '{{slug}}/index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - {label: "Title", name: "title", widget: "string"} + - {label: "Abstract", name: "abstract", widget: "text"} + - {label: "Where", name: "location", widget: "text"} + - {label: "From", name: "date", widget: "datetime"} + - {label: "To", name: "date_end", widget: "datetime", default: ""} + - {label: "All day event?", name: "all_day", widget: "boolean", default: false} + - label: Links/Tickets + name: links + required: false + widget: list + fields: + - {label: Link, name: url, widget: string} + - {label: Link text, name: name, widget: string, required: false} + - label: Icon pack + name: icon_pack + widget: select + multiple: false + required: false + options: + - {label: "None", value: ""} + - {label: "Solid", value: "fas"} + - {label: "Regular", value: "far"} + - {label: "Brand", value: "fab"} + - {label: "Academic", value: "ai"} + - {label: "Icon (see https://wowchemy.com/docs/page-builder/#icons)", name: icon, widget: string, required: false} + - {label: "Event", name: "event", widget: "string"} + - {label: "Event link", name: "event_url", widget: "string"} + - {label: "Publish this page on", name: "publishDate", widget: "datetime"} + - {label: "Markdown slides (reference a deck in 'content/slides/')", name: "slides", widget: "string", required: false} + - label: "Draft" + name: "draft" + widget: "boolean" + default: false + required: false + - label: "Featured" + name: "featured" + widget: "boolean" + default: false + required: false + - label: "Authors" + name: "authors" + required: false + widget: "list" + - label: "Tags" + name: "tags" + required: false + widget: "list" + - label: "Categories" + name: "categories" + required: false + widget: "list" + - label: "Projects (reference projects in 'content/project/')" + name: "projects" + required: false + widget: "list" + - label: "Featured Image" + name: "image" + required: false + widget: object + fields: + - label: "Upload an image named `featured.jpg/png`" + name: "filename" + widget: "image" + default: "featured" + required: false + media_library: + config: + multiple: false + - {label: Caption, name: caption, widget: string, required: false} + - {label: Description for screen readers, name: alt_text, widget: string, required: false} + - {label: "Where's the focal point in the image? Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.", name: focal_point, widget: string, required: false, default: "Smart"} + - {label: Thumbnail Only?, name: preview_only, widget: boolean, default: false, required: false} + - {label: "Details", name: "body", widget: "markdown", required: false} + - name: publications + label: Publications + label_singular: Publication + folder: 'content/publication' + path: '{{slug}}/index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - { label: "Title", name: "title", widget: "string" } + - { label: "Subtitle", name: "subtitle", widget: "string", required: false } + - label: "Publication type" + name: "publication_types" + required: true + default: ["0"] + widget: "select" + # Can only have 1 pub. type assigned, but need `multiple` option to save as a Hugo taxonomy list. + multiple: true + options: + - { label: "Uncategorized", value: "0" } + - { label: "Conference paper", value: "1" } + - { label: "Journal article", value: "2" } + - { label: "Preprint / Working Paper", value: "3" } + - { label: "Report", value: "4" } + - { label: "Book", value: "5" } + - { label: "Book section", value: "6" } + - { label: "Thesis", value: "7" } + - { label: "Patent", value: "8" } + - label: "Authors" + name: "authors" + required: true + widget: "list" + - label: "Author Notes (contributions or affiliations for each author)" + name: "author_notes" + required: false + widget: "list" + - { label: "DOI", name: "doi", widget: "string", required: false } + - { label: "Publication", name: "publication", widget: "string", required: false } + - { label: "Publication (abbreviated)", name: "publication_short", widget: "string", required: false } + - { label: "Abstract", name: "abstract", widget: "text", required: false } + - label: "Draft" + name: "draft" + widget: "boolean" + default: false + required: false + - label: "Featured" + name: "featured" + widget: "boolean" + default: false + required: false + - label: "Tags" + name: "tags" + required: false + widget: "list" + - label: "Categories" + name: "categories" + required: false + widget: "list" + - label: "Projects" + name: "projects" + required: false + widget: "list" + - {label: "Markdown slides (reference a deck in 'content/slides/')", name: "slides", widget: "string", required: false} + - label: "Featured Image" + name: "image" + required: false + widget: object + fields: + - label: "Upload an image named `featured.jpg/png`" + name: "filename" + widget: "image" + default: "featured" + required: false + media_library: + config: + multiple: false + - { label: Caption, name: caption, widget: string, required: false } + - { label: Description for screen readers, name: alt_text, widget: string, required: false } + - { label: "Where's the focal point in the image? Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.", name: focal_point, widget: string, required: false, default: "Smart" } + - { label: Thumbnail Only?, name: preview_only, widget: boolean, default: false, required: false } + - { label: "Summary (shortened abstract)", name: "summary", widget: "text", required: false } + - {label: "Details", name: "body", widget: "markdown", required: false} + - { label: "Publish this page on", name: "date", widget: "datetime" } + - name: slides + label: Slides + label_singular: Slides + folder: 'content/slides' + path: '{{slug}}/index' + filter: {field: "cms_exclude"} + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - {label: "Title", name: "title", widget: "string"} + - {label: "Slides (separate with `---`)", name: "body", widget: "markdown"} + - {label: "Publish on", name: "date", widget: "datetime"} + - {label: "Summary", name: "summary", widget: "text", required: false} + - label: "Draft" + name: "draft" + widget: "boolean" + default: false + required: false + - label: "Tags" + name: "tags" + required: false + widget: "list" + - label: "Slide options" + name: "slides" + required: false + widget: object + fields: + - { label: "Theme (see https://github.com/hakimel/reveal.js#theming)", name: theme, widget: string, required: false, default: black } + - label: "Featured Image" + name: "image" + required: false + widget: object + fields: + - label: "Upload an image named `featured.jpg/png`" + name: "filename" + widget: "image" + default: "featured" + required: false + media_library: + config: + multiple: false + - {label: Caption, name: caption, widget: string, required: false} + - {label: Description for screen readers, name: alt_text, widget: string, required: false} + - {label: "Where's the focal point in the image? Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.", name: focal_point, widget: string, required: false, default: "Smart"} + - {label: Thumbnail Only?, name: preview_only, widget: boolean, default: false, required: false} + - name: pages + label: "Pages" + files: + - file: "content/privacy.md" + label: "Privacy Policy" + name: "privacy" + fields: + - {label: "Title", name: "title", widget: "string"} + - {label: "Publish Date", name: "date", widget: "datetime"} + - {label: "Subtitle", name: "subtitle", widget: "string", required: false} + - {label: "Summary", name: "summary", widget: "markdown", required: false} + - label: "Draft" + name: "draft" + required: false + widget: "boolean" + default: false + - {label: "Body", name: "body", widget: "markdown"} + - file: "content/terms.md" + label: "Terms" + name: "terms" + fields: + - {label: "Title", name: "title", widget: "string"} + - {label: "Publish Date", name: "date", widget: "datetime"} + - {label: "Subtitle", name: "subtitle", widget: "string", required: false} + - {label: "Summary", name: "summary", widget: "markdown", required: false} + - label: "Draft" + name: "draft" + required: false + widget: "boolean" + default: false + - {label: "Body", name: "body", widget: "markdown"} diff --git a/wowchemy/assets/js/wowchemy-init.js b/wowchemy/assets/js/wowchemy-init.js index 10a27ed2..203b5263 100644 --- a/wowchemy/assets/js/wowchemy-init.js +++ b/wowchemy/assets/js/wowchemy-init.js @@ -14,5 +14,16 @@ window.wc = { isSiteThemeDark: wcIsSiteThemeDark, }; +// CMS authentication +if (window.netlifyIdentity) { + window.netlifyIdentity.on('init', (user) => { + if (!user) { + window.netlifyIdentity.on('login', () => { + document.location.href = '/admin/'; + }); + } + }); +} + // Initialize theme variation and set body theme class. initThemeVariation(); diff --git a/wowchemy/layouts/partials/site_head.html b/wowchemy/layouts/partials/site_head.html index 2f8fc246..c058c735 100644 --- a/wowchemy/layouts/partials/site_head.html +++ b/wowchemy/layouts/partials/site_head.html @@ -173,7 +173,8 @@ {{ partial "marketing/microsoft_clarity" . }} {{/* Netlify Identity integration. */}} - {{ if .IsHome | and (site.Params.cms.netlify_cms | default false) }} + {{ $use_cms := templates.Exists "wowchemycms/single.wowchemycms_config.yml" | default (site.Params.cms.netlify_cms | default false) }} + {{ if .IsHome | and $use_cms }} {{ end }} diff --git a/wowchemy/layouts/partials/site_js.html b/wowchemy/layouts/partials/site_js.html index fd54420f..82901a30 100644 --- a/wowchemy/layouts/partials/site_js.html +++ b/wowchemy/layouts/partials/site_js.html @@ -91,22 +91,6 @@ {{ $algoliaConfig = dict "appId" (site.Params.search.algolia.app_id | default "") "apiKey" (site.Params.search.algolia.api_key | default "") "indexName" (site.Params.search.algolia.index_name | default "") "poweredBy" (site.Params.search.algolia.show_logo | default false) }} {{ end }} - {{/* Netlify Identity integration. */}} - {{/* Complements loading of Netlify JS in `site_head`. */}} - {{ if .IsHome | and (site.Params.cms.netlify_cms | default false) }} - - {{ end }} - {{/* Charts */}} {{ if .HasShortcode "chart" }}