Examples › robotparts › The bar, Notion's pattern: visible views, folded filters, a search icon
The bar, Notion's pattern: visible views, folded filters, a search icon
robotparts' part pages put their views (Specs, User data, Config) on the bar as tabs. Zach: "If you have these
quick-switch views visible, then usually the pattern should be to make the filters more hidden (this is the Notion
pattern)." So with no filters attribute the bar folds the filters into one Filter button while the views show as tabs,
and spreads them out as Sort · Group · Filter · Properties when views="auto" turns the views into the chip; the
search waits behind an icon (search="icon") and grows in place when clicked or on "/".
The .base file and its data
Every tab above is one entry of this file; the views read these rows. ⋯ in the toolbar copies the current view as YAML.
# The bar, Notion's pattern for a part page (docs/CONTRACT.md §15): the views visible as tabs, so the filters fold
# (no `filters` attribute: tabs => one Filter button; when auto turns the views into the chip, Sort · Group · Filter ·
# Properties come back as words), and the search is an icon until it is wanted (search="icon"). Four of the
# toolbar-bar case's views over robotparts' 1,149 actuators. Check it: node bin/data-ui.mjs check <this file>
data: ../robotparts-actuators/actuators.json
facets:
- brand
- form
- drivetrain
- buses
- level
- { property: peak_torque, as: range }
- { property: mass, as: range }
- { property: price, as: range }
- { property: torque_density, as: has }
properties:
model: { displayName: Model }
brand: { displayName: Brand }
form: { displayName: Form }
drivetrain: { displayName: Drivetrain }
peak_torque: { displayName: Peak torque }
rated_torque: { displayName: Rated torque }
max_speed: { displayName: Max speed }
mass: { displayName: Mass }
gear_ratio: { displayName: Ratio }
voltage: { displayName: Voltage }
od: { displayName: OD }
length: { displayName: Length }
buses: { displayName: Bus }
torque_density: { displayName: Peak N·m/kg }
price: { displayName: Price from }
sellers: { displayName: Sellers }
level: { displayName: Level }
views:
- type: table
name: Rows
order: [model, brand, form, drivetrain, peak_torque, rated_torque, mass, price, buses]
sort:
- { property: peak_torque, direction: DESC }
- type: cards
name: Gallery
order: [model, brand, peak_torque, mass, price]
image: photo
imageFit: contain
imageAspectRatio: 0.8
cardSize: 190
- type: chart
name: Torque vs mass
chart:
mark: point
encoding:
x: { field: mass, type: quantitative }
y: { field: peak_torque, type: quantitative }
color: { field: brand, type: nominal }
- type: table
name: By brand
order: [model, form, peak_torque, rated_torque, max_speed, mass, gear_ratio, voltage, od, length, buses, price]
groupBy: { property: brand, direction: ASC }
sort:
- { property: peak_torque, direction: DESC }
summaries: { peak_torque: Max, mass: Min, price: Min }
// ../robotparts-actuators/actuators.json: 1,149 rows, 608 KB; the first 3
{
"id": "actuators",
"title": "Actuators",
"titleProperty": "name",
"linkProperty": "url",
"source": "robotparts dist/site/v2/catalog.json, release 2026.10.25 (lane/tables @ ab5ba92); mass from each spec's own unit; photo: robotparts media/photos.jsonl, 150 of 1725 copied at 240 px",
"properties": {
"name": {
"type": "text",
"hidden": true
},
"model": {
"type": "text",
"width": 190
},
"brand": {
"type": "text",
"width": 120
},
"form": {
"type": "text",
"width": 140,
"display": "badge"
},
"drivetrain": {
"type": "text",
"width": 104
},
"buses": {
"type": "list",
"width": 120
},
"level": {
"type": "number",
"width": 58
},
"url": {
"type": "text",
"hidden": true
},
"torque_density": {
"type": "number",
"unitText": "N·m/kg",
"width": 130,
"derived": "peak torque / mass, by robotparts"
},
"price": {
"type": "number",
"unitText": "USD",
"decimals": 0,
"width": 120
},
"sellers": {
"type": "number",
"width": 70
},
"peak_torque": {
"type": "number",
"unitText": "N·m",
"width": 126
},
"rated_torque": {
"type": "number",
"unitText": "N·m",
"width": 126
},
"max_speed": {
"type": "number",
"unitText": "rpm",
"width": 126
},
"mass": {
"type": "number",
"unitText": "g",
"width": 126
},
"gear_ratio": {
"type": "number",
"unitText": ":1",
"width": 126
},
"voltage": {
"type": "number",
"unitText": "V",
"width": 126
},
"od": {
"type": "number",
"unitText": "mm",
"width": 126
},
"length": {
"type": "number",
"unitText": "mm",
"width": 126
},
"photo": {
"type": "text",
"hidden": true,
"display": "image",
"note": "robotparts' primary photo, resized; only the parts this case copied have one"
},
"step_up": {
"type": "text",
"hidden": true,
"derived": "the next photographed part of the same brand up in peak torque (build_examples.py)",
"note": "an edge for the graph view: among the parts with a photo here, the brand's next one up in peak torque"
}
},
"rows": [
{
"id": "aifitlab-8541438771336",
"name": "Steadywin GIM4305-10",
"brand": "Steadywin",
"model": "GIM4305-10",
"form": "integrated actuator",
"drivetrain": "geared",
"buses": [
"can",
"rs485"
],
"level": 4,
"url": "https://robotparts.dev/actuator/aifitlab-8541438771336/",
"peak_torque": {
"value": 3.82,
"basis": "seller",
"source": "aifitlab.com"
},
"rated_torque": 1.05,
"max_speed": 402,
"mass": {
"value": 150,
"basis": "seller",
"source": "aifitlab.com"
},
"gear_ratio": 10,
"voltage": 24,
"od": 53,
"length": 26,
"torque_density": 25.467,
"price": 70,
"sellers": 1,
"photo": "photos/aifitlab-8541438771336.webp",
"step_up": "aifitlab-8542347853960"
},
{
"id": "aifitlab-8542347853960",
"name": "Steadywin GIM6010-8",
"brand": "Steadywin",
"model": "GIM6010-8",
"form": "integrated actuator",
"drivetrain": "geared",
"buses": [
"can",
"rs485"
],
"level": 1,
"url": "https://robotparts.dev/actuator/aifitlab-8542347853960/",
"peak_torque": {
"value": 11,
"basis": "seller",
"source": "aifitlab.com"
},
"rated_torque": 5,
"max_speed": 420,
"mass": {
"value": 388,
"basis": "seller",
"source": "aifitlab.com"
},
"gear_ratio": 8,
"voltage": 24,
"od": 80,
"length": 40,
"torque_density": 28.351,
"price": 70,
"sellers": 1,
"photo": "photos/aifitlab-8542347853960.webp",
"step_up": "aifitlab-8542620287112"
},
{
"id": "aifitlab-8542620287112",
"name": "Steadywin GIM8108-8",
"brand": "Steadywin",
"model": "GIM8108-8",
"form": "integrated actuator",
"drivetrain": "geared",
"buses": [
"can",
"rs485"
],
"level": 1,
"url": "https://robotparts.dev/actuator/aifitlab-8542620287112/",
"peak_torque": {
"value": 22,
"basis": "seller",
"source": "aifitlab.com"
},
"rated_torque": 7.5,
"max_speed": 320,
"mass": {
"value": 396,
"basis": "seller",
"source": "aifitlab.com"
},
"gear_ratio": 8,
"voltage": 48,
"od": 92,
"length": 55,
"torque_density": 55.556,
"price": 85,
"sellers": 1,
"photo": "photos/aifitlab-8542620287112.webp",
"step_up": null
}
],
"imageProperty": "photo"
}README.md
# The bar, Notion's pattern: visible views, folded filters, a search icon
robotparts' part pages put their views (Specs, User data, Config) on the bar as tabs. Zach: "If you have these
quick-switch views visible, then usually the pattern should be to make the filters more hidden (this is the Notion
pattern)." So with no `filters` attribute the bar folds the filters into one Filter button while the views show as tabs,
and spreads them out as Sort · Group · Filter · Properties when `views="auto"` turns the views into the chip; the
search waits behind an icon (`search="icon"`) and grows in place when clicked or on "/".
- **App:** robotparts
- **Replaces:** robotparts' part page header (its Specs / User data / Config tabs over a separate search box and
filter words).
- **Shows:** `views="auto"` with four views, no `filters` attribute (the default follows the views), `search="icon"`,
`display="panel"`, `selectable`.
- **Data:** `../robotparts-actuators/actuators.json` (the robotparts-actuators case's file).
The original UI it replaces
robotparts' part page header (its Specs / User data / Config tabs over a separate search box and filter words).
What it shows
views="auto" with four views, no filters attribute (the default follows the views), search="icon", display="panel", selectable.
Data
../robotparts-actuators/actuators.json (the robotparts-actuators case's file).