-
Notifications
You must be signed in to change notification settings - Fork 66
Feature: Templated Page Creation In Dashboard #158
Comments
Wrote a novel 😅 Didn't know how else to present the idea though! Let me know any thoughts – I think this could be a powerful addition to the platform. |
@srobbin, began playing with this over in universe#1 🙂 It feels really good... and is fully backward compatible! You should be able to pull down and play with any existing site (back up the DB first though). |
@amiller-gh This is really interesting, but I'm a little hesitant off the bat and need some time to digest. The biggest reason is that right now there's a clear separation of concerns: site structure is controlled by those who have access to the templates, and the dashboard is for editing pre-determined content. Giving dashboard users the ability to add pages blurs that line. I agree that the current model of creating permalinked record pages isn't great, though. Let me think on this one, and I'll reply again shortly. |
No worries! I think there's a lot of good in that experimental PR even if we don't allow the ability to create multiple pages beyond the default created ones – the ability to reason about page-scoped values is a mental model that I think will resonate with clients more. Ex: You're not editing the "Company Description" section that may or may not be used elsewhere on the site, your editing the "About Us" page. If something is a "Setting" you know it's pretty darn likely to be used elsewhere. The internal mental model for multiple instances of a page is like a special case of collections (aka multiple=true sections). Allowing users to create multiple standalone pages should be no more complicated rendering standalone pages for collections. Specific use case example: A user needs to make special one-off donation pages for events with special copy and a dedicated URL for each page. This could be done with a Beyond the Nifty side effect of the new parser: Partials have full support now, including passing scope, rendering block contexts (layout partials work now!!) and we don't have to maintain any parsing code for hash values and content excaping. By working directly with the AST we can transform templates as they go through the parser (ex: I enforce Vapid's distinction between un-prefixed paths and |
(Also, PR is very experimental still – section sorting / limit directives aren't implemented, tests won't pass, the |
This issue has been automatically marked as stale after 90 days of inactivity. It will be closed if no further activity occurs. |
Problem
Vapid's data model is restrictive for users that need the ability to create new standalone pages for their site. From the dashboard, users should be able to:
Proposed Solution
With a few small changes to the internal data model, we can enable these two features while maintaining full backward compatibility with current site structures.
Additionally – if we choose to go this syntax route – we can set up the framework for a breaking change down the line that will reduce the template syntax surface area, simplifying the developer experience even further. These new syntax features can be added now, and deprecation warnings can be added to the current compiler to help encourage migration. Because Vapid is statically analyzable, code mods for migration assistance are also possible.
In order to talk about these changes, we need to talk about it in the context of Vapid's current data model and templates constructs, and then map them to a model that will work in a multi-page world.
Current State of the World
Vapid data model actually already has a somewhat implicit understanding of pages, but it is not surfaced in the dashboard and there is no way for users to create new ones.
This is because with Vapid's current "everything is a
{{section}}
" data model, most projects end up with sections serving split concerns: some sections are more like site-wide settings, while others only appear in a single html file and operate as page content. We can codify this split responsibility of sections into the data model and template syntax.For clarity in this proposal, I will be using some new language to better describe both the current framework behavior and the new proposed behavior to enable more granular user editing:
Page
: A single rendered page on the site. These are currently non-partial.html
files in the site root, have no dedicated instance data, are not exposed in the dashboard, and are currently singletons. Often pages will have one or more dedicated sections that serve as their page content.Collection
: A collection ofRecord
s. These are currently designated by the multi-section{{#section <name> multiple=true}}
handlebar tag.Record
: An individual item in aCollection
.Record
s may have an optional standalone template to render a single record at a permalinked URL, currently represented by a magically named partial in the site root.Setting
: Any handlebar tag – in thegeneral
scope or a specific{{section}}
– that is shared between more than onePage
and/orRecord
template.Vapid's current behavior can be described as followed:
Page
Sections.html
file is aPage
..html
file._permalink
(currently the file name),_created_at
and_updated_at
(file timestamp info) but they are not exposed to the template system, not configurable in the dashboard, and not actually stored in the database.Page
s may choose to display multipleCollection
Records
using the multi-section syntax (see below).Page
singleton will automatically use the default generateCollection
singleton (see below).Collection
Sections andRecord
sCollection
instance is created for every multi-section type discovered in the site'sPage
templates, or by the presence of a standaloneRecord
template.Record
template to render a singleRecord
from theCollection
– currently, this is a specially named partial in the root of the sitewww
directory (see Passing information to partials #66 for additional thoughts).Collection
of designated sub-pageRecord
s.Collection
instances (Ex: I want a secondblog
collection that uses the sameRecord
templates and overall data model, but is an entirely separate list of posts).Record
instances are created for each generatedCollection
.Record
has autogenerated metadata fields_permalink
,_created_at
and_updated_at
that are exposed to the templating system but are not configurable in the dashboard.Record
s in anyCollection
. By default, there are zero sub-pages present in a newly createdCollection
.Setting
SectionsSetting
s are shared configuration values that are meant to span more than onePage
orRecord
. Non-multiple sections that appear in more than onePage
orCollection
item template are considered a shared siteSetting
.Required Data Updates
To meet the stated needs of this issue, the following data changes are required:
pages
sqlite table. Structure should bemultiple=true
sections fromsections
to a new table calledcollections
Themultiple
column may be dropped from the newcollections
table. Thesortable
andmultiple
columns may be dropped from the oldsections
tablesections
table tosettings
records.section_id
column torecords.collection_id
pages.template
andcollections.template
columns. Fill them in with the same value that is inpages.name
andcollections.name
. These will let Vapid know what template file to use. Thename
column will determine the page slug and dashboard page title.Required Dashboard Updates
To meet the stated needs of this issue, the following dashboard changes are required:
Page
s in the admin dashboard. By default, there is a single page created per template, as is currently done.Page
s, selecting from the projectPage
templates as data structure options.Page
s, including the default created ones. (this in part addresses Feature Request: Drafts #8. The ability to edit metadata for eachPage
orRecord
will finish it off.)Collection
instances, selecting from the available templates. By default oneCollection
will be created for each unique multi-section discovered in the templates, as is the current behavior.Collection
instances – including the defaultCollection
created.Collection
,Page
dashboard pages must allow users to select theCollection
they want to render on the page. Effectively, this means that{{#section collectionName multiple=true}}
becomes a kind of directive, where users can select theCollection
instance they want to render on the given page. This should be presented in the dashboard as a dropdown of all theCollection
instances in the project that match thatCollection
type (eg: I have two pages on my site for my pets, one for dogs, and one for cats. I can code a singlepets.html
page, create two instances of it – one called Dogs and one called Cats – and two Collections – one called Dogs and one called Cats – and choose to render the correct collection on each given page.)general
or a named{{#section}}
to be aSetting
and render it in the dashboard appropriately.Required Syntax Updates
I have one major outstanding question for this feature is: How do we differentiate between the
general
scope, and aPage
's specific content? Currently, thegeneral
scope is – by convention – un-prefixed in vapid templates. This poses a problem, since we need a way for developers to specify certain fields asPage
content to be edited in the dashboard under appropreate page side menu item. Do do this, we need a way to differentiate betweengeneral
siteSettings
, andPage
specific content.I see three options here:
Choose a reserved word prefix for
Page
content.Glimmer has chosen to prefix all component specific data values with
this
. We can use this syntax to differentiatePage
specific content in the template by prefixing it withthis
. So:Require all general references to be prefixed with
general.
Static Site Builds #155 introduces the ability to reference the general scope from any context with
{{general.value}}
. We could add this as a hard and fast rule and mandate that all general refernces either be prefixed, or wrapped with{{#section general}}
(presumably with the ability to reference any otherSetting
through dot syntax as well, ex:{{social.facebook}}
)Because the concept of
Page
specific values is new to this change, we can easily apply a code mod on upgrade to prefix all general values withgeneral.
to maintain backward compatibility.Attempt to infer what is
general
and what is aPage
value.Presumably,
Page
values will be unique to their.html
file. This means that if the same{{value}}
appears across two different.html
files (either in aPage
or aRecord
template) we can assume it is a shared setting and belongs ingeneral
. This approach has several downsides though:.html
templates in far-flung sections of the site.Personal Syntax Recommendation
If I had my 'druthers, I'd pick both solutions 1 and 2. This would mean that:
all
Settings
values must be referenced by{{dot.syntax}}
, andall
Page
values must be referenced via{{this.value}}
.Bare values (ex:
{{sectionValue}}
) would still reference thegeneral
scope but log a deprecation warning and support for bare values would be removed at a later date.Most contentiously – the
{{#section}}
block would log a deprecation warning and instead encourage users to reference settings values via{{dot.syntax}}
.Many modern templating languages (including the next evolution of Handlebars, Glimmer) have moved away from context unwrapping constructs because it becomes very hard to manage inherited scope – both for the compiler and the developer. With the ability to reference
Setting
scopes via dot syntax, the{{#section}}
block becomes vestigial. (Related, see my comments in Passing information to partials #66 about scope management in templates).The above four syntax updates would clear up the un-prefixed namespace for use by template helpers that – although not currently used – may be a valuable syntax to reserve for the future.
Optional Changes
These are things that are not entirely necessicary to deliver the features, but are nice to haves since we'd be touching bit swaths of project structure anyway 🙂
{{#section name multiple=true}}
in favor of a{{#collection name as |localName|}}
directive, which would be functionally equivalent but more descriptive. The compiler will log deprecation warnings until we're ready to remove{{#section}}
entirely, and we can provide an optional code mod to ease migration. This change would not effect the currentCollection
list rendering forRecord
templates in the proposal as drafted. Unlike the{{#section}}
block, the{{#collection}}
block would not unwrap the context so there are no accidental conflicts in thegeneral
namespace. Theas |localName|
syntax is a new Glimmer construct (next gen handlebars) to allow defining new local block scope values.Record
template partials to a new/www/collections
directory, remove the_
prefix, and not require a{{#section}} wrapper. This will reduce the (granted, already minimal) framework boilerplate, and align naming conventions if we go with the new
{{#collection name}}block mentioned above. We can maintain backward compatibility by falling back to the old magic
_partial.html` templates and logging a deprecation.{{#section collectionName multiple=true}}
is interpreted as a directive type inPage
dashboards, it opens up the option to override the order, limit and query settings for any given page. This may be a very handy feature.Describe alternatives you've considered
None... this was the one data model that could maintain backward compatibility with old sites, while still introducing the ability for ad-hoc user page creation in the site. Open to alternatives!
Additional context
This change would open up the dashboard to a number of new features that have been kicking around for a while:
Page
andRecord
metadata panels to provide custom page slugs, social media metadata, page draft/publishing settings, authorship accreditation, code injection, etcThe text was updated successfully, but these errors were encountered: