Unternehmenssoftware · Neue Ressource

Workday Canvas-Designsystem.

Erstelle einen lokalen Lernplan mit Canvas Kits zusammengesetztem FormField, einem kontrollierten TextInput und PrimaryButton. Unterscheide dabei zwischen aktuellen semantischen Token-Quellen und älteren space.x4-Migrationsbeispielen.

OpenDesign-Leitfaden7 Kapitel33 ReferenzeinträgeOriginaler Anwendungsleitfaden
01

Workday Canvas-Designsystem – Oberflächenvorschau

Filtere Kurstitel, füge Kurse jeweils nur einmal hinzu, entferne Auswahlen und vergleiche die aktuelle Gesamtzeit.

Ursprüngliche Offline-Interpretation von HTML-Interaktionsmustern für Canvas mit zurückhaltender Hierarchie für Unternehmen. Farbpalette und Layout sind Entscheidungen auf Anwendungsebene und stellen keine Darstellung eines Sana-Mandanten dar. · Implementierungsreferenz
02

Workday Canvas-Designsystem – Designreferenz

Aktueller Canvas Kit-Quellcode und Canvas-Token sys.json. Die JSON-Namen sind Quellpfade und keine erfundenen generierten CSS-Variablennamen. Werte, die auf Basistokens verweisen, sind als Referenzen angegeben; die datierte Migrationsreferenz ist ausdrücklich historisch.

Aktuelle Abstandssemantik

Quelle
Name / RegelWert / KonfigurationVerwendung
sys.padding.xs{base.size.100}Rolle für den horizontalen Innenabstand von Eingabefeldern.
sys.padding.md{base.size.200}Standard-Innenabstand der Komponente.
sys.padding.xl{base.size.300}Innenabstand der Karte.
sys.gap.sm{base.size.100}Kompakter Abstand zwischen Geschwisterelementen.
sys.gap.md{base.size.200}Standardabstand zwischen Inline-Elementen.
sys.gap.xl{base.size.400}Karteninnenabstand.
sys.gap.xxl{base.size.800}Abschnittsabstand.

Aktuelle Typografie und Form

Quelle
Name / RegelWert / KonfigurationVerwendung
sys.type.body.smfont-size body.sm + line-height body.sm + normal weightZusammengesetzte Rolle für Fließtext.
sys.font-size.body.sm{base.size.200}Referenz auf die Basisschriftgröße für Fließtext.
sys.line-height.body.sm{base.size.300}Referenz auf den Zeilenabstand für Fließtext.
sys.font-weight.normal{base.font-weight.400}Aktuelle Bezeichnung: normal, nicht regular.
sys.shape.sm{base.size.50}Kleine Abrundung.
sys.shape.md{base.size.100}Abrundung für Eingabefelder.
sys.shape.full{base.size.75} × 100Vollständige Abrundung.

Aufbau von FormField

Quelle
Name / RegelWert / KonfigurationVerwendung
FormField.LabelConnected label elementGenerierte Verknüpfung mit dem Eingabefeld.
FormField.Input as={TextInput}Polymorphic input slotNicht die alte label-Prop API.
FormField.HintLinked helper contentBeschreibe die erwartete Eingabe.
orientationvertical / horizontalStart / horizontalEndVerwende die aktuellen Ausrichtungswerte.
FormField.FieldInput and hint alignment wrapperNützlich in horizontalen Layouts.

Implementierung von TextInput

Quelle
Name / RegelWert / KonfigurationVerwendung
grow100% width when trueResponsive Vergrößerung des Eingabefelds.
widthnumber or stringOptionale Überschreibung.
minimum width fallbackpx2rem(280)Prüfe Layouts mit schmalen übergeordneten Containern.
errorerror / caution stylingDie Anwendung stellt die Validierung bereit.
transition0.2s box-shadow, 0.2s border-colorTatsächlicher Übergang im Quellcode.
font size rolesystem.legacy.fontSize.subtext.lgErsetze die internen Komponenten nicht durch einen unabhängigen Titeltyp.

