Giter Site home page Giter Site logo

pages-cms / pages-cms Goto Github PK

View Code? Open in Web Editor NEW
1.1K 12.0 90.0 420 KB

A user-friendly CMS for static site generators.

Home Page: https://pagescms.org

License: Other

HTML 0.13% JavaScript 25.34% Vue 62.98% CSS 11.55%
11ty astro cms docusaurus eleventy gatsby hugo jekyll nextjs ssg

pages-cms's Introduction

Pages CMS

Pages CMS is an Open Source Content Management System built for static websites (Jekyll, Next.js, VuePress, Hugo, etc).

It allows you to edit your website's content directly on GitHub via a user-friendly interface.

Documentation

For full documentation, go to pagescms.org/docs

How it works

Pages CMS is built as a Vue.js app with a few serverless functions to handle the Github login.

It is intended to be deployed with Cloudflare Pages, using Cloudflare Workers (referred to as functions functions) for the serverless code.

In a nutshell:

  • The serverless functions are just facilitating the OAuth dance (and logout) between the client and GitHub. The GitHub OAuth token is actually stored in the client.
  • Once logged in, the Vue app lets you select the repo (and branch) where your content may be at.
  • You can configure each repo/branch by adding a .pages.yml that describes the content structure and related settings (e.g. media folder).
  • The Vue app acts as a user-friendly interface on top of the GitHub API to manage content related files in your repo. With it you can search and filter collections, create/edit/delete entries, upload media...

Get started

Use online

The easiest way to get started is to use the online version of Pages CMS. You'll be able to log in with your GitHub account and get the latest version of Pages CMS.

This online version is identical to what's in this repo and as mentioned above, nothing is saved in the backend (OAuth tokens are saved on the client side).

But you can also install your own version locally or deploy it (for free) on Cloudflare following the steps below.

Install locally

To get a local version up and running:

  1. Install dependencies: npm install.
  2. Create a GitHub OAuth app: 0n GitHub, go to your Developer Settings and create a New OAuth App (or alternatively create one for one of your organizations). You can use the following settings for your development environment:
    • Application name: Pages CMS (dev)
    • Homepage URL: https://pagescms.org
    • Authorization callback URL: http://localhost:8788/auth/callback
  3. Create a file for environment variables: copy .dev.vars.exmple into .dev.vars and replace GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET with the values you got for your GitHub OAuth app. You shouldn't have to modify BASE_URL.
  4. Run it: npm run dev. This should run the app locally with Wrangler (allowing us to run the serverless functions locally).
  5. Visit localhost:8788.

Deploy on Cloudflare

  1. Prerequisite: you'll need a Cloudflare account (it's free). Once you have one:
  2. Create a Cloudflare Pages app:
    1. From your account dashboard, go to Workers & Pages, then click on Create application and select the Pages tab.
    2. From there you can connect your GitHub account and select the repo you want to deploy (assuming you've forked pages-cms/pages-cms).
    3. Cloudflare will give you a public URL (e.g. https://pages-cms-123.pages.dev).
  3. Create a GitHub OAuth app: same as for local, go to your Developer Settings and create a New OAuth App (or alternatively create one for one of your organizations) with the following settings:
    • Application name: Pages CMS
    • Homepage URL: https://pagescms.org
    • Authorization callback URL: https://pages-cms-123.pages.dev/auth/callback (replace https://pages-cms-123.pages.dev with whatever URL Cloudflare generated for you, or the custom domain you set up)
  4. Add the environment variables to Cloudflare:
    1. Go back to your Cloudflare Pages app, click on the Settings tab and select Environment variables in the sidebar.
    2. Fill in GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET with the values you got from GitHub.
    3. You will also need to set BASE_URL to the URL that was given to you when you create the Cloudflare Pages app (e.g. https://pages-cms-123.pages.dev).
  5. Open the app link (e.g. https://pages-cms-123.pages.dev).

Cloudflare has very generous free tiers and can also host your actual website. It's a great alternative to GitHub Pages, Netlify or Vercel.

License

Everything in this repo is released under the MIT License.

pages-cms's People

Contributors

hunvreus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pages-cms's Issues

Support for empty image paths

What I did:

(...)
      - name: images
        label: Images
        type: image
        list: true
        options:
          input: content/posts
          output: ""
          categories: [image]

Expected result:

Selecting abcdef.png in the editor and saving would output an empty path.

images:
  - abcdef.png

What happens:

images:
  - content/posts/{year}-{month}-{day}-{primary}/abcdef.png

Context:

I'm using Hugo with bundles. Posts or even single pages can have their content grouped together and paths to media with empty paths will resolve primarily to the bundle.

|- content/posts/{year}-{month}-{day}-{primary}
|-- abcdef.png
|-- index.md

Here's an example of a complete .pages.yml.

Note: I don't have to have both media and images but I'm utilizing them in this case to test if they can both be used in conjunction. Mapping the output to the entire path to images is not a viable solution for all scenarios for my theme and setup.

Thanks! I'm really impressed with this tool!

feat: add draft functionality

Issue

The larger the site gets, the higher the cost of each SSG operation, so even though it's possible to implement a mechanism on the generator side to determine if content is ready to be released, each "save" operation could still be causing the full SSG operation to run (with no actual changes to the site). This has the unintended consequence of making the save operation potentially very expensive.

Solution

Rather than saving changes to the main or master branch by default, it would be nice to make changes to a branch first, and then perform a merge to main as a sort of release operation.

This could have many "sharp edges" because it essentially implements a state machine using branches, so the naming convention would have to allow the app to determine the state of a page using the branch names. If a change is made to a page that causes a merge conflict with the branch, it would require manual intervention or a whole bunch of UI additions to resolve in the CMS.

[Feature] Add Option to Specify Root Folder or Discover .pages.yml

Hey,

Thank you so much for building this project! I really love it and the way it integrates with my Astro site :)

I have one thing I would love, could you perchance add the ability to specify the root folder? I use Appwrite in my repos and typically that means I have a functions folder, appwrite.json at the root, and then frontend or something for the website itself, and backend or api if needed for those respectively. That means I'm able to specify the input properly, but the output being put into frontend/src/content/posts for, for instance, media, is /frontend/src/content/media/some_image.jpg which needs to be /src/, so is there I think a root folder option (for the repo) would be tight

Alternatively, if I move the .pages.yml to my root folder, it could find it there instead of erroring if not at the root of the repo

Github Oauth app , vs github app

May is suggest using github app , vs github oauth app when setting up the project , so that when collaborators are added they wont have access to the entire repo.

I am sure you must have thought more about this , and the collaborators would probably just have a short lived token stored in a KV store or some other approach instead of requiring them to have a github account and giving them full access.

I am just trying to think about what could be the reason for choosing A vs B.

Also could we enable the discussions tab in this repo, so that something like this comment/ or queries could be posted there.
I noticed many people asked questions or posted suggestions like me , which are not really bugs/ issues.

Settings for HTML files

First: Great work here! I have tried several CMS for Jekyll/Hugo and this one comes the closest to winning for me. So I really want to make it work for me as well!

I have a Hugo blog with posts and pages that I have been able to set up.

I was hoping I would also be able to add my shortcodes directory to the CMS. I tried the following –

content:
  - name: shortcodes
      label: Shortcodes
      type: collection
      path: 'layouts/shortcodes'
      filename: fields.title.html
      format: raw
      subfolders: false
      fields:
          - name: title
            label: Title
            type: string
            required: true
          - name: code
            label: Code
            type: code
            options:
              language: html
            required: true

And it shows me this screen –
image

Clicking on an entry, shows me the code block as intended –
image

I am wondering if it is possible to edit/create files that do not have a YAML frontmatter? As is the case with my shortcodes here, I would like –

  1. The filename to be accessible as a field under View. So the 'collection view' doesn't show blanks.
  2. The filename to be definable when creating a new entry (shortcode).

Is that possible? Will it be possible in a later version?

Related Issue: #13

Dual Collections Results In Text Block

Hi there I'm currently having some issues with having two collections of content setup.
I'm looking to link posts to references. but when I go to the hosted pages cms app the references is just one large text box. I've added my yaml below

p.s. thank you for building this! its amazing
media: static/media

content:
  - name: references
    label: References  # Corrected the spelling
    type: collection
    path: src/lib/references
    view:
      fields: 
        - Reference-Name 
    fields:
      - name: references  # Changed to lowercase for consistency
        type: object
        fields:
          - name: referenceName  # Adjusted for consistency
            label: Reference Name
            type: string
          - name: referenceURL  
            label: Reference Link
            type: string
          - name: dateAccessed 
            label: Date Accessed
            type: date
          - name: category 
            type: select
            label: Category
            options:
              values: [Web, Book, Conference, Video]  # Corrected the spelling
          - name: note
            label: Reference Note
            type: string
  - name: posts
    label: Posts
    type: collection
    path: src/lib/posts
    view:
      fields:
        - title
        - published
        - date
    fields:
      - name: published
        label: Published
        type: boolean
        default: true
      - name: date
        label: Date
        type: date
      - name: title
        label: Title
        type: string
      - name: cover
        type: image
        label: Cover
        list: true
        options:
          path: static/media
          extensions: [ jpg, jpeg, png ]
      - name: category 
        type: select
        label: Category
        options:
          values: [Personal Finance,Investing,Stocks,Side Hustles]
      - name: body
        label: Body
        type: rich-text
      - name: SEO-Metadata
        label: SEO Data
        type: object
        fields:
        - name: SEO-Title
          type: string
          options:
            minlength: 20
            maxlength: 60
        - name: SEO-Image
          type: image
          label: SEO Image
          list: true
          options:
            path: static/media/SEO-Images
            extensions: [ jpg, jpeg, png ]
        - name: SEO-Desc
          label: SEO Description
          type: string
          options:
            minlength: 20
            maxlength: 60
        - name: Modified_at
          type: date
          label: Modified At
          options:
            time: true
            format: DD-MM-YYYY HH:mm

Accessibility issues

Currently, the fields are not linked to their labels which makes the CMS unusable for anyone who depends on a screen reader. Looking at the components I don't think fixing this would be a big lift; would you be open to a pull request?

feat: add customizable git messages

Issue

In the current implementation the git messages are hard coded and mostly sane defaults, but many CI/CD workflows require specific formatting or keywords in commit messages (for linting or job triggering). An example would be conventional commit linted system where a required <type> and optional [scope] prefix on commit messages could cause issues with deployment.

Suggested Resolution

The best solution I could come up with is to simply allow overriding of commit messages in the configuration file. This could get a bit heavy as there are a few different types of commit messages currently used, and several have multiple messages depending on the CRUD operation being performed, but this would be the most flexible solution.

ignore _index.md pages

For Hugo pages, you usually have the index page (empty _index.md file) for the list of all detailed pages (i.e. the list of all posts from which you can jump to the detailed one). currently this leads to an error for mapping the frontmatter. how can I let Pages CMS ignore these files?

Support for yaml lists

How would I configure this frontmatter in pages? It seems like there needs
to be an array object in the schema besides select. There isn't anything in the configuration help for yaml lists unless I'm missing something.

resources:
  - name: featured-image
    src: featured-image.jpg

I tried...

content:
  - name: posts
    label: Posts
    type: collection
    path: content/posts
    fields:
      - {name: draft, label: Draft, type: boolean, default: true}
      - {name: title, label: Title, type: string}
      - {name: date, label: Date, type: date}
      - name: resources
        label: Resources
        type: object
        fields:
          - name: name
            type: string
            hidden: true
            default: featured-image
          - name: src
            label: Featured Image
            type: image
    filename: index.md
    view:
      fields: [title, draft, date]

...which outputs something like...

resources:
  name: featured-image
  src: featured-image.jpg

... when I select an image in the UI an save.

I also tried...

content:
  - name: posts
    label: Posts
    type: collection
    path: content/posts
    fields:
      - {name: draft, label: Draft, type: boolean, default: true}
      - {name: title, label: Title, type: string}
      - {name: date, label: Date, type: date}
      - name: resources
        label: Resources
        type: object
        fields:
          - name: featured-image
            label: Featured Image
            type: object
            fields:
            - name: name
              type: string
              hidden: true
              default: featured-image
            - name: src
              label: Featured Image
              type: image
    filename: index.md
    view:
      fields: [title, draft, date]

...which outputs something like...

resources:
  featured-image:
      name: featured-image
      src: featured-image.jpg

This would better support resources metadata in Hugo. I highly suggest reading the spec to get a better sense of the capabilities beyond specifying one metadata entry. In this simple use-case, Hugo uses this frontmatter to insert the feature image into the post. If there is an additional feature-image-preview entry, then that will be displayed on the posts page as a small preview image above the link to the post.

I also use page bundles with Hugo, which is why filenames of my posts are index.md, similar to #10 which works fine (but there is no limit to how many entries you can make which is what the issue is about). The parent directory of index.md I like to name {year}-{month}-{day}-{primary} for example, but could be named anything.

Thanks for the great tool!

List with no names for its fields

Hi, I wanted to write my pages-cms settings to be able to edit tags like this:

tags:
  - tools
  - notes

But the closest settings I got was

content:
  - name: posts
    label: Posts
    type: collection
    path: src/content/blog
    view:
      fields: [ title, pubDatetime ]
      sort: [ pubDatetime ]
    fields:
      - { name: title, label: Title, type: string }
      - { name: pubDatetime, label: Publish Date Time, type: date }
      - { name: postSlug, label: Post Slug, type: string }
      - { name: featured, label: Featured, type: boolean }
      - { name: draft, label: Draft, type: boolean }
      - name: tags
        label: Tags
        type: object
        list: true
        fields:
--->    - { name: tag, label: Tag, type: string }
      - { name: ogImage, label: OG Image, type: image }
      - { name: description, label: Description, type: string }
      - { name: body, label: Body, type: rich-text }

Which gives

tags:
  - tag: tools
  - tag: notes

I cannot create fields with no names, as name is a required parameter. Is there any other way to achieve the effect I want?

Allow sorting of content by filename for Nuxt Content module

Hi! I've been playing around the Pages CMS in conjunction with Nuxt and really enjoying it. Thank you! I use the Nuxt Content module which allows for sorting of content via the filename e.g.

1.first-page.md
2.second-page.md
3.third-page.md

using the initial number in the filename to sort. Is there a way to get Pages CMS to use this for sorting content and also allow creation of new content using this scheme? Thanks so much!

Feature: Improve builtin text editor

Two improvements would be appreciated in the builtin text editor:

  • Auto texts highlights, specifically html/markdown codes. Highlights like how it is in the config file in "settings" tabs.
  • A warning before closing the window or going back, as of now, if you accidentally do any of these, all your progress is lost.

Use .env file

I'm very curious why use .dev files instead of well known .env files

Exclude Subfolder(s)

Great project here!

My Hugo site is set up as such:

└── content
    └── static_page.md
    └── index.md
    └── blog
        └── post_a.md
        └── post_b.md
...

So I've created the following configuration for Pages:

content:
  - name: blog
    label: Blog
    type: collection
    path: 'content/blog'
    view:
      fields: [ title, published, date ]
    fields:
      - name: draft
        label: Draft
        type: boolean
        default: true
      - name: date
        label: Date
        type: date
      - name: title
        label: Title
        type: string
      - name: body
        label: Body
        type: rich-text
  - name: pages
    label: Pages
    type: collection
    path: 'content'
    view:
      fields: [ title, type ]
    fields:
      - name: title
        label: Title
        type: string
      - name: type
        label: Type
        type: select
        options: 
          values:
            - value: page
              label: Page
      - name: body
        label: Body
        type: rich-text

However, this results in the blog folder showing up within my Pages section. It'd be great if there were a way to exclude subfolders so that I see my blog posts only under blog. (Or to know about such a method if it already exists!)

Blank defaults aren't working

Amazing work with this CMS! It's very fast and slick.

One issue I ran into is, my site expects blank values in the yam file:

  - name: Cara Fischer
    nation: ''
    life: ''
    image: ''
    learn_more_urls: null
    bio: ''
    fun_fact: ''
    quotes: null

In the page settings I put a blank string for the defaults:

        fields:
        - name: name
          label: Name
          type: string
          required: true
        - name: nation
          label: Nationality
          type: string
          default: ''
        - name: life
          label: Life Span
          type: string
          default: ''
        - name: image
          label: Profile Image
          type: image
        - name: learn_more_urls
          default: ''
          label: Learn More URLs
          type: string
          list: true
        - name: bio
          label: Biography
          type: rich-text
          default: ''
        - name: fun_fact
          label: Fun Fact
          type: text
          default: ''
        - name: quotes
          label: Quotes
          type: string
          list: true
          default: ''
        - name: meta_title
          label: Meta Title
          type: string
          default: ''
        - name: meta_description
          label: Meta Description
          type: text
          default: ''

However, this is saving like this with no fields or defaults:

  - name: Cara Fischer

Is this expected? Is it possible to have the fields populate?

Onboarding difficulties

Hi there, this seems quite a promising solution to a common problem I run in to, so thanks for your efforts so far.

When trying to get set up yesterday, I did find the onboarding process started off being very straightforward. I authenticated, pointed to a repo, wrote a config, could see my media in the media tab. So far, so good.

But at this point the onboarding process hits something of a brick wall, unless you're familiar with how the final CMS should look and work. A few comments, which may be worth looking at:

  1. When a newly created category is empty, there's no way via the UI to create an entry. This seems a big blocker, I had to guess that it was looking for an MD file in the defined folder and add an invalid-but-existing test.md file at the folder to get it to work. I could then use the UI to create an empty file and delete my test file.
  2. Related, the extension config option seems to not work – setting it to json gives "This field (extension) is not valid and will be ignored"
  3. Even after doing the above, it wasn't clear what format the content should be in. Frontmatter can be in JSON, for example. I thankfully found a comment on HN with someone else's example project and could copy over that content structure. – This one seems an obstacle to being able to let non-developers add content.

Once I'd dug in to the settings and set the layout to JSON and filename accordingly, the UI actually became much more intuitive. Perhaps a suggestion:

  • Default to JSON files/JSON based UI. Not only does JSON not require the same dependencies as Frontmatter, thus meaning it's a much more common data format, the editor view for JSON you've built is much more user friendly. It turns Pages from a dev only tool to something I could hand to a non technical person.
  • When a new category is created, but the path doesn't exist, show both the "folder doesn't exist" error and a create new post button. Creating a new post could simultaneously create that folder in the repo on save.

Though the above is only true once the bug in using the extension property is solved as, right now, the UI appears to work without it, but then the collection overview page cannot read the files:
image

Zola Support "Failed to parse frontmatter for 1 entry. Your settings may be wrong."

It looks like it doesn't support Zola yet?

This is the config file

    input: content/posts
    output: posts
content:
  - name: posts
    label: posts
    type: collection
    path: content/posts
    view:
      fields: [title, draft, date]
    fields:
      - { name: title, label: Title, type: string }
      - { name: date, label: Date, type: date }
      - { name: body, label: Body, type: rich-text }
      - { name: draft, label: Draft, default: true, type: boolean }
    filename: "{primary}/index.md"
  - name: config
    label: Zola Configs
    path: config.toml
    type: file
    fields:
      - name: title
        label: Website title
        type: string
      - name: description
        label: Website description
        type: string
        description: Will be used for any page with no description.
      - name: base_url
        label: Website URL
        type: string
        pattern: ^(https?:\/\/)?(www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$
      - name: banner
        label: Preview image
        type: image
        description: Image used in the social preview on social networks (e.g. Facebook, Twitter...)

The issue is after going to the "posts" tab, I can see the titles, but no dates or draft info, additionally, I get this error "Failed to parse frontmatter for 1 entry. Your settings may be wrong.", going inside the folder post, I don't see the "index.md" file too, just a blank space with no name, clicking on edit, will open the whole file as a one plain-text file to edit it, no rich text, none of the fields specified above as well.
And I haven't tried creating a new post either just in case not to mess things up.

The media are in the same folder as the post too.
The configuration file config.toml does open, but it seems it doesn't detect what I wrote above, just showing the whole file as a plain-text too, which is not a deal breaker for this one.

Too many open branches from dependabot

I'm receiving the following error message The branch "main" doesn't exist. Redirecting you to the default branch ("main").
I saw that the call for the https://api.github.com/repos/<owner>/<repo>/branches return 30 results and I have a lot of dependabot branches opened on my repo, so the main doesn't return on the list

I think a solution is to update the getBranches functions to use the api /repos/{owner}/{repo}/branches/{repoDetails.default_branch}
and insert the result on the being of the branches array
Or use pagination on the calls

I'll try to open a PR on the weekend
Cheers 😄

Media location for a folder per post

What's the configuration for a setup like this? All what I have tried so far didn't work and keeps assuming I have one folder for ALL my media, which is very chaotic.

Folder structure is simply like this

content/
     posts/
          post1/
                index.md
                image1.png
          post2/
                index.md
                image1.png
          post3/
                index.md
                image1.png

Docker Image

Is this project open to including a Dockerfile / Hub/ghcr.io image for self hosting?

I'd like to self host this in a private network and rely on Docker to do so. Adding an official image would help other folks to do the same!

For my particular case the dev server running in Docker would likely be sufficient.

One folder per post

I'm using Hugo and prefer to have one folder per post so that post text and all images are in the same place.

content/posts/
  2024-02-02-post-title/
    index.md
    image.png

Can I somehow configure pages-cms like that?

P.S. maybe you can enable discussions for such questions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.