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" }}