Implementierung von PrimaryButton

Quelle
Name / RegelWert / KonfigurationVerwendung
Backgroundbrand.action.base, with legacy accent fallbackMarkenfarben des Mandanten.
Hoverbrand.action.dark or colorSpace.hoverDer Status leitet sich von der Aktionsfarbe ab.
Pressedbrand.action.darkest or colorSpace.pressedDeutliche Darstellung beim Drücken.
variant="inverse"Inverse surface and foreground rolesFür einen geeigneten kontrastierenden Kontext.
Border radiussystem.legacy.shape.fullDer Quellcode bietet derzeit weiterhin Legacy-Kompatibilität.

Migrationsreferenz, keine aktuellen Tokennamen

Quelle
Name / RegelWert / KonfigurationVerwendung
Former space.s → system.space.x41rem in 2023 migration tableDer aktuelle Quellcode unterscheidet zwischen Innenabstand und Abstand.
Former space.m → system.space.x61.5rem in 2023 migration tableGehe nicht davon aus, dass alte Namen weiterhin bevorzugt werden.
Former borderRadius.m → system.shape.x10.25rem in 2023 migration tableDer aktuelle Quellcode verwendet semantische Formgrößen.
03

Vollständiger Leitfaden zum Workday Canvas-Designsystem

Ein praktischer Leitfaden zur Auswahl, Anwendung und Überprüfung dieses Systems für ein echtes Interface.

DESIGN-workday-canvas.md

Umfassende Anleitung, Einstieg in die Implementierung und Links zu den Quellen.

Leitfaden herunterladen

Workday Canvas-Designsystem: Prüfe den aktuellen Quellcode, bevor du ein Migrationsbeispiel übernimmst

Abstände unterscheiden jetzt nach ihrem Zweck

Canvas hat sich von den T-Shirt-Abstandskonstanten in canvas-kit-react/tokens über nummerierte system.space-Tokens hin zu Quellkategorien wie Innenabstand und Abstand weiterentwickelt. Das aktuelle sys.json gibt die zugrunde liegenden Werte als Referenzen auf Basistokens an. Diese Referenz übernimmt die tatsächlichen Pfade, statt einen CSS-Variablennamen durch das Aneinanderfügen von Wörtern zu erfinden.

Aus diesem OpenDesign-Leitfaden

Die Migrationstabelle ist bei der Umstellung einer älteren Anwendung weiterhin nützlich: Sie erklärt, warum der frühere Wert space.s einem Rem entsprach. Sie ist ein historischer Beleg und keine Zusicherung, dass jeder alte Export die bevorzugte aktuelle Schnittstelle ist. Die Vorschau verwendet ausdrücklich gewählte Anwendungsabstände von 16 und 24px; für die Tokennamen der Bibliothek ist weiterhin die Quelltabelle maßgeblich.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: Farben richten sich nach Mandant und Komponentenstatus

Ein primärer Button ist mehr als ein festgelegter Blauton

PrimaryButton liest zuerst brand.action.base aus und greift andernfalls auf den bisherigen primären Akzent zurück. Hover- und Gedrückt-Stile berücksichtigen ebenfalls zunächst die Markenrollen für Aktionen und leiten die Statusfarben anschließend über colorSpace-Hilfsfunktionen ab. Deshalb lässt sich der Themenvertrag der Komponente nicht nachbilden, indem man einfach eine fest codierte Hintergrundfarbe ändert.

Die ursprüngliche Lernvorschau verwendet eine zurückhaltende blaue Anwendungspalette und bezeichnet sich als Interpretation von HTML. Sie stellt weder einen bestimmten Kundenmandanten noch das neuere Sana Canvas-Theme dar. Im vollständigen nativen Beispiel stellen die installierten Tokenebenen die Komponentenfarben bereit.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: Zusammengesetzte Rollen bewahren Zeilenhöhe und Schriftstärke

Ein Größenalias bildet nicht den gesamten Stil ab

Das aktuelle Typografieobjekt body.sm vereint Schriftfamilie, normale Schriftstärke, Schriftgröße für Fließtext und Zeilenabstand für Fließtext. Überschriftenrollen verwenden die fette Schriftstärke. Wer nur eine Pixelgröße aus einem älteren Screenshot übernimmt, verliert diese Zusammenhänge. Im Quellcode wird die Schriftstärke als normal statt als regular bezeichnet, wie es in älteren Migrationstexten vorkommt.

Die Canvas Kit-Komponentenbibliothek enthält keine Schriftarten. Behandle das Laden von Schriftarten als separate Integrationsentscheidung. Das Offline-Beispiel verwendet eine System-Fallback-Schrift und gibt nicht vor, Roboto oder eine Sana-Schriftart mitzuliefern.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: FormField ist eine zusammengesetzte Komponente

Lass das Feld Label, Eingabefeld und Hinweis zusammensetzen

Der Quellcode stellt FormField.Label, FormField.Input und FormField.Hint bereit. Wenn du TextInput über die Input-Prop bereitstellst, kann das Modell die barrierefreien Verknüpfungen erzeugen. Das unterscheidet sich von älteren Beispielen, die dem äußeren Feld eine label-Prop übergaben und ein nicht umschlossenes Eingabefeld direkt darin platzierten.

Für horizontale Formulare sind horizontalStart und horizontalEnd die aktuellen Ausrichtungswerte. FormField.Field gruppiert das Eingabefeld und den Hinweis innerhalb dieser Ausrichtung. Unser Filter bleibt vertikal, weil seine Erläuterung direkt unter dem Label und dem Steuerelement stehen soll.

  • Füge in FormField.Label ein sichtbares Label ein.
  • Übergib TextInput über den zusammengesetzten Input-Slot.
  • Verwende Hint, um den Filterbereich zu erläutern.
  • Behalte die Validierungslogik beim Hinzufügen von Einschränkungen in der Anwendung.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: Auch ein Eingabefeld mit automatischer Größenanpassung braucht einen flexiblen übergeordneten Container

Berücksichtige die Mindestbreite

TextInput hat eine Fallback-Mindestbreite von 280px, die im Quellcode mit px2rem ausgedrückt wird. grow fordert die volle Breite an; dadurch passt ein starres zweispaltiges Elternelement nicht automatisch in einen schmalen Viewport. Der Offline-Katalog ordnet auf Mobilgeräten die Plan-Seitenleiste unter den Kurskarten an und lässt jede Layoutspalte schrumpfen.

Der Suchwert ist ein gewöhnlicher React-Zustand. Die App vergleicht die drei Kurstitel ohne Beachtung der Groß- und Kleinschreibung auf Teilzeichenfolgen und zeigt bei einem leeren Ergebnis einen ausdrücklichen Hinweis an. Der Filter hebt keine ausgewählten Kurse auf, denn Sichtbarkeit und Planmitgliedschaft sind unterschiedliche Zustände.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: Die Auswahl bleibt unabhängig von den sichtbaren Ergebnissen erhalten

Stabile Kurs-IDs verwenden und Summen ableiten

Jeder ursprüngliche Kurs hat eine ID, einen Titel und eine Dauer. Die Auswahlliste speichert IDs, während die angezeigte Gesamtdauer aus den Kursdatensätzen abgeleitet wird. Durch das Filtern des Katalogs wird kein ausgewählter Eintrag entfernt. Beim Entfernen eines Eintrags wird die Aktion „Hinzufügen“ sofort wieder verfügbar und die Gesamtdauer verringert sich.

Dies ist ein eigenständiges lokales Planungsszenario. Es ruft keine Workday-APIs auf, meldet keine Beschäftigten an und ändert keine Lernaufzeichnungen. Diese Abgrenzung verhindert, dass ein Prototyp den Eindruck erweckt, eine echte Geschäftstransaktion auszuführen.

  1. Nur die Katalogansicht filtern.
  2. Eine Kurs-ID nur einmal hinzufügen.
  3. Ausgewählte Kurse und Gesamtdauer anhand dieser IDs ableiten.
  4. Eine Auswahl entfernen, ohne die Suche zurückzusetzen.

