Planning app
A studio preparing for a collection launch. Work through the daily list, search or add an item, and open the photography brief. The progress figure follows the work you complete. Changes stay in this example and reset when you reload.
Point at any part of the page to see what it is made of.
- Page
ds-page- Unit
ds-row,ds-sidebar,ds-avatar-group
<style>
.example-stack { display:grid; grid-template-columns:minmax(0,1fr); gap:var(--ds-unit); min-width:0; align-content:start; }
.example-tight { display:grid; grid-template-columns:minmax(0,1fr); gap:calc(var(--ds-unit) / 2); min-width:0; align-content:start; }
.example-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--ds-unit); }
.example-two { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:calc(2 * var(--ds-unit)); align-items:start; }
.example-actions { display:flex; flex-wrap:wrap; align-items:flex-end; gap:calc(var(--ds-unit) / 2); }
.example-between { display:flex; flex-wrap:wrap; justify-content:space-between; align-items:flex-end; gap:var(--ds-unit); }
.example-grow { flex:1; min-width:0; }
.example-section { padding-block:var(--ds-unit); }
.example-between > ds-input { width:calc(10 * var(--ds-unit)); max-width:100%; }
.example-overflow { overflow-x:auto; }
.example-rule { border-top:1px solid var(--ds-border-color); padding-top:var(--ds-unit); }
.example-caption { display:flex; justify-content:space-between; gap:var(--ds-unit); }
.example-caption > * { min-width:0; }
.example-nav { display:flex; justify-content:space-between; align-items:flex-end; gap:var(--ds-unit); }
.example-brand { flex:none; }
.example-footer { padding-top:var(--ds-unit); }
.example-stack [hidden], .example-grid [hidden], .example-two [hidden], .example-tight [hidden] { display:none!important; }
.example-status:empty { display:none; }
.example-title { --ds-sf:calc(2 * var(--sf, 1)); --ds-display-text-size:40px; --ds-typeface-regular:var(--typeface-compressed); }
.example-copy { max-width:calc(24 * var(--ds-unit)); }
.example-shop-hero { display:grid; grid-template-columns:2fr 3fr; gap:var(--ds-unit); align-items:stretch; }
.example-shop-intro { display:flex; flex-direction:column; justify-content:space-between; gap:calc(2 * var(--ds-unit)); padding-block:var(--ds-unit); }
.example-shop-hero ds-image { align-self:start; }
.example-story { display:grid; grid-template-columns:1fr 2fr; gap:calc(2 * var(--ds-unit)); padding-block:calc(2 * var(--ds-unit)); }
.example-product { display:grid; gap:calc(var(--ds-unit) / 2); min-width:0; }
.example-bag { padding-block:var(--ds-unit); border-block:1px solid var(--ds-border-color); }
.example-workspace { --ds-page-nav:calc(8 * var(--ds-unit)); --ds-page-gap:calc(2 * var(--ds-unit)); }
.example-workspace-nav { display:grid; gap:calc(2 * var(--ds-unit)); }
.example-week { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:calc(var(--ds-unit) / 2); }
.example-day { display:grid; gap:calc(var(--ds-unit) / 2); min-height:calc(4 * var(--ds-unit)); padding-block:calc(var(--ds-unit) / 2); border-top:1px solid var(--ds-border-color); }
.example-day[aria-current] { border-top-color:var(--ds-text-color); }
.example-work { display:grid; grid-template-columns:minmax(0,3fr) minmax(0,2fr); gap:calc(2 * var(--ds-unit)); }
.example-brief { display:grid; gap:calc(var(--ds-unit) / 2); }
.example-contact-sheet { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:calc(var(--ds-unit) / 2); }
.example-contact-sheet > :first-child { grid-column:1 / -1; }
.example-item { box-sizing:border-box; display:grid; grid-template-columns:minmax(0,1fr) auto; gap:calc(var(--ds-unit) / 2); min-height:var(--ds-unit); align-items:end; border-bottom:1px solid var(--ds-border-color); }
.example-item label { display:flex; align-items:flex-end; gap:calc(var(--ds-unit) / 2); min-width:0; }
.example-item label ds-text { flex:1; }
.example-item-meta { display:flex; align-items:flex-end; gap:calc(var(--ds-unit) / 2); }
#balance-stat { --ds-stat-size:40px; --ds-stat-lines:3; --ds-stat-typeface:var(--typeface-compressed); }
.example-stats { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--ds-unit); }
.example-cash { display:grid; grid-template-columns:minmax(0,3fr) minmax(0,1fr); gap:calc(2 * var(--ds-unit)); }
.example-goal { display:grid; grid-template-columns:calc(6 * var(--ds-unit)) minmax(0,1fr); gap:var(--ds-unit); align-items:center; }
.example-audio-hero { display:grid; grid-template-columns:1fr 1fr; gap:var(--ds-unit); }
.example-audio-copy { display:flex; flex-direction:column; justify-content:space-between; gap:var(--ds-unit); padding:var(--ds-unit); background:var(--one-pink-pastel); }
.example-audio-copy .example-title { --ds-typeface-regular:var(--typeface-regular); }
.example-audio-strip { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--ds-unit); padding-block:var(--ds-unit); }
.example-audio-detail { display:grid; grid-template-columns:1fr 1fr; gap:calc(2 * var(--ds-unit)); align-items:center; }
.example-package { display:grid; grid-template-columns:1fr 1fr; gap:calc(2 * var(--ds-unit)); padding-block:calc(2 * var(--ds-unit)); }
.example-specs { display:grid; gap:0; }
.example-specs > div { display:flex; justify-content:space-between; gap:var(--ds-unit); border-bottom:1px solid var(--ds-border-color); padding-block:calc(var(--ds-unit) / 2); }
@media(max-width:900px) { .example-title { --ds-sf:var(--sf, 1); } .example-work { grid-template-columns:1fr; } .example-brief { grid-template-columns:1fr 1fr; gap:var(--ds-unit); } .example-cash { grid-template-columns:minmax(0,1fr); } }
@media(max-width:600px) {
.example-title { --ds-sf:var(--sf, 1); --ds-display-text-size:30px; }
.example-shop-hero,.example-audio-hero,.example-audio-detail,.example-package,.example-two,.example-story,.example-brief { grid-template-columns:1fr; gap:var(--ds-unit); }
.example-shop-intro { padding-block:0; gap:var(--ds-unit); }
.example-shop-hero { --hero-ratio:4 / 3; }
.example-grid { grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--ds-unit) calc(var(--ds-unit) / 2); }
.example-grid > :first-child { grid-column:1 / -1; }
.example-stats { grid-template-columns:repeat(2,minmax(0,1fr)); }
.example-stats > :first-child { grid-column:1 / -1; }
.example-audio-strip { grid-template-columns:1fr; }
.example-week { gap:calc(var(--ds-unit) / 2); }
.example-day { min-height:calc(3 * var(--ds-unit)); }
.example-day ds-text[size=small] { display:none; }
.example-nav .example-nav-secondary { display:none; }
.example-goal { grid-template-columns:calc(4 * var(--ds-unit)) minmax(0,1fr); }
.example-item { grid-template-columns:1fr; }
.example-item-meta { padding-inline-start:calc(1.5 * var(--ds-unit)); }
.example-package { padding-block:var(--ds-unit); }
}
</style><ds-page layout="sidebar" drawer divided fill class="example-workspace" data-ds-surface>
<div slot="nav" class="example-workspace-nav"><ds-row><ds-avatar initial="S" color="var(--one-zenith-blue)"></ds-avatar><ds-text literal strong>Studio</ds-text></ds-row><ds-sidebar label="Studio navigation" id="planner-nav"></ds-sidebar><div class="example-tight"><ds-text literal size="small" tone="muted">The team</ds-text><ds-avatar-group label="Project team"><ds-avatar initial="A" color="var(--one-pink)"></ds-avatar><ds-avatar initial="M" color="var(--one-zenith-blue)"></ds-avatar><ds-avatar initial="R" color="var(--one-orange-pastel)"></ds-avatar></ds-avatar-group><ds-text literal size="small" tone="muted">Alex, Mika & Ren</ds-text></div></div>
<div slot="header" class="example-between"><ds-text literal strong id="planner-heading">Today</ds-text><ds-tag>Autumn collection</ds-tag></div>
<div class="example-stack">
<div class="example-between"><div class="example-tight"><ds-text literal size="display" strong wrap role="heading" aria-level="1">A good week starts here.</ds-text><ds-text literal tone="muted" wrap>Monday, 19 October. Launch in four days.</ds-text></div><ds-stat id="planner-progress" value="1" figure="1 of 4" label="Ready for launch" literal></ds-stat></div>
<div class="example-week" aria-label="Launch week"><div class="example-day" aria-current="date"><ds-text literal size="small" tone="muted">Mon</ds-text><ds-text literal size="display">19</ds-text><ds-text literal size="small" wrap>Photographs</ds-text></div><div class="example-day" ><ds-text literal size="small" tone="muted">Tue</ds-text><ds-text literal size="display">20</ds-text><ds-text literal size="small" wrap>Design review</ds-text></div><div class="example-day" ><ds-text literal size="small" tone="muted">Wed</ds-text><ds-text literal size="display">21</ds-text><ds-text literal size="small" wrap>Print files</ds-text></div><div class="example-day" ><ds-text literal size="small" tone="muted">Thu</ds-text><ds-text literal size="display">22</ds-text><ds-text literal size="small" wrap>Final checks</ds-text></div><div class="example-day" ><ds-text literal size="small" tone="muted">Fri</ds-text><ds-text literal size="display">23</ds-text><ds-text literal size="small" wrap>Launch day</ds-text></div></div>
<div class="example-work">
<section class="example-stack"><div class="example-between"><ds-text literal size="display" strong wrap role="heading" aria-level="2">Make it happen</ds-text><ds-tag id="item-count">3 items</ds-tag></div><ds-input id="item-search" type="search" placeholder="Find an item" label="Find an item"></ds-input><div id="work-items"></div><ds-text literal id="planner-empty" tone="muted" wrap hidden>No items here. Try another view or search.</ds-text><div class="example-actions"><ds-input id="new-item" class="example-grow" label="New item" placeholder="What needs doing?"></ds-input><ds-button id="add-item" secondary><ds-icon type="plus" aria-hidden="true"></ds-icon> Add item</ds-button></div><ds-text id="planner-status" class="example-status" literal role="status" wrap></ds-text></section>
<section class="example-brief"><div class="example-contact-sheet"><ds-image src="/examples/images/room.jpg" alt="Chair by the window: location reference" ratio="16 / 7" position="50% 75%"></ds-image><ds-image src="/examples/images/chair.jpg" alt="Wooden chair: product reference" ratio="1" ></ds-image><ds-image src="/examples/images/cup.jpg" alt="Ceramic cup: material reference" ratio="1" ></ds-image></div><div class="example-tight"><ds-text literal strong>Collection shoot</ds-text><ds-text literal wrap tone="muted">Natural light. Familiar objects. An ordinary morning, looked at a little longer.</ds-text><ds-text literal size="small" tone="muted">Mika added 3 references</ds-text><ds-button control="slotted"><button id="brief-toggle" type="button" aria-expanded="false" aria-controls="brief-details">Read the brief <ds-icon type="down" aria-hidden="true"></ds-icon></button></ds-button><div id="brief-details" data-ds-prose hidden><p>Set the chair beside the window. Shoot the full room first, then the grain, the handle and the edge of the cup.</p><p>Deliver six landscape crops and three portraits by Tuesday’s review.</p></div></div></section>
</div>
<section class="example-tight example-rule"><ds-text literal strong>Coming together</ds-text><ds-row><ds-avatar initial="R" color="var(--one-orange-pastel)"></ds-avatar><ds-text literal wrap>Ren sent the print files</ds-text><span class="example-grow"></span><ds-text literal size="small" tone="muted">09:12</ds-text></ds-row><ds-row><ds-avatar initial="M" color="var(--one-zenith-blue)"></ds-avatar><ds-text literal wrap>Mika added the shoot references</ds-text><span class="example-grow"></span><ds-text literal size="small" tone="muted">08:45</ds-text></ds-row></section>
</div><div slot="footer" class="example-footer"><ds-text literal size="small" tone="muted" wrap>Fictional demo. Your changes stay here.</ds-text></div></ds-page> const navigation = document.querySelector('#planner-nav');
let view = 'today';
const items = [{name:'Choose the final photographs',done:false,owner:'M',due:'Today'},{name:'Review the collection page',done:false,owner:'A',due:'Tue'},{name:'Send the print files',done:true,owner:'R',due:'Done'},{name:'Write the launch note',done:false,owner:'A',due:'Thu'}];
function render() {
navigation.items = [{id:'today',label:'Today',current:view==='today'},{id:'all',label:'All items',current:view==='all'},{id:'completed',label:'Completed',current:view==='completed'}];
document.querySelector('#planner-heading').textContent = view === 'completed' ? 'Completed' : view === 'all' ? 'All items' : 'Today';
const query = document.querySelector('#item-search').value.toLowerCase();
const list = document.querySelector('#work-items'); list.replaceChildren();
items.forEach((item,index) => {
if ((view==='completed' && !item.done) || (view==='today' && item.done) || !item.name.toLowerCase().includes(query)) return;
const row = document.createElement('div'); row.className='example-item'; const label = document.createElement('label'); label.className = 'example-actions'; const face = document.createElement('ds-checkbox'); const check = document.createElement('input'); check.type='checkbox'; check.checked=item.done; face.append(check); const words=document.createElement('ds-text'); words.setAttribute('literal',''); words.textContent=item.name; words.setAttribute('wrap',''); label.append(face,words); const meta=document.createElement('div'); meta.className='example-item-meta'; const due=document.createElement('ds-text');due.setAttribute('literal','');due.setAttribute('size','small');due.setAttribute('tone','muted');due.textContent=item.due||'Unscheduled';const avatar=document.createElement('ds-avatar');avatar.setAttribute('initial',item.owner||'A');meta.append(due,avatar);
check.addEventListener('change', () => { item.done = check.checked; document.querySelector('#planner-status').textContent = item.name + (item.done ? ' completed.' : ' reopened.'); render(); });
row.append(label,meta); list.append(row);
});
document.querySelector('#item-count').textContent = list.children.length + ' items';
document.querySelector('#planner-empty').hidden=Boolean(list.children.length);
document.querySelector('#planner-progress').figure=items.filter(item=>item.done).length+' of '+items.length;
}
document.querySelector('#brief-toggle').addEventListener('click',event=>{const details=document.querySelector('#brief-details');details.hidden=!details.hidden;event.currentTarget.setAttribute('aria-expanded',String(!details.hidden));});
navigation.addEventListener('sidebar-activate', event => { view = event.detail.id; render(); document.querySelector('ds-page').closeDrawer(); });
document.querySelector('#item-search').addEventListener('input',render);
function add() { const input=document.querySelector('#new-item'); const name=input.value.trim(); if (!name) { input.focus(); return; } items.push({name,done:false}); input.value=''; view='all'; render(); document.querySelector('#planner-status').textContent='Item added.'; }
document.querySelector('#add-item').addEventListener('click',add);
document.querySelector('#new-item').addEventListener('keydown',event => { if(event.key==='Enter') add(); });
render(); The page uses the current DS1 components and tokens. The example only supplies content, layout composition and local interactions, so shared component updates carry through. Use Code to copy the example, Phone to check the narrow layout, or Show layers to inspect the pieces.