Web site Developer I Advertising I Social Media Advertising I Content material Creators I Branding Creators I Administration I System Answer
On this article, we’ll be constructing an interactive fiction expertise wherein a consumer can insert phrases that match elements of speech given by the content material creator. Let’s go!
Creating an interactive expertise with fiction generally is a chore with conventional content material administration instruments. Writing the prose, creating the varieties, combining them within the frontend — these are sometimes the area of three totally different individuals.
Let’s make it the area of only one content material creator wherein the consumer will fill out a kind earlier than studying the story — creating odd and infrequently humorous tales. The sort of expertise was popularized as “Madlibs.”
How The Generator Will Work
An editor can create a sequence of madlibs that an end-user can fill out and save a duplicate with their distinctive solutions. The editor will probably be working with the Sanity Studio inside a rich-text discipline that we’ll craft to supply further info for our front-end to construct out varieties.
For the editor, it can really feel like writing normal paragraph content material. They’ll be capable to write like they’re used to writing. They will then create particular blocks inside their content material that can specify part of speech and show textual content.
The front-end of the applying can then use that information to each show the textual content and construct a kind. We’ll use 11ty to create the frontend with some small templates. The shape that’s constructed will show to the consumer earlier than they see the textual content. They’ll know what kind of speech and normal context for the phrases and phrases they’ll enter.
After the shape is submitted, they’ll be given their absolutely shaped story (with hopefully hilarious outcomes). This creation will solely be set inside their browser. In the event that they want to share it, they’ll then click on the “Save” button. It will submit the whole textual content to a serverless perform in Netlify to put it aside to the Sanity information retailer. As soon as that has been created, a hyperlink will seem for the consumer to view the everlasting model of their madlib and share it with pals.
Since 11ty is a static web site generator, we are able to’t rely on a web site rebuild to generate every consumer’s saved Madlib on the fly. We will use 11ty’s new Serverless mode to construct them on request utilizing Netlify’s On-Demand Builders to cache every Madlib.
Sanity.io
Sanity.io is a unified content material platform that believes that content material is information and information can be utilized as content material. Sanity pairs a real-time information retailer with three open-source instruments: a robust question language (GROQ), a CMS (Sanity Studio), and a rich-text information specification (Moveable Textual content).
Moveable Textual content
Moveable Textual content is an open-source specification designed to deal with wealthy textual content as information. We’ll be utilizing Moveable Textual content for the wealthy textual content that our editors will enter right into a Sanity Studio. Information will enhance the wealthy textual content in a means that we are able to create a kind on the fly primarily based on the content material.
11ty And 11ty Serverless
11ty is a static web site generator in-built Node. It permits builders to ingest information from a number of sources, write templates in a number of templating engines, and output easy, clear HTML.
Within the upcoming 1.0 launch, 11ty is introducing the idea of 11ty Serverless. This replace permits websites to make use of the identical templates and information to render pages through a serverless perform or on-demand builder. 11ty Serverless begins to blur the road between “static web site generator” and server-rendered web page.
Netlify On-Demand Builders
Netlify has had serverless capabilities as a part of its platform for years. For instance, an “On-Demand Builder” is a serverless perform devoted to serving a cached file. Every builder works equally to a normal serverless perform on the primary name. Netlify then caches that web page on its edge CDN for every further name.
Constructing The Enhancing Interface And Datastore
Earlier than we are able to dive into serverless capabilities and the frontend, it will be useful to have our information arrange and able to question.
To do that, we’ll arrange a brand new undertaking and set up Sanity’s Studio (an open-source content material platform for managing information in your Sanity Content material Lake).
To create a brand new undertaking, we are able to use Sanity’s CLI instruments.
First, we have to create a brand new undertaking listing to accommodate each the front-end and the studio. I’ve referred to as mine madlibs
.
From inside this listing within the command line, run the next instructions:
npm i -g @sanity/cli
sanity init
The sanity init
command will run you thru a sequence of questions. Identify your undertaking madlibs
, create a brand new dataset referred to as manufacturing
, set the “output path” to studio
, and for “undertaking template,” choose “Clear undertaking with no predefined schemas.”
The CLI creates a brand new Sanity undertaking and installs all of the wanted dependencies for a brand new studio. Contained in the newly created studio
listing, we have now every little thing we have to make our modifying expertise.
Earlier than we create the primary interface, run sanity begin
within the studio
listing to run the studio.
Creating The madlib
Schema
A set of schema defines the studio’s modifying interface. To create a brand new interface, we’ll create a brand new schema within the schema folder.
// madlibs/studio/schemas/madlib.js
export default {
// Identify within the information
title: 'madlib',
// Title seen to editors
title: 'Madlib Template',
// Sort of schema (at this stage both doc or object)
kind: 'doc',
// An array of fields
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
title: 'Slug',
name: 'slug',
type: 'slug',
options: {
source: 'title',
maxLength: 200, // // will be ignored if slugify is set
}
},
]
}
The schema file is a JavaScript file that exports an object. This object defines the info’s title
, title
, kind
, and any fields the doc may have.
On this case, we’ll begin with a title
string and a slug
that may be generated from the title discipline. As soon as the file and preliminary code are created, we have to add this schema to our schema.js
file.
// /madlibs/studio/schema/schema.js
// First, we should import the schema creator
import createSchema from 'half:@sanity/base/schema-creator'
// Then import schema sorts from any plugins which may expose them
import schemaTypes from 'all:half:@sanity/base/schema-type'
// Imports our new schema
import madlib from './madlib'
// Then we give our schema to the builder and supply the end result to Sanity
export default createSchema({
// We title our schema
title: 'default',
// Then proceed to concatenate our doc kind
// to those offered by any plugins which are put in
sorts: schemaTypes.concat([
// document
// adds the schema to the list the studio will display
madlib,
])
})
Subsequent, we have to create a wealthy textual content editor for our madlib authors to write down the templates. Sanity has a built-in means of dealing with wealthy textual content that may convert to the versatile Moveable Textual content information construction.
To create the editor, we use an array
discipline that incorporates a particular schema kind: block
.
The block
kind will return all of the default choices for wealthy textual content. We will additionally lengthen this kind to create specialty blocks for our editors.
export default {
// Identify within the information
title: 'madlib',
// Title seen to editors
title: 'Madlib Template',
// Sort of schema (at this stage both doc or object)
kind: 'doc',
// An array of fields
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
title: 'Slug',
name: 'slug',
type: 'slug',
options: {
source: 'title',
maxLength: 200, // // will be ignored if slugify is set
}
},
{
title: 'Madlib Text',
name: 'text',
type: 'array',
of: [
{
type: 'block',
name: 'block',
of: [
// A new type of field that we'll create next
{ type: 'madlibField' }
]
},
]
},
]
}
This code will arrange the Moveable Textual content editor. It builds numerous forms of “blocks.” Blocks roughly equate to top-level information within the JSON information that Moveable Textual content will return. By default, normal blocks take the form of issues like paragraphs, headers, lists, and many others.
Customized blocks might be created for issues like photographs, movies, and different information. For our madlib fields, we wish to make “inline” blocks — blocks that move inside considered one of these bigger blocks. To try this, the block
kind can settle for its personal of
array. These fields might be any kind, however we’ll make a customized kind and add it to our schema in our case.
Creating A Customized Schema Sort For The Madlib Subject
To create a brand new customized kind, we have to create a brand new file and import the schema into schema.js
as we did for a brand new doc kind.
As a substitute of making a schema with a kind
of doc
, we have to create considered one of kind: object
.
This tradition kind must have two fields: the show textual content and the grammar kind. By structuring the info this manner, we open up future potentialities for inspecting our content material.
Alongside the info fields for this kind, we are able to additionally specify a customized preview to point out multiple discipline displayed within the wealthy textual content. To make this work, we outline a React part that can settle for the info from the fields and show the textual content the way in which we would like it.
// /madlibs/studio/schemas/object/madLibField.js
import React from 'react'
// A React Element that takes hte worth of knowledge
// and returns a easy preview of the info that can be utilized
// within the wealthy textual content editor
perform madlibPreview({ worth }) {
const { textual content, grammar } = worth
return (
{textual content} ({grammar})
);
}
export default {
title: 'Madlib Subject Particulars',
title: 'madlibField',
kind: 'object',
fields: [
{
name: 'displayText',
title: 'Display Text',
type: 'string'
},
{
name: 'grammar',
title: 'Grammar Type',
type: 'string'
}
],
// Defines a preview for the info within the Wealthy Textual content editor
preview: {
choose: {
// Selects information to move to our part
textual content: 'displayText',
grammar: 'grammar'
},
// Tells the sphere which preview to make use of
part: madlibPreview,
},
}
As soon as that’s created, we are able to add it to our schemas array and use it as a kind in our Moveable Textual content blocks.
// /madlibs/studio/schemas/schema.js
// First, we should import the schema creator
import createSchema from 'half:@sanity/base/schema-creator'
// Then import schema sorts from any plugins which may expose them
import schemaTypes from 'all:half:@sanity/base/schema-type'
import madlib from './madlib'
// Import the brand new object
import madlibField from './objects/madlibField'
// Then we give our schema to the builder and supply the end result to Sanity
export default createSchema({
// We title our schema
title: 'default',
// Then proceed to concatenate our doc kind
// to those offered by any plugins which are put in
sorts: schemaTypes.concat([
// documents
madlib,
//objects
madlibField
])
})
Creating The Schema For Consumer-generated Madlibs
For the reason that user-generated madlibs will probably be submitted from our frontend, we don’t technically want a schema for them. Nevertheless, if we create a schema, we get a simple solution to see all of the entries (and delete them if crucial).
We wish the construction for these paperwork to be the identical as our madlib templates. The primary variations on this schema from our madlib
schema are the title
, title
, and, optionally, making the fields read-only.
// /madlibs/studio/schema/userLib.js
export default {
title: 'userLib',
title: 'Consumer Generated Madlibs',
kind: 'doc',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
readOnly: true
},
{
title: 'Slug',
name: 'slug',
type: 'slug',
readOnly: true,
options: {
source: 'title',
maxLength: 200, // // will be ignored if slugify is set
},
},
{
title: 'Madlib Text',
name: 'text',
type: 'array',
readOnly: true,
of: [
{
type: 'block',
name: 'block',
of: [
{ type: 'madlibField' }
]
},
]
},
]
}
With that, we are able to add it to our schema.js
file, and our admin is full. Earlier than we transfer on, make sure you add a minimum of one madlib template. I discovered the primary paragraph of Moby Dick labored surprisingly properly for some humorous outcomes.
Constructing The Frontend With 11ty
To create the frontend, we’ll use 11ty. 11ty is a static web site generator written in and prolonged by Node. It does the job of making HTML from a number of sources of knowledge properly, and with some new options, we are able to lengthen that to server-rendered pages and build-rendered pages.
Setting Up 11ty
First, we’ll must get issues arrange.
Inside the primary madlibs
listing, let’s create a brand new web site
listing. This listing will home our 11ty web site.
Open a brand new terminal and alter the listing into the web site
listing. From there, we have to set up a number of dependencies.
// Create a brand new package deal.json
npm init -y
// Set up 11ty and Sanity utilities
npm set up @11ty/eleventy@beta @sanity/block-content-to-html @sanity/shopper
As soon as these have been put in, we’ll add a few scripts to our package deal.json
// /madlibs/web site/package deal.json
"scripts": {
"begin": "eleventy --serve",
"construct": "eleventy"
},
Now that we have now a construct and begin script, let’s add a base template for our pages to make use of and an index web page.
By default, 11ty will look in an _includes
listing for our templates, so create that listing and add a base.njk
file to it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta title="viewport" content material="width=device-width, initial-scale=1.0">
<title>Madlibs</title>
{# Primary reset #}
<hyperlink rel="stylesheet" href="https://unpkg.com/some-nice-basic-css/global.css" />
</head>
<physique>
<nav class="container navigation">
<a category="emblem" href="https://smashingmagazine.com/">Madlibs</a>
</nav>
<div class="stack container bordered">
{# Inserts content material from a web page file and renders it as html #}
{ protected }
</div>
{% block scripts %}
{# Block to insert scripts from youngster templates #}
{% endblock %}
</physique>
</html>
As soon as we have now a template, we are able to create a web page. First, within the root of the web site
listing, add an index.html
file. Subsequent, we’ll use frontmatter so as to add somewhat information — a title and the format file to make use of.
---
title: Madlibs
format: 'base.njk'
---
<p>Some madlibs to take your thoughts off issues. They're saved in <a href="https://sanity.io">Sanity.io</a>, constructed with <a href="https://11ty.dev">11ty</a>, and do fascinating issues with Netlify serverless capabilities.</p>
Now you can begin 11ty by working npm begin
within the web site
listing.
Now, we wish to create pages dynamically from information from Sanity. To do that, we’ll create a JavaScript Information file and a Pagination template.
Earlier than we dive into these recordsdata, we have to create a few utilities for working with the Sanity information.
Contained in the web site
listing, let’s create a utils
listing.
The primary utility we’d like is an initialized Sanity JS shopper. First, create a file named sanityClient.js
within the new utils
listing.
// /madlibs/web site/utils/sanityClient.js'
const sanityClient = require('@sanity/shopper')
module.exports = sanityClient({
// The undertaking ID
projectId: '<YOUR-ID>',
// The dataset we created
dataset: 'manufacturing',
// The API model we wish to use
// Greatest observe is to set this to immediately's date
apiVersion: '2021-06-07',
// Use the CDN as an alternative of fetching immediately from the info retailer
useCdn: true
})
Since our wealthy textual content is saved as Moveable Textual content JSON, we’d like a solution to convert the info to HTML. We’ll create a utility to do that for us. First, create a file named portableTextUtils.js
within the utils
listing.
For Sanity and 11ty websites, we usually will wish to convert the JSON to both Markdown or HTML. For this web site, we’ll use HTML to have granular management over the output.
Earlier, we put in @sanity/block-content-to-html
, which is able to assist us serialize the info to HTML. The package deal will work on all fundamental forms of Moveable Textual content blocks and kinds. Nevertheless, we have now a customized block kind that wants a customized serializer.
// Initializes the package deal
const toHtml = require('@sanity/block-content-to-html')
const h = toHtml.h;
const serializers = {
sorts: {
madlibField: ({ node }) => {
// Takes every node of `kind` `madlibField`
// and returns an HTML span with an id, class, and textual content
return h('span', node.displayText, { id: node._key, className: 'empty' })
}
}
}
const prepText = (information) => {
// Takes the info from a particular Sanity doc
// and creates a brand new htmlText property to comprise the HTML
// This lets us hold the Moveable Textual content information intact and nonetheless show HTML
return {
...information,
htmlText: toHtml({
blocks: information.textual content, // Moveable Textual content information
serializers: serializers // The serializer to make use of
})
}
}
// We solely must export prepText for our capabilities
module.exports = { prepText }
The serializers
object on this code has a sorts
object. On this object, we create a specialised serializer for any kind. The important thing within the object ought to match the kind
given in our information. In our case, that is madlibField
. Every kind may have a perform that returns a component written utilizing hyperscript capabilities.
On this case, we create a span
with kids of the displayText
from the present information. Later we’ll want distinctive IDs primarily based on the info’s _key
, and we’ll want a category to type these. We offer these in an object because the third argument for the h()
perform. We’ll use this identical serializer setup for each our madlib templates and the user-generated madlibs.
Now that we have now our utilities, it’s time to create a JavaScript information file. First, create a _data
within the web site
listing. On this file, we are able to add world information to our 11ty web site. Subsequent, create a madlibs.js
file. This file is the place our JavaScript will run to tug every madlib template. The information will probably be obtainable to any of our templates and pages beneath the madlibs
key.
// Get our utilities
const shopper = require('../utils/sanityClient')
const {prepText} = require('../utils/portableTextUtils')
// The GROQ question used to seek out particular paperwork and
// form the output
const question = `*[_type == "madlib"]{
title,
"slug": slug.present,
textual content,
_id,
"formFields": textual content[]{
kids[_type == "madlibField"]{
displayText,
grammar,
_key
}
}.kids[]
}`
module.exports = async perform() {
// Fetch information primarily based on the question
const madlibs = await shopper.fetch(question);
// Put together the Moveable Textual content information
const preppedMadlib = madlibs.map(prepText)
// Return the total array
return preppedMadlib
}
To fetch the info, we have to get the utilities we simply created. The Sanity shopper has a fetch()
technique to move a GROQ question. We’ll map over the array of paperwork the question returns to arrange their Moveable Textual content after which return that to 11ty’s information cascade.
The GROQ question on this code instance is doing a lot of the work for us. We begin by requesting all paperwork with a _type
of madlib
from our Sanity content material lake. Then we specify which information we wish to return. The information begins merely: we’d like the title, slug, wealthy textual content, and id from the doc, however we additionally wish to reformat the info right into a set of kind fields, as properly.
To try this, we create a brand new property on the info being returned: formFields
. This seems on the textual content
information (a Moveable Textual content array) and loops over it with the []
operator. We will then construct a brand new undertaking on this information like we’re doing with the whole doc with the {}
operator.
Every textual content
object has a kids
array. We will loop via that, and if the merchandise matches the filter contained in the []
, we are able to run one other projection on that. On this case, we’re filtering all kids
which have a _type == "madlibField"
. In different phrases, any inline block that has an merchandise with the sort we created. We want the displayText
, grammar
, and _key
for every of those. It will return an array of textual content
objects with the youngsters matching our filter. We have to flatten this to be an array of youngsters. To do that, we are able to add the .kids[]
after the initiatives. It will return a flat array with simply the youngsters parts we’d like.
This offers us all of the paperwork in an array with simply the info we’d like (together with newly reformatted gadgets).
To make use of them in our 11ty construct, we’d like a template that can use Pagination.
Within the root of the web site
, create a madlib.njk
file. This file will generate every madlib web page from the info.
---
format: 'base.njk'
pagination:
information: madlibs
alias: madlib
dimension: 1
permalink: "madlibs/{ slug }/index.html"
---
Within the entrance matter of this file, we specify some information 11ty can use to generate our pages:
format
The template to make use of to render the web page.pagination
An object with pagination info.pagination.information
The information key for pagination to learn.pagination.alias
A key to make use of on this file for ease.pagination.dimension
The variety of madlibs per web page (on this case, 1 per web page to create particular person pages).permalink
The URLs at which every of those ought to dwell (might be partially generated from information).
With that information in place, we are able to specify the best way to show each bit of knowledge for an merchandise within the array.
---
format: 'base.njk'
pagination:
information: madlibs
alias: madlib
dimension: 1
permalink: "madlibs/{ slug }/index.html"
---
<h2>{{ madlib.title }}</h2>
<p><em>Directions:</em> Fill out this manner, submit it and get your story. It can hopfully make little-to-no sense. Afterward, it can save you the madlib and ship it to your mates.</p>
<div class="madlibtext">
<a href="#" class="saver">Reserve it</a>
{ protected }
</div>
<h2>Type</h2>
<kind class="madlibForm stack">
{% for enter in madlib.formFields %}
<label>
{{ enter.displayText }} ({{ enter.grammar }})
<enter kind="textual content" class="libInput" title={{enter._key}}>
</label>
{% endfor %}
<button>Carried out</button>
</kind>
We will correctly format the title and HTML textual content. We will then use the formFields
array to create a kind that customers can enter their distinctive solutions.
There’s some further markup to be used in our JavaScript — a kind button and a hyperlink to save lots of the finalized madlib. The hyperlink and madlib textual content will probably be hidden (no peeking for our customers!).
For each madlib template, you created in your studio, 11ty will construct a singular web page. The ultimate URLs ought to appear like this
http://localhost:8080/madlibs/the-slug-in-the-studio/
Making The Madlibs Interactive
With our madlibs generated, we have to make them interactive. We’ll sprinkle somewhat JavaScript and CSS to make them interactive. Earlier than we are able to use CSS and JS, we have to inform 11ty to repeat the static recordsdata to our constructed web site.
Copying Static Property To The Ultimate Construct
Within the root of the web site
listing, create the next recordsdata and directories:
property/css/type.css
— for any further styling,property/js/madlib.js
— for the interactions,.eleventy.js
— the 11ty configuration file.
When these recordsdata are created, we have to inform 11ty to repeat the property to the ultimate construct. These directions dwell within the .eleventy.js
configuration file.
module.exports = perform(eleventyConfig) {
eleventyConfig.addPassthroughCopy("property/");
}
This instructs 11ty to repeat the whole property
listing to the ultimate construct.
The one crucial CSS to make the location work is a snippet to cover and present the madlib textual content. Nevertheless, if you need the entire feel and appear, yow will discover all of the kinds on this file.
.madlibtext {
show: none
}
.madlibtext.present {
show: block;
}
Filling In The Madlib With Consumer Enter And JavaScript
Any frontend framework will work with 11ty if you happen to arrange a construct course of. For this instance, we’ll use plain JavaScript to maintain issues easy. The primary activity is to take the consumer information within the kind and populate the generic madlib template that 11ty generated from our Sanity information.
// Connect the shape handler
const kind = doc.querySelector('.madlibForm')
kind.addEventListener('submit', completeLib);
perform showText() {
// Discover the madlib textual content within the doc
const textDiv = doc.querySelector('.madlibtext')
// Toggle the category "present" to be current
textDiv.classList.toggle('present')
}
// A perform that takes the submit occasion
// From the occasion, it can get the contents of the inputs
// and write them to web page and present the total textual content
perform completeLib(occasion) {
// Do not submit the shape
occasion.preventDefault();
const { goal } = occasion // The goal is the shape ingredient
// Get all inputs from the shape in array format
const inputs = Array.from(goal.parts)
inputs.forEach(enter => {
// The button is an enter and we do not need that within the remaining information
if (enter.kind != 'textual content') return
// Discover a span by the enter's title
// These will each be the _key worth
const replacedContent = doc.getElementById(enter.title)
// Change the content material of the span with the enter's worth
replacedContent.innerHTML = enter.worth
})
// Present the finished madlib
showText();
}
This performance is available in three elements: attaching an occasion listener, taking the shape enter, inserting it into the HTML, after which displaying the textual content.
When the shape is submitted, the code creates an array from the shape’s inputs. Subsequent, it finds parts on the web page with ids that match the enter’s title — each created from the _key
values of every block. It then replaces the content material of that ingredient with the worth from the info.
As soon as that’s executed, we toggle the total madlib textual content to point out on the web page.
We have to add this script to the web page. To do that, we create a brand new template for the madlibs to make use of. Within the _includes
listing, create a file named lib.njk
. This template will lengthen the bottom template we created and insert the script on the backside of the web page’s physique.
{% extends 'base.njk' %}
{% block scripts %}
<script>
var pt = { protected }
var information = {
libId: `{{ madlib._id }}`,
libTitle: `{{ madlib.title }}`
}
</script>
<script src="https://smashingmagazine.com/assets/js/madlib.js"></script>
{% endblock %}
Then, our madlib.njk
pagination template wants to make use of this new template for its format.
---
format: 'lib.njk'
pagination:
information: madlibs
alias: madlib
dimension: 1
permalink: "madlibs/{ slug }/index.html"
---
// web page content material
We now have a functioning madlib generator. To make this extra strong, let’s permit customers to save lots of and share their accomplished madlibs.
Saving A Consumer Madlib To Sanity With A Netlify Perform
Now that we have now a madlib exhibited to the consumer, we have to create the hyperlink for saving ship the data to Sanity.
To try this, we’ll add some extra performance to our front-end JavaScript. However, first, we have to add some extra information pulled from Sanity into our JavaScript, so we’ll add a few new variables within the scripts
block on the lib.njk
template.
{% extends 'base.njk' %}
{% block scripts %}
<script>
// Moveable Textual content information
var pt = { protected }
var information = {
libId: `{{ madlib._id }}`,
libTitle: `{{ madlib.title }}`
}
</script>
<script src="https://smashingmagazine.com/assets/js/madlib.js"></script>
{% endblock %}
We will write a script to ship it and the user-generated solutions to a serverless perform to ship to Sanity with that further information.
// /madlibs/web site/property/js/madlib.js
// ... completeLib()
async perform saveLib(occasion) {
occasion.preventDefault();
// Return an Map of ids and content material to show into an object
const blocks = Array.from(doc.querySelectorAll('.empty')).map(merchandise => {
return [item.id, { content: item.outerText }]
})
// Creates Object prepared for storage from blocks map
const userContentBlocks = Object.fromEntries(blocks);
// Codecs the info for posting
const finalData = {
userContentBlocks,
pt, // From nunjucks on web page
...information // From nunjucks on web page
}
// Runs the put up information perform for createLib
postData('/.netlify/capabilities/createLib', finalData)
.then(information => {
// When put up is profitable
// Create a div for the ultimate hyperlink
const landingZone = doc.createElement('div')
// Give the hyperlink a category
landingZone.className = "libUrl"
// Add the div after the saving hyperlink
saver.after(landingZone)
// Add the brand new hyperlink contained in the touchdown zone
landingZone.innerHTML = `Your url is /userlibs/${information._id}/`
}).catch(error => {
// When errors occur, do one thing with them
console.log(error)
});
}
async perform postData(url="", information = {}) {
// A wrapper perform for normal JS fetch
const response = await fetch(url, {
technique: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content material-Sort': 'utility/json'
},
physique: JSON.stringify(information)
});
return response.json(); // parses JSON response into native JavaScript objects
}
We add a brand new occasion listener to the “Save” hyperlink in our HTML.
The saveLib
perform will take the info from the web page and the user-generated information and mix them in an object to be dealt with by a brand new serverless perform. The serverless perform must take that information and create a brand new Sanity doc. When creating the perform, we would like it to return the _id
for the brand new doc. We use that to create a singular hyperlink that we add to the web page. This hyperlink will probably be the place the newly generated web page will probably be.
Setting Up Netlify Dev
To make use of Netlify Capabilities, we’ll must get our undertaking arrange on Netlify. We wish Netlify to construct and serve from the web site
listing. To provide Netlify this info, we have to create a netlify.toml
file on the root of the whole undertaking.
[build]
command = "npm run construct" # Command to run
capabilities = "capabilities" # Listing we retailer the capabilities
publish = "_site" # Folder to publish (11ty robotically makes the _site folder
base = "web site" # Folder that's the root of the construct
To develop these domestically, it’s useful to put in Netlify’s CLI globally.
npm set up -g netlify-cli
As soon as that’s put in, you may run netlify dev
in your undertaking. It will take the place of working your begin
NPM script.
The CLI will run you thru connecting your repository to Netlify. As soon as it’s executed, we’re able to develop our first perform.
Creating A Perform To Save Madlibs To Sanity
Since our TOML file units the capabilities listing to capabilities
, we have to create the listing. Contained in the listing, make a createLib.js
file. This would be the serverless perform for making a madlib within the Sanity information retailer.
The usual Sanity shopper we’ve been utilizing is read-only. To provide it write permissions, we have to reconfigure it to make use of an API learn+write token. To generate a token, log into the undertaking dashboard and go to the undertaking settings in your madlibs undertaking. Within the settings, discover the Tokens space and generate a brand new token with “Editor” permissions. When the token is generated, save the string to Netlify’s atmosphere variables dashboard with the title SANITY_TOKEN
. Netlify Dev will robotically pull these atmosphere variables into the undertaking whereas working.
To reconfigure the shopper, we’ll require the file from our utilities, after which run the .config()
technique. It will allow us to set any configuration worth for this particular use. We’ll set the token to the brand new atmosphere variable and set useCdn
to false.
// Sanity JS Consumer
// The construct shopper is read-only
// To make use of to write down, we have to add an API token with correct permissions
const shopper = require('../utils/sanityClient')
shopper.config({
token: course of.env.SANITY_TOKEN,
useCdn: false
})
The fundamental construction for a Netlify perform is to export a handler perform that’s handed an occasion and returns an object with a standing code and string physique.
// Grabs native env variables from .env file
// Not crucial if utilizing Netlify Dev CLI
require('dotenv').config()
// Sanity JS Consumer
// The construct shopper is read-only
// To make use of to write down, we have to add an API token with correct permissions
const shopper = require('../utils/sanityClient')
shopper.config({
token: course of.env.SANITY_TOKEN,
useCdn: false
})
// Small ID creation package deal
const { nanoid } = require('nanoid')
exports.handler = async (occasion) => {
// Get information off the occasion physique
const {
pt,
userContentBlocks,
id,
libTitle
} = JSON.parse(occasion.physique)
// Create new Moveable Textual content JSON
// from the outdated PT and the consumer submissions
const newBlocks = findAndReplace(pt, userContentBlocks)
// Create new Sanity doc object
// The doc's _id and slug are primarily based on a singular ID from nanoid
const docId = nanoid()
const doc = {
_type: "userLib",
_id: docId,
slug: { present: docId },
madlib: id,
title: `${libTitle} creation`,
textual content: newBlocks,
}
// Submit the brand new doc object to Sanity
// Return the response again to the browser
return shopper.create(doc).then((res) => {
// Log the success into our perform log
console.log(`Userlib was created, doc ID is ${res._id}`)
// return with a 200 standing and a stringified JSON object we get from the Sanity API
return { statusCode: 200, physique: JSON.stringify(doc) };
}).catch(err => {
// If there's an error, log it
// and return a 500 error and a JSON string of the error
console.log(err)
return {
statusCode: 500, physique: JSON.stringify(err)
}
})
}
// Perform for modifying the Moveable Textual content JSON
// pt is the unique moveable Textual content
// mods is an object of modifications to make
perform findAndReplace(pt, mods) {
// For every block object, verify to see if a mod is required and return an object
const newPT = pt.map((block) => ({
...block, // Insert all present information
kids: block.kids.map(span => {
// For each merchandise in kids, see if there is a modification on the mods object
// If there may be, set modContent to the brand new content material, if not, set it to the unique textual content
const modContent = mods[span._key] ? mods[span._key].content material : span.textual content
// Return an object with all the unique information, and a brand new property
// displayText to be used within the frontends
return {
...span,
displayText: modContent
}
})
}))
// Return the brand new Moveable Textual content JSON
return newPT
}
The physique is the info we simply submitted. For ease, we’ll destructure the info off the occasion.physique
object. Then, we have to evaluate the unique Moveable Textual content and the consumer content material we submitted and create the brand new Moveable Textual content JSON that we are able to undergo Sanity.
To try this, we run a discover and change perform. This perform maps over the unique Moveable Textual content and for each youngster within the blocks, change its content material with the corresponding information from the modfications object. If there isn’t a modification, it can retailer the unique textual content.
With modified Moveable Textual content in hand, we are able to create a brand new object to retailer as a doc within the Sanity content material lake. Every doc wants a singular identifier (which we are able to use the nanoid
NPM package deal to create. We’ll additionally let this newly created ID be the slug for consistency.
The remainder of the info is mapped to the right key in our userLib
schema we created within the studio and submitted with the authenticated shopper’s .create()
technique. When success or failure returns from Sanity, we move that alongside to the frontend for dealing with.
Now, we have now information being saved to our Sanity undertaking. Go forward and fill out a madlib and submit. You possibly can view the creation within the studio. These hyperlinks that we’re producing don’t work but, although. That is the place 11ty Serverless is available in.
Setting Up 11ty Serverless
You will have observed once we put in 11ty that we used a particular model. That is the beta of the upcoming 1.0 launch. 11ty Serverless is without doubt one of the huge new options in that launch.
Putting in The Serverless Plugin
11ty Serverless is an included plugin that may be initialized to create all of the boilerplate for working 11ty in a serverless perform. To stand up and working, we have to add the plugin to our .eleventy.js
configuration file.
const { EleventyServerlessBundlerPlugin } = require("@11ty/eleventy");
module.exports = perform (eleventyConfig) {
eleventyConfig.addPassthroughCopy("property/");
eleventyConfig.addPlugin(EleventyServerlessBundlerPlugin, {
title: "userlibs", // the title to make use of for the capabilities
functionsDir: "./capabilities/", // The capabilities listing
copy: ["utils/"], // Any recordsdata that have to be copied to make our scripts work
excludeDependencies: ["./_data/madlibs.js"] // Exclude any recordsdata you do not wish to run
});
};
After creating this file, restart 11ty by rerunning netlify dev
. On the subsequent run, 11ty will create a brand new listing in our capabilities
listing named userlibs
(matching the title within the serverless configuration) to accommodate every little thing it must must run in a serverless perform. The index.js
file on this listing is created if it doesn’t exist, however any adjustments you make will persist.
We have to make one small change to the top of this file. By default, 11ty Serverless will initialize utilizing normal serverless capabilities. It will run the perform on each load of the route. That’s an costly load for content material that may’t be modified after it’s been generated. As a substitute, we are able to change it to make use of Netlify’s On-Demand Builders. It will construct the web page on the primary request and cache the end result for any later requests. This cache will persist till the subsequent construct of the location.
To replace the perform, open the index.js
file and alter the ending of the file.
// Remark this line out
exports.handler = handler
// Uncomment these strains
const { builder } = require("@netlify/capabilities");
exports.handler = builder(handler);
Since this file is utilizing Netlify’s capabilities package deal, we additionally want to put in that package deal.
npm set up @netlify/capabilities
Creating A Information File For Consumer-generated Madlibs
Now that we have now an On-Demand Builder, we have to pull the info for user-generated madlibs. We will create a brand new JavaScript information file within the _data
file named userlibs.js
. Like our madlibs information file, the file title would be the key to get this information in our templates.
// /madlibs/web site/_data/userlibs.js
const shopper = require('../utils/sanityClient')
const {prepText} = require('../utils/portableTextUtils')
const question = `*[_type == "userLib"]{
title,
"slug": slug.present,
textual content,
_id
}`
module.exports = async perform() {
const madlibs = await shopper.fetch(question);
// Defend towards no madlibs returning
if (madlibs.size == 0) return {"404": {}}
// Run via our moveable textual content serializer
const preppedMadlib = madlibs.map(prepText)
// Convert the array of paperwork into an object
// Every merchandise within the Object may have a key of the merchandise slug
// 11ty's Pagination will create pages for each
const mapLibs = preppedMadlib.map(merchandise => ([item.slug, item]))
const objLibs = Object.fromEntries(mapLibs)
return objLibs
}
This information file is just like what we wrote earlier, however as an alternative of returning the array, we have to return an object. The article’s keys are what the serverless bundle will use to tug the proper madlib on request. In our case, we’ll make the merchandise’s slug
the important thing because the serverless route will probably be on the lookout for a slug.
Now that the plugin is prepared, we are able to create a brand new pagination template to make use of the generated perform.
Within the root of our web site
, add a userlibs.njk
template. This template will probably be just like the madlibs.njk
template, however it can use totally different information with none interactivity.
---
format: 'base.njk'
pagination:
information: userLibs
alias: userlib
dimension: 1
serverless: eleventy.serverless.path.slug
permalink:
userlibs: "/userlibs/:slug/"
---
<h2>{{ userlib.title }}</h2>
<div>
{ protected }
</div>
On this template, we use base.njk
to keep away from together with the JavaScript. We specify the brand new userlibs
information for pagination.
To tug the proper information, we have to specify what the lookup key will probably be. On the pagination object, we do that with the serverless
property. When utilizing serverless routes, we get entry to a brand new object: eleventy.serverless
. On this object, there’s a path
object that incorporates info on what URL the consumer requested. On this case, we’ll have a slug
property on that object. That should correspond to a key on our pagination information.
To get the slug
on our path, we have to add it to the permalink
object. 11ty Serverless permits for multiple route for a template. The route’s key must match the title offered within the .eleventy.js
configuration. On this case, it ought to be userlibs
. We specify the static /userlibs/
begin to the trail after which add a dynamic ingredient: :slug/
. This slug will probably be what will get handed to eleventy.serverless.path.slug
.
Now, the hyperlink that we created earlier by submitting a madlib to Sanity will work.
Subsequent Steps
Now we have now a madlib generator that saves to an information retailer. We construct solely the mandatory pages to permit a consumer to create a brand new madlib. After they create one, we make these pages on-demand with 11ty and Netlify Capabilities. From right here, we are able to lengthen this additional.
- Statically construct the user-generated content material in addition to render them on request.
- Create a counter for the entire variety of madlibs saved by every madlib template.
- Create an inventory of phrases customers use by elements of speech.
When you may statically construct AND dynamically render, what kinds of functions does this open up?

(vf, yk, il)