Unterstützende Spezifikation lesen

Workday Canvas-Designsystem: Tokens laden, bevor thematisierte Komponenten erwartet werden

Provider und CSS-Ebenen haben unterschiedliche Aufgaben

Das aktuelle Beispiel für den Einstieg importiert die Styles für Basis-, Marken-, Komponenten- und Systemvariablen am Einstiegspunkt der Anwendung und umschließt anschließend die Benutzeroberfläche mit CanvasProvider. Ein Provider ersetzt nicht allein diese CSS-Definitionen. Der Code hier folgt dieser Zusammensetzung und stellt ein vollständiges React-Root bereit.

Sana Canvas ist optional: Seine Variablen werden nach den Systemvariablen geladen, und das dokumentierte html-Attribut data-theme wählt es aus. Eingebettete Anwendungen, die das Dokument-Root nicht steuern können, verfügen über eine eigene Provider-Theme-Option zur Weitergabe an Pop-ups. Fügen Sie dieses Theme beim Aktualisieren von Paketen nicht versehentlich zu einem bestehenden Mandanten hinzu.

Unterstützende Spezifikation lesen

Beispiele für Komponenten des Workday Canvas-Designsystems

Vollständige, eigenständige interaktive Demo

Speichern Sie das vollständige Dokument als index.html und öffnen Sie es in einem Browser. Eine eigenständige Offline-Interpretation von HTML-Interaktionsmustern und einer zurückhaltenden Unternehmenshierarchie. Farbpalette und Layout sind Entscheidungen für die Anwendung und keine Darstellung eines Sana-Mandanten.

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Canvas learning plan interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#f3f5f7;color:#20272f;font:16px/1.5 system-ui,sans-serif}button,input{font:inherit}header{background:white;border-bottom:1px solid #d5dbe0;padding:16px 24px;display:flex;gap:12px;align-items:center}.mark{width:32px;height:32px;border:4px solid #ed9b28;border-bottom:0;border-radius:50% 50% 0 0;height:16px;margin-right:8px}header span{font-size:14px;color:#59616b;margin-left:auto}main{max-width:1100px;margin:32px auto;padding:0 24px}h1{font-size:28px;line-height:36px;margin:0 0 8px}p{margin:0 0 24px}label{display:block;font-size:14px;font-weight:600;margin-bottom:8px}#search{width:100%;max-width:580px;height:40px;border:1px solid #89949f;border-radius:8px;padding:8px 12px;background:white}.hint{font-size:12px;color:#59616b;margin:8px 0 24px}.layout{display:grid;grid-template-columns:1fr 290px;gap:24px;align-items:start}.course{display:grid;grid-template-columns:96px 1fr;gap:24px;background:white;padding:24px;border-radius:8px;border:1px solid #d5dbe0;margin-bottom:16px;min-width:0}.art{height:96px;display:grid;place-items:center;border-radius:8px;font-size:40px;color:#005cb9;background:#e7f1fd}.art.orange{background:#fff0d6;color:#805200}.art.green{background:#e6f4ed;color:#236443}.category{font-size:12px;color:#59616b;text-transform:uppercase;letter-spacing:1px}h2{font-size:20px;line-height:28px;margin:4px 0 8px}.course p{font-size:14px;margin:0 0 16px;color:#59616b}.row{display:flex;justify-content:space-between;align-items:center;gap:16px}.row span{font-size:14px;color:#59616b}button{border:0;border-radius:999px;background:#005cb9;color:white;font-size:14px;font-weight:600;padding:8px 16px;cursor:pointer}button:disabled{opacity:.5;cursor:default}button:focus-visible,input:focus-visible{outline:3px solid #005cb9;outline-offset:3px}.plan{padding:24px;background:white;border:1px solid #d5dbe0;border-radius:8px}.plan h2{margin:0 0 16px}.number{font-size:36px;font-weight:700;line-height:1.2}.plan-total{padding-bottom:20px;border-bottom:1px solid #d5dbe0;margin-bottom:20px}.plan-total span{font-size:14px}.plan ul{padding:0;list-style:none;margin:0}.plan li{border-bottom:1px solid #e6e9ed;padding:0 0 16px;margin:0 0 16px;font-size:14px}.remove{background:transparent;color:#005cb9;padding:4px 0;display:block;border-radius:3px;text-decoration:underline;font-weight:400}.empty{font-size:14px;color:#59616b}.boundary{font-size:12px;color:#59616b;margin-top:24px}.no-results{background:white;border:1px solid #d5dbe0;padding:24px;border-radius:8px}@media(max-width:720px){main{padding:0 16px;margin:24px auto}.layout{grid-template-columns:1fr}.course{padding:16px;grid-template-columns:60px 1fr;gap:16px}.art{height:60px;font-size:28px}header span{display:none}.row{align-items:flex-start;flex-direction:column;gap:8px}.plan{padding:20px}}
</style><header><div class="mark" aria-hidden="true"></div><strong>Learning workspace</strong><span>Personal development · Local plan</span></header><main><h1>Make room to grow</h1><p>Choose a few focused lessons for your learning plan.</p><label for="search">Find a course</label><input id="search" type="search" placeholder="Search course titles" aria-describedby="hint"><p id="hint" class="hint">Search filters the catalog; your selected courses stay in the plan.</p><div class="layout"><section id="catalog" aria-label="Course catalog"></section><aside class="plan"><h2>Your local plan</h2><div class="plan-total" role="status"><div class="number" id="minutes">0</div><span>minutes · <span id="count">0</span> <span id="course-word">courses</span></span></div><ul id="selected"></ul><p class="empty" id="empty">Add a course to start your plan.</p><small>No enrollment is submitted.</small></aside></div><p class="boundary">Independent HTML interpretation of Canvas composition patterns. Original palette, course illustrations and content; no Workday account or enrollment service is connected.</p></main><script>const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25,category:'Communication',description:'Practice clear observations and constructive next steps.',art:'◎',color:''},{id:'planning',name:'Planning a focused week',minutes:20,category:'Personal effectiveness',description:'Protect attention and organize a realistic working week.',art:'▤',color:'orange'},{id:'meetings',name:'Running inclusive meetings',minutes:30,category:'Teamwork',description:'Make space for different voices and useful decisions.',art:'◌',color:'green'}];let chosen=new Set;const catalog=document.querySelector('#catalog');function render(){let matches=courses.filter(c=>c.name.toLowerCase().includes(document.querySelector('#search').value.toLowerCase()));catalog.innerHTML=matches.length?matches.map(c=>`<article class="course"><div class="art ${c.color}" aria-hidden="true">${c.art}</div><div><div class="category">${c.category}</div><h2>${c.name}</h2><p>${c.description}</p><div class="row"><span>${c.minutes} minutes</span><button data-add="${c.id}" ${chosen.has(c.id)?'disabled':''}>${chosen.has(c.id)?'Added to plan':'Add to plan'}</button></div></div></article>`).join(''):'<div class="no-results">No matching courses. Try “feedback” or clear your search.</div>';let selected=courses.filter(c=>chosen.has(c.id));document.querySelector('#minutes').textContent=selected.reduce((sum,c)=>sum+c.minutes,0);document.querySelector('#count').textContent=selected.length;document.querySelector('#course-word').textContent=selected.length===1?'course':'courses';document.querySelector('#empty').hidden=selected.length>0;document.querySelector('#selected').innerHTML=selected.map(c=>`<li>${c.name}<button class="remove" data-remove="${c.id}" aria-label="Remove ${c.name}">Remove</button></li>`).join('');document.querySelectorAll('[data-add]').forEach(b=>b.onclick=()=>{let id=b.dataset.add;chosen.add(id);render();document.querySelector('[data-remove="'+id+'"]').focus()});document.querySelectorAll('[data-remove]').forEach(b=>b.onclick=()=>{let id=b.dataset.remove;chosen.delete(id);render();let add=document.querySelector('[data-add="'+id+'"]');(add||document.querySelector('#search')).focus()})}document.querySelector('#search').oninput=render;render();</script></html>

