Initial commit
This commit is contained in:
commit
5a3bf52ebb
86 changed files with 2639 additions and 0 deletions
1
studio/.eslintignore
Normal file
1
studio/.eslintignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
dist/*
|
||||
16
studio/.eslintrc.js
Normal file
16
studio/.eslintrc.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
extends: ['standard', 'standard-react'],
|
||||
parser: 'babel-eslint',
|
||||
rules: {
|
||||
'react/prop-types': 0,
|
||||
'object-curly-spacing': ['error', 'never']
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
pragma: 'React',
|
||||
version: '16.8.6'
|
||||
}
|
||||
}
|
||||
}
|
||||
6
studio/.gitignore
vendored
Normal file
6
studio/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/dist
|
||||
/node_modules
|
||||
|
||||
# Lock files
|
||||
/package-lock.json
|
||||
/yarn.lock
|
||||
4
studio/.prettierrc
Normal file
4
studio/.prettierrc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
}
|
||||
1
studio/README.md
Normal file
1
studio/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
# TestGatsbySanity-studio
|
||||
6
studio/config/.checksums
Normal file
6
studio/config/.checksums
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!",
|
||||
"@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea",
|
||||
"@sanity/default-login": "6fb6d3800aa71346e1b84d95bbcaa287879456f2922372bb0294e30b968cd37f",
|
||||
"@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6"
|
||||
}
|
||||
3
studio/config/@sanity/data-aspects.json
Normal file
3
studio/config/@sanity/data-aspects.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"listOptions": {}
|
||||
}
|
||||
6
studio/config/@sanity/default-layout.json
Normal file
6
studio/config/@sanity/default-layout.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"toolSwitcher": {
|
||||
"order": [],
|
||||
"hidden": []
|
||||
}
|
||||
}
|
||||
7
studio/config/@sanity/default-login.json
Normal file
7
studio/config/@sanity/default-login.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"providers": {
|
||||
"mode": "append",
|
||||
"redirectOnSingle": false,
|
||||
"entries": []
|
||||
}
|
||||
}
|
||||
53
studio/dashboardConfig.js
Normal file
53
studio/dashboardConfig.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
export default {
|
||||
widgets: [
|
||||
{
|
||||
name: 'sanity-tutorials',
|
||||
options: {
|
||||
templateRepoId: 'sanity-io/sanity-template-gatsby-portfolio'
|
||||
}
|
||||
},
|
||||
{name: 'structure-menu'},
|
||||
{
|
||||
name: 'project-info',
|
||||
options: {
|
||||
__experimental_before: [
|
||||
{
|
||||
name: 'netlify',
|
||||
options: {
|
||||
description:
|
||||
'NOTE: Because these sites are static builds, they need to be re-deployed to see the changes when documents are published.',
|
||||
sites: [
|
||||
{
|
||||
buildHookId: '5cd4441832c8cca9fab7c1b2',
|
||||
title: 'Sanity Studio',
|
||||
name: 'TestGatsbySanity-studio',
|
||||
apiId: '322eb270-ce44-446b-989e-a2000fa7acab'
|
||||
},
|
||||
{
|
||||
buildHookId: '5cd44418d31f16c9c00451cd',
|
||||
title: 'Portfolio Website',
|
||||
name: 'TestGatsbySanity',
|
||||
apiId: '24555f21-7e83-43f5-8a76-82dec0822171'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
title: 'GitHub repo',
|
||||
value: 'https://github.com/WaylonWalker/TestGatsbySanity',
|
||||
category: 'Code'
|
||||
},
|
||||
{title: 'Frontend', value: 'https://TestGatsbySanity.netlify.com', category: 'apps'}
|
||||
]
|
||||
}
|
||||
},
|
||||
{name: 'project-users', layout: {height: 'auto'}},
|
||||
{
|
||||
name: 'document-list',
|
||||
options: {title: 'Recent projects', order: '_createdAt desc', types: ['project']},
|
||||
layout: {width: 'medium'}
|
||||
}
|
||||
]
|
||||
}
|
||||
36
studio/deskStructure.js
Normal file
36
studio/deskStructure.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import S from '@sanity/desk-tool/structure-builder'
|
||||
import MdSettings from 'react-icons/lib/md/settings'
|
||||
|
||||
const hiddenDocTypes = listItem =>
|
||||
!['category', 'person', 'project', 'siteSettings'].includes(listItem.getId())
|
||||
|
||||
export default () =>
|
||||
S.list()
|
||||
.title('Content')
|
||||
.items([
|
||||
S.listItem()
|
||||
.title('Settings')
|
||||
.child(
|
||||
S.editor()
|
||||
.id('siteSettings')
|
||||
.schemaType('siteSettings')
|
||||
.documentId('siteSettings')
|
||||
)
|
||||
.icon(MdSettings),
|
||||
S.listItem()
|
||||
.title('Projects')
|
||||
.schemaType('project')
|
||||
.child(S.documentTypeList('project').title('Projects')),
|
||||
S.listItem()
|
||||
.title('People')
|
||||
.schemaType('person')
|
||||
.child(S.documentTypeList('person').title('People')),
|
||||
S.listItem()
|
||||
.title('Categories')
|
||||
.schemaType('category')
|
||||
.child(S.documentTypeList('category').title('Categories')),
|
||||
// This returns an array of all the document types
|
||||
// defined in schema.js. We filter out those that we have
|
||||
// defined the structure above
|
||||
...S.documentTypeListItems().filter(hiddenDocTypes)
|
||||
])
|
||||
4
studio/netlify.toml
Normal file
4
studio/netlify.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/"
|
||||
status = 200
|
||||
43
studio/package.json
Normal file
43
studio/package.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "TestGatsbySanity-studio",
|
||||
"version": "1.0.0",
|
||||
"main": "package.json",
|
||||
"author": "Sanity <hello@sanity.io>",
|
||||
"scripts": {
|
||||
"dev": "sanity start",
|
||||
"format": "prettier-eslint --write \"**/*.js\" \"!node_modules/**\"",
|
||||
"build": "sanity build",
|
||||
"graphql-deploy": "sanity graphql deploy --playground",
|
||||
"lint": "eslint .",
|
||||
"test": "sanity check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sanity/base": "^0.140.17",
|
||||
"@sanity/cli": "^0.140.17",
|
||||
"@sanity/components": "^0.140.20",
|
||||
"@sanity/core": "^0.140.20",
|
||||
"@sanity/dashboard": "^0.140.19",
|
||||
"@sanity/default-layout": "^0.140.20",
|
||||
"@sanity/default-login": "^0.140.15",
|
||||
"@sanity/desk-tool": "^0.140.20",
|
||||
"date-fns": "^1.30.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"sanity-plugin-dashboard-widget-document-list": "^0.0.8",
|
||||
"sanity-plugin-dashboard-widget-netlify": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-config-standard-react": "^7.0.2",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"eslint-plugin-node": "^9.0.1",
|
||||
"eslint-plugin-promise": "^4.1.1",
|
||||
"eslint-plugin-react": "^7.13.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"prettier-eslint-cli": "^4.7.1"
|
||||
}
|
||||
}
|
||||
13
studio/plugins/dashboard-widget-structure-menu/sanity.json
Normal file
13
studio/plugins/dashboard-widget-structure-menu/sanity.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"paths": {
|
||||
"source": "./src",
|
||||
"compiled": "./lib"
|
||||
},
|
||||
"parts": [
|
||||
{
|
||||
"name": "part:@sanity/dashboard/widget/create",
|
||||
"implements": "part:@sanity/dashboard/widget",
|
||||
"path": "widget.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
@import 'part:@sanity/base/theme/variables-style';
|
||||
|
||||
.root {
|
||||
composes: container from "part:@sanity/dashboard/widget-styles";
|
||||
}
|
||||
|
||||
.header {
|
||||
composes: header from "part:@sanity/dashboard/widget-styles";
|
||||
}
|
||||
|
||||
.title {
|
||||
composes: title from "part:@sanity/dashboard/widget-styles";
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
padding: var(--small-padding);
|
||||
grid-gap: var(--small-padding);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
overflow-x: auto;
|
||||
border-top: 1px solid var(--hairline-color);
|
||||
|
||||
@media (--screen-medium) {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
composes: item from 'part:@sanity/base/theme/layout/selectable-style';
|
||||
display: block;
|
||||
border-radius: 2px;
|
||||
padding: var(--small-padding);
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.iconWrapper {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import {Link} from 'part:@sanity/base/router'
|
||||
import FolderIcon from 'part:@sanity/base/folder-icon'
|
||||
import FileIcon from 'part:@sanity/base/file-icon'
|
||||
import React from 'react'
|
||||
import styles from './StructureMenuWidget.css'
|
||||
|
||||
function getIconComponent (item) {
|
||||
if (item.icon) return item.icon
|
||||
if (!item.schemaType) return FileIcon
|
||||
return item.schemaType.icon || FolderIcon
|
||||
}
|
||||
|
||||
function StructureMenuWidget (props) {
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<div className={styles.header}>
|
||||
<h3 className={styles.title}>Edit your content</h3>
|
||||
</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
{props.structure.items.map(item => {
|
||||
const Icon = getIconComponent(item)
|
||||
return (
|
||||
<div key={item.id}>
|
||||
<Link className={styles.link} href={`/desk/${item.id}`}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<Icon />
|
||||
</div>
|
||||
<div>{item.title}</div>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StructureMenuWidget
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {default as StructureMenuWidget} from './StructureMenuWidget'
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* global __DEV__ */
|
||||
|
||||
import {defer, from as observableFrom, of as observableOf, throwError} from 'rxjs'
|
||||
import {mergeMap} from 'rxjs/operators'
|
||||
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
const {StructureBuilder} = require('@sanity/structure')
|
||||
|
||||
let prevStructureError = null
|
||||
if (__DEV__) {
|
||||
if (module.hot && module.hot.data) {
|
||||
prevStructureError = module.hot.data.prevError
|
||||
}
|
||||
}
|
||||
|
||||
export function isSubscribable (thing) {
|
||||
return thing && (typeof thing.then === 'function' || typeof thing.subscribe === 'function')
|
||||
}
|
||||
|
||||
export function isStructure (structure) {
|
||||
return (
|
||||
structure &&
|
||||
(typeof structure === 'function' ||
|
||||
typeof structure.serialize !== 'function' ||
|
||||
typeof structure.then !== 'function' ||
|
||||
typeof structure.subscribe !== 'function' ||
|
||||
typeof structure.type !== 'string')
|
||||
)
|
||||
}
|
||||
|
||||
export function serializeStructure (item, context, resolverArgs = []) {
|
||||
// Lazy
|
||||
if (typeof item === 'function') {
|
||||
return serializeStructure(item(...resolverArgs), context, resolverArgs)
|
||||
}
|
||||
|
||||
// Promise/observable returning a function, builder or plain JSON structure
|
||||
if (isSubscribable(item)) {
|
||||
return observableFrom(item).pipe(
|
||||
mergeMap(val => serializeStructure(val, context, resolverArgs))
|
||||
)
|
||||
}
|
||||
|
||||
// Builder?
|
||||
if (item && typeof item.serialize === 'function') {
|
||||
return serializeStructure(item.serialize(context))
|
||||
}
|
||||
|
||||
// Plain value?
|
||||
return observableOf(item)
|
||||
}
|
||||
|
||||
export function getDefaultStructure () {
|
||||
const items = StructureBuilder.documentTypeListItems()
|
||||
return StructureBuilder.list()
|
||||
.id('__root__')
|
||||
.title('Content')
|
||||
.showIcons(items.some(item => item.getSchemaType().icon))
|
||||
.items(items)
|
||||
}
|
||||
|
||||
// We are lazy-requiring/resolving the structure inside of a function in order to catch errors
|
||||
// on the root-level of the module. Any loading errors will be caught and emitted as errors
|
||||
// eslint-disable-next-line complexity
|
||||
export function loadStructure () {
|
||||
let structure
|
||||
try {
|
||||
const mod = require('part:@sanity/desk-tool/structure?') || getDefaultStructure()
|
||||
structure = mod && mod.__esModule ? mod.default : mod
|
||||
|
||||
// On invalid modules, when HMR kicks in, we sometimes get an empty object back when the
|
||||
// source has changed without fixing the problem. In this case, keep showing the error
|
||||
if (
|
||||
__DEV__ &&
|
||||
prevStructureError &&
|
||||
structure &&
|
||||
structure.constructor.name === 'Object' &&
|
||||
Object.keys(structure).length === 0
|
||||
) {
|
||||
return throwError(prevStructureError)
|
||||
}
|
||||
|
||||
prevStructureError = null
|
||||
} catch (err) {
|
||||
prevStructureError = err
|
||||
return throwError(err)
|
||||
}
|
||||
|
||||
if (!isStructure(structure)) {
|
||||
return throwError(
|
||||
new Error(
|
||||
`Structure needs to export a function, an observable, a promise or a stucture builder, got ${typeof structure}`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Defer to catch immediately thrown errors on serialization
|
||||
return defer(() => serializeStructure(structure))
|
||||
}
|
||||
11
studio/plugins/dashboard-widget-structure-menu/src/props.js
Normal file
11
studio/plugins/dashboard-widget-structure-menu/src/props.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import {combineLatest} from 'rxjs'
|
||||
import {map} from 'rxjs/operators'
|
||||
import {loadStructure} from './lib/structure'
|
||||
|
||||
export function toPropsStream (props$) {
|
||||
const structure$ = loadStructure()
|
||||
|
||||
return combineLatest(props$, structure$).pipe(
|
||||
map(([props, structure]) => ({...props, structure}))
|
||||
)
|
||||
}
|
||||
10
studio/plugins/dashboard-widget-structure-menu/src/widget.js
Normal file
10
studio/plugins/dashboard-widget-structure-menu/src/widget.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import {withPropsStream} from 'react-props-stream'
|
||||
import {withRouterHOC} from 'part:@sanity/base/router'
|
||||
import {StructureMenuWidget} from './components'
|
||||
import {toPropsStream} from './props'
|
||||
|
||||
export default {
|
||||
name: 'structure-menu',
|
||||
component: withRouterHOC(withPropsStream(toPropsStream, StructureMenuWidget)),
|
||||
layout: {width: 'full'}
|
||||
}
|
||||
35
studio/sanity.json
Normal file
35
studio/sanity.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"root": true,
|
||||
"project": {
|
||||
"name": "TestGatsbySanity"
|
||||
},
|
||||
"api": {
|
||||
"projectId": "dkwlsoid",
|
||||
"dataset": "production"
|
||||
},
|
||||
"plugins": [
|
||||
"@sanity/base",
|
||||
"@sanity/components",
|
||||
"@sanity/default-layout",
|
||||
"@sanity/default-login",
|
||||
"@sanity/dashboard",
|
||||
"@sanity/desk-tool",
|
||||
"dashboard-widget-structure-menu",
|
||||
"dashboard-widget-document-list",
|
||||
"dashboard-widget-netlify"
|
||||
],
|
||||
"parts": [
|
||||
{
|
||||
"name": "part:@sanity/base/schema",
|
||||
"path": "./schemas/schema.js"
|
||||
},
|
||||
{
|
||||
"name": "part:@sanity/desk-tool/structure",
|
||||
"path": "./deskStructure.js"
|
||||
},
|
||||
{
|
||||
"implements": "part:@sanity/dashboard/config",
|
||||
"path": "./dashboardConfig.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
17
studio/schemas/documents/category.js
Normal file
17
studio/schemas/documents/category.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export default {
|
||||
name: 'category',
|
||||
type: 'document',
|
||||
title: 'Category',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
title: 'Description'
|
||||
}
|
||||
]
|
||||
}
|
||||
41
studio/schemas/documents/person.js
Normal file
41
studio/schemas/documents/person.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import MdPerson from 'react-icons/lib/md/person'
|
||||
|
||||
export default {
|
||||
name: 'person',
|
||||
type: 'document',
|
||||
title: 'Person',
|
||||
icon: MdPerson,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
title: 'Name'
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'slug',
|
||||
title: 'Slug',
|
||||
description: 'Some frontend will require a slug to be set to be able to show the person',
|
||||
options: {
|
||||
source: 'name',
|
||||
maxLength: 96
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
title: 'Image',
|
||||
type: 'figure'
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
title: 'Bio',
|
||||
type: 'bioPortableText'
|
||||
}
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'name',
|
||||
media: 'image'
|
||||
}
|
||||
}
|
||||
}
|
||||
90
studio/schemas/documents/project.js
Normal file
90
studio/schemas/documents/project.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import {format} from 'date-fns'
|
||||
|
||||
export default {
|
||||
name: 'project',
|
||||
title: 'Project',
|
||||
type: 'document',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
title: 'Title',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
title: 'Slug',
|
||||
type: 'slug',
|
||||
description: 'Some frontend will require a slug to be set to be able to show the project',
|
||||
options: {
|
||||
source: 'title',
|
||||
maxLength: 96
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
title: 'Published at',
|
||||
description: 'You can use this field to schedule projects where you show them',
|
||||
type: 'datetime'
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
title: 'Excerpt',
|
||||
type: 'simplePortableText'
|
||||
},
|
||||
{
|
||||
name: 'members',
|
||||
title: 'Members',
|
||||
type: 'array',
|
||||
of: [{type: 'projectMember'}]
|
||||
},
|
||||
{
|
||||
name: 'startedAt',
|
||||
title: 'Started at',
|
||||
type: 'datetime'
|
||||
},
|
||||
{
|
||||
name: 'endedAt',
|
||||
title: 'Ended at',
|
||||
type: 'datetime'
|
||||
},
|
||||
{
|
||||
name: 'mainImage',
|
||||
title: 'Main image',
|
||||
type: 'figure'
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
title: 'Categories',
|
||||
type: 'array',
|
||||
of: [{type: 'reference', to: {type: 'category'}}]
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
title: 'Body',
|
||||
type: 'projectPortableText'
|
||||
},
|
||||
{
|
||||
name: 'relatedProjects',
|
||||
title: 'Related projects',
|
||||
type: 'array',
|
||||
of: [{type: 'reference', to: {type: 'project'}}]
|
||||
}
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
publishedAt: 'publishedAt',
|
||||
slug: 'slug',
|
||||
media: 'mainImage'
|
||||
},
|
||||
prepare ({title = 'No title', publishedAt, slug, media}) {
|
||||
const dateSegment = format(publishedAt, 'YYYY/MM')
|
||||
const path = `/${dateSegment}/${slug.current}/`
|
||||
return {
|
||||
title,
|
||||
media,
|
||||
subtitle: publishedAt ? path : 'Missing publishing date'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
studio/schemas/documents/siteSettings.js
Normal file
35
studio/schemas/documents/siteSettings.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
export default {
|
||||
name: 'siteSettings',
|
||||
type: 'document',
|
||||
title: 'Site Settings',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
title: 'Description',
|
||||
description: 'Describe your portfolio for search engines and social media.'
|
||||
},
|
||||
{
|
||||
name: 'keywords',
|
||||
type: 'array',
|
||||
title: 'Keywords',
|
||||
description: 'Add keywords that describes your portfolio.',
|
||||
of: [{type: 'string'}],
|
||||
options: {
|
||||
layout: 'tags'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
type: 'reference',
|
||||
description: 'Publish an author and set a reference to them here.',
|
||||
title: 'Author',
|
||||
to: [{type: 'person'}]
|
||||
}
|
||||
]
|
||||
}
|
||||
34
studio/schemas/objects/bioPortableText.js
Normal file
34
studio/schemas/objects/bioPortableText.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
export default {
|
||||
name: 'bioPortableText',
|
||||
type: 'array',
|
||||
title: 'Excerpt',
|
||||
of: [
|
||||
{
|
||||
title: 'Block',
|
||||
type: 'block',
|
||||
styles: [{title: 'Normal', value: 'normal'}],
|
||||
lists: [],
|
||||
marks: {
|
||||
decorators: [
|
||||
{title: 'Strong', value: 'strong'},
|
||||
{title: 'Emphasis', value: 'em'},
|
||||
{title: 'Code', value: 'code'}
|
||||
],
|
||||
annotations: [
|
||||
{
|
||||
name: 'link',
|
||||
type: 'object',
|
||||
title: 'URL',
|
||||
fields: [
|
||||
{
|
||||
title: 'URL',
|
||||
name: 'href',
|
||||
type: 'url'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
34
studio/schemas/objects/figure.js
Normal file
34
studio/schemas/objects/figure.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
export default {
|
||||
name: 'figure',
|
||||
title: 'Image',
|
||||
type: 'image',
|
||||
options: {
|
||||
hotspot: true
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
title: 'Caption',
|
||||
name: 'caption',
|
||||
type: 'string',
|
||||
options: {
|
||||
isHighlighted: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'string',
|
||||
title: 'Alternative text',
|
||||
validation: Rule => Rule.error('You have to fill out the alternative text.').required(),
|
||||
description: 'Important for SEO and accessiblity.',
|
||||
options: {
|
||||
isHighlighted: true
|
||||
}
|
||||
}
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
imageUrl: 'asset.url',
|
||||
title: 'caption'
|
||||
}
|
||||
}
|
||||
}
|
||||
42
studio/schemas/objects/projectMember.js
Normal file
42
studio/schemas/objects/projectMember.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
export default {
|
||||
type: 'object',
|
||||
name: 'projectMember',
|
||||
title: 'Project Member',
|
||||
fields: [
|
||||
{
|
||||
title: 'Person',
|
||||
name: 'person',
|
||||
type: 'reference',
|
||||
to: {type: 'person'}
|
||||
},
|
||||
{
|
||||
title: 'Roles',
|
||||
name: 'roles',
|
||||
type: 'array',
|
||||
of: [{type: 'string'}],
|
||||
options: {
|
||||
layout: 'radio',
|
||||
list: [
|
||||
{title: 'Designer', value: 'designer'},
|
||||
{title: 'Developer', value: 'developer'},
|
||||
{title: 'Editor', value: 'editor'},
|
||||
{title: 'Manager', value: 'manager'}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
personName: 'person.name',
|
||||
roles: 'roles',
|
||||
media: 'person.image'
|
||||
},
|
||||
prepare (data) {
|
||||
return {
|
||||
...data,
|
||||
title: data.personName,
|
||||
subtitle: data.roles && data.roles.join('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
studio/schemas/objects/projectPortableText.js
Normal file
51
studio/schemas/objects/projectPortableText.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
export default {
|
||||
title: 'Portable Text',
|
||||
name: 'projectPortableText',
|
||||
type: 'array',
|
||||
of: [
|
||||
{
|
||||
title: 'Block',
|
||||
type: 'block',
|
||||
// Styles let you set what your user can mark up blocks with. These
|
||||
// corrensponds with HTML tags, but you can set any title or value
|
||||
// you want and decide how you want to deal with it where you want to
|
||||
// use your content.
|
||||
styles: [
|
||||
{title: 'Normal', value: 'normal'},
|
||||
{title: 'H1', value: 'h1'},
|
||||
{title: 'H2', value: 'h2'},
|
||||
{title: 'H3', value: 'h3'},
|
||||
{title: 'H4', value: 'h4'},
|
||||
{title: 'Quote', value: 'blockquote'}
|
||||
],
|
||||
lists: [{title: 'Bullet', value: 'bullet'}],
|
||||
// Marks let you mark up inline text in the block editor.
|
||||
marks: {
|
||||
// Decorators usually describe a single property – e.g. a typographic
|
||||
// preference or highlighting by editors.
|
||||
decorators: [{title: 'Strong', value: 'strong'}, {title: 'Emphasis', value: 'em'}],
|
||||
// Annotations can be any object structure – e.g. a link or a footnote.
|
||||
annotations: [
|
||||
{
|
||||
title: 'URL',
|
||||
name: 'link',
|
||||
type: 'object',
|
||||
fields: [
|
||||
{
|
||||
title: 'URL',
|
||||
name: 'href',
|
||||
type: 'url'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// You can add additional types here. Note that you can't use
|
||||
// primitive types such as 'string' and 'number' in the same array
|
||||
// as a block type.
|
||||
{
|
||||
type: 'figure'
|
||||
}
|
||||
]
|
||||
}
|
||||
39
studio/schemas/objects/simplePortableText.js
Normal file
39
studio/schemas/objects/simplePortableText.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* This is the schema definition for the rich text fields used for
|
||||
* for this blog studio. When you import it in schemas.js it can be
|
||||
* reused in other parts of the studio with:
|
||||
* {
|
||||
* name: 'someName',
|
||||
* title: 'Some title',
|
||||
* type: 'simplePortableText'
|
||||
* }
|
||||
*/
|
||||
export default {
|
||||
title: 'Portable Text',
|
||||
name: 'simplePortableText',
|
||||
type: 'array',
|
||||
of: [
|
||||
{
|
||||
title: 'Block',
|
||||
type: 'block',
|
||||
// Styles let you set what your user can mark up blocks with. These
|
||||
// corrensponds with HTML tags, but you can set any title or value
|
||||
// you want and decide how you want to deal with it where you want to
|
||||
// use your content.
|
||||
styles: [{title: 'Normal', value: 'normal'}],
|
||||
lists: [],
|
||||
// Marks let you mark up inline text in the block editor.
|
||||
marks: {
|
||||
// Decorators usually describe a single property – e.g. a typographic
|
||||
// preference or highlighting by editors.
|
||||
decorators: [
|
||||
{title: 'Strong', value: 'strong'},
|
||||
{title: 'Emphasis', value: 'em'},
|
||||
{title: 'Code', value: 'code'}
|
||||
],
|
||||
// Annotations can be any object structure – e.g. a link or a footnote.
|
||||
annotations: []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
41
studio/schemas/schema.js
Normal file
41
studio/schemas/schema.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// First, we must import the schema creator
|
||||
import createSchema from 'part:@sanity/base/schema-creator'
|
||||
|
||||
// Then import schema types from any plugins that might expose them
|
||||
import schemaTypes from 'all:part:@sanity/base/schema-type'
|
||||
|
||||
// Document types
|
||||
import category from './documents/category'
|
||||
import person from './documents/person'
|
||||
import project from './documents/project'
|
||||
import siteSettings from './documents/siteSettings'
|
||||
|
||||
// Object types
|
||||
import bioPortableText from './objects/bioPortableText'
|
||||
import figure from './objects/figure'
|
||||
import projectMember from './objects/projectMember'
|
||||
import projectPortableText from './objects/projectPortableText'
|
||||
import simplePortableText from './objects/simplePortableText'
|
||||
|
||||
// Then we give our schema to the builder and provide the result to Sanity
|
||||
export default createSchema({
|
||||
// We name our schema
|
||||
name: 'portfolio',
|
||||
// Then proceed to concatenate our our document type
|
||||
// to the ones provided by any plugins that are installed
|
||||
types: schemaTypes.concat([
|
||||
// When added to this list, object types can be used as
|
||||
// { type: 'typename' } in other document schemas
|
||||
bioPortableText,
|
||||
figure,
|
||||
projectMember,
|
||||
projectPortableText,
|
||||
simplePortableText,
|
||||
// The following are document types which will appear
|
||||
// in the studio.
|
||||
category,
|
||||
person,
|
||||
project,
|
||||
siteSettings
|
||||
])
|
||||
})
|
||||
1
studio/static/.gitkeep
Normal file
1
studio/static/.gitkeep
Normal file
|
|
@ -0,0 +1 @@
|
|||
Files placed here will be served by the Sanity server under the `/static`-prefix
|
||||
BIN
studio/static/favicon.ico
Normal file
BIN
studio/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue