New design for the widgets section in the docs (#866)

* Initial commit for the new widgets section

* Placing all the widgets and refining the CSS and Hugo logic

* Initial commit for the new widgets section

* Placing all the widgets and refining the CSS and Hugo logic

* Rebased and updated the info according to @verythorough contribution

* Fixing the yaml codes for the relation and select widget sections

* Merging with widgets.md and app.j

* Fixing some silly mistakes (sorry!)

* Following @verythorough contributions :)

* Adding the markdown widget and fixing the widgets container background

* Adding the URL functionality and myself as a contributor :)

* Adding myself as a contributor :)
This commit is contained in:
Henrique Cavalieri 2018-01-03 20:14:15 -02:00 committed by Caleb
parent 4515eddbc4
commit 1167f27939
25 changed files with 567 additions and 312 deletions

View File

@ -448,6 +448,15 @@
"contributions": [
"doc"
]
},
{
"login": "hcavalieri",
"name": "Henrique Cavalieri",
"avatar_url": "https://avatars0.githubusercontent.com/u/27744332?v=4",
"profile": "https://kaordica.com.br",
"contributions": [
"doc"
]
}
]
}

View File

@ -1,5 +1,5 @@
# Netlify CMS
[![All Contributors](https://img.shields.io/badge/all_contributors-55-orange.svg)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-56-orange.svg)](#contributors)
[![](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/netlify/netlifycms)
A CMS for static site generators. Give non-technical users a simple way to edit
@ -56,7 +56,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
| [<img src="https://avatars3.githubusercontent.com/u/4349324?v=4" width="100px;"/><br /><sub><b>Benjamin Kniffler</b></sub>](https://github.com/bkniffler)<br /> | [<img src="https://avatars1.githubusercontent.com/u/845983?v=4" width="100px;"/><br /><sub><b>Mike Wickett</b></sub>](http://www.wickett.ca)<br /> | [<img src="https://avatars1.githubusercontent.com/u/2751799?v=4" width="100px;"/><br /><sub><b>Rory Claasen</b></sub>](http://roryclaasen.me)<br /> | [<img src="https://avatars3.githubusercontent.com/u/724844?v=4" width="100px;"/><br /><sub><b>Frederic Brodbeck</b></sub>](http://www.freder.io/)<br /> | [<img src="https://avatars2.githubusercontent.com/u/1245746?v=4" width="100px;"/><br /><sub><b>Stuart Dum</b></sub>](https://github.com/simplystuart)<br /> | [<img src="https://avatars0.githubusercontent.com/u/8184251?v=4" width="100px;"/><br /><sub><b>Ryan Watters</b></sub>](https://github.com/rdwatters)<br /> | [<img src="https://avatars3.githubusercontent.com/u/4315?v=4" width="100px;"/><br /><sub><b>Helder S Ribeiro</b></sub>](https://twitter.com/hsribei)<br /> |
| [<img src="https://avatars1.githubusercontent.com/u/979966?v=4" width="100px;"/><br /><sub><b>Artem Govorov</b></sub>](http://dm.gl)<br /> | [<img src="https://avatars3.githubusercontent.com/u/2683300?v=4" width="100px;"/><br /><sub><b>Cédric Delpoux</b></sub>](http://xuopled.netlify.com/)<br /> | [<img src="https://avatars3.githubusercontent.com/u/83225?v=4" width="100px;"/><br /><sub><b>imorente</b></sub>](https://github.com/imorente)<br /> | [<img src="https://avatars3.githubusercontent.com/u/5230460?v=4" width="100px;"/><br /><sub><b>David Francoeur</b></sub>](http://davidfrancoeur.com)<br /> | [<img src="https://avatars3.githubusercontent.com/u/1954977?v=4" width="100px;"/><br /><sub><b>Rusta</b></sub>](https://github.com/Rusta)<br /> | [<img src="https://avatars1.githubusercontent.com/u/1299786?v=4" width="100px;"/><br /><sub><b>Henrik Lau Eriksson</b></sub>](http://henrik.laueriksson.com)<br /> | [<img src="https://avatars0.githubusercontent.com/u/1294877?v=4" width="100px;"/><br /><sub><b>Kraig Walker</b></sub>](https://www.kraigwalker.com)<br /> |
| [<img src="https://avatars1.githubusercontent.com/u/2994311?v=4" width="100px;"/><br /><sub><b>Rich Cook</b></sub>](http://www.TalesofMurder.com)<br /> | [<img src="https://avatars3.githubusercontent.com/u/1309950?v=4" width="100px;"/><br /><sub><b>Damien Van Der Windt</b></sub>](https://github.com/damienvdw)<br /> | [<img src="https://avatars2.githubusercontent.com/u/1571899?v=4" width="100px;"/><br /><sub><b>Matt Jared</b></sub>](http://mattjared.github.io/)<br /> | [<img src="https://avatars1.githubusercontent.com/u/1100280?v=4" width="100px;"/><br /><sub><b>bruce-one</b></sub>](https://github.com/bruce-one)<br /> | [<img src="https://avatars3.githubusercontent.com/u/103008?v=4" width="100px;"/><br /><sub><b>Frank Taillandier</b></sub>](https://frank.taillandier.me)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=DirtyF "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/2936813?v=4" width="100px;"/><br /><sub><b>Aquib Master</b></sub>](http://aquibm.com/)<br />[💻](https://github.com/netlify/netlify-cms/commits?author=aquibm "Code") | [<img src="https://avatars0.githubusercontent.com/u/3147296?v=4" width="100px;"/><br /><sub><b>Eric Jinks</b></sub>](http://ericjinks.com)<br />[💻](https://github.com/netlify/netlify-cms/commits?author=Jinksi "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/784848?v=4" width="100px;"/><br /><sub><b>Tony Alves</b></sub>](https://github.com/talves)<br />[💻](https://github.com/netlify/netlify-cms/commits?author=talves "Code") | [<img src="https://avatars3.githubusercontent.com/u/782?v=4" width="100px;"/><br /><sub><b>Ernie Bello</b></sub>](http://ern.me)<br />[🐛](https://github.com/netlify/netlify-cms/issues?q=author%3Aebello "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/6202476?v=4" width="100px;"/><br /><sub><b>Alexander Kushi-Willis</b></sub>](https://ackushiw.com)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=ackushiw "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/54089?v=4" width="100px;"/><br /><sub><b>Igor Kuznetsov</b></sub>](http://www.igk.ru)<br />[🐛](https://github.com/netlify/netlify-cms/issues?q=author%3Aigk1972 "Bug reports") [💻](https://github.com/netlify/netlify-cms/commits?author=igk1972 "Code") [🔌](#plugin-igk1972 "Plugin/utility libraries") | [<img src="https://avatars2.githubusercontent.com/u/1312538?v=4" width="100px;"/><br /><sub><b>Tim Erickson</b></sub>](http://neutyp.com)<br />[🎨](#design-neutyp "Design") | [<img src="https://avatars0.githubusercontent.com/u/871552?v=4" width="100px;"/><br /><sub><b>David Jones</b></sub>](http://davidejones.com)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=davidejones "Documentation") |
| [<img src="https://avatars3.githubusercontent.com/u/784848?v=4" width="100px;"/><br /><sub><b>Tony Alves</b></sub>](https://github.com/talves)<br />[💻](https://github.com/netlify/netlify-cms/commits?author=talves "Code") | [<img src="https://avatars3.githubusercontent.com/u/782?v=4" width="100px;"/><br /><sub><b>Ernie Bello</b></sub>](http://ern.me)<br />[🐛](https://github.com/netlify/netlify-cms/issues?q=author%3Aebello "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/6202476?v=4" width="100px;"/><br /><sub><b>Alexander Kushi-Willis</b></sub>](https://ackushiw.com)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=ackushiw "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/54089?v=4" width="100px;"/><br /><sub><b>Igor Kuznetsov</b></sub>](http://www.igk.ru)<br />[🐛](https://github.com/netlify/netlify-cms/issues?q=author%3Aigk1972 "Bug reports") [💻](https://github.com/netlify/netlify-cms/commits?author=igk1972 "Code") [🔌](#plugin-igk1972 "Plugin/utility libraries") | [<img src="https://avatars2.githubusercontent.com/u/1312538?v=4" width="100px;"/><br /><sub><b>Tim Erickson</b></sub>](http://neutyp.com)<br />[🎨](#design-neutyp "Design") | [<img src="https://avatars0.githubusercontent.com/u/871552?v=4" width="100px;"/><br /><sub><b>David Jones</b></sub>](http://davidejones.com)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=davidejones "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/27744332?v=4" width="100px;"/><br /><sub><b>Henrique Cavalieri</b></sub>](https://kaordica.com.br)<br />[📖](https://github.com/netlify/netlify-cms/commits?author=hcavalieri "Documentation") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View File

@ -17,7 +17,7 @@ To see working examples of all of the built-in widgets, try making a 'Kitchen Si
The following options are available on all fields:
- `required`: specify as `false` to make a field optional; defaults to `true`
- `pattern`: add field validation by specifying a list with a regex pattern and an error message; more extensive validation can be achieved with [custom widgets](https://www.netlifycms.org/docs/custom-widgets/#advanced-field-validation)
- `pattern`: add field validation by specifying a list with a [regex pattern](https://regexr.com/) and an error message; more extensive validation can be achieved with [custom widgets](https://www.netlifycms.org/docs/custom-widgets/#advanced-field-validation)
- **Example:**
```yaml
@ -27,310 +27,4 @@ The following options are available on all fields:
pattern: ['.{10,}', "Must have at least 20 characters"]
```
## Boolean
The boolean widget translates a toggle switch input to a true/false value.
- **Name:** `boolean`
- **UI:** toggle switch
- **Data type:** boolean
- **Options:**
- `default`: accepts `true` or `false`; defaults to `false`
- **Example:**
```yaml
- {label: "Draft", name: "draft", widget: "boolean", default: true}
```
## Date
The date widget translates a date picker input to a date string. For saving date and time together, use the [DateTime](#datetime) widget.
- **Name:** `date`
- **UI:** date picker
- **Data type:** Moment.js-formatted date string
- **Options:**
- `default`: accepts a date string, or an empty string to accept blank input; otherwise defaults to current date
- `format`: accepts Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/); defaults to ISO8601 format `YYYY-MM-DD`
- **Example:**
```yaml
- label: "Birthdate"
name: "birthdate"
widget: "date"
default: ""
format: "MMM Do YY"
```
## DateTime
The datetime widget translates a datetime picker to a datetime string. For saving the date only, use the [Date](#date) widget.
- **Name:** `datetime`
- **UI:** datetime picker
- **Data type:** Moment.js-formatted datetime string
- **Options:**
- `default`: accepts a datetime string, or an empty string to accept blank input; otherwise defaults to current datetime
- `format`: accepts Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/); defaults to ISO8601 format `YYYY-MM-DDTHH:mm:ssZ`
- **Example:**
```yaml
- label: "Start time"
name: "start"
widget: "datetime"
default: ""
format: "LLL"
```
## File
The file widget allows editors to upload a file or select an existing one from the media library. The path to the file will be saved to the field as a string.
- **Name:** `file`
- **UI:** file picker button opens media gallery
- **Data type:** file path string, based on `media_folder`/`public_folder` configuration
- **Options:**
- `default`: accepts a file path string; defaults to null
- **Example:**
```yaml
- label: "Manual PDF"
name: "manual_pdf"
widget: "file"
default: "/uploads/general-manual.pdf"
```
## Hidden
Hidden widgets do not display in the UI. In folder collections that allow users to create new items, you will often want to set a default for hidden fields, so they will be set without requiring an input.
- **Name:** `hidden`
- **UI:** none
- **Data type:** any valid data type
- **Options:**
- `default`: accepts any valid data type; recommended for collections that allow adding new items
- **Example:**
```yaml
- {label: "Layout", name: "layout", widget: "hidden", default: "blog"}
```
## Image
The image widget allows editors to upload an image or select an existing one from the media library. The path to the image file will be saved to the field as a string.
- **Name:** `image`
- **UI:** file picker button opens media gallery allowing image files (jpg, jpeg, webp, gif, png, bmp, tiff, svg) only; displays selected image thumbnail
- **Data type:** file path string, based on `media_folder`/`public_folder` configuration
- **Options:**
- `default`: accepts a file path string; defaults to null
- **Example:**
```yaml
- label: "Featured Image"
name: "thumbnail"
widget: "image"
default: "/uploads/chocolate-dogecoin.jpg"
```
## List
The list widget allows you to create a repeatable item in the UI which saves as a list of widget values. map a user-provided string with a comma delimiter into a list. You can choose any widget as a child of a list widget—even other lists.
- **Name:** `list`
- **UI:** if `fields` is specified, field containing a repeatable child widget, with controls for adding, deleting, and re-ordering the repeated widgets; if unspecified, a text input for entering comma-separated values
- **Data type:** list of widget values
- **Options:**
- `default`: if `fields` is specified, declare defaults on the child widgets; if not, you may specify a list of strings to populate the text field
- `field`: a single widget field to be repeated
- `fields`: a nested list of multiple widget fields to be included in each repeatable iteration
- **Example** (`field`/`fields` not specified):
```yaml
- label: "Tags"
name: "tags"
widget: "list"
default: ["news"]
```
- **Example** (with `field`):
```yaml
- label: "Gallery"
name: "galleryImages"
widget: "list"
field:
- {label: Image, name: image, widget: image}
```
- **Example** (with `fields`):
```yaml
- label: "Testimonials"
name: "testimonials"
widget: "list"
fields:
- {label: Quote, name: quote, widget: string, default: "Everything is awesome!"}
- label: Author
name: author
widget: object
fields:
- {label: Name, name: name, widget: string, default: "Emmet"}
- {label: Avatar, name: avatar, widget: image, default: "/img/emmet.jpg"}
```
## Number
The number widget uses an HTML number input, saving the value as a string, integer, or floating point number.
- **Name:** `number`
- **UI:** HTML [number input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number)
- **Data type:** string by default; configured by `valueType` option
- **Options:**
- `default`: accepts string or number value; defaults to empty string
- `valueType`: accepts `int` or `float`; any other value results in saving as a string
- `min`: accepts a number for minimum value accepted; unset by default
- `max`: accepts a number for maximum value accepted; unset by default
- **Example:**
```yaml
- label: "Puppy Count"
name: "puppies"
widget: "number"
default: 2
valueType: "int"
min: 1
max: 101
```
## Object
The object widget allows you to group multiple widgets together, nested under a single field. You can choose any widget as a child of an object widget—even other objects.
- **Name:** `object`
- **UI:** a field containing one or more child widgets
- **Data type:** list of child widget values
- **Options:**
- `default`: you can set defaults within each sub-field's configuration
- `fields`: (**required**) a nested list of widget fields to include in your widget
- **Example:**
```yaml
- label: "Profile"
name: "profile"
widget: "object"
fields:
- {label: "Public", name: "public", widget: "boolean", default: true}
- {label: "Name", name: "name", widget: "string"}
- label: "Birthdate"
name: "birthdate"
widget: "date"
default: ""
format: "MM/DD/YYYY"
- label: "Address"
name: "address"
widget: "object"
fields:
- {label: "Street Address", name: "street", widget: "string"}
- {label: "City", name: "city", widget: "string"}
- {label: "Postal Code", name: "post-code", widget: "string"}
```
## Relation
The relation widget allows you to reference items from another collection. It provides a search input with a list of entries from the collection you're referencing, and the list automatically updates with matched entries based on what you've typed.
- **Name:** `relation`
- **UI:** text input with search result dropdown
- **Data type:** data type of the value pulled from the related collection item
- **Options:**
- `default`: accepts any widget data type; defaults to an empty string
- `collection`: (**required**) name of the collection being referenced (string)
- `searchFields`: (**required**) list of one or more names of fields in the referenced collection to search for the typed value
- `valueField`: (**required**) name of the field from the referenced collection whose value will be stored for the relation
- **Example** (assuming a separate "authors" collection with "name" and "twitterHandle" fields):
```yaml
- label: Post Author
name: author
widget: relation
collection: authors
searchFields: [name, twitterHandle]
valueField: name
```
The generated UI input will search the authors collection by name and twitterHandle as the user types. On selection, the author name will be saved for the field.
## Select
The select widget allows you to pick a single string value from a dropdown menu.
- **Name:** `select`
- **UI:** HTML select input
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- `options`: (**required**) a list of options for the dropdown menu; can be listed in two ways:
- string values: the label displayed in the dropdown is the value saved in the file
- object with `label` and `value` fields: the label displays in the dropdown; the value is saved in the file
- **Example** (options as strings):
```yaml
- label: "Align Content"
name: "align"
widget: "select"
options: ["left", "center", "right"]
```
- **Example** (options as objects):
```yaml
- label: "City"
name: "airport-code"
widget: "select"
options:
- { label: "Chicago", value: "ORD" }
- { label: "Paris", value: "CDG" }
- { label: "Tokyo", value: "HND" }
```
## String
The string widget translates a basic text input to a string value. For larger textarea inputs, use the [text](#text) widget.
- **Name:** `string`
- **UI:** text input
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- **Example:**
```yaml
- {label: "Title", name: "title", widget: "string"}
```
## Text
The text widget takes a multiline text field and saves it as a string. For shorter text inputs, use the [string](#string) widget.
- **Name:** `text`
- **UI:** HTML textarea
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- **Example:**
```yaml
- {label: "Description", name: "description", widget: "text"}
```
## Default widgets

View File

@ -0,0 +1,20 @@
---
label: "Boolean"
target: "boolean"
type: "widget"
---
### Boolean
The boolean widget translates a toggle switch input to a true/false value.
- **Name:** `boolean`
- **UI:** toggle switch
- **Data type:** boolean
- **Options:**
- `default`: accepts `true` or `false`; defaults to `false`
- **Example:**
```yaml
- {label: "Draft", name: "draft", widget: "boolean", default: true}
```

View File

@ -0,0 +1,25 @@
---
label: "Date"
target: "date"
type: "widget"
---
### Date
The date widget translates a date picker input to a date string. For saving date and time together, use the datetime widget.
- **Name:** `date`
- **UI:** date picker
- **Data type:** Moment.js-formatted date string
- **Options:**
- `default`: accepts a date string, or an empty string to accept blank input; otherwise defaults to current date
- `format`: accepts Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/); defaults to ISO8601 format `YYYY-MM-DD`
- **Example:**
```yaml
- label: "Birthdate"
name: "birthdate"
widget: "date"
default: ""
format: "MMM Do YY"
```

View File

@ -0,0 +1,25 @@
---
label: "DateTime"
target: "datetime"
type: "widget"
---
### DateTime
The datetime widget translates a datetime picker to a datetime string. For saving the date only, use the date widget.
- **Name:** `datetime`
- **UI:** datetime picker
- **Data type:** Moment.js-formatted datetime string
- **Options:**
- `default`: accepts a datetime string, or an empty string to accept blank input; otherwise defaults to current datetime
- `format`: accepts Moment.js [tokens](https://momentjs.com/docs/#/parsing/string-format/); defaults to ISO8601 format `YYYY-MM-DDTHH:mm:ssZ`
- **Example:**
```yaml
- label: "Start time"
name: "start"
widget: "datetime"
default: ""
format: "LLL"
```

View File

@ -0,0 +1,23 @@
---
label: "File"
target: "file"
type: "widget"
---
### File
The file widget allows editors to upload a file or select an existing one from the media library. The path to the file will be saved to the field as a string.
- **Name:** `file`
- **UI:** file picker button opens media gallery
- **Data type:** file path string, based on `media_folder`/`public_folder` configuration
- **Options:**
- `default`: accepts a file path string; defaults to null
- **Example:**
```yaml
- label: "Manual PDF"
name: "manual_pdf"
widget: "file"
default: "/uploads/general-manual.pdf"
```

View File

@ -0,0 +1,20 @@
---
label: "Hidden"
target: "hidden"
type: "widget"
---
### Hidden
Hidden widgets do not display in the UI. In folder collections that allow users to create new items, you will often want to set a default for hidden fields, so they will be set without requiring an input.
- **Name:** `hidden`
- **UI:** none
- **Data type:** any valid data type
- **Options:**
- `default`: accepts any valid data type; recommended for collections that allow adding new items
- **Example:**
```yaml
- {label: "Layout", name: "layout", widget: "hidden", default: "blog"}
```

View File

@ -0,0 +1,23 @@
---
label: "Image"
target: "image"
type: "widget"
---
### Image
The image widget allows editors to upload an image or select an existing one from the media library. The path to the image file will be saved to the field as a string.
- **Name:** `image`
- **UI:** file picker button opens media gallery allowing image files (jpg, jpeg, webp, gif, png, bmp, tiff, svg) only; displays selected image thumbnail
- **Data type:** file path string, based on `media_folder`/`public_folder` configuration
- **Options:**
- `default`: accepts a file path string; defaults to null
- **Example:**
```yaml
- label: "Featured Image"
name: "thumbnail"
widget: "image"
default: "/uploads/chocolate-dogecoin.jpg"
```

View File

@ -0,0 +1,51 @@
---
label: "List"
target: "list"
type: "widget"
---
### List
The list widget allows you to create a repeatable item in the UI which saves as a list of widget values. map a user-provided string with a comma delimiter into a list. You can choose any widget as a child of a list widget—even other lists.
- **Name:** `list`
- **UI:** if `fields` is specified, field containing a repeatable child widget, with controls for adding, deleting, and re-ordering the repeated widgets; if unspecified, a text input for entering comma-separated values
- **Data type:** list of widget values
- **Options:**
- `default`: if `fields` is specified, declare defaults on the child widgets; if not, you may specify a list of strings to populate the text field
- `field`: a single widget field to be repeated
- `fields`: a nested list of multiple widget fields to be included in each repeatable iteration
- **Example** (`field`/`fields` not specified):
```yaml
- label: "Tags"
name: "tags"
widget: "list"
default: ["news"]
```
- **Example** (with `field`):
```yaml
- label: "Gallery"
name: "galleryImages"
widget: "list"
field:
- {label: Image, name: image, widget: image}
```
- **Example** (with `fields`):
```yaml
- label: "Testimonials"
name: "testimonials"
widget: "list"
fields:
- {label: Quote, name: quote, widget: string, default: "Everything is awesome!"}
- label: Author
name: author
widget: object
fields:
- {label: Name, name: name, widget: string, default: "Emmet"}
- {label: Avatar, name: avatar, widget: image, default: "/img/emmet.jpg"}
```

View File

@ -0,0 +1,27 @@
---
label: "Markdown"
target: "markdown"
type: "widget"
---
### Markdown
The markdown widget provides a full fledged text editor - which is based on [slate](https://github.com/ianstormtaylor/slate) - that allows users to format text with features such as headings and blockquotes. Users are also allowed to write in markdown by simply flipping a switch.
*Please note:* in case you want to use your markdown editor to fill a markdown's file content after the frontmatter, you'll have name the field as `body` so then the CMS can recognize it and save the file accordingly.
- **Name:** `markdown`
- **UI:** full text editor
- **Data type:** markdown
- **Options:**
- `default`: accepts markdown content
- **Example:**
```yaml
- {label: "Blog post content", name: "body", widget: "markdown"}
```
This would render as:
![Markdown widget example](/img/widgets-markdown.png)

View File

@ -0,0 +1,30 @@
---
label: "Number"
target: "number"
type: "widget"
---
### Number
The number widget uses an HTML number input, saving the value as a string, integer, or floating point number.
- **Name:** `number`
- **UI:** HTML [number input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number)
- **Data type:** string by default; configured by `valueType` option
- **Options:**
- `default`: accepts string or number value; defaults to empty string
- `valueType`: accepts `int` or `float`; any other value results in saving as a string
- `min`: accepts a number for minimum value accepted; unset by default
- `max`: accepts a number for maximum value accepted; unset by default
- **Example:**
```yaml
- label: "Puppy Count"
name: "puppies"
widget: "number"
default: 2
valueType: "int"
min: 1
max: 101
```

View File

@ -0,0 +1,38 @@
---
label: "Object"
target: "object"
type: "widget"
---
### Object
The object widget allows you to group multiple widgets together, nested under a single field. You can choose any widget as a child of an object widget—even other objects.
- **Name:** `object`
- **UI:** a field containing one or more child widgets
- **Data type:** list of child widget values
- **Options:**
- `default`: you can set defaults within each sub-field's configuration
- `fields`: (**required**) a nested list of widget fields to include in your widget
- **Example:**
```yaml
- label: "Profile"
name: "profile"
widget: "object"
fields:
- {label: "Public", name: "public", widget: "boolean", default: true}
- {label: "Name", name: "name", widget: "string"}
- label: "Birthdate"
name: "birthdate"
widget: "date"
default: ""
format: "MM/DD/YYYY"
- label: "Address"
name: "address"
widget: "object"
fields:
- {label: "Street Address", name: "street", widget: "string"}
- {label: "City", name: "city", widget: "string"}
- {label: "Postal Code", name: "post-code", widget: "string"}
```

View File

@ -0,0 +1,29 @@
---
label: "Relation"
target: "relation"
type: "widget"
---
### Relation
The relation widget allows you to reference items from another collection. It provides a search input with a list of entries from the collection you're referencing, and the list automatically updates with matched entries based on what you've typed.
- **Name:** `relation`
- **UI:** text input with search result dropdown
- **Data type:** data type of the value pulled from the related collection item
- **Options:**
- `default`: accepts any widget data type; defaults to an empty string
- `collection`: (**required**) name of the collection being referenced (string)
- `searchFields`: (**required**) list of one or more names of fields in the referenced collection to search for the typed value
- `valueField`: (**required**) name of the field from the referenced collection whose value will be stored for the relation
- **Example** (assuming a separate "authors" collection with "name" and "twitterHandle" fields):
```yaml
- label: "Post Author"
name: "author"
widget: "relation"
collection: "authors"
searchFields: "[name, twitterHandle]"
valueField: "name"
```
The generated UI input will search the authors collection by name and twitterHandle as the user types. On selection, the author name will be saved for the field.

View File

@ -0,0 +1,38 @@
---
label: "Select"
target: "select"
type: "widget"
---
### Select
The select widget allows you to pick a single string value from a dropdown menu.
- **Name:** `select`
- **UI:** HTML select input
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- `options`: (**required**) a list of options for the dropdown menu; can be listed in two ways:
- string values: the label displayed in the dropdown is the value saved in the file
- object with `label` and `value` fields: the label displays in the dropdown; the value is saved in the file
- **Example** (options as strings):
```yaml
- label: "Align Content"
name: "align"
widget: "select"
options: ["left", "center", "right"]
```
- **Example** (options as objects):
```yaml
- label: "City"
name: "airport-code"
widget: "select"
options:
- { label: "Chicago", value: "ORD" }
- { label: "Paris", value: "CDG" }
- { label: "Tokyo", value: "HND" }
```

View File

@ -0,0 +1,20 @@
---
label: "String"
target: "string"
type: "widget"
---
### String
The string widget translates a basic text input to a string value. For larger textarea inputs, use the text widget.
- **Name:** `string`
- **UI:** text input
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- **Example:**
```yaml
- {label: "Title", name: "title", widget: "string"}
```

View File

@ -0,0 +1,21 @@
---
label: "Text"
target: "text"
type: "widget"
---
### Text
The text widget takes a multiline text field and saves it as a string. For shorter text inputs, use the string widget.
- **Name:** `text`
- **UI:** HTML textarea
- **Data type:** string
- **Options:**
- `default`: accepts a string; defaults to an empty string
- **Example:**
```yaml
- {label: "Description", name: "description", widget: "text"}
```

View File

@ -7,7 +7,9 @@
<nav class="docs-nav" id="docs-nav">
{{ $subjects := where .Site.Pages "Section" "docs" }}
{{ range sort $subjects "Params.position" }}
{{- if ne .Type "widget" -}}
<a href="{{ .Permalink }}" class="nav-link {{ if eq .Params.position $activePage }}active{{ end }}">{{ .Title }}</a>
{{- end -}}
{{ end }}
</nav>
<div class="mobile docs-nav">
@ -15,7 +17,9 @@
<option value="" selected="selected">Select A Topic</option>
{{ $subjects := where .Site.Pages "Section" "docs" }}
{{ range sort $subjects "Params.position" }}
{{- if ne .Type "widget" -}}
<option value="{{ .Permalink }}" class="nav-link {{ if eq .Params.position $activePage }}active{{ end }}">{{ .Title }}</option>
{{- end -}}
{{ end }}
</select>
</div>
@ -23,6 +27,9 @@
<article class="docs-content" id="docs-content">
{{ partial "edit-link" . }}
{{ .Content }}
{{- if eq .Title "Widgets" -}} <!-- Check if is widgets page, if so, add the partial "widgets" for the widget cloud functionality -->
{{- partial "widgets" . -}}
{{- end -}}
</article>
</div>
</div>

View File

@ -21,5 +21,8 @@ inputSelector: '.algolia-search',
debug: false // Set debug to true if you want to inspect the dropdown
});
</script>
{{- if eq .Title "Widgets" -}} <!-- Check if is widgets page, if so, add the widget cloud js script -->
<script src="/widgets.js"></script>
{{- end -}}
</body>
</html>

View File

@ -0,0 +1,14 @@
<section class="widgets">
<div class="widgets__cloud">
{{- range $index, $widget := where .Site.RegularPages "Type" "eq" "widget" -}}
<span class="widgets__item {{if eq $index 0}}widgets__item_active{{end}}" data-widget-target="{{.Params.target}}">{{.Params.label}}</span>
{{- end -}}
</div>
<div class="widgets__container">
{{- range $index, $widget := where .Site.RegularPages "Type" "eq" "widget" -}}
<div class="widget {{if eq $index 0}}widget_open{{end}}" id="{{.Params.target}}">
{{.Content}}
</div>
{{- end -}}
</div>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,66 @@
// Widgets section
function widgetsCloud() {
const widgetItems = document.getElementsByClassName("widgets__item"), // Widget word cloud
widgets = document.getElementsByClassName("widget"); // Widgets' bodies
let activeWidgetItem = document.getElementsByClassName("widgets__item_active")[0]; // Active button in the widgets cloud
if (document.getElementsByClassName("widgets")) {
if (window.location.hash) { // Function to check if the given URL has a hash to make each widget shareable
const targetWidget = document.getElementById(window.location.hash.substr(1)),
openedWidget = document.getElementsByClassName("widget_open")[0];
let targetWidgetItem = "";
for (let i = 0; i < widgetItems.length; i++) {
if (widgetItems[i].dataset.widgetTarget == window.location.hash.substr(1)) {
targetWidgetItem = widgetItems[i]
}
};
changeWidgets(openedWidget, targetWidget, targetWidgetItem); // Runs the function to change which widget is displayed
setTimeout(() => {
document.getElementsByClassName("widgets")[0].scrollIntoView({
behavior: "smooth",
block: "nearest"
}); // Scrolls to the widgets section
},200)
}
for (let i = 0; i < widgetItems.length; i++) {
widgetItems[i].addEventListener("click", e => { // Add click event for each widget button in the cloud
const targetWidget = document.getElementById(e.target.dataset.widgetTarget), // Defines which widget the user is trying to render
openedWidget = document.getElementsByClassName("widget_open")[0], // Defines the current open widget
targetWidgetItem = e.target; // Defines the current open widget
changeWidgets(openedWidget, targetWidget, targetWidgetItem); // Runs the function to change which widget is displayed
})
}
}
function changeWidgets(active, target, cloudItem) {
target.classList.add("widget_opening"); // Starts the process of opening the next widget
active.classList.remove("widget_open"); // Removes the active state of the current widget
active.classList.add("widget_closing"); // But guarantees the current active widget a closing class for transition purposes
activeWidgetItem.classList.remove("widgets__item_active"); // Removes the active state of the current widget item in the cloud
activeWidgetItem = cloudItem; // Sets the new active widget item as the clicked one
activeWidgetItem.classList.add("widgets__item_active"); // And adds the active CSS class to it
if (history.pushState) {
history.pushState(null, null, '#' + cloudItem.dataset.widgetTarget);
}
else {
location.hash = '#' + cloudItem.dataset.widgetTarget;
}
setTimeout(() => {
target.classList.remove("widget_opening"); // Removes the opening class to finish transition
target.classList.add("widget_open"); // Defines the new target widget
active.classList.remove("widget_closing"); // Finally gets completely rid of the previously openened widget
}, 150) // When the transition is done, finish the process by attributing the final classes to each widget
}
}
widgetsCloud();

View File

@ -0,0 +1,71 @@
.widgets {
margin: 2rem 0;
}
.widgets__cloud {
margin: $micro calc(-$micro / 2);
}
.widgets__item {
color: $darkGrey;
border: 2px solid $darkGreen;
border-radius: $borderRadius;
padding: calc($micro /2) $micro;
margin: calc($micro / 2);
cursor: pointer;
transition: color .2s ease, background .2s ease;
display: inline-block;
font-weight: normal;
}
.widgets__item:hover, .widgets__item_active {
background: $darkGreen;
color: white !important;
}
.widgets__container {
margin: 1em 0;
background: $lightGrey;
border-radius: $borderRadius;
transition: height .15s ease;
}
.widget {
padding: .5em 1em;
display: none;
}
.widget_open {
display: block;
}
.widget_closing {
display: block;
animation: widgetOpacity .15s ease forwards reverse;
}
.widget_opening {
display: block;
position: absolute;
top: 0;
left: 0;
opacity: 0;
animation: widgetOpacity .15s .05s ease forwards;
}
@keyframes widgetOpacity {
from {
opacity: 0
}
to {
opacity: 1
}
}
.widget pre {
background: #eee !important; /* making sure the pre has proper background contrast */
}
.widget h3 {
margin-top: 0 !important;
}

View File

@ -7,4 +7,5 @@
@import "imports/community.css";
@import "imports/collab.css";
@import "imports/docs.css";
@import "imports/widgets.css";
@import "imports/footer.css";

View File

@ -121,4 +121,4 @@ var eventInfoLoad = function() {
}
}
eventInfoLoad();
eventInfoLoad();