Code-Referenz

  • Durch das Hinzufügen eines Kurses ändert sich der beispielhafte Lernplan. Der native Eintrag veranschaulicht separat CanvasProvider und das zusammengesetzte FormField API; es wird keine Anmeldung übermittelt.

Zusammengesetztes Feld und auswählbare Lerneinheiten

FormField erstellt die Verknüpfung zum Eingabefeld, TextInput filtert die ursprünglichen Kursdaten, und jede PrimaryButton fügt einen Eintrag nur einmal hinzu. Beim Entfernen wird die Gesamtdauer der Auswahl neu berechnet.

jsx
// In a React 18+ application with a bundler:
// npm install @workday/canvas-kit-react @workday/canvas-tokens-web @workday/canvas-kit-styling @emotion/react @emotion/styled
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import {CanvasProvider} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {system} from '@workday/canvas-tokens-web';
import {cssVar} from '@workday/canvas-kit-styling';
import '@workday/canvas-tokens-web/css/base/_variables.css';
import '@workday/canvas-tokens-web/css/brand/_variables.css';
import '@workday/canvas-tokens-web/css/component/_variables.css';
import '@workday/canvas-tokens-web/css/system/_variables.css';
// Default theme example; do not silently add a Sana theme to an existing tenant.
const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25},{id:'planning',name:'Planning a focused week',minutes:20},{id:'meetings',name:'Running inclusive meetings',minutes:30}];
function LearningPlan(){
 const [query,setQuery]=useState(''),[chosen,setChosen]=useState([]);
 const visible=courses.filter(c=>c.name.toLowerCase().includes(query.toLowerCase()));
 const selected=courses.filter(c=>chosen.includes(c.id));
 return <main style={{fontFamily:cssVar(system.fontFamily.default),maxWidth:900,margin:'auto',padding:24}}>
 <h1>Build a learning plan</h1>
 <FormField><FormField.Label>Find a course</FormField.Label>
  <FormField.Input as={TextInput} grow value={query} onChange={e=>setQuery(e.target.value)}/>
  <FormField.Hint>Filter the three example course titles.</FormField.Hint>
 </FormField>
 <ul>{visible.map(c=><li key={c.id} style={{margin:'24px 0'}}><h2>{c.name}</h2><p>{c.minutes} minutes</p>
  <PrimaryButton type="button" disabled={chosen.includes(c.id)} onClick={()=>setChosen(old=>[...old,c.id])}>
   {chosen.includes(c.id)?'Added to plan':'Add to plan'}
  </PrimaryButton></li>)}</ul>
 {!visible.length&&<p>No matching courses.</p>}
 <section aria-label="Learning plan"><h2>Your local plan</h2><p role="status">{selected.length} courses · {selected.reduce((sum,c)=>sum+c.minutes,0)} minutes</p>
 <ul>{selected.map(c=><li key={c.id}>{c.name} <button type="button" onClick={()=>setChosen(old=>old.filter(id=>id!==c.id))}>Remove {c.name}</button></li>)}</ul>
 <p>No enrollment is submitted.</p></section></main>;
}
createRoot(document.getElementById('root')).render(<CanvasProvider><LearningPlan/></CanvasProvider>);

Code-Referenz

  • Jeder eigenständige Kurseintrag hat eine eigene PrimaryButton; für den gesamten Plan gibt es keine irreführende Anmeldeaktion.
  • Für das Entfernen wird ein ausdrücklich von der Anwendung bereitgestellter nativer Button verwendet.
  • Der deaktivierte Zustand „Hinzugefügt“ verhindert Duplikate, während eine Live-Zählung die Änderung bestätigt.
04

Workday Canvas-Designsystem-Agenteneinrichtung

Ausgangspunkt für die Implementierung

Vollständige React-Zusammensetzung für eine gebündelte Anwendung. Aktuelle Einrichtung von CanvasProvider und Token-CSS; ursprüngliche Kursdaten und native Steuerelemente zum Entfernen. Keine Remote-Anmeldung. Quelle geprüft, in diesem Workspace jedoch nicht als Paket kompiliert.

jsx
// In a React 18+ application with a bundler:
// npm install @workday/canvas-kit-react @workday/canvas-tokens-web @workday/canvas-kit-styling @emotion/react @emotion/styled
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import {CanvasProvider} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {system} from '@workday/canvas-tokens-web';
import {cssVar} from '@workday/canvas-kit-styling';
import '@workday/canvas-tokens-web/css/base/_variables.css';
import '@workday/canvas-tokens-web/css/brand/_variables.css';
import '@workday/canvas-tokens-web/css/component/_variables.css';
import '@workday/canvas-tokens-web/css/system/_variables.css';
// Default theme example; do not silently add a Sana theme to an existing tenant.
const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25},{id:'planning',name:'Planning a focused week',minutes:20},{id:'meetings',name:'Running inclusive meetings',minutes:30}];
function LearningPlan(){
 const [query,setQuery]=useState(''),[chosen,setChosen]=useState([]);
 const visible=courses.filter(c=>c.name.toLowerCase().includes(query.toLowerCase()));
 const selected=courses.filter(c=>chosen.includes(c.id));
 return <main style={{fontFamily:cssVar(system.fontFamily.default),maxWidth:900,margin:'auto',padding:24}}>
 <h1>Build a learning plan</h1>
 <FormField><FormField.Label>Find a course</FormField.Label>
  <FormField.Input as={TextInput} grow value={query} onChange={e=>setQuery(e.target.value)}/>
  <FormField.Hint>Filter the three example course titles.</FormField.Hint>
 </FormField>
 <ul>{visible.map(c=><li key={c.id} style={{margin:'24px 0'}}><h2>{c.name}</h2><p>{c.minutes} minutes</p>
  <PrimaryButton type="button" disabled={chosen.includes(c.id)} onClick={()=>setChosen(old=>[...old,c.id])}>
   {chosen.includes(c.id)?'Added to plan':'Add to plan'}
  </PrimaryButton></li>)}</ul>
 {!visible.length&&<p>No matching courses.</p>}
 <section aria-label="Learning plan"><h2>Your local plan</h2><p role="status">{selected.length} courses · {selected.reduce((sum,c)=>sum+c.minutes,0)} minutes</p>
 <ul>{selected.map(c=><li key={c.id}>{c.name} <button type="button" onClick={()=>setChosen(old=>old.filter(id=>id!==c.id))}>Remove {c.name}</button></li>)}</ul>
 <p>No enrollment is submitted.</p></section></main>;
}
createRoot(document.getElementById('root')).render(<CanvasProvider><LearningPlan/></CanvasProvider>);

Ein Prompt für dein Projekt

Agenten-Prompt
Verwenden Sie die aktuelle Canvas-FormField-Zusammensetzung und die Token-CSS-Ebenen. Halten Sie die Kursfilterung vom Auswahlzustand getrennt, verhindern Sie Duplikate und leiten Sie die Gesamtdauer ab. Bewahren Sie das Mandanten-Theme mithilfe semantischer Rollen. Verwechseln Sie historische nummerierte Namen für Abstände nicht mit den aktuell bevorzugten Quellkategorien.
05

Workday Canvas-Designsystem: Quellen und Geltungsbereich

Eigenständige Referenz zum OpenDesign-Designsystem. Es findet weder eine Anmeldung von Beschäftigten noch eine Einbindung von Workday API statt. Aktuelle Quellnamen und ältere Migrationsnamen sind klar voneinander abgegrenzt.