Building a Purple Experience
Components
Table-of-content (TOC)
10 min
note the toc field in the toolbar is deprecated this guide presents a fully configurable and flexible method for implementing a toc (table of contents) button in experience reference app https //staging purplemanager com/#appdetail;id=9e5a0da6 c284 4720 9b59 d942b2c48bf7 https //staging purplemanager com/#appdetail;id=9e5a0da6 c284 4720 9b59 d942b2c48bf7 toc button 1\ overview instead of relying on the deprecated toolbar field, you can create a custom toc button using an html component this approach allows full control over styling, icon selection, and functionality 2\ json configuration 2 1 views json { "tag" "img", "type" "html", "tap" { "type" "setcontextvariables", "variables" \[ { "key" "tocopened", "value" "$functions updatetoc($context tocopened)" } ] }, "attributes" { "src" "resource //dynamic/storefront/assets/images/icons/toc svg", }, "class" "toc icon" } 2 2 custom server js updatetoc (tocopened) => { return !tocopened; } explanation tag "img" → specifies the element type (an image in this case) type "html" → renders as a raw html component tap sets the tocopened context variable by calling the updatetoc function this toggles the toc list open/closed attributes src path to the toc icon image in this example, the icon is stored in dynamic resources class "toc icon" → apply custom css for styling toc pannel this section explains how to configure a fully functional toc panel that displays a list of content items, allows navigation to each, and provides a close action 1\ json configuration 1 1 toc data source { "type" "content", "contextkey" "toc content", "filter" { "properties" { "key" "slug", "value" "\ bundleslug" } }, "fetchoptions" { "includebundledcontent" true } } explanation purpose this data source should be added to the data field of the view it provides the content list for the toc panel content type in this example, a bundle type is requested includebundledcontent ensures that post data within the bundle is included in the response alternative the same logic can be implemented in the url resolver const content = await dataresolver findcontentbyid(id, { includebundledcontent true }); 1 2 list configuration 1 2 1 views json { "content" \[ { "tag" "div", "type" "html", "content" "\[]", "class" "toc backface", "tap" { "type" "setcontextvariables", "variables" \[ { "key" "tocopened", "value" "$functions updatetoc($context tocopened)" } ] }, "condition" { "value" "$context tocopened", "comparevalue" "true" } }, { "content" \[ { "content" \[ { "content" \[ { "tag" "h2", "type" "html", "content" "toc title" }, { "content" \[ { "tag" "button", "type" "html", "class" "icon icon close", "tap" { "type" "setcontextvariables", "variables" \[ { "key" "tocopened", "value" "$functions updatetoc($context tocopened)" } ] } } ], "type" "section", "tag" "div", "class" "toc actions" } ], "type" "section", "class" "toc header" }, { "content" \[ { "content" { "content" \[ { "tag" "img", "type" "html", "content" "", "attributes" { "src" "$context context thumbnails default" }, "class" "toc image" }, { "content" \[ { "tag" "h2", "type" "html", "content" "$context context name", "class" "toc title" }, { "tag" "p", "type" "html", "content" "$context context description", "class" "toc description" } ], "type" "section", "class" "toc content" } ], "type" "section", "tap" { "type" "navigate", "path" "read/$context\['toc content']\[0] properties slug/$context context properties slug/" }, "class" "toc card" }, "datasource" { "data" "$functions getbundlelist($context\['toc content']\[0])", "type" "context" }, "type" "list" } ], "type" "section", "class" "toc content" } ], "type" "section", "class" "toc collapsible" } ], "type" "section", "condition" { "comparevalue" "true", "value" "$context tocopened" } } ], "type" "section", "class" "toc container" } 1 2 2 custom server js getbundlelist (bundle) => { return bundle contents map(content => content post) } 1 2 3 custom css toc icon { filter invert(1); } toc container toc backface { position fixed; width 100%; height 100%; top 0; left 0; background color rgba(0, 0, 0, 0 6); } toc { padding 0 28px 24px 28px; font family var( contentfont); border radius 4px; display grid; justify content end; } toc collapsible { position fixed; top 56px; z index 1; width 100%; max width 384px; right 0; bottom 50px; height auto; overflow auto; background color white; webkit overflow scrolling touch; } toc collapsible toc header button { display block; } toc toc actions { display flex; justify content end; webkit justify content flex end; align items flex end; webkit align items flex end; } toc toc actions button icon { margin right 0 2em; } toc toc header { text transform uppercase; border bottom 2px solid black; padding bottom 12px; padding top 35px; display flex; background color white; z index 1; justify content space between; position webkit sticky; position sticky; top 0; height 70px; } toc toc header h2 { letter spacing 0 3px; font size 16px; line height 22px; font weight 500; } toc toc header button { display none; color black; font size 16px; } toc toc content { display grid; } toc card { display flex; align items center; background #fff; border radius 12px; box shadow 0 4px 10px rgba(0, 0, 0, 0 05); padding 16px; margin bottom 12px; transition transform 0 2s ease, box shadow 0 2s ease; } toc card\ hover { transform translatey( 2px); box shadow 0 6px 16px rgba(0, 0, 0, 0 08); } toc image { width 64px; height 64px; border radius 50%; object fit cover; margin right 16px; } toc content { flex 1; } toc title { font size 1 2rem; margin 0; font weight 600; color #333; } toc description { font size 0 9rem; margin top 4px; color #666; } 2\ component breakdown toc backface displays a gray overlay behind the toc panel when it’s open clicking it closes the toc panel using setcontextvariables visibility is controlled by the condition "$context tocopened" === true toc header displays the toc title contains the toc actions section with a close button to hide the toc panel toc content (main list) displays the list of toc items uses the toc content data source from 1 1 uses the helper function getbundlelist to normalize data into a list of posts works with any source type (bundle, dossier, collection) as long as the result is a post list toc item (toc card) contains thumbnail (toc image) post title (toc title) description (toc description) clicking a toc item navigates to the post using read/$context\['toc content']\[0] properties slug/$context context properties slug/ post slug $context context properties slug bundle slug $context\['toc content']\[0] properties slug notes the toc panel naming is preferred because it describes the container that opens/closes to display the toc list the actual list inside the panel is referred to as the toc list you can customize layout, styles, and actions to fit project needs