Sfoglia il codice sorgente

feat: add Wowchemy CMS module

George Cushen 4 anni fa
parent
commit
5072eddcc1

+ 28 - 0
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
+---
+```

+ 16 - 0
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

+ 3 - 0
wowchemy-cms/go.mod

@@ -0,0 +1,3 @@
+module github.com/wowchemy/wowchemy-hugo-modules/wowchemy-cms
+
+go 1.15

+ 15 - 0
wowchemy-cms/static/admin/index.html

@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang="en-us">
+<head>
+  <meta name="robots" content="noindex">
+  <meta charset="utf-8">
+  <meta content="width=device-width, initial-scale=1.0" name="viewport">
+  <title>Wowchemy Content Manager</title>
+  <!-- Include Netlify Identity for authentication. -->
+  <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
+</head>
+<body>
+<!-- Include the latest Netlify CMS v2.x.x script that builds the admin panel. -->
+<script src="https://cdn.jsdelivr.net/npm/netlify-cms@2/dist/netlify-cms.min.js"></script>
+</body>
+</html>

+ 521 - 0
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"}

+ 11 - 0
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();

+ 2 - 1
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 }}
     <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
   {{ end }}
 

+ 0 - 16
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) }}
-    <script>
-      if (window.netlifyIdentity) {
-        window.netlifyIdentity.on("init", user => {
-          if (!user) {
-            window.netlifyIdentity.on("login", () => {
-              document.location.href = "/admin/";
-            });
-          }
-        });
-      }
-    </script>
-    {{ end }}
-
     {{/* Charts */}}
     {{ if .HasShortcode "chart" }}
     <script>