After modelling our content, and using Tina's API for data-fetching, we can add TinaCMS to our site's frontend and add contextual editing.
Contextual editing can be set up on a page with the useTina hook
// ...
import { useTina } from 'tinacms/dist/edit-state'
const query = `{
getPageDocument(relativePath: "home.mdx"){
data{
body
}
}
}`
export default function Home(props) {
// Pass our data through the "useTina" hook to make it editable
const { data } = useTina({
query,
variables: {},
data: props.data,
})
// Note how our page body uses "data", and not the original "props.data".
// This ensures that the content will be updated in edit-mode as the user types
return <h1>{data.getPageDocument.data.body}</h1>
}
export const getStaticProps = async () => {
const data = await staticRequest({
query,
variables = {},
})
// return the original data, which is used in our production page
return { props: { data } }
}
useTina hook:useTina is used to make a piece of Tina content contextually editable. It is code-split, so that in production, this hook will simply pass through its data value. In edit-mode, it registers an editable form in the sidebar, and contextually updates its value as the user types.
useTina takes in a parameter with a few keys:
query and variables: These are the same values that you would use for the backend data-fetching.data: This is the production value that gets passed through to the response unchanged in production.At this point, when your editors go to /your-page-url in edit-mode, they will be able to edit and see those changes reflected in real-time. Next, let's wire up the CMS so that users will be navigated to that same editing experience when clicking any document in the Document List (instead of seeing the basic editor).
To accomplish this, we will make use of the RouteMappingPlugin.
RouteMappingPluginThe RouteMappingPlugin is used by the CMS's Document List to navigate to a document's contextual editor rather than the basic editor.
RouteMappingPlugin(mapper: (collection: Collection, document: Document) => string | undefined)The RouteMappingPlugin accepts a single argument - the mapper function - that is run when a document is clicked within a Document List:
mapper returns a string, the string is used as the document's route rather than the default.mapper returns undefined, the user is navigated to the document's basic editor.This is an example of the RouteMappingPlugin added to our tina-cloud-starter template:
...
cmsCallback={(cms) => {
/**
* 1. Import `tinacms` and `RouteMappingPlugin`
**/
import('tinacms').then(({ RouteMappingPlugin }) => {
/**
* 2. Define the `RouteMappingPlugin`
**/
const RouteMapping = new RouteMappingPlugin(
(collection, document) => {
/**
* Because the `authors` and `global` collections do not
* have dedicated pages, we return `undefined`.
**/
if (["authors", "global"].includes(collection.name)) {
return undefined;
}
/**
* While the `pages` collection does have dedicated pages,
* their URLs are different than their document names.
**/
if (["pages"].includes(collection.name)) {
if (document.sys.filename === "home") {
return `/`;
}
if (document.sys.filename === "about") {
return `/about`;
}
return undefined;
}
/**
* Finally, any other collections (`posts`, for example)
* have URLs based on values in the `collection` and `document`.
**/
return `/${collection.name}/${document.sys.filename}`;
}
);
/**
* 3. Add the `RouteMappingPlugin` to the `cms`.
**/
cms.plugins.add(RouteMapping);
});
}useTina hook. In production, it returns the original data unchanged. In edit-mode, it returns the live data, which is updated as the user types in the sidebar.RouteMappingPlugin to automatically navigate to the contextual-editing experience from the CMS.