UI State Metrics Panel
Three datasets, one derived store. $data picks the channel, and every binding in the panel reads from it, so the total, the seven bars, and the footnote all switch together.
Adding a channel is one more store and one more branch in $data. Nothing else in the markup changes.
Visitors
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Code
The following example assumes that you have imported the component and set up the theme.
<sv-ui-state>59 collapsed lines
<sv-store name="$channel" value="direct"></sv-store>
<sv-store type="json" name="$direct" value='{"total":"12.4k","best":"Saturday","bars":[46,58,39,72,64,88,55]}'></sv-store> <sv-store type="json" name="$search" value='{"total":"31.9k","best":"Wednesday","bars":[62,70,94,81,77,40,33]}'></sv-store> <sv-store type="json" name="$social" value='{"total":"7.2k","best":"Sunday","bars":[28,24,35,30,52,68,90]}'></sv-store>
<sv-store derive="$channel === 'direct' ? $direct : $channel === 'search' ? $search : $social" name="$data"></sv-store>
<div class="panel"> <div> <span class="panel-title">Visitors</span> <strong class="panel-total" bind-text="$data.total"></strong> </div>
<div class="panel-chart"> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[0] + '%'"></div> <span>Mon</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[1] + '%'"></div> <span>Tue</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[2] + '%'"></div> <span>Wed</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[3] + '%'"></div> <span>Thu</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[4] + '%'"></div> <span>Fri</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[5] + '%'"></div> <span>Sat</span> </div> <div class="panel-col"> <div class="panel-bar" bind-style="block-size:$data.bars[6] + '%'"></div> <span>Sun</span> </div> </div>
<p class="panel-note" bind-text="'Best day: ' + $data.best"></p>
<div class="panel-channels"> <button type="button" bind-class-toggle="is-active:$channel === 'direct'" bind-event="click:$channel('direct')"> Direct </button> <button type="button" bind-class-toggle="is-active:$channel === 'search'" bind-event="click:$channel('search')"> Search </button> <button type="button" bind-class-toggle="is-active:$channel === 'social'" bind-event="click:$channel('social')"> Social </button> </div> </div></sv-ui-state>
<style>76 collapsed lines
.panel { display: grid; gap: 0.9em; inline-size: min(24rem, 100%); padding: 1.2em; margin-inline: auto; background-color: var(--sv-gray-6); border-radius: var(--sv-bdr-rad-md);
.panel-title { display: block; font-size: 0.8em; color: var(--sv-gray-3); }
.panel-total { font-size: 1.6em; }
.panel-chart { display: grid; grid-auto-columns: 1fr; grid-auto-flow: column; gap: 0.4em; block-size: 7rem; }
.panel-col { display: grid; grid-template-rows: 1fr auto; gap: 0.4em; align-items: end;
span { font-size: 0.7em; color: var(--sv-gray-3); text-align: center; } }
.panel-bar { background-color: var(--sv-accent); border-radius: var(--sv-bdr-rad-sm); transition: block-size 0.25s; }
.panel-note { margin: 0; font-size: 0.8em; color: var(--sv-gray-3); }
.panel-channels { display: flex; gap: 0.3em; padding-block-start: 0.75em; border-block-start: var(--sv-bdr-sz-sm) solid var(--sv-gray-5);
button { flex: 1; padding: 0.4em 0.5em; font: inherit; font-size: 0.85em; color: var(--sv-gray-3); cursor: pointer; background-color: var(--sv-gray-7); border: var(--sv-bdr-sz-sm) solid transparent; border-radius: var(--sv-bdr-rad-sm);
&.is-active { color: var(--sv-gray-0); border-color: var(--sv-accent); } } } }</style>