) : (
diff --git a/examples/blog-starter/components/hero-post.js b/examples/blog-starter/components/hero-post.js
index ddb182a8b716..6dc49f20a8bb 100644
--- a/examples/blog-starter/components/hero-post.js
+++ b/examples/blog-starter/components/hero-post.js
@@ -25,7 +25,7 @@ export default function HeroPost({
diff --git a/examples/blog-starter/components/post-preview.js b/examples/blog-starter/components/post-preview.js
index 3e3009fa2721..712eea6e92ec 100644
--- a/examples/blog-starter/components/post-preview.js
+++ b/examples/blog-starter/components/post-preview.js
@@ -23,7 +23,7 @@ export default function PostPreview({
/>
diff --git a/examples/blog-starter/package.json b/examples/blog-starter/package.json
index ee9d9ba4dc95..29d3f61c590c 100644
--- a/examples/blog-starter/package.json
+++ b/examples/blog-starter/package.json
@@ -16,8 +16,8 @@
"remark-html": "15.0.1"
},
"devDependencies": {
- "autoprefixer": "^10.4.0",
- "postcss": "^8.4.4",
- "tailwindcss": "^3.0.1"
+ "autoprefixer": "^10.4.2",
+ "postcss": "^8.4.7",
+ "tailwindcss": "^3.0.23"
}
}
diff --git a/examples/cms-tina/.gitignore b/examples/cms-tina/.gitignore
new file mode 100644
index 000000000000..1437c53f70bc
--- /dev/null
+++ b/examples/cms-tina/.gitignore
@@ -0,0 +1,34 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# vercel
+.vercel
diff --git a/examples/cms-tina/.tina/__generated__/.gitignore b/examples/cms-tina/.tina/__generated__/.gitignore
new file mode 100644
index 000000000000..5baa59d64639
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/.gitignore
@@ -0,0 +1 @@
+db
\ No newline at end of file
diff --git a/examples/cms-tina/.tina/__generated__/_graphql.json b/examples/cms-tina/.tina/__generated__/_graphql.json
new file mode 100644
index 000000000000..4f7ac4cfe7ef
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/_graphql.json
@@ -0,0 +1,2072 @@
+{
+ "kind": "Document",
+ "definitions": [
+ {
+ "kind": "ScalarTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "Reference"
+ },
+ "description": {
+ "kind": "StringValue",
+ "value": "References another document, used as a foreign key"
+ },
+ "directives": []
+ },
+ {
+ "kind": "ScalarTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ },
+ "description": {
+ "kind": "StringValue",
+ "value": ""
+ },
+ "directives": []
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "SystemInfo"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "filename"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "basename"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "breadcrumbs"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "excludeExtension"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Boolean"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "path"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "extension"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "template"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Collection"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PageInfo"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "hasPreviousPage"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Boolean"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "hasNextPage"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Boolean"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "startCursor"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "endCursor"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InterfaceTypeDefinition",
+ "description": {
+ "kind": "StringValue",
+ "value": ""
+ },
+ "name": {
+ "kind": "Name",
+ "value": "Node"
+ },
+ "interfaces": [],
+ "directives": [],
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "id"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "ID"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InterfaceTypeDefinition",
+ "description": {
+ "kind": "StringValue",
+ "value": ""
+ },
+ "name": {
+ "kind": "Name",
+ "value": "Document"
+ },
+ "interfaces": [],
+ "directives": [],
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "sys"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "SystemInfo"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "id"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "ID"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "form"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "values"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InterfaceTypeDefinition",
+ "description": {
+ "kind": "StringValue",
+ "value": "A relay-compliant pagination connection"
+ },
+ "name": {
+ "kind": "Name",
+ "value": "Connection"
+ },
+ "interfaces": [],
+ "directives": [],
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "totalCount"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "Query"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getCollection"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Collection"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getCollections"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Collection"
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "node"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "id"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Node"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getDocumentList"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "before"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "after"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "first"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "last"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentConnection"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getDocumentFields"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getPostsDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "getPostsList"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "before"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "after"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "first"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "last"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsConnection"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "DocumentConnectionEdges"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "cursor"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "node"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [
+ {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Connection"
+ }
+ }
+ ],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "DocumentConnection"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "pageInfo"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PageInfo"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "totalCount"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "edges"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentConnectionEdges"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "Collection"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "name"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "slug"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "label"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "path"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "format"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "matches"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "templates"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "fields"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "documents"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "before"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "after"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "first"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "last"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentConnection"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "UnionTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ },
+ "directives": [],
+ "types": [
+ {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PostsAuthor"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "name"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "picture"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PostsOgImage"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "url"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "Posts"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "title"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "excerpt"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "coverImage"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "date"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "author"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsAuthor"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "ogImage"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsOgImage"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "body"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [
+ {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Node"
+ }
+ },
+ {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Document"
+ }
+ }
+ ],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "id"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "ID"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "sys"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "SystemInfo"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "data"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Posts"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "form"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "values"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "dataJSON"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "JSON"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PostsConnectionEdges"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "cursor"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "node"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [
+ {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Connection"
+ }
+ }
+ ],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "PostsConnection"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "pageInfo"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PageInfo"
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "totalCount"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "Float"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "edges"
+ },
+ "arguments": [],
+ "type": {
+ "kind": "ListType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsConnectionEdges"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "ObjectTypeDefinition",
+ "interfaces": [],
+ "directives": [],
+ "name": {
+ "kind": "Name",
+ "value": "Mutation"
+ },
+ "fields": [
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "addPendingDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "template"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "updateDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "params"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentMutation"
+ }
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "createDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "collection"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "params"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentMutation"
+ }
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentNode"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "updatePostsDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "params"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsMutation"
+ }
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ }
+ }
+ }
+ },
+ {
+ "kind": "FieldDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "createPostsDocument"
+ },
+ "arguments": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "relativePath"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "params"
+ },
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsMutation"
+ }
+ }
+ }
+ }
+ ],
+ "type": {
+ "kind": "NonNullType",
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsDocument"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InputObjectTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "DocumentMutation"
+ },
+ "fields": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "posts"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsMutation"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InputObjectTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "PostsAuthorMutation"
+ },
+ "fields": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "name"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "picture"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InputObjectTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "PostsOgImageMutation"
+ },
+ "fields": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "url"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "kind": "InputObjectTypeDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "PostsMutation"
+ },
+ "fields": [
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "title"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "excerpt"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "coverImage"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "date"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "author"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsAuthorMutation"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "ogImage"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "PostsOgImageMutation"
+ }
+ }
+ },
+ {
+ "kind": "InputValueDefinition",
+ "name": {
+ "kind": "Name",
+ "value": "body"
+ },
+ "type": {
+ "kind": "NamedType",
+ "name": {
+ "kind": "Name",
+ "value": "String"
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/examples/cms-tina/.tina/__generated__/_lookup.json b/examples/cms-tina/.tina/__generated__/_lookup.json
new file mode 100644
index 000000000000..6e651b843207
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/_lookup.json
@@ -0,0 +1,29 @@
+{
+ "DocumentConnection": {
+ "type": "DocumentConnection",
+ "resolveType": "multiCollectionDocumentList",
+ "collections": ["posts"]
+ },
+ "Node": {
+ "type": "Node",
+ "resolveType": "nodeDocument"
+ },
+ "DocumentNode": {
+ "type": "DocumentNode",
+ "resolveType": "multiCollectionDocument",
+ "createDocument": "create",
+ "updateDocument": "update"
+ },
+ "PostsDocument": {
+ "type": "PostsDocument",
+ "resolveType": "collectionDocument",
+ "collection": "posts",
+ "createPostsDocument": "create",
+ "updatePostsDocument": "update"
+ },
+ "PostsConnection": {
+ "type": "PostsConnection",
+ "resolveType": "collectionDocumentList",
+ "collection": "posts"
+ }
+}
diff --git a/examples/cms-tina/.tina/__generated__/_schema.json b/examples/cms-tina/.tina/__generated__/_schema.json
new file mode 100644
index 000000000000..46e9b5f5c4c1
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/_schema.json
@@ -0,0 +1,87 @@
+{
+ "version": {
+ "fullVersion": "0.59.7",
+ "major": "0",
+ "minor": "59",
+ "patch": "7"
+ },
+ "meta": {},
+ "collections": [
+ {
+ "label": "Blog Posts",
+ "name": "posts",
+ "path": "_posts",
+ "fields": [
+ {
+ "type": "string",
+ "label": "Title",
+ "name": "title",
+ "namespace": ["posts", "title"]
+ },
+ {
+ "type": "string",
+ "label": "Excerpt",
+ "name": "excerpt",
+ "namespace": ["posts", "excerpt"]
+ },
+ {
+ "type": "string",
+ "label": "Cover Image",
+ "name": "coverImage",
+ "namespace": ["posts", "coverImage"]
+ },
+ {
+ "type": "string",
+ "label": "Date",
+ "name": "date",
+ "namespace": ["posts", "date"]
+ },
+ {
+ "type": "object",
+ "label": "author",
+ "name": "author",
+ "fields": [
+ {
+ "type": "string",
+ "label": "Name",
+ "name": "name",
+ "namespace": ["posts", "author", "name"]
+ },
+ {
+ "type": "string",
+ "label": "Picture",
+ "name": "picture",
+ "namespace": ["posts", "author", "picture"]
+ }
+ ],
+ "namespace": ["posts", "author"]
+ },
+ {
+ "type": "object",
+ "label": "OG Image",
+ "name": "ogImage",
+ "fields": [
+ {
+ "type": "string",
+ "label": "Url",
+ "name": "url",
+ "namespace": ["posts", "ogImage", "url"]
+ }
+ ],
+ "namespace": ["posts", "ogImage"]
+ },
+ {
+ "type": "string",
+ "label": "Blog Post Body",
+ "name": "body",
+ "isBody": true,
+ "ui": {
+ "component": "textarea"
+ },
+ "namespace": ["posts", "body"]
+ }
+ ],
+ "namespace": ["posts"]
+ }
+ ]
+}
diff --git a/examples/cms-tina/.tina/__generated__/frags.gql b/examples/cms-tina/.tina/__generated__/frags.gql
new file mode 100644
index 000000000000..4c1472d2fce0
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/frags.gql
@@ -0,0 +1,16 @@
+fragment PostsParts on Posts {
+ title
+ excerpt
+ coverImage
+ date
+ author {
+ __typename
+ name
+ picture
+ }
+ ogImage {
+ __typename
+ url
+ }
+ body
+}
diff --git a/examples/cms-tina/.tina/__generated__/queries.gql b/examples/cms-tina/.tina/__generated__/queries.gql
new file mode 100644
index 000000000000..949e4040d5e9
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/queries.gql
@@ -0,0 +1,38 @@
+query getPostsDocument($relativePath: String!) {
+ getPostsDocument(relativePath: $relativePath) {
+ sys {
+ filename
+ basename
+ breadcrumbs
+ path
+ relativePath
+ extension
+ }
+ id
+ data {
+ ...PostsParts
+ }
+ }
+}
+
+query getPostsList {
+ getPostsList {
+ totalCount
+ edges {
+ node {
+ id
+ sys {
+ filename
+ basename
+ breadcrumbs
+ path
+ relativePath
+ extension
+ }
+ data {
+ ...PostsParts
+ }
+ }
+ }
+ }
+}
diff --git a/examples/cms-tina/.tina/__generated__/schema.gql b/examples/cms-tina/.tina/__generated__/schema.gql
new file mode 100644
index 000000000000..42acbd89517d
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/schema.gql
@@ -0,0 +1,196 @@
+# DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
+"""
+References another document, used as a foreign key
+"""
+scalar Reference
+
+"""
+
+"""
+scalar JSON
+
+type SystemInfo {
+ filename: String!
+ basename: String!
+ breadcrumbs(excludeExtension: Boolean): [String!]!
+ path: String!
+ relativePath: String!
+ extension: String!
+ template: String!
+ collection: Collection!
+}
+
+type PageInfo {
+ hasPreviousPage: Boolean!
+ hasNextPage: Boolean!
+ startCursor: String!
+ endCursor: String!
+}
+
+"""
+
+"""
+interface Node {
+ id: ID!
+}
+
+"""
+
+"""
+interface Document {
+ sys: SystemInfo
+ id: ID!
+ form: JSON!
+ values: JSON!
+}
+
+"""
+A relay-compliant pagination connection
+"""
+interface Connection {
+ totalCount: Float!
+}
+
+type Query {
+ getCollection(collection: String): Collection!
+ getCollections: [Collection!]!
+ node(id: String): Node!
+ getDocument(collection: String, relativePath: String): DocumentNode!
+ getDocumentList(
+ before: String
+ after: String
+ first: Float
+ last: Float
+ ): DocumentConnection!
+ getDocumentFields: JSON!
+ getPostsDocument(relativePath: String): PostsDocument!
+ getPostsList(
+ before: String
+ after: String
+ first: Float
+ last: Float
+ ): PostsConnection!
+}
+
+type DocumentConnectionEdges {
+ cursor: String
+ node: DocumentNode
+}
+
+type DocumentConnection implements Connection {
+ pageInfo: PageInfo
+ totalCount: Float!
+ edges: [DocumentConnectionEdges]
+}
+
+type Collection {
+ name: String!
+ slug: String!
+ label: String
+ path: String!
+ format: String
+ matches: String
+ templates: [JSON]
+ fields: [JSON]
+ documents(
+ before: String
+ after: String
+ first: Float
+ last: Float
+ ): DocumentConnection!
+}
+
+union DocumentNode = PostsDocument
+
+type PostsAuthor {
+ name: String
+ picture: String
+}
+
+type PostsOgImage {
+ url: String
+}
+
+type Posts {
+ title: String
+ excerpt: String
+ coverImage: String
+ date: String
+ author: PostsAuthor
+ ogImage: PostsOgImage
+ body: String
+}
+
+type PostsDocument implements Node & Document {
+ id: ID!
+ sys: SystemInfo!
+ data: Posts!
+ form: JSON!
+ values: JSON!
+ dataJSON: JSON!
+}
+
+type PostsConnectionEdges {
+ cursor: String
+ node: PostsDocument
+}
+
+type PostsConnection implements Connection {
+ pageInfo: PageInfo
+ totalCount: Float!
+ edges: [PostsConnectionEdges]
+}
+
+type Mutation {
+ addPendingDocument(
+ collection: String!
+ relativePath: String!
+ template: String
+ ): DocumentNode!
+ updateDocument(
+ collection: String
+ relativePath: String!
+ params: DocumentMutation!
+ ): DocumentNode!
+ createDocument(
+ collection: String
+ relativePath: String!
+ params: DocumentMutation!
+ ): DocumentNode!
+ updatePostsDocument(
+ relativePath: String!
+ params: PostsMutation!
+ ): PostsDocument!
+ createPostsDocument(
+ relativePath: String!
+ params: PostsMutation!
+ ): PostsDocument!
+}
+
+input DocumentMutation {
+ posts: PostsMutation
+}
+
+input PostsAuthorMutation {
+ name: String
+ picture: String
+}
+
+input PostsOgImageMutation {
+ url: String
+}
+
+input PostsMutation {
+ title: String
+ excerpt: String
+ coverImage: String
+ date: String
+ author: PostsAuthorMutation
+ ogImage: PostsOgImageMutation
+ body: String
+}
+
+schema {
+ query: Query
+ mutation: Mutation
+}
diff --git a/examples/cms-tina/.tina/__generated__/types.ts b/examples/cms-tina/.tina/__generated__/types.ts
new file mode 100644
index 000000000000..8abb47270af4
--- /dev/null
+++ b/examples/cms-tina/.tina/__generated__/types.ts
@@ -0,0 +1,470 @@
+//@ts-nocheck
+// DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
+import { gql } from 'tinacms'
+export type Maybe
= T | null
+export type InputMaybe = Maybe
+export type Exact = {
+ [K in keyof T]: T[K]
+}
+export type MakeOptional = Omit &
+ { [SubKey in K]?: Maybe }
+export type MakeMaybe = Omit &
+ { [SubKey in K]: Maybe }
+/** All built-in and custom scalars, mapped to their actual values */
+export type Scalars = {
+ ID: string
+ String: string
+ Boolean: boolean
+ Int: number
+ Float: number
+ /** References another document, used as a foreign key */
+ Reference: any
+ JSON: any
+}
+
+export type SystemInfo = {
+ __typename?: 'SystemInfo'
+ filename: Scalars['String']
+ basename: Scalars['String']
+ breadcrumbs: Array
+ path: Scalars['String']
+ relativePath: Scalars['String']
+ extension: Scalars['String']
+ template: Scalars['String']
+ collection: Collection
+}
+
+export type SystemInfoBreadcrumbsArgs = {
+ excludeExtension?: InputMaybe
+}
+
+export type PageInfo = {
+ __typename?: 'PageInfo'
+ hasPreviousPage: Scalars['Boolean']
+ hasNextPage: Scalars['Boolean']
+ startCursor: Scalars['String']
+ endCursor: Scalars['String']
+}
+
+export type Node = {
+ id: Scalars['ID']
+}
+
+export type Document = {
+ sys?: Maybe
+ id: Scalars['ID']
+ form: Scalars['JSON']
+ values: Scalars['JSON']
+}
+
+/** A relay-compliant pagination connection */
+export type Connection = {
+ totalCount: Scalars['Float']
+}
+
+export type Query = {
+ __typename?: 'Query'
+ getCollection: Collection
+ getCollections: Array
+ node: Node
+ getDocument: DocumentNode
+ getDocumentList: DocumentConnection
+ getDocumentFields: Scalars['JSON']
+ getPostsDocument: PostsDocument
+ getPostsList: PostsConnection
+}
+
+export type QueryGetCollectionArgs = {
+ collection?: InputMaybe
+}
+
+export type QueryNodeArgs = {
+ id?: InputMaybe
+}
+
+export type QueryGetDocumentArgs = {
+ collection?: InputMaybe
+ relativePath?: InputMaybe
+}
+
+export type QueryGetDocumentListArgs = {
+ before?: InputMaybe
+ after?: InputMaybe
+ first?: InputMaybe
+ last?: InputMaybe
+}
+
+export type QueryGetPostsDocumentArgs = {
+ relativePath?: InputMaybe
+}
+
+export type QueryGetPostsListArgs = {
+ before?: InputMaybe
+ after?: InputMaybe
+ first?: InputMaybe
+ last?: InputMaybe
+}
+
+export type DocumentConnectionEdges = {
+ __typename?: 'DocumentConnectionEdges'
+ cursor?: Maybe
+ node?: Maybe
+}
+
+export type DocumentConnection = Connection & {
+ __typename?: 'DocumentConnection'
+ pageInfo?: Maybe
+ totalCount: Scalars['Float']
+ edges?: Maybe>>
+}
+
+export type Collection = {
+ __typename?: 'Collection'
+ name: Scalars['String']
+ slug: Scalars['String']
+ label?: Maybe
+ path: Scalars['String']
+ format?: Maybe
+ matches?: Maybe
+ templates?: Maybe>>
+ fields?: Maybe>>
+ documents: DocumentConnection
+}
+
+export type CollectionDocumentsArgs = {
+ before?: InputMaybe
+ after?: InputMaybe
+ first?: InputMaybe
+ last?: InputMaybe
+}
+
+export type DocumentNode = PostsDocument
+
+export type PostsAuthor = {
+ __typename?: 'PostsAuthor'
+ name?: Maybe
+ picture?: Maybe
+}
+
+export type PostsOgImage = {
+ __typename?: 'PostsOgImage'
+ url?: Maybe
+}
+
+export type Posts = {
+ __typename?: 'Posts'
+ title?: Maybe
+ excerpt?: Maybe
+ coverImage?: Maybe
+ date?: Maybe
+ author?: Maybe
+ ogImage?: Maybe
+ body?: Maybe
+}
+
+export type PostsDocument = Node &
+ Document & {
+ __typename?: 'PostsDocument'
+ id: Scalars['ID']
+ sys: SystemInfo
+ data: Posts
+ form: Scalars['JSON']
+ values: Scalars['JSON']
+ dataJSON: Scalars['JSON']
+ }
+
+export type PostsConnectionEdges = {
+ __typename?: 'PostsConnectionEdges'
+ cursor?: Maybe
+ node?: Maybe
+}
+
+export type PostsConnection = Connection & {
+ __typename?: 'PostsConnection'
+ pageInfo?: Maybe
+ totalCount: Scalars['Float']
+ edges?: Maybe>>
+}
+
+export type Mutation = {
+ __typename?: 'Mutation'
+ addPendingDocument: DocumentNode
+ updateDocument: DocumentNode
+ createDocument: DocumentNode
+ updatePostsDocument: PostsDocument
+ createPostsDocument: PostsDocument
+}
+
+export type MutationAddPendingDocumentArgs = {
+ collection: Scalars['String']
+ relativePath: Scalars['String']
+ template?: InputMaybe
+}
+
+export type MutationUpdateDocumentArgs = {
+ collection?: InputMaybe
+ relativePath: Scalars['String']
+ params: DocumentMutation
+}
+
+export type MutationCreateDocumentArgs = {
+ collection?: InputMaybe
+ relativePath: Scalars['String']
+ params: DocumentMutation
+}
+
+export type MutationUpdatePostsDocumentArgs = {
+ relativePath: Scalars['String']
+ params: PostsMutation
+}
+
+export type MutationCreatePostsDocumentArgs = {
+ relativePath: Scalars['String']
+ params: PostsMutation
+}
+
+export type DocumentMutation = {
+ posts?: InputMaybe
+}
+
+export type PostsAuthorMutation = {
+ name?: InputMaybe
+ picture?: InputMaybe
+}
+
+export type PostsOgImageMutation = {
+ url?: InputMaybe
+}
+
+export type PostsMutation = {
+ title?: InputMaybe
+ excerpt?: InputMaybe
+ coverImage?: InputMaybe
+ date?: InputMaybe
+ author?: InputMaybe
+ ogImage?: InputMaybe
+ body?: InputMaybe
+}
+
+export type PostsPartsFragment = {
+ __typename?: 'Posts'
+ title?: string | null
+ excerpt?: string | null
+ coverImage?: string | null
+ date?: string | null
+ body?: string | null
+ author?: {
+ __typename: 'PostsAuthor'
+ name?: string | null
+ picture?: string | null
+ } | null
+ ogImage?: { __typename: 'PostsOgImage'; url?: string | null } | null
+}
+
+export type GetPostsDocumentQueryVariables = Exact<{
+ relativePath: Scalars['String']
+}>
+
+export type GetPostsDocumentQuery = {
+ __typename?: 'Query'
+ getPostsDocument: {
+ __typename?: 'PostsDocument'
+ id: string
+ sys: {
+ __typename?: 'SystemInfo'
+ filename: string
+ basename: string
+ breadcrumbs: Array
+ path: string
+ relativePath: string
+ extension: string
+ }
+ data: {
+ __typename?: 'Posts'
+ title?: string | null
+ excerpt?: string | null
+ coverImage?: string | null
+ date?: string | null
+ body?: string | null
+ author?: {
+ __typename: 'PostsAuthor'
+ name?: string | null
+ picture?: string | null
+ } | null
+ ogImage?: { __typename: 'PostsOgImage'; url?: string | null } | null
+ }
+ }
+}
+
+export type GetPostsListQueryVariables = Exact<{ [key: string]: never }>
+
+export type GetPostsListQuery = {
+ __typename?: 'Query'
+ getPostsList: {
+ __typename?: 'PostsConnection'
+ totalCount: number
+ edges?: Array<{
+ __typename?: 'PostsConnectionEdges'
+ node?: {
+ __typename?: 'PostsDocument'
+ id: string
+ sys: {
+ __typename?: 'SystemInfo'
+ filename: string
+ basename: string
+ breadcrumbs: Array
+ path: string
+ relativePath: string
+ extension: string
+ }
+ data: {
+ __typename?: 'Posts'
+ title?: string | null
+ excerpt?: string | null
+ coverImage?: string | null
+ date?: string | null
+ body?: string | null
+ author?: {
+ __typename: 'PostsAuthor'
+ name?: string | null
+ picture?: string | null
+ } | null
+ ogImage?: { __typename: 'PostsOgImage'; url?: string | null } | null
+ }
+ } | null
+ } | null> | null
+ }
+}
+
+export const PostsPartsFragmentDoc = gql`
+ fragment PostsParts on Posts {
+ title
+ excerpt
+ coverImage
+ date
+ author {
+ __typename
+ name
+ picture
+ }
+ ogImage {
+ __typename
+ url
+ }
+ body
+ }
+`
+export const GetPostsDocumentDocument = gql`
+ query getPostsDocument($relativePath: String!) {
+ getPostsDocument(relativePath: $relativePath) {
+ sys {
+ filename
+ basename
+ breadcrumbs
+ path
+ relativePath
+ extension
+ }
+ id
+ data {
+ ...PostsParts
+ }
+ }
+ }
+ ${PostsPartsFragmentDoc}
+`
+export const GetPostsListDocument = gql`
+ query getPostsList {
+ getPostsList {
+ totalCount
+ edges {
+ node {
+ id
+ sys {
+ filename
+ basename
+ breadcrumbs
+ path
+ relativePath
+ extension
+ }
+ data {
+ ...PostsParts
+ }
+ }
+ }
+ }
+ }
+ ${PostsPartsFragmentDoc}
+`
+export type Requester = (
+ doc: DocumentNode,
+ vars?: V,
+ options?: C
+) => Promise
+export function getSdk(requester: Requester) {
+ return {
+ getPostsDocument(
+ variables: GetPostsDocumentQueryVariables,
+ options?: C
+ ): Promise<{
+ data: GetPostsDocumentQuery
+ variables: GetPostsDocumentQueryVariables
+ query: string
+ }> {
+ return requester<
+ {
+ data: GetPostsDocumentQuery
+ variables: GetPostsDocumentQueryVariables
+ query: string
+ },
+ GetPostsDocumentQueryVariables
+ >(GetPostsDocumentDocument, variables, options)
+ },
+ getPostsList(
+ variables?: GetPostsListQueryVariables,
+ options?: C
+ ): Promise<{
+ data: GetPostsListQuery
+ variables: GetPostsListQueryVariables
+ query: string
+ }> {
+ return requester<
+ {
+ data: GetPostsListQuery
+ variables: GetPostsListQueryVariables
+ query: string
+ },
+ GetPostsListQueryVariables
+ >(GetPostsListDocument, variables, options)
+ },
+ }
+}
+export type Sdk = ReturnType
+
+// TinaSDK generated code
+import { staticRequest } from 'tinacms'
+const requester: (doc: any, vars?: any, options?: any) => Promise = async (
+ doc,
+ vars,
+ _options
+) => {
+ let data = {}
+ try {
+ data = await staticRequest({
+ query: doc,
+ variables: vars,
+ })
+ } catch (e) {
+ // swallow errors related to document creation
+ console.warn('Warning: There was an error when fetching data')
+ console.warn(e)
+ }
+
+ return { data, query: doc, variables: vars || {} }
+}
+
+/**
+ * @experimental this class can be used but may change in the future
+ **/
+export const ExperimentalGetTinaClient = () => getSdk(requester)
diff --git a/examples/cms-tina/.tina/components/TinaDynamicProvider.js b/examples/cms-tina/.tina/components/TinaDynamicProvider.js
new file mode 100644
index 000000000000..5f6bd24bc870
--- /dev/null
+++ b/examples/cms-tina/.tina/components/TinaDynamicProvider.js
@@ -0,0 +1,15 @@
+import dynamic from 'next/dynamic'
+const TinaProvider = dynamic(() => import('./TinaProvider'), { ssr: false })
+import { TinaEditProvider } from 'tinacms/dist/edit-state'
+
+const DynamicTina = ({ children }) => {
+ return (
+ <>
+ {children}}>
+ {children}
+
+ >
+ )
+}
+
+export default DynamicTina
diff --git a/examples/cms-tina/.tina/components/TinaProvider.js b/examples/cms-tina/.tina/components/TinaProvider.js
new file mode 100644
index 000000000000..96d00b56aa8b
--- /dev/null
+++ b/examples/cms-tina/.tina/components/TinaProvider.js
@@ -0,0 +1,14 @@
+import TinaCMS from 'tinacms'
+import { tinaConfig } from '../schema.ts'
+
+// Importing the TinaProvider directly into your page will cause Tina to be added to the production bundle.
+// Instead, import the tina/provider/index default export to have it dynamially imported in edit-moode
+/**
+ *
+ * @private Do not import this directly, please import the dynamic provider instead
+ */
+const TinaProvider = ({ children }) => {
+ return {children}
+}
+
+export default TinaProvider
diff --git a/examples/cms-tina/.tina/schema.ts b/examples/cms-tina/.tina/schema.ts
new file mode 100644
index 000000000000..12f738c64a26
--- /dev/null
+++ b/examples/cms-tina/.tina/schema.ts
@@ -0,0 +1,105 @@
+import { defineSchema, defineConfig } from 'tinacms'
+
+export default defineSchema({
+ collections: [
+ {
+ label: 'Blog Posts',
+ name: 'posts',
+ path: '_posts',
+ fields: [
+ {
+ type: 'string',
+ label: 'Title',
+ name: 'title',
+ },
+ {
+ type: 'string',
+ label: 'Excerpt',
+ name: 'excerpt',
+ },
+ {
+ type: 'string',
+ label: 'Cover Image',
+ name: 'coverImage',
+ },
+ {
+ type: 'string',
+ label: 'Date',
+ name: 'date',
+ },
+ {
+ type: 'object',
+ label: 'author',
+ name: 'author',
+ fields: [
+ {
+ type: 'string',
+ label: 'Name',
+ name: 'name',
+ },
+ {
+ type: 'string',
+ label: 'Picture',
+ name: 'picture',
+ },
+ ],
+ },
+ {
+ type: 'object',
+ label: 'OG Image',
+ name: 'ogImage',
+ fields: [
+ {
+ type: 'string',
+ label: 'Url',
+ name: 'url',
+ },
+ ],
+ },
+ {
+ type: 'string',
+ label: 'Blog Post Body',
+ name: 'body',
+ isBody: true,
+ ui: {
+ component: 'textarea',
+ },
+ },
+ ],
+ },
+ ],
+})
+
+// Your tina config
+// ==============
+const branch = 'main'
+// When working locally, hit our local filesystem.
+// On a Vercel deployment, hit the Tina Cloud API
+const apiURL =
+ process.env.NODE_ENV == 'development'
+ ? 'http://localhost:4001/graphql'
+ : `https://content.tinajs.io/content/${process.env.NEXT_PUBLIC_TINA_CLIENT_ID}/github/${branch}`
+
+export const tinaConfig = defineConfig({
+ apiURL,
+ cmsCallback: (cms) => {
+ // add your CMS callback code here (if you want)
+
+ // The Route Mapper
+ /**
+ * 1. Import `tinacms` and `RouteMappingPlugin`
+ **/
+ import('tinacms').then(({ RouteMappingPlugin }) => {
+ /**
+ * 2. Define the `RouteMappingPlugin` see https://tina.io/docs/tinacms-context/#the-routemappingplugin for more details
+ **/
+ const RouteMapping = new RouteMappingPlugin((collection, document) => {
+ return undefined
+ })
+ /**
+ * 3. Add the `RouteMappingPlugin` to the `cms`.
+ **/
+ cms.plugins.add(RouteMapping)
+ })
+ },
+})
diff --git a/examples/cms-tina/README.md b/examples/cms-tina/README.md
new file mode 100644
index 000000000000..6f0b3efb5d94
--- /dev/null
+++ b/examples/cms-tina/README.md
@@ -0,0 +1,77 @@
+# A statically generated blog example using Next.js and TinaCMS
+
+This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [TinaCMS](https://tina.io/) as the CMS and editor.
+
+> This boilerplate demonstrates a basic usage and best practices. If you are looking for a more feature rich Tina experience with contextual editing.
+> check out [tina-cloud-starter](https://github.com/tinacms/tina-cloud-start/git).
+
+### Related examples
+
+- [WordPress](/examples/cms-wordpress)
+- [DatoCMS](/examples/cms-datocms)
+- [Sanity](/examples/cms-sanity)
+- [TakeShape](/examples/cms-takeshape)
+- [Prismic](/examples/cms-prismic)
+- [Contentful](/examples/cms-contentful)
+- [Strapi](/examples/cms-strapi)
+- [Agility CMS](/examples/cms-agilitycms)
+- [ButterCMS](/examples/cms-buttercms)
+- [Storyblok](/examples/cms-storyblok)
+- [GraphCMS](/examples/cms-graphcms)
+- [Kontent](/examples/cms-kontent)
+- [Umbraco Heartcore](/examples/cms-umbraco-heartcore)
+- [Blog Starter](/examples/blog-starter)
+- [Builder.io](/examples/cms-builder-io)
+
+## How to use
+
+Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
+
+```bash
+npx create-next-app --example cms-tina cms-tina-app
+# or
+yarn create next-app --example cms-ghost cms-tina-app
+```
+
+### Setp 1. Run Next.js in development mode
+
+To get started, no configuration is needed for local development and editing.
+
+```bash
+npm install
+npm run tina-dev
+
+# or
+
+yarn install
+yarn tina-dev
+```
+
+Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).
+
+### Step 2. Editing blog posts.
+
+Tina is git backed and uses markdown, JSON or MDX to power websites. To enter edit mode locally you just need to visit [http://localhost:3000/admin](http://localhost:3000/admin)
+
+You can then select the collection "Blog Posts" and then the content you would like to edit.
+
+Once you hit save, Tina will use our graphQL modify the content on your filesystem.
+
+### Step 4. Deploy on Vercel
+
+You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
+
+#### Deploy Your Local Project
+
+To deploy your local project to Vercel, push it to GitHub. Once you have pushed to GitHub, sign up for your Tina Cloud account at [https://app.tina.io/register](https://app.tina.io/register). Then follow the steps below:
+
+1. Select new project
+2. Select Import your site
+3. Follow steps to connect your GitHub repo.
+4. Copy your Client ID
+
+Then [import to Vercel](https://vercel.com/import/git?utm_source=github&utm_medium=readme&utm_campaign=next-example).
+
+**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set NEXT_PUBLIC_TINA_CLIENT_ID to the client ID above.
+
+Once you have successfully deployed to Vercel, go back to your Tina dashboard and under the project configuration enter the url in the Site URL(s) for example: https://tina-cms.vercel.app.
diff --git a/examples/cms-tina/_posts/dynamic-routing.md b/examples/cms-tina/_posts/dynamic-routing.md
new file mode 100644
index 000000000000..b6ef7a26e6ae
--- /dev/null
+++ b/examples/cms-tina/_posts/dynamic-routing.md
@@ -0,0 +1,19 @@
+---
+title: 'Dynamic Routing and Static Generation'
+excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.'
+coverImage: '/assets/blog/dynamic-routing/cover.jpg'
+date: '2020-03-16T05:35:07.322Z'
+author:
+ name: JJ Kasper
+ picture: '/assets/blog/authors/jj.jpeg'
+ogImage:
+ url: '/assets/blog/dynamic-routing/cover.jpg'
+---
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
+
+Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt. Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae. Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
+
+## Lorem Ipsum
+
+Tristique senectus et netus et malesuada fames ac turpis. Ridiculous mus mauris vitae ultricies leo integer malesuada nunc vel. In mollis nunc sed id semper. Egestas tellus rutrum tellus pellentesque. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Quis blandit turpis cursus in hac habitasse platea dictumst quisque. Eros donec ac odio tempor orci dapibus ultrices. Aliquam sem et tortor consequat id porta nibh. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla. Diam vulputate ut pharetra sit amet. Ut tellus elementum sagittis vitae et leo. Arcu non odio euismod lacinia at quis risus sed vulputate.
diff --git a/examples/cms-tina/_posts/hello-world.md b/examples/cms-tina/_posts/hello-world.md
new file mode 100644
index 000000000000..8d85a1df8f17
--- /dev/null
+++ b/examples/cms-tina/_posts/hello-world.md
@@ -0,0 +1,19 @@
+---
+title: 'Learn How to Pre-render Pages Using Static Generation with Next.js'
+excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.'
+coverImage: '/assets/blog/hello-world/cover.jpg'
+date: '2020-03-16T05:35:07.322Z'
+author:
+ name: Tim Neutkens
+ picture: '/assets/blog/authors/tim.jpeg'
+ogImage:
+ url: '/assets/blog/hello-world/cover.jpg'
+---
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
+
+Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt. Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae. Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
+
+## Lorem Ipsum
+
+Tristique senectus et netus et malesuada fames ac turpis. Ridiculous mus mauris vitae ultricies leo integer malesuada nunc vel. In mollis nunc sed id semper. Egestas tellus rutrum tellus pellentesque. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Quis blandit turpis cursus in hac habitasse platea dictumst quisque. Eros donec ac odio tempor orci dapibus ultrices. Aliquam sem et tortor consequat id porta nibh. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla. Diam vulputate ut pharetra sit amet. Ut tellus elementum sagittis vitae et leo. Arcu non odio euismod lacinia at quis risus sed vulputate.
diff --git a/examples/cms-tina/_posts/preview.md b/examples/cms-tina/_posts/preview.md
new file mode 100644
index 000000000000..3d70ba7f99d1
--- /dev/null
+++ b/examples/cms-tina/_posts/preview.md
@@ -0,0 +1,19 @@
+---
+title: 'Preview Mode for Static Generation'
+excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.'
+coverImage: '/assets/blog/preview/cover.jpg'
+date: '2020-03-16T05:35:07.322Z'
+author:
+ name: Joe Haddad
+ picture: '/assets/blog/authors/joe.jpeg'
+ogImage:
+ url: '/assets/blog/preview/cover.jpg'
+---
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
+
+Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt. Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae. Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
+
+## Lorem Ipsum
+
+Tristique senectus et netus et malesuada fames ac turpis. Ridiculous mus mauris vitae ultricies leo integer malesuada nunc vel. In mollis nunc sed id semper. Egestas tellus rutrum tellus pellentesque. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Quis blandit turpis cursus in hac habitasse platea dictumst quisque. Eros donec ac odio tempor orci dapibus ultrices. Aliquam sem et tortor consequat id porta nibh. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla. Diam vulputate ut pharetra sit amet. Ut tellus elementum sagittis vitae et leo. Arcu non odio euismod lacinia at quis risus sed vulputate.
diff --git a/examples/cms-tina/components/alert.js b/examples/cms-tina/components/alert.js
new file mode 100644
index 000000000000..b924cb097f16
--- /dev/null
+++ b/examples/cms-tina/components/alert.js
@@ -0,0 +1,42 @@
+import Container from './container'
+import cn from 'classnames'
+import { EXAMPLE_PATH } from '../lib/constants'
+
+export default function Alert({ preview }) {
+ return (
+
+
+
+ {preview ? (
+ <>
+ This page is a preview.{' '}
+
+ Click here
+ {' '}
+ to exit preview mode.
+ >
+ ) : (
+ <>
+ The source code for this blog is{' '}
+
+ available on GitHub
+
+ .
+ >
+ )}
+
+
+
+ )
+}
diff --git a/examples/cms-tina/components/avatar.js b/examples/cms-tina/components/avatar.js
new file mode 100644
index 000000000000..0ae7f66413cc
--- /dev/null
+++ b/examples/cms-tina/components/avatar.js
@@ -0,0 +1,16 @@
+import Image from 'next/image'
+
+export default function Avatar({ name, picture }) {
+ return (
+
+ )
+}
diff --git a/examples/cms-tina/components/container.js b/examples/cms-tina/components/container.js
new file mode 100644
index 000000000000..fc1c29dfb074
--- /dev/null
+++ b/examples/cms-tina/components/container.js
@@ -0,0 +1,3 @@
+export default function Container({ children }) {
+ return {children}
+}
diff --git a/examples/cms-tina/components/cover-image.js b/examples/cms-tina/components/cover-image.js
new file mode 100644
index 000000000000..d3e21d21f161
--- /dev/null
+++ b/examples/cms-tina/components/cover-image.js
@@ -0,0 +1,29 @@
+import cn from 'classnames'
+import Link from 'next/link'
+import Image from 'next/image'
+
+export default function CoverImage({ title, src, slug, height, width }) {
+ const image = (
+
+ )
+ return (
+
+ {slug ? (
+
+
{image}
+
+ ) : (
+ image
+ )}
+
+ )
+}
diff --git a/examples/cms-tina/components/date-formatter.js b/examples/cms-tina/components/date-formatter.js
new file mode 100644
index 000000000000..9de4f4880011
--- /dev/null
+++ b/examples/cms-tina/components/date-formatter.js
@@ -0,0 +1,6 @@
+import { parseISO, format } from 'date-fns'
+
+export default function DateFormatter({ dateString }) {
+ const date = parseISO(dateString)
+ return {format(date, 'LLLL d, yyyy')}
+}
diff --git a/examples/cms-tina/components/footer.js b/examples/cms-tina/components/footer.js
new file mode 100644
index 000000000000..da9eed88ec26
--- /dev/null
+++ b/examples/cms-tina/components/footer.js
@@ -0,0 +1,30 @@
+import Container from './container'
+import { EXAMPLE_PATH } from '../lib/constants'
+
+export default function Footer() {
+ return (
+
+
+
+
+ Statically Generated with Next.js.
+
+
+
+
+
+ )
+}
diff --git a/examples/cms-tina/components/header.js b/examples/cms-tina/components/header.js
new file mode 100644
index 000000000000..562e7e3eebb6
--- /dev/null
+++ b/examples/cms-tina/components/header.js
@@ -0,0 +1,12 @@
+import Link from 'next/link'
+
+export default function Header() {
+ return (
+
+
+ Blog
+
+ .
+
+ )
+}
diff --git a/examples/cms-tina/components/hero-post.js b/examples/cms-tina/components/hero-post.js
new file mode 100644
index 000000000000..6dc49f20a8bb
--- /dev/null
+++ b/examples/cms-tina/components/hero-post.js
@@ -0,0 +1,43 @@
+import Avatar from '../components/avatar'
+import DateFormatter from '../components/date-formatter'
+import CoverImage from '../components/cover-image'
+import Link from 'next/link'
+
+export default function HeroPost({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}) {
+ return (
+
+ )
+}
diff --git a/examples/cms-tina/components/intro.js b/examples/cms-tina/components/intro.js
new file mode 100644
index 000000000000..048fc170a13e
--- /dev/null
+++ b/examples/cms-tina/components/intro.js
@@ -0,0 +1,21 @@
+import { CMS_NAME } from '../lib/constants'
+
+export default function Intro() {
+ return (
+
+
+ Blog.
+
+
+ A statically generated blog example using{' '}
+
+ Next.js
+ {' '}
+ and {CMS_NAME}.
+
+
+ )
+}
diff --git a/examples/cms-tina/components/layout.js b/examples/cms-tina/components/layout.js
new file mode 100644
index 000000000000..99d95353131e
--- /dev/null
+++ b/examples/cms-tina/components/layout.js
@@ -0,0 +1,16 @@
+import Alert from '../components/alert'
+import Footer from '../components/footer'
+import Meta from '../components/meta'
+
+export default function Layout({ preview, children }) {
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/examples/cms-tina/components/markdown-styles.module.css b/examples/cms-tina/components/markdown-styles.module.css
new file mode 100644
index 000000000000..95d4f8b04172
--- /dev/null
+++ b/examples/cms-tina/components/markdown-styles.module.css
@@ -0,0 +1,18 @@
+.markdown {
+ @apply text-lg leading-relaxed;
+}
+
+.markdown p,
+.markdown ul,
+.markdown ol,
+.markdown blockquote {
+ @apply my-6;
+}
+
+.markdown h2 {
+ @apply text-3xl mt-12 mb-4 leading-snug;
+}
+
+.markdown h3 {
+ @apply text-2xl mt-8 mb-4 leading-snug;
+}
diff --git a/examples/cms-tina/components/meta.js b/examples/cms-tina/components/meta.js
new file mode 100644
index 000000000000..349fc3d73a7a
--- /dev/null
+++ b/examples/cms-tina/components/meta.js
@@ -0,0 +1,42 @@
+import Head from 'next/head'
+import { CMS_NAME, HOME_OG_IMAGE_URL } from '../lib/constants'
+
+export default function Meta() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/cms-tina/components/more-stories.js b/examples/cms-tina/components/more-stories.js
new file mode 100644
index 000000000000..57fdbb6c4659
--- /dev/null
+++ b/examples/cms-tina/components/more-stories.js
@@ -0,0 +1,24 @@
+import PostPreview from '../components/post-preview'
+
+export default function MoreStories({ posts }) {
+ return (
+
+
+ More Stories
+
+
+ {posts.map((post) => (
+
+ ))}
+
+
+ )
+}
diff --git a/examples/cms-tina/components/post-body.js b/examples/cms-tina/components/post-body.js
new file mode 100644
index 000000000000..4cc2bb52bcce
--- /dev/null
+++ b/examples/cms-tina/components/post-body.js
@@ -0,0 +1,12 @@
+import markdownStyles from './markdown-styles.module.css'
+
+export default function PostBody({ content }) {
+ return (
+
+ )
+}
diff --git a/examples/cms-tina/components/post-header.js b/examples/cms-tina/components/post-header.js
new file mode 100644
index 000000000000..76789f7a98c1
--- /dev/null
+++ b/examples/cms-tina/components/post-header.js
@@ -0,0 +1,26 @@
+import Avatar from '../components/avatar'
+import DateFormatter from '../components/date-formatter'
+import CoverImage from '../components/cover-image'
+import PostTitle from '../components/post-title'
+
+export default function PostHeader({ title, coverImage, date, author }) {
+ return (
+ <>
+ {title}
+
+
+
+
+
+ >
+ )
+}
diff --git a/examples/cms-tina/components/post-preview.js b/examples/cms-tina/components/post-preview.js
new file mode 100644
index 000000000000..712eea6e92ec
--- /dev/null
+++ b/examples/cms-tina/components/post-preview.js
@@ -0,0 +1,37 @@
+import Avatar from '../components/avatar'
+import DateFormatter from '../components/date-formatter'
+import CoverImage from './cover-image'
+import Link from 'next/link'
+
+export default function PostPreview({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}) {
+ return (
+
+
+
+
+
+
+
+
+
{excerpt}
+
+
+ )
+}
diff --git a/examples/cms-tina/components/post-title.js b/examples/cms-tina/components/post-title.js
new file mode 100644
index 000000000000..edd8cba65c25
--- /dev/null
+++ b/examples/cms-tina/components/post-title.js
@@ -0,0 +1,7 @@
+export default function PostTitle({ children }) {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/examples/cms-tina/components/section-separator.js b/examples/cms-tina/components/section-separator.js
new file mode 100644
index 000000000000..4ca5c65fdc6e
--- /dev/null
+++ b/examples/cms-tina/components/section-separator.js
@@ -0,0 +1,3 @@
+export default function SectionSeparator() {
+ return
+}
diff --git a/examples/cms-tina/lib/api.js b/examples/cms-tina/lib/api.js
new file mode 100644
index 000000000000..b9612a8ac536
--- /dev/null
+++ b/examples/cms-tina/lib/api.js
@@ -0,0 +1,43 @@
+import fs from 'fs'
+import { join } from 'path'
+import matter from 'gray-matter'
+
+const postsDirectory = join(process.cwd(), '_posts')
+
+export function getPostSlugs() {
+ return fs.readdirSync(postsDirectory)
+}
+
+export function getPostBySlug(slug, fields = []) {
+ const realSlug = slug.replace(/\.md$/, '')
+ const fullPath = join(postsDirectory, `${realSlug}.md`)
+ const fileContents = fs.readFileSync(fullPath, 'utf8')
+ const { data, content } = matter(fileContents)
+
+ const items = {}
+
+ // Ensure only the minimal needed data is exposed
+ fields.forEach((field) => {
+ if (field === 'slug') {
+ items[field] = realSlug
+ }
+ if (field === 'content') {
+ items[field] = content
+ }
+
+ if (typeof data[field] !== 'undefined') {
+ items[field] = data[field]
+ }
+ })
+
+ return items
+}
+
+export function getAllPosts(fields = []) {
+ const slugs = getPostSlugs()
+ const posts = slugs
+ .map((slug) => getPostBySlug(slug, fields))
+ // sort posts by date in descending order
+ .sort((post1, post2) => (post1.date > post2.date ? -1 : 1))
+ return posts
+}
diff --git a/examples/cms-tina/lib/constants.js b/examples/cms-tina/lib/constants.js
new file mode 100644
index 000000000000..671a9c22b49a
--- /dev/null
+++ b/examples/cms-tina/lib/constants.js
@@ -0,0 +1,4 @@
+export const EXAMPLE_PATH = 'cms-tina'
+export const CMS_NAME = 'Tina'
+export const HOME_OG_IMAGE_URL =
+ 'https://og-image.vercel.app/Next.js%20Blog%20Starter%20Example.png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg'
diff --git a/examples/cms-tina/lib/markdownToHtml.js b/examples/cms-tina/lib/markdownToHtml.js
new file mode 100644
index 000000000000..735fed2df383
--- /dev/null
+++ b/examples/cms-tina/lib/markdownToHtml.js
@@ -0,0 +1,7 @@
+import { remark } from 'remark'
+import html from 'remark-html'
+
+export default async function markdownToHtml(markdown) {
+ const result = await remark().use(html).process(markdown)
+ return result.toString()
+}
diff --git a/examples/cms-tina/package.json b/examples/cms-tina/package.json
new file mode 100644
index 000000000000..4ab85e58294a
--- /dev/null
+++ b/examples/cms-tina/package.json
@@ -0,0 +1,29 @@
+{
+ "private": true,
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start",
+ "tina-dev": "yarn tinacms server:start -c \"next dev\"",
+ "tina-build": "yarn tinacms server:start -c \"next build\"",
+ "tina-start": "yarn tinacms server:start -c \"next start\""
+ },
+ "dependencies": {
+ "@tinacms/cli": "^0.60.8",
+ "classnames": "2.3.1",
+ "date-fns": "2.28.0",
+ "gray-matter": "4.0.3",
+ "next": "latest",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "remark": "14.0.2",
+ "remark-html": "15.0.1",
+ "styled-components": "^5.3.3",
+ "tinacms": "^0.66.7"
+ },
+ "devDependencies": {
+ "autoprefixer": "^10.4.2",
+ "postcss": "^8.4.7",
+ "tailwindcss": "^3.0.23"
+ }
+}
diff --git a/examples/cms-tina/pages/_app.js b/examples/cms-tina/pages/_app.js
new file mode 100644
index 000000000000..8ad946c7ebb1
--- /dev/null
+++ b/examples/cms-tina/pages/_app.js
@@ -0,0 +1,12 @@
+import Tina from '../.tina/components/TinaDynamicProvider.js'
+
+import '../styles/index.css'
+const App = ({ Component, pageProps }) => {
+ return (
+
+
+
+ )
+}
+
+export default App
diff --git a/examples/cms-tina/pages/_document.js b/examples/cms-tina/pages/_document.js
new file mode 100644
index 000000000000..c55951c0d5da
--- /dev/null
+++ b/examples/cms-tina/pages/_document.js
@@ -0,0 +1,15 @@
+import Document, { Html, Head, Main, NextScript } from 'next/document'
+
+export default class MyDocument extends Document {
+ render() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/examples/cms-tina/pages/admin.js b/examples/cms-tina/pages/admin.js
new file mode 100644
index 000000000000..edebe7a815a7
--- /dev/null
+++ b/examples/cms-tina/pages/admin.js
@@ -0,0 +1,2 @@
+import { TinaAdmin } from 'tinacms'
+export default TinaAdmin
diff --git a/examples/cms-tina/pages/index.js b/examples/cms-tina/pages/index.js
new file mode 100644
index 000000000000..c46462c0f423
--- /dev/null
+++ b/examples/cms-tina/pages/index.js
@@ -0,0 +1,51 @@
+import Container from '../components/container'
+import MoreStories from '../components/more-stories'
+import HeroPost from '../components/hero-post'
+import Intro from '../components/intro'
+import Layout from '../components/layout'
+import { getAllPosts } from '../lib/api'
+import Head from 'next/head'
+import { CMS_NAME } from '../lib/constants'
+
+export default function Index({ allPosts }) {
+ const heroPost = allPosts[0]
+ const morePosts = allPosts.slice(1)
+ return (
+ <>
+
+
+ Next.js Blog Example with {CMS_NAME}
+
+
+
+ {heroPost && (
+
+ )}
+ {morePosts.length > 0 && }
+
+
+ >
+ )
+}
+
+export async function getStaticProps() {
+ const allPosts = getAllPosts([
+ 'title',
+ 'date',
+ 'slug',
+ 'author',
+ 'coverImage',
+ 'excerpt',
+ ])
+
+ return {
+ props: { allPosts },
+ }
+}
diff --git a/examples/cms-tina/pages/posts/[slug].js b/examples/cms-tina/pages/posts/[slug].js
new file mode 100644
index 000000000000..83a1fb464af4
--- /dev/null
+++ b/examples/cms-tina/pages/posts/[slug].js
@@ -0,0 +1,84 @@
+import { useRouter } from 'next/router'
+import ErrorPage from 'next/error'
+import Container from '../../components/container'
+import PostBody from '../../components/post-body'
+import Header from '../../components/header'
+import PostHeader from '../../components/post-header'
+import Layout from '../../components/layout'
+import { getPostBySlug, getAllPosts } from '../../lib/api'
+import PostTitle from '../../components/post-title'
+import Head from 'next/head'
+import { CMS_NAME } from '../../lib/constants'
+import markdownToHtml from '../../lib/markdownToHtml'
+
+export default function Post({ post, morePosts, preview }) {
+ const router = useRouter()
+ if (!router.isFallback && !post?.slug) {
+ return
+ }
+ return (
+
+
+
+ {router.isFallback ? (
+ Loading…
+ ) : (
+ <>
+
+
+
+ {post.title} | Next.js Blog Example with {CMS_NAME}
+
+
+
+
+
+
+ >
+ )}
+
+
+ )
+}
+
+export async function getStaticProps({ params }) {
+ const post = getPostBySlug(params.slug, [
+ 'title',
+ 'date',
+ 'slug',
+ 'author',
+ 'content',
+ 'ogImage',
+ 'coverImage',
+ ])
+ const content = await markdownToHtml(post.content || '')
+
+ return {
+ props: {
+ post: {
+ ...post,
+ content,
+ },
+ },
+ }
+}
+
+export async function getStaticPaths() {
+ const posts = getAllPosts(['slug'])
+
+ return {
+ paths: posts.map((post) => {
+ return {
+ params: {
+ slug: post.slug,
+ },
+ }
+ }),
+ fallback: false,
+ }
+}
diff --git a/examples/cms-tina/postcss.config.js b/examples/cms-tina/postcss.config.js
new file mode 100644
index 000000000000..3fa0a9514dc9
--- /dev/null
+++ b/examples/cms-tina/postcss.config.js
@@ -0,0 +1,8 @@
+// If you want to use other PostCSS plugins, see the following:
+// https://tailwindcss.com/docs/using-with-preprocessors
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/examples/cms-tina/public/assets/blog/authors/jj.jpeg b/examples/cms-tina/public/assets/blog/authors/jj.jpeg
new file mode 100644
index 000000000000..e3d521436a6c
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/authors/jj.jpeg differ
diff --git a/examples/cms-tina/public/assets/blog/authors/joe.jpeg b/examples/cms-tina/public/assets/blog/authors/joe.jpeg
new file mode 100644
index 000000000000..d9677ad61c00
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/authors/joe.jpeg differ
diff --git a/examples/cms-tina/public/assets/blog/authors/tim.jpeg b/examples/cms-tina/public/assets/blog/authors/tim.jpeg
new file mode 100644
index 000000000000..cc49257b8230
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/authors/tim.jpeg differ
diff --git a/examples/cms-tina/public/assets/blog/dynamic-routing/cover.jpg b/examples/cms-tina/public/assets/blog/dynamic-routing/cover.jpg
new file mode 100644
index 000000000000..c660c92679ee
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/dynamic-routing/cover.jpg differ
diff --git a/examples/cms-tina/public/assets/blog/hello-world/cover.jpg b/examples/cms-tina/public/assets/blog/hello-world/cover.jpg
new file mode 100644
index 000000000000..33b7dc4b73ce
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/hello-world/cover.jpg differ
diff --git a/examples/cms-tina/public/assets/blog/preview/cover.jpg b/examples/cms-tina/public/assets/blog/preview/cover.jpg
new file mode 100644
index 000000000000..6a975fb36d05
Binary files /dev/null and b/examples/cms-tina/public/assets/blog/preview/cover.jpg differ
diff --git a/examples/cms-tina/public/favicons/android-chrome-192x192.png b/examples/cms-tina/public/favicons/android-chrome-192x192.png
new file mode 100644
index 000000000000..2f07282a59cd
Binary files /dev/null and b/examples/cms-tina/public/favicons/android-chrome-192x192.png differ
diff --git a/examples/cms-tina/public/favicons/android-chrome-512x512.png b/examples/cms-tina/public/favicons/android-chrome-512x512.png
new file mode 100644
index 000000000000..dbb0faea8404
Binary files /dev/null and b/examples/cms-tina/public/favicons/android-chrome-512x512.png differ
diff --git a/examples/cms-tina/public/favicons/apple-touch-icon.png b/examples/cms-tina/public/favicons/apple-touch-icon.png
new file mode 100644
index 000000000000..8f4033b2a8b3
Binary files /dev/null and b/examples/cms-tina/public/favicons/apple-touch-icon.png differ
diff --git a/examples/cms-tina/public/favicons/browserconfig.xml b/examples/cms-tina/public/favicons/browserconfig.xml
new file mode 100644
index 000000000000..9824d87b1151
--- /dev/null
+++ b/examples/cms-tina/public/favicons/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #000000
+
+
+
diff --git a/examples/cms-tina/public/favicons/favicon-16x16.png b/examples/cms-tina/public/favicons/favicon-16x16.png
new file mode 100644
index 000000000000..29deaf6716e7
Binary files /dev/null and b/examples/cms-tina/public/favicons/favicon-16x16.png differ
diff --git a/examples/cms-tina/public/favicons/favicon-32x32.png b/examples/cms-tina/public/favicons/favicon-32x32.png
new file mode 100644
index 000000000000..e3b4277bf093
Binary files /dev/null and b/examples/cms-tina/public/favicons/favicon-32x32.png differ
diff --git a/examples/cms-tina/public/favicons/favicon.ico b/examples/cms-tina/public/favicons/favicon.ico
new file mode 100644
index 000000000000..ea2f437d9db6
Binary files /dev/null and b/examples/cms-tina/public/favicons/favicon.ico differ
diff --git a/examples/cms-tina/public/favicons/mstile-150x150.png b/examples/cms-tina/public/favicons/mstile-150x150.png
new file mode 100644
index 000000000000..f2dfd904bf1b
Binary files /dev/null and b/examples/cms-tina/public/favicons/mstile-150x150.png differ
diff --git a/examples/cms-tina/public/favicons/safari-pinned-tab.svg b/examples/cms-tina/public/favicons/safari-pinned-tab.svg
new file mode 100644
index 000000000000..72ab6e050cb1
--- /dev/null
+++ b/examples/cms-tina/public/favicons/safari-pinned-tab.svg
@@ -0,0 +1,33 @@
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/cms-tina/public/favicons/site.webmanifest b/examples/cms-tina/public/favicons/site.webmanifest
new file mode 100644
index 000000000000..a672d9a233c5
--- /dev/null
+++ b/examples/cms-tina/public/favicons/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "Next.js",
+ "short_name": "Next.js",
+ "icons": [
+ {
+ "src": "/favicons/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/favicons/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#000000",
+ "background_color": "#000000",
+ "display": "standalone"
+}
diff --git a/examples/cms-tina/styles/index.css b/examples/cms-tina/styles/index.css
new file mode 100644
index 000000000000..b5c61c956711
--- /dev/null
+++ b/examples/cms-tina/styles/index.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/examples/cms-tina/tailwind.config.js b/examples/cms-tina/tailwind.config.js
new file mode 100644
index 000000000000..b176069a2c6b
--- /dev/null
+++ b/examples/cms-tina/tailwind.config.js
@@ -0,0 +1,33 @@
+module.exports = {
+ content: ['./components/**/*.js', './pages/**/*.js'],
+ theme: {
+ extend: {
+ colors: {
+ 'accent-1': '#FAFAFA',
+ 'accent-2': '#EAEAEA',
+ 'accent-7': '#333',
+ success: '#0070f3',
+ cyan: '#79FFE1',
+ },
+ spacing: {
+ 28: '7rem',
+ },
+ letterSpacing: {
+ tighter: '-.04em',
+ },
+ lineHeight: {
+ tight: 1.2,
+ },
+ fontSize: {
+ '5xl': '2.5rem',
+ '6xl': '2.75rem',
+ '7xl': '4.5rem',
+ '8xl': '6.25rem',
+ },
+ boxShadow: {
+ sm: '0 5px 10px rgba(0, 0, 0, 0.12)',
+ md: '0 8px 30px rgba(0, 0, 0, 0.12)',
+ },
+ },
+ },
+}