Initial commit
This commit is contained in:
commit
5a3bf52ebb
86 changed files with 2639 additions and 0 deletions
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'}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue