-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Content as Data #1167
Comments
@jstockdi So taking your playlist example ---
title: Playlist
name: "My Cool Playlist"
songs:
- title: You Can Close Your Eyes
url: http://archive.org/download/james-taylor-montreux-jazz-fest-1988-rsr/01 You Can Close Your Eyes.mp3
- title: Country Road
url: http://archive.org/download/james-taylor-montreux-jazz-fest-1988-rsr/09 Country Road.mp3
---
<!doctype html>
<html lang="en" prefix="og:http://ogp.me/ns#">
<head>
<title>Playlist</title>
<script type="module" src="../components/player.js"></script>
</head>
<body>
<app-header></app-header>
<h1>Welcome to the Player!</h1>
<app-player name="${globalThis.page.name}" playlist='${globalThis.page.songs}'></app-player>
<app-footer></app-footer>
</body>
</html> And here's the export default class Player extends HTMLElement {
constructor() {
super();
this.title = '';
this.playlist = [];
}
async connectedCallback() {
this.playlist = JSON.parse(this.getAttribute("playlist") || "[]");
this.title = this.getAttribute("name") || "";
if (!this.shadowRoot) {
const list = this.playlist.map((item) => `<li>${item.title}</li>`).join("\n");
const template = document.createElement('template');
template.innerHTML = `
<div style="text-align: left; width: 30%; margin:0 auto;">
<h1>${this.title}</h1>
<ul>
${list}
</ul>
<button>Start Playlist</button>
</div>
`;
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
this.shadowRoot.querySelector('button')?.addEventListener('click', this.startPlaylist.bind(this));
}
startPlaylist() {
const { title, playlist } = this;
console.log('starting playlist =>', { title, playlist });
alert(`starting playlist => ${title}`);
}
} You can pass frontmatter right into your component, almost thinking of it like an ESI You can see the demo running here The patches are pretty straightforward, just like you has posed in #1229 if you want to run with those, while I get this into Greenwood. I plan to include this in the next release line (v0.30.0) which is in progress (#1208) and something I hope to have wrapped up in the next couple months, but this will likely be available earlier via an alpha release, so will keep you posted. |
I dig the syntax and usage here, the patch makes sense. Thinking broadly... Rich Frontmatter should include:
Should there be a patch to graph.js? Possibly adding the rich front-matter in...
In the playlist example... the graph.json could get pretty large, but in other cases, making menus or supporting tags, it could be quite useful. Currently, tags have to be implemented using CSV and parsing... w/ rich front-matter, I am guessing GQL queries could pre-render then... |
Yeah, that should be handled automatically by the frontmatter package we're using, which is what is allowing us to
Yeah, the one downside to the active frontmatter approach, in particular when combined with collections, is that a lot of that data would get serialized into the page, as seen in my demo <app-player name="My Cool Playlist" playlist="[{"title":"You Can Close Your Eyes","url":"http://archive.org/download/james-taylor-montreux-jazz-fest-1988-rsr/01 You Can Close Your Eyes.mp3"},{"title":"Country Road","url":"http://archive.org/download/james-taylor-montreux-jazz-fest-1988-rsr/09 Country Road.mp3"}]">
<template shadowrootmode="open">
<div style="text-align: left; width: 30%; margin:0 auto;">
<h1>My Cool Playlist</h1>
<ol>
<li>You Can Close Your Eyes</li>
<li>Country Road</li>
</ol>
<button>Start Playlist</button>
</div>
</template>
</app-player> Which could definitely add to the HTML payload size a bit for collections, which would be graph data, but hopefully narrowed down significantly since would just be a collection (subset) of pages. And at least it would be just HTML, so would be the least "punishing" to the browser / usage. 😅
Yeah, there is always the ability to do this all in client-side JavaScript either using // notice this is not a .gql file, but perhaps the logic could be shared?
import { getChildren } from '@greenwood/cli/src/queries/menu.js';
export default class BlogPostsPage extends HTMLElement {
// we can pass in the graph to component, or figure out a way to get it into `getChildren`
constructor(request, graph) {
super();
this.graph = graph;
}
async connectedCallback() {
const { graph } = this;
const blogPosts = getChildren(graph, { parent: 'blog' });
this.innerHTML = `
${
blogPosts.map((post) => {
return `<h2>${post.title}</h2>
}).join('');
}
`;
} So that way users will now have multiple options, which I think provide a good set of pros / cons and authoring preferences:
|
Whoa... Gotta stop by tonight to check this out |
Type of Change
RFC
Summary
Coming out of #952 (and now while working on the new Greenwood website), wanted to track some specific thoughts and ideas around accessing content as data with Greenwood and making it easier to work in HTML / markdown for happy path cases, and mostly to provide an alternative to using GraphQL as built into Greenwood.
In addition, the "graph", if that's even a good name for it, is showing its age by now and in need of some TLC.
Details
Collections
Although Greenwood has the concept of menus, which is a way to group content in the context of a navigation and whatnot, perhaps a more general purpose name going forward may a "Collection", as inspired by Astro's (Content Collections](https://docs.astro.build/en/guides/content-collections/). Ultimately it should be whatever meaning the user wants to give, be it navigation, a bunch of blog posts, or something else entirely.
Things like:
(I think Menu's may have added extra functionality on top of that like ordering and what not, but maybe that should just be considered a "type" of collection?)
For example, say listing out the table of contents for a blog using constructor props instead of the Children GraphQL query
Frontmatter
We may also want to rename it from
index
toorder
since these aren't arrays, and the starting index thing may be confusing / misleading.HTML
We already have frontmatter support for markdown and JS
But might be good to see if we can extend frontmatter support to HTML as well, assuming it doesn't break all the HTML parsers
Rich Frontmatter
As reported in #1229 , would be good to see how we can support "rich" frontmatter data, and to the use case presenting point, what more could we do with frontmatter in this use case, as it would be really nice to leverage this data somehow combined with a custom element
Rendering Strategies / Contexts
Somewhat related to #951 , one caveat around content as data is what to about CSR use cases, like when authoring HTML. How can you get content as data into a custom element using only HTML as you will be coupled to API calls and have to handle them somehow for production builds, since the plan isn't to support an actual Greenwood GraphQL server for production, and so all data is pre-generated at build time, this making it pretty much read-only.
Graph Structure
There are definitely some breaking changes to be made to the graph, to better align on terminology and overall usefulness to Greenwood and users. So given a current item in the graph
id
andlabel
?path
andfilename
? anything else worth cleaning up?imports
field toresources
in frontmatter configindex
->order
path
->url
(instance of URL or at least thehref
property for serialiazing)outputPath
/id
I wonder if there is a case to rename this to
pages
instead? A graph implies nodes, some sort of linking structure, etc which it is definitely not in its current state.Would be good to go through and evaluate all currently open and related issues
The text was updated successfully, but these errors were encountered: