Tableau thermique du calendrier de consommation d’énergie du campus
Créez un tableau de bord de chaleur du calendrier dans un contexte de consommation énergétique du campus : avec contenu réel, contrôles actionnables, retours d’état clairs et disposition adaptative aux différentes tailles d’écran.
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 thermique du calendrier de consommation d’énergie du campus</title>
<style>
:root { --ink:#3a2419; --paper:#fbf3df; --accent:#c66a2d; --secondary:#b5c88d; --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:Didot,"Songti SC",serif; background:linear-gradient(30deg,transparent 48%,color-mix(in srgb,var(--accent) 9%,transparent) 49% 51%,transparent 52%),var(--paper);background-size:52px 90px; }
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(1040px,calc(100% - 36px));margin:auto;padding:64px 0}.mast{display:grid;justify-items:center;text-align:center;border-block:3px double var(--accent);padding:26px;gap:20px;margin-bottom:32px}.mast h1{font-family:Didot,"Songti SC",serif;font-weight:700;font-size:clamp(38px,8vw,86px);letter-spacing:.035em;margin:0;line-height:1}.eyebrow{display:block;color:var(--accent);font:800 11px/1 ui-monospace,monospace;letter-spacing:.3em}.intro{max-width:600px;margin-inline:auto;line-height:1.8}.scenario{padding:8px 26px;border-inline:1px solid var(--accent);letter-spacing:.16em}.demo{border:4px double var(--accent);border-radius:0;clip-path:polygon(24px 0,calc(100% - 24px) 0,100% 24px,100% calc(100% - 24px),calc(100% - 24px) 100%,24px 100%,0 calc(100% - 24px),0 24px);position:relative;min-height:440px;overflow:hidden;padding:clamp(28px,5vw,60px);background:var(--paper)}@media(max-width:700px){.page{width:calc(100% - 20px);padding:24px 0}.mast{padding:18px}.demo{padding:18px}}
.panel{padding:16px;border:3px double var(--accent);background:var(--paper)}.stack{display:grid;gap:14px}.row{display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:10px;overflow:auto}.action{padding:10px 15px;border:1px solid var(--accent);background:transparent;font-family:Didot,serif;letter-spacing:.06em}.action.primary,.action.is-active{color:var(--paper);background:var(--ink)}.metric{font-family:Didot,serif;font-size:clamp(36px,8vw,74px);letter-spacing:.04em}.status{min-height:24px;padding:9px;border-inline:1px solid var(--accent);text-align:center}.muted{line-height:1.8}.chip{padding:5px 14px;border-inline:1px solid var(--accent);letter-spacing:.1em}.meter{height:5px;background:var(--line)}.meter>i{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--secondary))}
.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}}
.calendar-heatmap-studio{display:grid;gap:12px;max-width:860px;margin:auto}.calendar-heatmap-studio header{display:flex;justify-content:space-between;gap:18px;align-items:end}.calendar-heatmap-studio h2{margin:.3em 0}.heatmap-layout{display:grid;grid-template-columns:minmax(0,1.2fr) 220px;gap:14px}.weekday-row,.calendar-heatmap{display:grid;grid-template-columns:repeat(7,1fr);gap:7px}.weekday-row{text-align:center;font-size:12px}.calendar-heatmap button{aspect-ratio:1;border:0;border-radius:8px;background:color-mix(in srgb,var(--accent) calc(var(--heat)*20%),var(--paper))}.calendar-heatmap [data-heat="0"]{--heat:0}.calendar-heatmap [data-heat="1"]{--heat:1}.calendar-heatmap [data-heat="2"]{--heat:2}.calendar-heatmap [data-heat="3"]{--heat:3}.calendar-heatmap [data-heat="4"]{--heat:4;color:var(--paper)}.calendar-heatmap button[aria-selected="true"]{outline:3px solid var(--ink);outline-offset:2px}.calendar-heatmap-studio footer{display:flex;gap:5px;justify-content:flex-end;align-items:center}.calendar-heatmap-studio footer i{width:16px;height:16px;border-radius:4px;background:var(--line)}.calendar-heatmap-studio footer i:nth-of-type(2){background:color-mix(in srgb,var(--accent) 25%,var(--paper))}.calendar-heatmap-studio footer i:nth-of-type(3){background:color-mix(in srgb,var(--accent) 50%,var(--paper))}.calendar-heatmap-studio footer i:nth-of-type(4){background:color-mix(in srgb,var(--accent) 75%,var(--paper))}.calendar-heatmap-studio footer i:nth-of-type(5){background:var(--accent)}.heatmap-layout aside{display:grid;align-content:start;gap:10px;padding:16px;border-left:4px solid var(--accent);background:color-mix(in srgb,var(--secondary) 12%,transparent)}.heatmap-layout aside ol{display:grid;gap:8px;padding-left:18px;margin:0}@media(max-width:700px){.calendar-heatmap-studio header{align-items:stretch;flex-direction:column}.heatmap-layout{grid-template-columns:1fr}}.workflow-dispatch{display:grid;grid-template-columns:minmax(210px,.48fr) minmax(0,1.52fr);gap:18px}.dispatch-console{display:grid;align-content:start;gap:16px;padding:22px;border:1px solid var(--line);border-radius:18px;background:color-mix(in srgb,var(--secondary) 12%,var(--paper))}.dispatch-console h2{margin:.2em 0}.dispatch-console form,.dispatch-console label{display:grid;gap:7px}.dispatch-console input,.dispatch-console select{min-width:0;width:100%;padding:10px;border:1px solid var(--line);border-radius:8px;background:var(--paper)}.dispatch-console fieldset{display:flex;gap:12px;border:1px solid var(--line);border-radius:10px}.dispatch-console fieldset label{display:flex;align-items:center}.dispatch-workbench{--dispatch-load:.22;min-width:0;padding:14px;border-left:8px solid color-mix(in srgb,var(--accent) calc(var(--dispatch-load)*100%),var(--line));background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 8%,transparent),transparent 28%)}.dispatch-workbench[data-dispatch-priority="urgent"]{box-shadow:inset 0 0 0 2px var(--accent)}@media(max-width:900px){.workflow-dispatch{grid-template-columns:1fr}.dispatch-console{order:2}}
</style>
</head>
<body data-aesthetic="art-deco" data-composition="split-note">
<main class="page">
<header class="mast"><div><span class="eyebrow">art-deco / tableau thermique du calendrier / BEGINNER</span><h1>Tableau thermique du calendrier de consommation d’énergie du campus</h1><p class="intro">Créez un tableau de bord de chaleur du calendrier dans un contexte de consommation énergétique du campus : avec contenu réel, contrôles actionnables, retours d’état clairs et disposition adaptative aux différentes tailles d’écran.</p></div><span class="scenario">Consommation énergétique du campus</span></header>
<div class="composition-split"><aside class="split-note"><b>CASE 02</b><span>Maîtriser la structure sémantique, la composition responsive, les interactions au clavier et la synchronisation des états du panneau de chaleur du calendrier.</span></aside><section class="demo" aria-label="Zone interactive du tableau thermique du calendrier de consommation énergétique du campus"><div class="workflow-dispatch"><aside class="dispatch-console"><span class="eyebrow">DISPATCH de la consommation énergétique du campus</span><h2>Tableau de bord de la consommation énergétique du campus</h2><form id="workflowDispatchForm"><label>Type de tâche<select id="workflowDispatchKind"><option>Vue de surveillance de la consommation d’énergie du campus</option><option>Vue de traitement de la consommation d’énergie du campus</option><option>Vue de bilan de la consommation énergétique du campus</option></select></label><label>Seuil d’alerte<input id="workflowDispatchAmount" type="number" min="1" max="9999" value="36"><span>point</span></label><fieldset><legend>Priorité de traitement</legend><label><input type="radio" name="workflowPriority" value="normal" checked>Standard</label><label><input type="radio" name="workflowPriority" value="urgent">Urgent</label></fieldset><button class="action primary" type="submit">Panneau d’application</button></form><label>Tâche en cours<select id="workflowDispatchActive" aria-label="Basculer la tâche en cours"><option value="1">Vue de surveillance de la consommation d’énergie du campus</option><option value="2">Vue de traitement de la consommation d’énergie du campus</option></select></label><output id="workflowDispatchSummary">En attente de planification</output></aside><section id="workflowCore" class="workflow-core dispatch-workbench" data-dispatch-priority="normal"><!-- 11DZ_CORE_START:dashboards-admin-calendar-heatmap --><div class="calendar-heatmap-studio"><header><div><span class="eyebrow">CALENDAR HEATMAP</span><h2>Calendrier actif de la consommation énergétique du campus</h2></div><output id="heatmapSelection">Sélectionnez une date pour voir le niveau d’activité</output></header><div class="heatmap-layout"><section><div class="weekday-row"><span>Un</span><span>Deux</span><span>trois</span><span>quatre</span><span>Cinq</span><span>Six</span><span>Jour</span></div><div class="calendar-heatmap" role="grid" aria-label="7 activité mensuelle"><button type="button" role="gridcell" data-heat="2" aria-label="7 mois 1 jour, activité 2" data-core-bridge="dashboards-admin-calendar-heatmap">1</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 2 jour, activité 4">2</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 3 jour, activité 1">3</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 4 jour, activité 3">4</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 5 jour, activité 0">5</button><button type="button" role="gridcell" data-heat="2" aria-label="7 du mois 6, activité 2">6</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 7 jour, activité 4">7</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 8 jour, activité 1">8</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 9 jour, activité 3">9</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 10 jour, activité 0">10</button><button type="button" role="gridcell" data-heat="2" aria-label="7 mois 11 jour, niveau d’activité 2">11</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 12 jour, niveau d’activité 4">12</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 13 jour, activité 1">13</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 14 jour, activité 3">14</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 15 jour, activité 0">15</button><button type="button" role="gridcell" data-heat="2" aria-label="7 mois 16 jour, activité 2">16</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 17 jour, activité 4">17</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 18 jour, activité 1">18</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 19 jour, activité 3">19</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 20 jour, activité 0">20</button><button type="button" role="gridcell" data-heat="2" aria-label="7 mois 21 jour, activité 2">21</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 22 jour, activité 4">22</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 23 jour, niveau d’activité 1">23</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 24 jour, activité 3">24</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 25 jour, activité 0">25</button><button type="button" role="gridcell" data-heat="2" aria-label="7 le 26 du mois, activité 2">26</button><button type="button" role="gridcell" data-heat="4" aria-label="7 mois 27 jour, activité 4">27</button><button type="button" role="gridcell" data-heat="1" aria-label="7 mois 28 jour, activité 1">28</button><button type="button" role="gridcell" data-heat="3" aria-label="7 mois 29 jour, activité 3">29</button><button type="button" role="gridcell" data-heat="0" aria-label="7 mois 30 jour, activité 0">30</button><button type="button" role="gridcell" data-heat="2" aria-label="7 mois 31 jour, activité 2">31</button></div><footer><span>Peu</span><i data-heat="0"></i><i data-heat="1"></i><i data-heat="2"></i><i data-heat="3"></i><i data-heat="4"></i><span>plusieurs</span></footer></section><aside><strong id="heatmapWeekSummary">Cumul de la première semaine 0</strong><ol id="heatmapWeeks"><li>Semaine 1</li><li>Semaine 2</li><li>Semaine 3</li><li>Semaine 4</li><li>Semaine 5</li></ol></aside></div></div><!-- 11DZ_CORE_END --></section></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-calendar-heatmap */
const heatValues=[2,4,1,3,0,2,4,1,3,0,2,4,1,3,0,2,4,1,3,0,2,4,1,3,0,2,4,1,3,0,2];const heatCells=[...document.querySelectorAll('.calendar-heatmap button')];function renderHeatWeeks(){const weeks=Array.from({length:5},(_,week)=>heatValues.slice(week*7,week===4?31:(week+1)*7).reduce((sum,value)=>sum+value,0));document.querySelector('#heatmapWeeks').replaceChildren(...weeks.map((value,index)=>{const item=document.createElement('li');item.textContent='Deuxième '+(index+1)+' Semaine · cumul '+value;return item;}));document.querySelector('#heatmapWeekSummary').textContent='Cumul de la première semaine '+weeks[0];}heatCells.forEach((cell,index)=>cell.addEventListener('click',()=>{heatCells.forEach(item=>item.removeAttribute('aria-selected'));cell.setAttribute('aria-selected','true');const week=Math.min(4,Math.floor(index/7));document.querySelector('#heatmapSelection').textContent='7 mois '+(index+1)+' Jour · activité '+cell.dataset.heat;document.querySelector('#heatmapWeekSummary').textContent='Deuxième '+(week+1)+' Cumul hebdomadaire '+heatValues.slice(week*7,week===4?31:(week+1)*7).reduce((sum,value)=>sum+value,0);announce(document.querySelector('#heatmapSelection').textContent);}));renderHeatWeeks();
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"dashboards-admin-calendar-heatmap","selector":"[data-core-bridge=\"dashboards-admin-calendar-heatmap\"]","mode":"click","key":"Enter"};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.addEventListener("click",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 workflowDispatchCore=document.querySelector('#workflowCore');const workflowDispatchForm=document.querySelector('#workflowDispatchForm');const workflowDispatchSelect=document.querySelector('#workflowDispatchActive');const workflowDispatchJobs=new Map([["1",{"label":"Vue de surveillance de la consommation d’énergie du campus","amount":12,"priority":"normal","touches":0}],["2",{"label":"Vue de traitement de la consommation d’énergie du campus","amount":21,"priority":"urgent","touches":0}]]);let workflowDispatchSerial=workflowDispatchJobs.size;function workflowDispatchDrive(job,activate=false){workflowDispatchCore.dataset.dispatchPriority=job.priority;workflowDispatchCore.style.setProperty('--dispatch-load',Math.min(.95,.16+job.amount/120));const bridge=activate?workflowBridgeActivate():{changed:false,summary:workflowBridgeSummary()};document.querySelector('#workflowDispatchSummary').textContent=job.label+' · '+job.amount+' point · '+bridge.summary;announce('Tâches en cours de consommation d’énergie du campus :'+job.label);}function workflowDispatchRender(activeId,activate=false){workflowDispatchSelect.replaceChildren(...[...workflowDispatchJobs].map(([id,job])=>{const option=document.createElement('option');option.value=id;option.textContent=job.label+(job.priority==='urgent'?' · Urgent':'');return option;}));workflowDispatchSelect.value=activeId;workflowDispatchDrive(workflowDispatchJobs.get(activeId),activate);}workflowDispatchForm.addEventListener('submit',event=>{event.preventDefault();const data=new FormData(workflowDispatchForm);const id=String(++workflowDispatchSerial);workflowDispatchJobs.set(id,{label:document.querySelector('#workflowDispatchKind').value,amount:Math.max(1,Number(document.querySelector('#workflowDispatchAmount').value)||1),priority:data.get('workflowPriority'),touches:0});workflowDispatchRender(id,true);});workflowDispatchSelect.addEventListener('change',()=>workflowDispatchDrive(workflowDispatchJobs.get(workflowDispatchSelect.value),true));workflowDispatchCore.addEventListener('focusin',()=>{const job=workflowDispatchJobs.get(workflowDispatchSelect.value);if(!job)return;job.touches+=1;document.querySelector('#workflowDispatchSummary').textContent=job.label+' · '+job.amount+' point · '+workflowBridgeSummary();});workflowDispatchRender('1',false);
workflowBridgeReset();
</script>
</body>
</html>