Tableaux de bord et interfaces d’administration

Tableau de rétention groupée du réseau de soins

Réalisez un panneau de rétention par cohorte pour un contexte de réseau de soins : il doit contenir du contenu réel, des contrôles interactifs, des retours d’état clairs et une mise en page adaptable à toutes les tailles d’écran.

Tableaux de bord et interfaces d’administrationTableau de rétention de groupeHTML TableCSSJavaScript
Après activation de JavaScript, ce cas peut être modifié, exécuté et enregistré. Code source fixe ci-dessous :
<!doctype html>
<html lang="fr" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Tableau de rétention groupée du réseau de soins</title>
  <style>
    :root { --ink:#18332f; --paper:#f4efe4; --accent:#d45f3e; --secondary:#8fc4ad; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:"Kaiti SC",STKaiti,"Songti SC",serif; background:radial-gradient(circle at 12% 18%,color-mix(in srgb,var(--accent) 12%,transparent) 0 1px,transparent 2px),var(--paper);background-size:19px 19px; }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(980px,calc(100% - 32px));margin:auto;padding:72px 0 92px}.mast{display:grid;grid-template-columns:1fr auto;transform:rotate(-.25deg);gap:32px;align-items:center;margin-bottom:46px}.mast h1{font-family:"Kaiti SC",STKaiti,serif;font-weight:700;font-size:clamp(40px,8vw,84px);letter-spacing:.02em;margin:0;line-height:1.12}.intro{max-width:650px;margin-top:18px;line-height:2}.scenario{padding:12px;border:2px solid var(--accent);color:var(--accent);transform:rotate(3deg)}.eyebrow{display:block;margin-bottom:9px;color:var(--accent);letter-spacing:.18em}.demo{border-radius:2px;transform:rotate(.12deg);box-shadow:0 30px 70px color-mix(in srgb,var(--ink) 18%,transparent);position:relative;min-height:430px;overflow:hidden;padding:clamp(28px,6vw,66px);background:color-mix(in srgb,var(--paper) 92%,#fff)}@media(max-width:700px){.page{width:calc(100% - 20px);padding:28px 0}.mast{grid-template-columns:1fr}.scenario{justify-self:start}.demo{padding:20px}}
    .panel{padding:26px;border:1px solid var(--line);border-radius:2px;background:var(--paper)}.stack{display:grid;gap:28px}.row{display:flex;gap:20px;flex-wrap:wrap}.action{padding:9px 2px;border:0;border-bottom:2px solid var(--line);background:transparent}.action.primary,.action.is-active{border-color:var(--accent);color:var(--accent)}.muted{font-size:14px;line-height:1.9}.status{min-height:20px;margin-top:28px;font-size:13px}.metric{font-size:clamp(40px,9vw,88px);font-weight:500;letter-spacing:-.06em}.meter{height:2px;background:var(--line)}.meter>i{display:block;height:100%;background:var(--accent)}.chip{font-size:11px;letter-spacing:.12em;text-transform:uppercase}
    .composition-split{display:grid;grid-template-columns:150px minmax(0,1fr);gap:18px;align-items:start}.split-note{position:sticky;top:20px;display:grid;gap:14px;padding:18px 12px;border-block:3px double var(--accent);font-size:13px;line-height:1.65}.split-note b{font:900 12px/1 ui-monospace,monospace;letter-spacing:.12em}.split-note span{writing-mode:vertical-rl;min-height:120px;color:color-mix(in srgb,var(--ink) 60%,transparent)}.composition-split .demo{min-width:0}@media(max-width:900px){.composition-split{grid-template-columns:1fr}.split-note{position:static;grid-template-columns:auto 1fr}.split-note span{writing-mode:horizontal-tb;min-height:0}}
    .cohort-ribbon-studio{display:grid;gap:18px}.cohort-ribbon-studio header{display:flex;justify-content:space-between;gap:18px;align-items:end}.cohort-ribbon-studio h2{margin:.3em 0}.cohort-ribbon-grid{display:grid;grid-template-columns:minmax(0,1.3fr) 240px;gap:14px}.cohort-ribbon-cards{display:grid;gap:12px}.cohort-ribbon-cards article{display:grid;gap:12px;padding:16px;border:1px solid var(--line);border-radius:18px;background:var(--paper)}.cohort-ribbon-cards article header{display:flex;justify-content:space-between;gap:12px;align-items:center}.cohort-ribbon-cards ol{display:grid;gap:8px;padding:0;margin:0;list-style:none}.cohort-ribbon-cards li{display:grid;grid-template-columns:60px 58px 1fr;gap:10px;align-items:center}.cohort-ribbon-cards b{font-size:22px}.cohort-ribbon-cards i{display:block;height:12px;border-radius:999px;background:linear-gradient(90deg,var(--accent) calc(var(--fill)*1%),color-mix(in srgb,var(--line) 82%,transparent) 0)}.cohort-ribbon-grid aside{display:grid;align-content:start;gap:10px;padding:18px;border-left:4px solid var(--accent);background:color-mix(in srgb,var(--secondary) 10%,transparent)}.cohort-ribbon-grid aside ol{display:grid;gap:8px;padding-left:18px;margin:0}@media(max-width:760px){.cohort-ribbon-studio header{align-items:stretch;flex-direction:column}.cohort-ribbon-grid{grid-template-columns:1fr}}.workflow-session{display:grid;gap:14px}.session-command{display:grid;grid-template-columns:1fr auto minmax(170px,.45fr) auto;gap:16px;align-items:end;padding:18px;border-block:4px double var(--ink)}.session-command h2{margin:.2em 0}.session-command output{font:900 clamp(28px,5vw,54px)/1 ui-monospace,monospace}.session-command label{display:grid;grid-template-columns:1fr auto;gap:7px;font-size:12px}.session-command input{grid-column:1/-1;width:100%}#workflowSessionProgress{height:12px;overflow:hidden;border-radius:2px;background:var(--line)}#workflowSessionProgress i{display:block;width:0;height:100%;background:var(--accent)}.session-stage{min-width:0;transition:filter .25s,transform .25s}.session-stage[data-session-phase="running"]{transform:translateY(-3px)}.session-stage[data-session-phase="paused"]{filter:grayscale(.65)}.session-stage[data-session-phase="complete"]{filter:contrast(.78);opacity:.72}.session-log{display:grid;grid-template-columns:auto 1fr;gap:18px;align-items:start}.session-log ol{display:flex;flex-wrap:wrap;gap:7px;padding:0;margin:0;list-style:none}.session-log li{padding:5px 8px;border:1px solid var(--line);font-size:12px}@media(max-width:900px){.session-stage{order:-1}.session-command{grid-template-columns:1fr auto}.session-command label{grid-column:1/-1}.session-log{grid-template-columns:1fr}}
  </style>
</head>
<body data-aesthetic="paper" data-composition="split-note">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">paper / panneau de rétention par groupe / INTERMEDIATE</span><h1>Tableau de rétention groupée du réseau de soins</h1><p class="intro">Réalisez un panneau de rétention par cohorte pour un contexte de réseau de soins : il doit contenir du contenu réel, des contrôles interactifs, des retours d’état clairs et une mise en page adaptable à toutes les tailles d’écran.</p></div><span class="scenario">Réseau de soins</span></header>
    <div class="composition-split"><aside class="split-note"><b>CASE 02</b><span>Maîtrisez la structure sémantique, l’organisation réactive, les opérations au clavier et la synchronisation d’état d’un panneau de rétention par groupe.</span></aside><section class="demo" aria-label="Zone d’interaction du panneau de rétention groupée du réseau de soins"><div class="workflow-session"><header class="session-command"><div><span class="eyebrow">réseau de soins SESSION</span><h2>Chronomètre du réseau de soins</h2></div><output id="workflowSessionClock">00:45</output><label>Durée du tour<input id="workflowSessionLength" type="range" min="15" max="90" step="15" value="45"><span>s</span></label><button id="workflowSessionToggle" class="action primary" type="button">Ouvrir le panneau d’application</button></header><div id="workflowSessionProgress" role="progressbar" aria-label="Progression du réseau de soins" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><i></i></div><section id="workflowCore" class="workflow-core session-stage" data-session-phase="ready" tabindex="-1"><!-- 11DZ_CORE_START:dashboards-admin-cohort-panel --><div class="cohort-ribbon-studio"><header><div><span class="eyebrow">CARE COHORT RIBBONS</span><h2>Couloir de rétention du réseau de soins</h2></div><label>Afficher le pourcentage <input id="cohortPercent" type="checkbox" checked data-core-bridge="dashboards-admin-cohort-panel"></label></header><div class="cohort-ribbon-grid"><section class="cohort-ribbon-cards"><article><header><strong>Rejoindre cette semaine</strong><span id="cohortLead0">Semaine 0 100%</span></header><ol><li><span>Semaine 0</span><b data-cohort="100" data-group="0" data-week="0">100%</b><i style="--fill:100"></i></li><li><span>Semaine 1</span><b data-cohort="84" data-group="0" data-week="1">84%</b><i style="--fill:84"></i></li><li><span>Semaine 2</span><b data-cohort="73" data-group="0" data-week="2">73%</b><i style="--fill:73"></i></li><li><span>Semaine 3</span><b data-cohort="68" data-group="0" data-week="3">68%</b><i style="--fill:68"></i></li></ol></article><article><header><strong>rejoint la semaine dernière</strong><span id="cohortLead1">Semaine 0 92%</span></header><ol><li><span>Semaine 0</span><b data-cohort="92" data-group="1" data-week="0">92%</b><i style="--fill:92"></i></li><li><span>Semaine 1</span><b data-cohort="78" data-group="1" data-week="1">78%</b><i style="--fill:78"></i></li><li><span>Semaine 2</span><b data-cohort="69" data-group="1" data-week="2">69%</b><i style="--fill:69"></i></li><li><span>Semaine 3</span><b data-cohort="58" data-group="1" data-week="3">58%</b><i style="--fill:58"></i></li></ol></article><article><header><strong>Il y a deux semaines</strong><span id="cohortLead2">Semaine 0 88%</span></header><ol><li><span>Semaine 0</span><b data-cohort="88" data-group="2" data-week="0">88%</b><i style="--fill:88"></i></li><li><span>Semaine 1</span><b data-cohort="71" data-group="2" data-week="1">71%</b><i style="--fill:71"></i></li><li><span>Semaine 2</span><b data-cohort="57" data-group="2" data-week="2">57%</b><i style="--fill:57"></i></li><li><span>Semaine 3</span><b data-cohort="44" data-group="2" data-week="3">44%</b><i style="--fill:44"></i></li></ol></article><article><header><strong>Adhéré il y a trois semaines</strong><span id="cohortLead3">Semaine 0 82%</span></header><ol><li><span>Semaine 0</span><b data-cohort="82" data-group="3" data-week="0">82%</b><i style="--fill:82"></i></li><li><span>Semaine 1</span><b data-cohort="63" data-group="3" data-week="1">63%</b><i style="--fill:63"></i></li><li><span>Semaine 2</span><b data-cohort="49" data-group="3" data-week="2">49%</b><i style="--fill:49"></i></li><li><span>Semaine 3</span><b data-cohort="39" data-group="3" data-week="3">39%</b><i style="--fill:39"></i></li></ol></article></section><aside><strong id="cohortTopWeek">Groupe le plus stable : arrivé cette semaine</strong><p id="cohortModeHint">On observe actuellement la fidélité des retours du réseau de soins en pourcentage.</p><ol id="cohortSummaryList"></ol></aside></div></div><!-- 11DZ_CORE_END --></section><footer class="session-log"><strong id="workflowSessionScore">0 points de contrôle interactifs</strong><ol id="workflowSessionLaps" aria-label="Journal de ronde"></ol></footer></div><p id="status" class="status" role="status" aria-live="polite"></p></section></div>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:dashboards-admin-cohort-panel */
const careCohortCells=[...document.querySelectorAll('[data-cohort]')];const careCohortCards=["Rejoindre cette semaine","rejoint la semaine dernière","Il y a deux semaines","Adhéré il y a trois semaines"];function renderCareCohort(asPercent){const grouped=careCohortCards.map((_,group)=>careCohortCells.filter(cell=>Number(cell.dataset.group)===group).map(cell=>Number(cell.dataset.cohort)));const peaks=grouped.map(values=>values.reduce((sum,value)=>sum+value,0));const topGroup=peaks.indexOf(Math.max(...peaks));document.querySelector('#cohortTopWeek').textContent='Le groupe le plus stable :'+careCohortCards[topGroup];document.querySelector('#cohortModeHint').textContent=asPercent?'On observe actuellement la fidélité des retours du réseau de soins en pourcentage.':'Observation de la couverture des rappels à l’aide d’effectifs estimés pour le moment.';document.querySelector('#cohortSummaryList').replaceChildren(...grouped.map((values,index)=>{const item=document.createElement('li');const tail=values.at(-1);item.textContent=careCohortCards[index]+' · semaine 3 '+(asPercent?tail+'%':Math.round(tail*2.6)+' personne');return item;}));careCohortCells.forEach(cell=>{const value=Number(cell.dataset.cohort);cell.textContent=asPercent?value+'%':Math.round(value*2.6)+' personne';});grouped.forEach((values,index)=>{document.querySelector('#cohortLead'+index).textContent='Semaine 0 '+(asPercent?values[0]+'%':Math.round(values[0]*2.6)+' personne');});}document.querySelector('#cohortPercent').addEventListener('change',event=>{renderCareCohort(event.currentTarget.checked);announce(event.currentTarget.checked?'Pourcentage de rétention affiché':'Nombre estimé affiché');});renderCareCohort(true);
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"dashboards-admin-cohort-panel","selector":"[data-core-bridge=\"dashboards-admin-cohort-panel\"]","mode":"toggle","key":" "};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Version de base '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.setAttribute('aria-keyshortcuts',workflowBridgeSpec.key===' '?'Space':workflowBridgeSpec.key);const workflowBridgeToggleKeyMatches=event=>event.key===workflowBridgeSpec.key||event.key==='Spacebar'||event.code==='Space';workflowBridgeControl.addEventListener('keydown',event=>{if(!workflowBridgeToggleKeyMatches(event))return;event.preventDefault();});workflowBridgeControl.addEventListener('keyup',event=>{if(!workflowBridgeToggleKeyMatches(event))return;event.preventDefault();workflowBridgeControl.click();});workflowBridgeControl.addEventListener("change",workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();workflowBridgeControl.click();const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowSessionCore=document.querySelector('#workflowCore');const workflowSessionToggle=document.querySelector('#workflowSessionToggle');const workflowSessionLength=document.querySelector('#workflowSessionLength');const workflowSessionState={phase:'ready',elapsed:0,limit:Number(workflowSessionLength.value),checkpoints:[],timer:null};function workflowSessionFormat(seconds){return String(Math.floor(seconds/60)).padStart(2,'0')+':'+String(seconds%60).padStart(2,'0');}function workflowSessionDrive(){const percent=Math.min(100,Math.round(workflowSessionState.elapsed/workflowSessionState.limit*100));document.querySelector('#workflowSessionClock').textContent=workflowSessionFormat(Math.max(0,workflowSessionState.limit-workflowSessionState.elapsed));const progress=document.querySelector('#workflowSessionProgress');progress.setAttribute('aria-valuenow',String(percent));progress.querySelector('i').style.width=percent+'%';workflowSessionCore.dataset.sessionPhase=workflowSessionState.phase;document.querySelector('#workflowSessionScore').textContent=workflowSessionState.checkpoints.length+' points de contrôle d’interaction';}function workflowSessionLap(label){workflowSessionState.checkpoints.push({label,at:workflowSessionState.elapsed});const item=document.createElement('li');item.textContent=label+' · '+workflowSessionFormat(workflowSessionState.elapsed);document.querySelector('#workflowSessionLaps').append(item);workflowSessionDrive();}function workflowSessionStop(complete=false){clearInterval(workflowSessionState.timer);workflowSessionState.timer=null;workflowSessionState.phase=complete?'complete':'paused';workflowSessionToggle.textContent=complete?'Recommencer':'Tour suivant';workflowSessionToggle.setAttribute('aria-pressed','false');workflowSessionDrive();announce(complete?'Fin du tour du réseau de soins':'La ronde est suspendue');}function workflowSessionStart(){if(workflowSessionState.phase==='complete'){workflowSessionState.elapsed=0;workflowSessionState.checkpoints=[];document.querySelector('#workflowSessionLaps').replaceChildren();}workflowSessionState.phase='running';workflowSessionToggle.textContent='Tour de pause';workflowSessionToggle.setAttribute('aria-pressed','true');const bridge=workflowBridgeActivate();workflowSessionLap(bridge.summary);clearInterval(workflowSessionState.timer);workflowSessionState.timer=setInterval(()=>{workflowSessionState.elapsed+=1;if(workflowSessionState.elapsed>=workflowSessionState.limit){workflowSessionStop(true);return;}workflowSessionDrive();},1000);workflowSessionDrive();announce('La session de coordination du réseau de soins a commencé · '+bridge.summary);}workflowSessionToggle.addEventListener('click',()=>workflowSessionState.phase==='running'?workflowSessionStop():workflowSessionStart());workflowSessionLength.addEventListener('input',()=>{workflowSessionState.limit=Number(workflowSessionLength.value);workflowSessionState.elapsed=Math.min(workflowSessionState.elapsed,workflowSessionState.limit);workflowSessionDrive();});workflowSessionCore.addEventListener('keydown',event=>{if(event.key==='Enter'||event.key===' '){workflowSessionLap('Opérations au clavier');}});workflowSessionCore.addEventListener('click',event=>{if(event.target.closest('[data-core-bridge]'))workflowSessionLap('Opération principale · '+workflowBridgeSummary());});document.addEventListener('visibilitychange',()=>{if(document.hidden&&workflowSessionState.phase==='running')workflowSessionStop();});workflowSessionDrive();
workflowBridgeReset();
  </script>
</body>
</html>
Commentaires sur la pageVous avez découvert un problème ou avez une suggestion d’amélioration ?
Les fonctions de retour nécessitent l’utilisation de la version en ligne

Veuillez activer JavaScript dans la version en ligne avant de soumettre ; les fonctionnalités locales de l’outil ou du cas ne sont pas affectées.

Aller vers la version en ligne pour envoyer des commentaires