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 "/".

robotpartstablecardschart4 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 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).