Examples › robotparts › The bar, Notion's way: tabs and pills

The bar, Notion's way: tabs and pills

The same 1,149 actuators under toolbar="bar" views="tabs" filters="pills" promote="" display="panel": every view a tab (the ones that don't fit fold into "N more…"), compact filter pills under the bar, and Notion's View settings as a resizable side panel. Zach on the two apps: "Notion has compact filters and spread out views."

robotpartstablecardschartpivot10 views of one actuators.json

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 way (docs/CONTRACT.md §15): views="tabs", filters="pills", display="panel". The same file as the
# toolbar-bar case (robotparts' 1,149 actuators); only the element's attributes differ (site.json). Notion spreads
# the views out as tabs and keeps the filters compact. 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 }
  - type: table
    name: Brand › form
    order: [model, peak_torque, mass, gear_ratio, voltage, price]
    groupBy: { property: brand, direction: ASC }
    subGroupBy: { property: form, direction: ASC }
    sort:
      - { property: peak_torque, direction: DESC }
    summaries: { peak_torque: Max, price: Min }
    fold: closed
  - type: table
    name: Torque density
    filters: '!torque_density.isEmpty()'
    order: [model, brand, torque_density, peak_torque, mass, price]
    sort:
      - { property: torque_density, direction: DESC }
    display: { torque_density: bar }
  - type: table
    name: Geared CAN under $150
    filters:
      and:
        - 'drivetrain == "geared"'
        - 'buses.contains("can")'
        - 'price < 150'
    order: [model, brand, price, peak_torque, mass, gear_ratio, voltage]
    sort:
      - { property: price, direction: ASC }
    display: { price: bar }
  - type: table
    name: All, flat
    order: [model, brand, form, drivetrain, peak_torque, rated_torque, max_speed, mass, gear_ratio, voltage, od, length, buses, torque_density, price, sellers, level]
    sort:
      - { property: brand, direction: ASC }
      - { property: model, direction: ASC }
  - type: pivot
    name: Brand × form
    order: [brand]
    splitBy: [form]
    value: { property: null, summary: Count }
    sort:
      - { property: brand, direction: ASC }
  - type: pivot
    name: Torque by drivetrain × form
    order: [drivetrain]
    splitBy: [form]
    value: { property: peak_torque, summary: Median, display: dist }
// ../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 way: tabs and pills

The same 1,149 actuators under `toolbar="bar" views="tabs" filters="pills" promote="" display="panel"`: every view a tab (the
ones that don't fit fold into "N more…"), compact filter pills under the bar, and Notion's View settings as a
resizable side panel. Zach on the two apps: "Notion has compact filters and spread out views."

- **App:** robotparts
- **Replaces:** Notion's database header (view tabs with "N more…" and +, the Filter / Sort words and the View settings
  side panel), as robotparts' tab mock drew it (zach_brain Sources/Images/Pasted image 20261026122336.png and
  …122558.png).
- **Shows:** `views="tabs"` with overflow into "N more…", `promote=""` (everything else inside Display), `filters="pills"` (the pill row once a filter is set), `display="panel"`, `selectable`.
- **Data:** `../robotparts-actuators/actuators.json` (the robotparts-actuators case's file).

The original UI it replaces

Notion's database header (view tabs with "N more…" and +, the Filter / Sort words and the View settings side panel), as robotparts' tab mock drew it (zach_brain Sources/Images/Pasted image 20261026122336.png and …122558.png).

What it shows

views="tabs" with overflow into "N more…", promote="" (everything else inside Display), filters="pills" (the pill row once a filter is set), display="panel", selectable.

Data

../robotparts-actuators/actuators.json (the robotparts-actuators case's file).