Skip to content

Commit

Permalink
feat(cli): add new dashboard template (#3430)
Browse files Browse the repository at this point in the history
Co-authored-by: Victoria Bergquist <victoria.bergquist@gmail.com>
Co-authored-by: Fred Carlsen <fred@sjelfull.no>
  • Loading branch information
3 people committed Aug 12, 2022
1 parent 20e26d8 commit 09f10a9
Show file tree
Hide file tree
Showing 104 changed files with 2,878 additions and 83 deletions.
1 change: 1 addition & 0 deletions .module-aliases.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
'@sanity/base': './packages/@sanity/base/src/_exports',

'@sanity/desk-tool': './packages/@sanity/desk-tool/src/_exports',
'@sanity/dashboard': './packages/@sanity/dashboard/src',

'@sanity/schema': './packages/@sanity/schema/src/_exports',

Expand Down
1 change: 1 addition & 0 deletions packages/@sanity/cli/.depcheckignore.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"@sanity/base",
"@sanity/color",
"@sanity/desk-tool",
"@sanity/dashboard",
"@sanity/form-builder",
"@sanity/icons",
"@sanity/types",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export const datasetUrl = 'https://public.sanity.io/pets-example-dataset-2022-06-20.tar.gz'
export const dependencies = {
'sanity-plugin-asset-source-unsplash': '^0.2.1',
'sanity-plugin-media': '^1.4.10',
'@sanity/icons': '^1.2.6',
'@portabletext/react': '^1.0.6',
'react-fast-compare': '^3.2.0',
'@sanity/dashboard': '^2.30.3',
rxjs: '^6.5.3',
}

export const generateSanityManifest = (base) => ({
...base,
plugins: ['@sanity/dashboard'].concat(base.plugins.concat(['asset-source-unsplash', 'media'])),
parts: [
{
implements: 'part:@sanity/dashboard/config',
path: './dashboardConfig.js',
},
{
name: 'part:@sanity/dashboard/widget/new-document-list',
implements: 'part:@sanity/dashboard/widget',
path: './widgets/new-document-list/DocumentList',
},
{
name: 'part:@sanity/base/schema',
path: './schemas/schema',
},
{
name: 'part:@sanity/desk-tool/structure',
path: './deskStructure.js',
},
{
implements: 'part:@sanity/base/brand-logo',
path: './components/logo/petsProjectLogo.jsx',
},
{
implements: 'part:@sanity/base/theme/variables/override-style',
path: './style.css',
},
],
})
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const dependencies = {
export const generateSanityManifest = (base) => ({
...base,
plugins: base.plugins.concat(['asset-source-unsplash', 'media']),

parts: [
{
name: 'part:@sanity/base/schema',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
clean: require('./clean'),
'get-started': require('./get-started'),
'getting-started-pets': require('./getting-started-pets'),
'getting-started-dashboard': require('./getting-started-dashboard'),
moviedb: require('./moviedb'),
ecommerce: require('./ecommerce'),
shopify: require('./shopify'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Logs
/logs
*.log

# Coverage directory used by tools like istanbul
/coverage

# Dependency directories
node_modules

# Compiled sanity studio
/dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Logs
/logs
*.log

# Coverage directory used by tools like istanbul
/coverage

# Dependency directories
node_modules

# Compiled sanity studio
/dist
61 changes: 61 additions & 0 deletions packages/@sanity/cli/templates/getting-started-dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Sanity 🐶🐱 Pets\*Project

Congratulations, you have now installed the template 🐶🐱 Pets\*Project studio, an open source real-time content editing environment connected to the Sanity backend.

If you want to explore more:

- [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme)
- [Join the community Slack](https://slack.sanity.io/?utm_source=readme)
- [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme)

## Features

Here are some features that we already have set up so you can explore at your own pace:

### Customised document previews

You can quickly and visually test the data that will be used by the front end directly in the studio. ([documentation](https://www.sanity.io/blog/evolve-authoring-experiences-with-views-and-split-panes))

<p align="center">
<img alt="studio preview for a pet called Sarabi and a small description about them" src="static/readMeImages/PetPreview.png" width="400" height="320">
</p>

### References input

You can edit (and create) documents from a different document with a different schema (for example, you can create a `human` and assign it immediately to a `pet` that you were already editing! ) ([documentation](https://www.sanity.io/docs/reference-type))

<p align="center">
<img alt="reference input that shows one human (Oksana) with the preview of the number of pets they own" src="static/readMeImages/ReferenceInput.png" width="400" height="90">
</p>

### Image input - crop and hotspot (and how that affects different elements)

With the hotspot and crop tool in the image input you can very quickly narrow down to which part of the image you want to focus on without having to upload different assets ([documentation](https://www.sanity.io/docs/image-type#hotspot-3e6da78954a8))

<p align="center">
<img alt="displays two cat pictures with different dimensions, focused on a Twitter header on mobile versus the same header on desktop" src="static/readMeImages/ImageInput.png" width="400" height="450">
</p>

### Image input

Use the Unsplash and Media browser plugins from the start!

You can test out how the Unsplash and Media browser plugins are used and explore how to use them ([documentation](https://www.sanity.io/plugins?category=assetSource))

<p align="center">
<img alt="image input with a dropdown list that shows options for different asset sources: including unsplashed and media" src="static/readMeImages/AssetSource.png" width="400" height="250">
</p>

### Array input types

You can see how the array inputs were used (in conjunction with references in places) and how we were able to use them in the previews by using GROQ ([documentation](https://www.sanity.io/docs/array-type))

<p align="center">
<img alt="array input with a list of favourite toys with a preview of the range of their prices" src="static/readMeImages/ArrayInput.png" width="400" height="200">
</p>

### GROQ

GROQ is Sanity's open-source query language. It's a powerful and intuitive language that's easy to learn. ([documentation](https://www.sanity.io/docs/how-queries-work))

See how we've used GROQ in the previews to fetch data and how we've read it on the rendering of the component. In the examples, we make sure that you can not only fetch the last published version but the drafts that haven't been published as well ([documentation](https://www.sanity.io/docs/query-cheat-sheet))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {DocumentTextIcon} from '@sanity/icons'
import React from 'react'

const articleIcon = () => <DocumentTextIcon />

export default articleIcon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {UserIcon} from '@sanity/icons'
import React from 'react'

const humanIcon = () => <UserIcon />

export default humanIcon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {HeartIcon} from '@sanity/icons'
import React from 'react'

const petIcon = () => <HeartIcon />

export default petIcon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
import {BottleIcon} from '@sanity/icons'

const productIcon = () => <BottleIcon />

export default productIcon
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, {forwardRef} from 'react'
import {FormField} from '@sanity/base/components'
import PatchEvent, {set, unset} from '@sanity/form-builder/PatchEvent'
import {TextArea, Flex, Text, Stack} from '@sanity/ui'
import PropTypes from 'prop-types'

/**
* ## What does it do
* Renders character count under a string field.
*
* This is a minor extension to the FormField example in the docs:
* https://www.sanity.io/docs/custom-input-widgets#8d6dac48f8fd
*
* ## Usage
*
* {
* type: 'string',
* name: 'myStringField',
* inputComponent: CharacterCount
* }
*/
export const CharacterCount = forwardRef(function CharacterCount(props, ref) {
const {
type, // Schema information
value, // Current field value
readOnly, // Boolean if field is not editable
placeholder, // Placeholder text from the schema
markers, // Markers including validation rules
presence, // Presence information for collaborative avatars
onFocus, // Method to handle focus state
onBlur, // Method to handle blur state
onChange,
} = props

const handleChange = React.useCallback(
(event) => {
const inputValue = event.currentTarget.value
onChange(PatchEvent.from(inputValue ? set(inputValue) : unset()))
},
[onChange]
)

return (
<FormField
description={type.description} // Creates description from schema
title={type.title} // Creates label from schema title
__unstable_markers={markers} // Handles all markers including validation
__unstable_presence={presence} // Handles presence avatars
>
<Stack space={2}>
<TextArea
value={value ? value : ''} // Current field value
readOnly={readOnly} // If "readOnly" is defined make this field read only
placeholder={placeholder} // If placeholder is defined, display placeholder text
onFocus={onFocus} // Handles focus events
onBlur={onBlur} // Handles blur events
ref={ref}
onChange={handleChange} // A function to call when the input value changes
/>

<Flex>
<Text muted size={1}>
Character count: {value ? value.length : 0}
</Text>
</Flex>
</Stack>
</FormField>
)
})

CharacterCount.propTypes = {
onChange: PropTypes.func,
type: PropTypes.object,
value: PropTypes.string,
markers: PropTypes.array,
presence: PropTypes.array,
readOnly: PropTypes.bool,
placeholder: PropTypes.string,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, {forwardRef, useCallback, useEffect, useState} from 'react'
import {Flex} from '@sanity/ui'
import {FormField} from '@sanity/base/components'
import * as Patches from '@sanity/form-builder/lib/patch/patches'
import PatchEvent from '@sanity/form-builder/lib/PatchEvent'
import PropTypes from 'prop-types'
import {useDebouncedEffect} from '../../helpers/debounce-hooks'

/**
* ## What does it do
* Renders a number input as a slider with min and max values, and a step.
*
* ## Usage
*
* {
* type: 'number'
* name: 'myNumberField',
* inputComponent: RangeInput
* options: {
* rang:e {
* min: 0,
* max: 1,
* step: 0.1
* }
* }
* }
*/

export const RangeInput = forwardRef(function RangeInput(props, ref) {
const {type, markers, presence, onChange, value: receivedValue} = props
const {range} = type.options || {}
const {min = 0, max = 100, step = 1} = range || {}
const value = receivedValue ?? min
const [visibleValue, setVisibleValue] = useState(value)

// This updates the visible value if a patch is received after component is mounted
useEffect(() => setVisibleValue(value), [value])

const handleChange = useCallback(
(newValue) => {
// Trigger patch only if new value is different from current value.
// This prevents unnecessary saving when you load a draft document
newValue !== value && onChange(PatchEvent.from(Patches.set(newValue)))
},
[onChange, value]
)

const handleInputChange = useCallback((event) => {
const target = event.currentTarget
const number = Number(target.value)
if (isNaN(number) || !target.validity.valid) {
return
}
setVisibleValue(number)
}, [])

// Debounce patching when visibleValue changes. This allows you to drag the slider without firing multiple patches
useDebouncedEffect(
() => {
handleChange(visibleValue)
},
[visibleValue],
500
)

const maxAndDecimals = max + step

return (
<FormField
title={type.title}
description={type.description}
__unstable_markers={markers}
__unstable_presence={presence}
>
<Flex gap={2} paddingTop={1} paddingBottom={1}>
<Flex style={{position: 'relative'}}>
<div style={{position: 'absolute', left: 0}}>{visibleValue}</div>
{/*Need this to prevent things from jumping around as the value goes from low to high*/}
<div aria-hidden={true} style={{visibility: 'hidden'}}>
{maxAndDecimals}
</div>
</Flex>
<Flex flex={1}>
<input
style={{width: '100%'}}
type="range"
min={min}
max={max}
step={step}
ref={ref}
value={visibleValue}
onChange={handleInputChange}
/>
</Flex>
</Flex>
</FormField>
)
})

RangeInput.propTypes = {
onChange: PropTypes.func,
type: PropTypes.object,
value: PropTypes.number,
markers: PropTypes.array,
presence: PropTypes.array,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import {Heading} from '@sanity/ui'

// This custom logo is using components from Sanity UI,
// Sanity's interface library. You can find its documentation under:
// https://www.sanity.io/ui

const petsProjectLogo = () => <Heading size={1}>🐶🐱 Pets*Project</Heading>

export default petsProjectLogo

2 comments on commit 09f10a9

@vercel
Copy link

@vercel vercel bot commented on 09f10a9 Aug 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

studio-workshop – ./

studio-workshop-git-next.sanity.build
studio-workshop.sanity.build

@vercel
Copy link

@vercel vercel bot commented on 09f10a9 Aug 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-studio – ./

test-studio-git-next.sanity.build
test-studio.sanity.build

Please sign in to comment.