Skip to content

Commit 34be932

Browse files
authored
Add orderable document list readme (#1508)
1 parent 1a6465d commit 34be932

1 file changed

Lines changed: 200 additions & 0 deletions

File tree

  • plugins/@sanity/orderable-document-list
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# @sanity/orderable-document-list
2+
3+
# What is it?
4+
5+
Drag-and-drop Document Ordering without leaving the Editing surface.
6+
7+
![2022-04-26 12 23 39](https://user-images.githubusercontent.com/9684022/165289621-dbd9d841-028e-40c7-be14-7398fcdb1210.gif)
8+
9+
This plugin aims to be OS-like in that you can select and move multiple documents by holding `shift` and clicking a second item, and toggling on/off selections by holding `command/control`.
10+
11+
## Requirements
12+
13+
A Sanity Studio with [Desk Structure](https://www.sanity.io/docs/structure-builder-introduction) configured:
14+
15+
```ts
16+
import {defineConfig} from 'sanity'
17+
import {structureTool, StructureBuilder} from 'sanity/structure'
18+
19+
export default defineConfig({
20+
//...
21+
plugins: [
22+
structureTool({
23+
structure: (S, context) => {
24+
/* Structure code */
25+
},
26+
}),
27+
],
28+
})
29+
```
30+
31+
## Installation
32+
33+
Run the following command in your studio directory
34+
35+
```sh
36+
npm install --save @sanity/orderable-document-list
37+
```
38+
39+
or
40+
41+
```sh
42+
yarn add @sanity/orderable-document-list
43+
```
44+
45+
## Usage
46+
47+
### 1. Import the Document List into your Desk Structure
48+
49+
The config parameter requires `type`, `S` and `context`. It also accepts `title`, `icon`, `filter` and `params`.
50+
`S` and `context` are available in desk-tool structure callback, and should be forwarded as is:
51+
52+
```ts
53+
import {defineConfig} from 'sanity'
54+
import {structureTool, StructureBuilder} from 'sanity/structure'
55+
import {orderableDocumentListDeskItem} from '@sanity/orderable-document-list'
56+
57+
export default defineConfig({
58+
//...
59+
plugins: [
60+
structureTool({
61+
structure: (S, context) => {
62+
return S.list()
63+
.title('Content')
64+
.items([
65+
// Minimum required configuration
66+
orderableDocumentListDeskItem({type: 'category', S, context}),
67+
68+
// Optional configuration
69+
orderableDocumentListDeskItem({
70+
type: 'project',
71+
title: 'Projects',
72+
icon: Paint,
73+
// Required if using multiple lists of the same 'type'
74+
id: 'orderable-en-projects',
75+
// See notes on adding a `filter` below
76+
filter: `__i18n_lang == $lang`,
77+
params: {
78+
lang: 'en_US',
79+
},
80+
createIntent: false, // do not add an option for item creation
81+
menuItems: [], // allow an array of `S.menuItem()` to be injected to orderable document list menu
82+
// pass from the structure callback params above
83+
S,
84+
context,
85+
}),
86+
87+
// ... all other desk items, e.g. all other document types not already included
88+
// @see https://www.sanity.io/docs/studio/structure-builder-cheat-sheet#k4eb3b1891dc2
89+
...S.documentTypeListItems().filter((item) => !(['category', 'project'].includes(item.getId())))
90+
])
91+
},
92+
}),
93+
],
94+
})
95+
```
96+
97+
**Caution: Adding a `filter`**
98+
99+
By default, the plugin will display _all_ documents of the same `type`. However, you may wish to add a `filter` to reduce this down to a subset of documents. A typical usecase is for [internationalized document schema](https://github.com/sanity-io/document-internationalization) to order documents of just the base language version.
100+
101+
However, order ranks are still computed based on _all_ documents of the same `type`. Creating multiple lists with different `filter` settings could produce unexpected results.
102+
103+
### 2. Add the `orderRank` field to your schema(s).
104+
105+
You must pass in the `type` of the schema and the schema `context`, to create an `initialValue` value.
106+
Context is available in the schema callback, and should be forwarded as is.
107+
108+
Additionally, pass in overrides for the field, such as making it visible by passing `hidden: false`.
109+
110+
You cannot override the `name`, `type` or `initialValue` attributes.
111+
112+
You can configure the placement of new documents by setting `newItemPosition` to `before` (defaults to `after`).
113+
114+
```js
115+
// sanity.config.js
116+
import {defineConfig} from "sanity";
117+
import {structureTool, StructureBuilder} from "sanity/structure";
118+
import {orderRankField, orderRankOrdering} from '@sanity/orderable-document-list'
119+
120+
export default defineConfig({
121+
//...
122+
plugins: [
123+
structureTool({structure: (S, context) => {/* snip */}})
124+
],
125+
schema: {
126+
types: (previousTypes) => {
127+
return [
128+
...previousTypes,
129+
{
130+
name: "category",
131+
title: "Category",
132+
type: "document",
133+
// Optional: The plugin also exports a set of 'orderings' for use in other Document Lists
134+
// https://www.sanity.io/docs/sort-orders
135+
orderings: [orderRankOrdering],
136+
fields: [
137+
// Minimum required configuration
138+
orderRankField({ type: "category" }),
139+
140+
// OR placing new documents on top
141+
orderRankField({ type: "category", newItemPosition: "before" }),
142+
143+
// OR you can override _some_ of the field settings
144+
orderRankField({ type: "category", hidden: false }),
145+
146+
// ...all other fields
147+
],
148+
},
149+
]
150+
}
151+
}
152+
}
153+
```
154+
155+
### 3. Generate initial Ranks
156+
157+
On first load, your Document list will not have any Order. You can select "Reset Order" from the menu in the top right of the list.
158+
You can also re-run this at any time.
159+
160+
The `orderRankField` will query the last/first Document to set an `initialValue` to come after/before it.
161+
The placement of new documents can be configured by `newItemPosition` on the `orderRankField` in the document.
162+
163+
## Querying Ordered Documents
164+
165+
Now when writing a GROQ Query for Documents, use the `orderRank` field value to return ordered results:
166+
167+
```groq
168+
*[_type == "category"]|order(orderRank)
169+
```
170+
171+
If fetching documents using [the `document-internationalization` plugin](https://github.com/sanity-io/document-internationalization), you may want to sort by the rank of the base document when the document is not in the base language, so all locales share the same order. When changing the order of documents using this plugin, the `orderRank` field of documents in alternate locales won't be updated. The query below ensures a consistent order for documents in the base language and in alternate languages.
172+
173+
```groq
174+
*[_type == "category" && __i18n_lang == $lang]|order(coalesce(__i18n_base->orderRank, orderRank))
175+
```
176+
177+
## Notes
178+
179+
To get this first version out the door there are few configuration settings and a lot of opinions. Such as:
180+
181+
- The `name` of the `orderRank` field is constant
182+
- The ability to only sort across _all_ Documents of a `type`
183+
184+
Feedback and PRs welcome :)
185+
186+
### Breaking change in the v3 version
187+
188+
`orderableDocumentListDeskItem` requires context from sanity config now.
189+
See the examples above.
190+
191+
## How it works
192+
193+
Uses [kvandakes](https://github.com/kvandake)'s [TypeScript implementation](https://github.com/kvandake/lexorank-ts) of [Jira's Lexorank](https://www.youtube.com/watch?v=OjQv9xMoFbg) to create a "lexographical" Document order.
194+
195+
Put simply it updates the position of an individual – or many – Documents in an ordered list without updating any others. It's fast.
196+
197+
198+
## License
199+
200+
[MIT](LICENSE) © Sanity.io

0 commit comments

Comments
 (0)