canvas-design-mcp 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CLAUDE.md +200 -0
  2. package/DESIGN.md +288 -0
  3. package/PROFESSOR-INSTRUCTIONS.txt +131 -0
  4. package/README.md +250 -0
  5. package/dist/canvas-api.d.ts +24 -0
  6. package/dist/canvas-api.d.ts.map +1 -0
  7. package/dist/canvas-api.js +146 -0
  8. package/dist/canvas-api.js.map +1 -0
  9. package/dist/config.d.ts +5 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +22 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/design-engine.d.ts +5 -0
  14. package/dist/design-engine.d.ts.map +1 -0
  15. package/dist/design-engine.js +23 -0
  16. package/dist/design-engine.js.map +1 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +567 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/tools/accessibility.d.ts +7 -0
  22. package/dist/tools/accessibility.d.ts.map +1 -0
  23. package/dist/tools/accessibility.js +149 -0
  24. package/dist/tools/accessibility.js.map +1 -0
  25. package/dist/tools/contrast.d.ts +2 -0
  26. package/dist/tools/contrast.d.ts.map +1 -0
  27. package/dist/tools/contrast.js +7 -0
  28. package/dist/tools/contrast.js.map +1 -0
  29. package/dist/tools/critique.d.ts +23 -0
  30. package/dist/tools/critique.d.ts.map +1 -0
  31. package/dist/tools/critique.js +194 -0
  32. package/dist/tools/critique.js.map +1 -0
  33. package/dist/tools/generate.d.ts +18 -0
  34. package/dist/tools/generate.d.ts.map +1 -0
  35. package/dist/tools/generate.js +101 -0
  36. package/dist/tools/generate.js.map +1 -0
  37. package/dist/tools/gotchas.d.ts +7 -0
  38. package/dist/tools/gotchas.d.ts.map +1 -0
  39. package/dist/tools/gotchas.js +61 -0
  40. package/dist/tools/gotchas.js.map +1 -0
  41. package/dist/tools/ingest.d.ts +44 -0
  42. package/dist/tools/ingest.d.ts.map +1 -0
  43. package/dist/tools/ingest.js +211 -0
  44. package/dist/tools/ingest.js.map +1 -0
  45. package/dist/tools/list-courses.d.ts +16 -0
  46. package/dist/tools/list-courses.d.ts.map +1 -0
  47. package/dist/tools/list-courses.js +79 -0
  48. package/dist/tools/list-courses.js.map +1 -0
  49. package/dist/tools/page-io.d.ts +19 -0
  50. package/dist/tools/page-io.d.ts.map +1 -0
  51. package/dist/tools/page-io.js +77 -0
  52. package/dist/tools/page-io.js.map +1 -0
  53. package/dist/tools/panopto.d.ts +36 -0
  54. package/dist/tools/panopto.d.ts.map +1 -0
  55. package/dist/tools/panopto.js +188 -0
  56. package/dist/tools/panopto.js.map +1 -0
  57. package/dist/tools/personas.d.ts +21 -0
  58. package/dist/tools/personas.d.ts.map +1 -0
  59. package/dist/tools/personas.js +464 -0
  60. package/dist/tools/personas.js.map +1 -0
  61. package/dist/tools/philosophy.d.ts +21 -0
  62. package/dist/tools/philosophy.d.ts.map +1 -0
  63. package/dist/tools/philosophy.js +137 -0
  64. package/dist/tools/philosophy.js.map +1 -0
  65. package/dist/tools/publish.d.ts +31 -0
  66. package/dist/tools/publish.d.ts.map +1 -0
  67. package/dist/tools/publish.js +198 -0
  68. package/dist/tools/publish.js.map +1 -0
  69. package/dist/tools/redesign.d.ts +18 -0
  70. package/dist/tools/redesign.d.ts.map +1 -0
  71. package/dist/tools/redesign.js +68 -0
  72. package/dist/tools/redesign.js.map +1 -0
  73. package/dist/tools/update-kb.d.ts +10 -0
  74. package/dist/tools/update-kb.d.ts.map +1 -0
  75. package/dist/tools/update-kb.js +93 -0
  76. package/dist/tools/update-kb.js.map +1 -0
  77. package/dist/tools/validate.d.ts +10 -0
  78. package/dist/tools/validate.d.ts.map +1 -0
  79. package/dist/tools/validate.js +76 -0
  80. package/dist/tools/validate.js.map +1 -0
  81. package/dist/types.d.ts +65 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/dist/wizard.d.ts +3 -0
  86. package/dist/wizard.d.ts.map +1 -0
  87. package/dist/wizard.js +229 -0
  88. package/dist/wizard.js.map +1 -0
  89. package/docs/canvas-design-kb/00-meta/Changelog.md +42 -0
  90. package/docs/canvas-design-kb/00-meta/Contributing.md +58 -0
  91. package/docs/canvas-design-kb/00-meta/KB-Overview.md +51 -0
  92. package/docs/canvas-design-kb/01-canvas-rce/CSS-Inline-Strategy.md +166 -0
  93. package/docs/canvas-design-kb/01-canvas-rce/Canvas-Built-In-CSS-Classes.md +243 -0
  94. package/docs/canvas-design-kb/01-canvas-rce/Canvas-Page-Types.md +59 -0
  95. package/docs/canvas-design-kb/01-canvas-rce/HTML-Allowlist.md +204 -0
  96. package/docs/canvas-design-kb/01-canvas-rce/RCE-Limitations-and-Workarounds.md +151 -0
  97. package/docs/canvas-design-kb/01-canvas-rce/RCE-Overview.md +92 -0
  98. package/docs/canvas-design-kb/02-design-md/DESIGN-MD-Canvas-Template.md +323 -0
  99. package/docs/canvas-design-kb/02-design-md/DESIGN-MD-File-Structure.md +245 -0
  100. package/docs/canvas-design-kb/02-design-md/DESIGN-MD-Overview.md +120 -0
  101. package/docs/canvas-design-kb/02-design-md/DESIGN-MD-Toolchain.md +234 -0
  102. package/docs/canvas-design-kb/03-design-systems/Color-and-Typography.md +146 -0
  103. package/docs/canvas-design-kb/03-design-systems/Component-Library.md +299 -0
  104. package/docs/canvas-design-kb/03-design-systems/Design-System-Principles.md +99 -0
  105. package/docs/canvas-design-kb/04-tools/Canvas-Theme-Editor.md +40 -0
  106. package/docs/canvas-design-kb/04-tools/Other-Canvas-Design-Tools.md +47 -0
  107. package/docs/canvas-design-kb/05-patterns/Course-Home-Page.md +224 -0
  108. package/docs/canvas-design-kb/06-accessibility/Accessibility-Overview.md +128 -0
  109. package/docs/canvas-design-kb/07-resources/Inspiration-and-Showcases.md +121 -0
  110. package/docs/canvas-design-kb/07-resources/Official-Canvas-Links.md +54 -0
  111. package/docs/canvas-design-kb/README.md +58 -0
  112. package/docs/feature-roadmap.md +123 -0
  113. package/docs/installation.md +340 -0
  114. package/package.json +45 -0
  115. package/scripts/deploy-public.ps1 +68 -0
  116. package/src/kb/design-principles.md +45 -0
  117. package/src/templates/ignite-assignment-page.html +203 -0
  118. package/src/templates/two-column-dashboard.html +33 -0
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { InstitutionConfig } from './types.js';
2
+ export declare function runWizard(): Promise<InstitutionConfig>;
3
+ //# sourceMappingURL=wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAqCpD,wBAAsB,SAAS,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA6N5D"}
package/dist/wizard.js ADDED
@@ -0,0 +1,229 @@
1
+ import { confirm, input, password } from '@inquirer/prompts';
2
+ import Color from 'color';
3
+ import { saveConfig } from './config.js';
4
+ import { wcagContrastRatio } from './tools/contrast.js';
5
+ import { getPhilosophyKb, savePhilosophyKb, updatePhilosophyKb, PHILOSOPHY_TEMPLATE, } from './tools/philosophy.js';
6
+ function deriveColors(primary, secondary) {
7
+ const c = Color(primary);
8
+ return {
9
+ primary,
10
+ primaryDark: c.darken(0.25).hex(),
11
+ primaryLight: c.lightness(93).hex(),
12
+ secondary,
13
+ };
14
+ }
15
+ function printMcpConfig() {
16
+ const config = {
17
+ mcpServers: {
18
+ 'canvas-design': {
19
+ command: 'npx',
20
+ args: ['canvas-design-mcp'],
21
+ },
22
+ },
23
+ };
24
+ console.log('\n┌─────────────────────────────────────────────────────────┐');
25
+ console.log('│ Add this to your Claude Code MCP settings: │');
26
+ console.log('└─────────────────────────────────────────────────────────┘\n');
27
+ console.log(JSON.stringify(config, null, 2));
28
+ console.log('\nRestart Claude Code (or your MCP host) to activate.\n');
29
+ console.log('Works in: Claude Code · VS Code · ChatGPT Codex · any MCP host\n');
30
+ }
31
+ export async function runWizard() {
32
+ console.log('\n╔═══════════════════════════════════════════════════════════╗');
33
+ console.log('║ Canvas Design Studio — First Run Setup ║');
34
+ console.log('╚═══════════════════════════════════════════════════════════╝\n');
35
+ console.log('This wizard saves your institution config once.');
36
+ console.log('All fields except Canvas URL and API token can be changed later.\n');
37
+ const institution = await input({
38
+ message: 'Institution name:',
39
+ default: 'Boise State University',
40
+ });
41
+ let primaryHex;
42
+ while (true) {
43
+ primaryHex = await input({
44
+ message: 'Primary brand color (#hex):',
45
+ default: '#0033A0',
46
+ validate: (v) => /^#[0-9A-Fa-f]{6}$/.test(v) || 'Enter a valid hex color (e.g. #0033A0)',
47
+ });
48
+ const primaryRatio = wcagContrastRatio(primaryHex, '#ffffff');
49
+ if (primaryRatio >= 4.5) {
50
+ console.log(` Contrast on white: ${primaryRatio.toFixed(2)}:1 — passes WCAG AA`);
51
+ break;
52
+ }
53
+ console.log(` Contrast on white: ${primaryRatio.toFixed(2)}:1 — ${primaryRatio >= 3.0 ? 'marginal' : 'fails'} for body text (AA requires 4.5:1)`);
54
+ console.log(' White text on this color may not be readable at small sizes. Consider darkening slightly.');
55
+ const go = await confirm({ message: 'Proceed with this color?', default: true });
56
+ if (go)
57
+ break;
58
+ }
59
+ let secondaryHex;
60
+ while (true) {
61
+ secondaryHex = await input({
62
+ message: 'Secondary / accent color (#hex):',
63
+ default: '#D64309',
64
+ validate: (v) => /^#[0-9A-Fa-f]{6}$/.test(v) || 'Enter a valid hex color (e.g. #D64309)',
65
+ });
66
+ const secondaryRatio = wcagContrastRatio(secondaryHex, '#ffffff');
67
+ if (secondaryRatio >= 4.5) {
68
+ console.log(` Contrast on white: ${secondaryRatio.toFixed(2)}:1 — passes WCAG AA`);
69
+ break;
70
+ }
71
+ console.log(` Contrast on white: ${secondaryRatio.toFixed(2)}:1 — ${secondaryRatio >= 3.0 ? 'marginal' : 'fails'} for body text (AA requires 4.5:1)`);
72
+ console.log(' White text on this color may not be readable at small sizes. Consider darkening slightly.');
73
+ const go = await confirm({ message: 'Proceed with this color?', default: true });
74
+ if (go)
75
+ break;
76
+ }
77
+ const canvasUrl = await input({
78
+ message: 'Canvas base URL:',
79
+ default: 'https://boisestate.instructure.com',
80
+ validate: (v) => v.startsWith('https://') || 'URL must start with https://',
81
+ });
82
+ const apiToken = await password({
83
+ message: 'Canvas API token (optional — leave blank to generate HTML and paste it manually):',
84
+ mask: '*',
85
+ validate: (v) => !v || v.length > 10 || 'Token looks too short — leave blank or paste the full token from Canvas Account Settings > Approved Integrations',
86
+ });
87
+ const professorEmail = await input({
88
+ message: 'Professor email for FERPA scan allowlist (optional):',
89
+ default: '',
90
+ });
91
+ const favoriteCoursesRaw = await input({
92
+ message: 'Favorite Canvas course IDs, comma-separated (optional):',
93
+ default: '',
94
+ validate: (v) => {
95
+ if (!v.trim())
96
+ return true;
97
+ return v.split(',').every(id => /^\d+$/.test(id.trim())) || 'Use only numeric Canvas course IDs separated by commas.';
98
+ },
99
+ });
100
+ const favoriteCourses = favoriteCoursesRaw
101
+ .split(',')
102
+ .map(id => id.trim())
103
+ .filter(Boolean)
104
+ .map(Number);
105
+ const colors = deriveColors(primaryHex, secondaryHex);
106
+ const config = {
107
+ institution,
108
+ colors,
109
+ canvasUrl,
110
+ apiToken: apiToken || '',
111
+ professorEmail: professorEmail.trim() || undefined,
112
+ favoriteCourses: favoriteCourses.length > 0 ? favoriteCourses : undefined,
113
+ kbTipShown: false,
114
+ };
115
+ saveConfig(config);
116
+ // Optional Panopto section — always skippable
117
+ const panoptoDomain = await input({
118
+ message: 'Panopto domain (e.g. bsu.hosted.panopto.com, or leave blank to skip):',
119
+ default: '',
120
+ });
121
+ if (panoptoDomain.trim()) {
122
+ const whitelistAnswer = await input({
123
+ message: 'Is Panopto whitelisted for iframes in Canvas? (yes / no / unsure):',
124
+ default: 'unsure',
125
+ validate: (v) => ['yes', 'no', 'unsure'].includes(v.toLowerCase()) || 'Enter yes, no, or unsure',
126
+ });
127
+ const iframeWhitelisted = whitelistAnswer.toLowerCase() === 'yes' ? true :
128
+ whitelistAnswer.toLowerCase() === 'no' ? false :
129
+ null;
130
+ const panoptoClientId = await input({
131
+ message: 'Panopto API client ID (leave blank to skip — enables video search and caption download):',
132
+ default: '',
133
+ });
134
+ let panoptoClientSecret = '';
135
+ if (panoptoClientId.trim()) {
136
+ panoptoClientSecret = await password({
137
+ message: 'Panopto API client secret:',
138
+ mask: '*',
139
+ });
140
+ }
141
+ config.panopto = {
142
+ domain: panoptoDomain.trim().replace(/^https?:\/\//i, ''),
143
+ iframeWhitelisted,
144
+ ...(panoptoClientId.trim() ? { clientId: panoptoClientId.trim(), clientSecret: panoptoClientSecret } : {}),
145
+ };
146
+ saveConfig(config);
147
+ console.log(`✓ Panopto domain: ${panoptoDomain.trim()}`);
148
+ console.log(` iFrame whitelisted: ${iframeWhitelisted === null ? 'unsure' : String(iframeWhitelisted)}`);
149
+ if (panoptoClientId.trim())
150
+ console.log('✓ Panopto API credentials saved');
151
+ }
152
+ // Philosophy KB phase — runs after Panopto, before final summary
153
+ const kbResult = getPhilosophyKb();
154
+ if (!kbResult.exists) {
155
+ const buildKb = await confirm({
156
+ message: 'Would you like to build your teaching philosophy KB now?\nClaude uses it to tailor every Canvas page to your style.\n(You can skip and build it in Claude later.)',
157
+ default: true,
158
+ });
159
+ if (buildKb) {
160
+ console.log('\nBuilding your teaching philosophy KB...\n');
161
+ const philosophyQuestions = [
162
+ "What's one thing you always tell students about this subject that you wish they'd really internalize?",
163
+ "What does a student who truly gets it do differently from one who just completes the work?",
164
+ "What's the biggest mistake students make on your assignments?",
165
+ "What separates an A from a B in concrete terms?",
166
+ "Are there teaching frameworks you consciously draw from? (Bloom's, UDL, constructivism, andragogy, etc.)",
167
+ "Any quotes or sayings you use regularly in class?",
168
+ ];
169
+ const answers = [];
170
+ for (const q of philosophyQuestions) {
171
+ const answer = await input({ message: q });
172
+ if (answer.trim())
173
+ answers.push(answer.trim());
174
+ }
175
+ const coreContent = answers.map(a => `- ${a}`).join('\n');
176
+ const kbContent = PHILOSOPHY_TEMPLATE.replace('## Core Teaching Philosophy\n', `## Core Teaching Philosophy\n\n${coreContent}\n`);
177
+ savePhilosophyKb(kbContent);
178
+ console.log('✓ Teaching philosophy KB saved');
179
+ }
180
+ else {
181
+ savePhilosophyKb(PHILOSOPHY_TEMPLATE);
182
+ console.log('✓ Philosophy KB template saved — build it in Claude anytime');
183
+ }
184
+ }
185
+ else {
186
+ const updateKb = await confirm({
187
+ message: 'You already have a philosophy KB. Would you like to review or update it?',
188
+ default: false,
189
+ });
190
+ if (updateKb) {
191
+ console.log('\nYour current philosophy KB:\n');
192
+ console.log(kbResult.content);
193
+ console.log('');
194
+ const addCourse = await confirm({
195
+ message: 'Would you like to add course-specific focus for a course?',
196
+ default: false,
197
+ });
198
+ if (addCourse) {
199
+ const courseKey = await input({
200
+ message: 'Course key (e.g. "ITM 370 — AI Augmented Projects"):',
201
+ validate: (v) => v.trim().length > 0 || 'Course key is required',
202
+ });
203
+ const courseNote = await input({
204
+ message: `What should Claude know specifically about ${courseKey.trim()}?`,
205
+ });
206
+ if (courseNote.trim()) {
207
+ updatePhilosophyKb({ entry: courseNote.trim(), section: 'course', courseKey: courseKey.trim() });
208
+ console.log(`✓ Course-specific focus added for ${courseKey.trim()}`);
209
+ }
210
+ }
211
+ }
212
+ }
213
+ console.log('\n✓ Config saved to ~/.canvas-design-mcp/institution.json');
214
+ console.log(`✓ Primary: ${colors.primary} → dark: ${colors.primaryDark} light: ${colors.primaryLight}`);
215
+ console.log(`✓ Secondary: ${colors.secondary}`);
216
+ if (!apiToken.trim()) {
217
+ console.log(' Canvas API token skipped. You can still generate HTML and paste it into Canvas manually.');
218
+ }
219
+ if (professorEmail.trim()) {
220
+ console.log(`✓ FERPA scan allowlist email: ${professorEmail.trim()}`);
221
+ }
222
+ if (favoriteCourses.length > 0) {
223
+ console.log(`✓ Favorite Canvas courses: ${favoriteCourses.join(', ')}`);
224
+ }
225
+ console.log('✓ Canvas Design Studio is ready\n');
226
+ printMcpConfig();
227
+ return config;
228
+ }
229
+ //# sourceMappingURL=wizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.js","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ Parent: [Canvas Design Knowledge Base](../README.md) | [KB Overview](KB-Overview.md)
4
+
5
+ ## 2026-05-10 - Public Documentation Cleanup
6
+
7
+ - Removed production guidance for the third-party Canvas design add-on and deleted those 04-tools pages.
8
+ - Kept third-party showcase references only where they are framed as external inspiration in [Inspiration and Showcases](../07-resources/Inspiration-and-Showcases.md).
9
+ - Converted the KB map and major reference pages away from Obsidian-style links.
10
+ - Reworked public resources so Canvas Design Studio is positioned as a standalone Canvas-safe HTML generator, not an integration with a commercial Canvas add-on.
11
+
12
+ ## 2026-04-28 - Resource Evaluation Pass
13
+
14
+ New files:
15
+
16
+ - [Canvas Built-In CSS Classes](../01-canvas-rce/Canvas-Built-In-CSS-Classes.md) - Canvas utility classes such as `border`, `content-box`, `grid-row`, `col-*`, and `ic-Table`.
17
+ - [Other Canvas Design Tools](../04-tools/Other-Canvas-Design-Tools.md) - external Canvas design references, including Loree, HowToCanvas, Fleximode, JHU, Canvas Commons, and Canvas source links.
18
+ - [Inspiration and Showcases](../07-resources/Inspiration-and-Showcases.md) - real Canvas examples and design lessons.
19
+
20
+ Updated files:
21
+
22
+ - [HTML Allowlist](../01-canvas-rce/HTML-Allowlist.md) - added built-in CSS class notes.
23
+ - [RCE Limitations and Workarounds](../01-canvas-rce/RCE-Limitations-and-Workarounds.md) - grid gap workaround references built-in classes.
24
+ - [Official Canvas Links](../07-resources/Official-Canvas-Links.md) - consolidated production-facing Canvas and utility links.
25
+ - [README](../README.md) - updated KB map and quick reference table.
26
+
27
+ ## 2026-04-28 - Initial Build
28
+
29
+ - Created the first knowledge base structure.
30
+ - Populated the core Canvas RCE, design-system, pattern, accessibility, and resource files.
31
+
32
+ ## Template for Future Entries
33
+
34
+ ```text
35
+ ## YYYY-MM-DD - Brief description
36
+
37
+ - What changed and why
38
+ - Source/reference if applicable
39
+ - Files affected: path/to/file.md
40
+ ```
41
+
42
+ [KB Overview](KB-Overview.md) | [Contributing](Contributing.md)
@@ -0,0 +1,58 @@
1
+ # Contributing to This KB
2
+
3
+ > **Parent:** [README](../README.md) | **Related:** [KB Overview](./KB-Overview.md), [Changelog](./Changelog.md)
4
+
5
+ ---
6
+
7
+ ## How to Add Notes
8
+
9
+ ### Adding a New Pattern
10
+
11
+ 1. Create a new file in `05-patterns/` named descriptively: `Assignment-Page.md`, `Reading-Page.md`, etc.
12
+ 2. Include the standard front matter: `> **Parent:** [README](../README.md) | **Related:** ...`
13
+ 3. Add the anatomy, full HTML template, and customization checklist
14
+ 4. Link from [README](../README.md) in the appropriate section
15
+ 5. Add to [Changelog](./Changelog.md)
16
+
17
+ ### Adding a New Component to the Library
18
+
19
+ 1. Open [Component Library](../03-design-systems/Component-Library.md)
20
+ 2. Add a numbered section with the component name
21
+ 3. Include the ready-to-paste HTML
22
+ 4. Add a note about any Canvas-specific gotchas
23
+ 5. Update [Changelog](./Changelog.md)
24
+
25
+ ### Updating an Existing Note
26
+
27
+ When Canvas changes behavior or a tool releases a new version:
28
+ 1. Update the relevant file(s)
29
+ 2. Add a dated entry to [Changelog](./Changelog.md)
30
+ 3. If a link has changed, update the URL and note the change
31
+
32
+ ---
33
+
34
+ ## Formatting Conventions
35
+
36
+ - **Parent link** at top of every file
37
+ - **Related** links to closely connected files
38
+ - **Source** links to external authoritative references
39
+ - **⚠️** for warnings or "use with caution" notes
40
+ - **✅/❌** for allowed/not-allowed comparisons
41
+ - HTML code blocks use triple backticks with `html` language tag
42
+ - Inline code uses single backticks for HTML tags and CSS properties
43
+
44
+ ---
45
+
46
+ ## What to Check Before Publishing a Pattern
47
+
48
+ - [ ] All HTML tested in Canvas RCE (paste into HTML view, save, verify nothing stripped)
49
+ - [ ] Checked in student view
50
+ - [ ] Tested on mobile (or Canvas mobile app)
51
+ - [ ] Color contrast checked against WCAG AA
52
+ - [ ] Heading hierarchy correct (H2 → H3 → H4)
53
+ - [ ] All images have `alt` attributes
54
+ - [ ] Links have descriptive text
55
+
56
+ ---
57
+
58
+ *[KB Overview](./KB-Overview.md) | [Changelog](./Changelog.md)*
@@ -0,0 +1,51 @@
1
+ # KB Overview
2
+
3
+ Parent: [Canvas Design Knowledge Base](../README.md)
4
+
5
+ This knowledge base is structured around three concerns:
6
+
7
+ 1. Canvas constraints: what HTML and CSS survive inside the Canvas Rich Content Editor.
8
+ 2. Design systems: how to define a consistent visual language for a course.
9
+ 3. Patterns and examples: reusable Canvas-safe components plus real course examples for inspiration.
10
+
11
+ ## Folder Structure
12
+
13
+ ```text
14
+ canvas-design-kb/
15
+ |-- README.md # Top-level map
16
+ |-- 00-meta/ # KB management
17
+ |-- 01-canvas-rce/ # How Canvas handles HTML/CSS
18
+ |-- 02-design-md/ # DESIGN.md specification notes
19
+ |-- 03-design-systems/ # Design system principles and components
20
+ |-- 04-tools/ # Canvas admin/tooling context
21
+ |-- 05-patterns/ # Page and component templates
22
+ |-- 06-accessibility/ # WCAG and inclusive design
23
+ `-- 07-resources/ # External links and references
24
+ ```
25
+
26
+ ## Update Cadence
27
+
28
+ | Area | When to review |
29
+ |---|---|
30
+ | HTML allowlist | When Canvas releases a major update |
31
+ | DESIGN.md spec | Monthly while the spec is evolving |
32
+ | Patterns and templates | Whenever a reusable page pattern is added |
33
+ | Accessibility | When WCAG or institutional guidance changes |
34
+ | External links | Before each public release |
35
+
36
+ ## How to Use in Canvas Design Studio
37
+
38
+ 1. Use [DESIGN.md Canvas Template](../02-design-md/DESIGN-MD-Canvas-Template.md) as the course design contract.
39
+ 2. Treat [HTML Allowlist](../01-canvas-rce/HTML-Allowlist.md) and [CSS Inline Strategy](../01-canvas-rce/CSS-Inline-Strategy.md) as hard constraints.
40
+ 3. Pull reusable snippets from [Component Library](../03-design-systems/Component-Library.md).
41
+ 4. Use [Course Home Page](../05-patterns/Course-Home-Page.md) as the first page-level pattern.
42
+ 5. Validate final HTML with [Accessibility Overview](../06-accessibility/Accessibility-Overview.md) and the `validate_canvas_html` MCP tool.
43
+
44
+ ## Key Decisions
45
+
46
+ - Canvas strips `<style>` tags from content, so generated page CSS must be inline.
47
+ - Canvas reserves `<h1>` for the page title, so generated content starts at `<h2>`.
48
+ - The beginner workflow remains first-class: generate Canvas-safe HTML, then paste it manually into Canvas.
49
+ - Optional Canvas API publishing is a convenience, not a requirement.
50
+
51
+ See also: [Changelog](Changelog.md), [Contributing](Contributing.md)
@@ -0,0 +1,166 @@
1
+ # CSS Inline Strategy for Canvas
2
+
3
+ > **Parent:** [README](../README.md) | **Related:** [HTML Allowlist](./HTML-Allowlist.md), [RCE Overview](./RCE-Overview.md)
4
+
5
+ ---
6
+
7
+ ## The Core Constraint
8
+
9
+ Canvas strips `<style>` blocks from the RCE on save. **Every CSS declaration must live in a `style=""` attribute on the element it affects.**
10
+
11
+ This is non-negotiable at the page level unless your institution has a Canvas admin who can inject global CSS via the Theme Editor (see [Canvas Theme Editor](../04-tools/Canvas-Theme-Editor.md)).
12
+
13
+ ---
14
+
15
+ ## Writing Inline Styles That Survive
16
+
17
+ ### ✅ Reliable Patterns
18
+
19
+ ```html
20
+ <!-- Basic block with border and padding -->
21
+ <div style="border: 2px solid #0F6E56; padding: 16px; margin-bottom: 16px;">
22
+ Content here
23
+ </div>
24
+
25
+ <!-- Colored background callout -->
26
+ <div style="background: #e1f5ee; border-left: 4px solid #0F6E56; padding: 14px 18px;">
27
+ <strong>Tip:</strong> Important note here.
28
+ </div>
29
+
30
+ <!-- Two-column flex layout -->
31
+ <div style="display: flex; margin-bottom: 20px;">
32
+ <div style="flex: 1; padding: 12px; border: 1px solid #ddd;">Left column</div>
33
+ <div style="flex: 1; padding: 12px; border: 1px solid #ddd; margin-left: 12px;">Right column</div>
34
+ </div>
35
+
36
+ <!-- Card with border-radius -->
37
+ <div style="border: 1px solid #e0e0d8; border-radius: 10px; padding: 18px; margin-bottom: 16px;">
38
+ Card content
39
+ </div>
40
+
41
+ <!-- Styled button link -->
42
+ <a href="#" style="display: inline-block; background: #0F6E56; color: #ffffff; padding: 10px 20px; border-radius: 6px; text-decoration: none; font-weight: bold;">
43
+ Button Label
44
+ </a>
45
+ ```
46
+
47
+ ### ❌ Things That Will Be Stripped
48
+
49
+ ```html
50
+ <!-- STRIPPED: <style> block -->
51
+ <style>
52
+ .my-card { border-radius: 8px; }
53
+ </style>
54
+
55
+ <!-- STRIPPED: box-shadow -->
56
+ <div style="box-shadow: 0 2px 8px rgba(0,0,0,0.15);">
57
+
58
+ <!-- STRIPPED: transform -->
59
+ <div style="transform: rotate(3deg);">
60
+
61
+ <!-- STRIPPED: transition -->
62
+ <div style="transition: all 0.3s ease;">
63
+
64
+ <!-- STRIPPED: gap (use margin instead) -->
65
+ <div style="display: flex; gap: 16px;">
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Color Strategy
71
+
72
+ Since `opacity` is stripped, use **RGBA colors** for semi-transparent effects:
73
+
74
+ ```html
75
+ <!-- Semi-transparent background -->
76
+ <div style="background: rgba(15, 110, 86, 0.1); padding: 16px;">
77
+
78
+ <!-- Border with transparency -->
79
+ <div style="border: 1px solid rgba(0,0,0,0.15); padding: 16px;">
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Flex Layout Without `gap`
85
+
86
+ Since `gap` isn't reliable, use negative margins on the parent + margins on children:
87
+
88
+ ```html
89
+ <!-- Flex grid with spacing -->
90
+ <div style="display: flex; flex-wrap: wrap; margin-right: -12px;">
91
+ <div style="flex: 1; min-width: 200px; margin-right: 12px; margin-bottom: 12px; border: 1px solid #ddd; padding: 16px; border-radius: 8px;">
92
+ Item 1
93
+ </div>
94
+ <div style="flex: 1; min-width: 200px; margin-right: 12px; margin-bottom: 12px; border: 1px solid #ddd; padding: 16px; border-radius: 8px;">
95
+ Item 2
96
+ </div>
97
+ </div>
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Using CSS Inliner Tools
103
+
104
+ For complex layouts built externally (e.g., in a local HTML file with a `<style>` block), use an **inliner tool** to convert all CSS to inline styles before pasting into Canvas:
105
+
106
+ | Tool | URL | Notes |
107
+ |---|---|---|
108
+ | Juice (CLI) | https://github.com/Automattic/juice | Best for automation |
109
+ | CSS Inliner (web) | https://htmlemail.io/inline/ | Good for one-off use |
110
+ | Premailer | https://premailer.dialect.ca/ | Email-focused but works |
111
+
112
+ **Workflow:**
113
+ 1. Write HTML with a `<style>` block (readable, maintainable)
114
+ 2. Run through inliner
115
+ 3. Paste resulting inline-only HTML into Canvas RCE HTML view
116
+ 4. Save and verify
117
+
118
+ ---
119
+
120
+ ## Account-Level CSS (Admin Only)
121
+
122
+ If you have Canvas admin access, you can inject global CSS via:
123
+
124
+ **Admin → Account → Themes → Upload JS/CSS**
125
+
126
+ This allows `<style>` classes to work across all courses in the account. Useful for institution-wide design systems.
127
+
128
+ See [Canvas Theme Editor](../04-tools/Canvas-Theme-Editor.md) for details.
129
+
130
+ ---
131
+
132
+ ## Property Reference Cheat Sheet
133
+
134
+ | CSS Property | Canvas Allowed? | Notes |
135
+ |---|---|---|
136
+ | `background` | ✅ | Includes `background-color` shorthand |
137
+ | `border` | ✅ | All border shorthand works |
138
+ | `border-radius` | ✅ | Works reliably |
139
+ | `color` | ✅ | Text color |
140
+ | `display` | ✅ | `flex`, `grid`, `block`, `inline-block` all work |
141
+ | `flex` | ✅ | Shorthand works; individual flex properties vary |
142
+ | `font` | ✅ | Shorthand; `font-size`, `font-weight`, `font-family` all survive |
143
+ | `height` / `width` | ✅ | Including `%` and `px` values |
144
+ | `margin` / `padding` | ✅ | All variants |
145
+ | `max-width` / `min-width` | ✅ | Responsive containment |
146
+ | `overflow` | ✅ | Useful for layout containment |
147
+ | `position` | ✅ | `relative`, `absolute` work |
148
+ | `text-align` | ✅ | |
149
+ | `text-decoration` | ✅ | |
150
+ | `vertical-align` | ✅ | |
151
+ | `z-index` | ✅ | |
152
+ | `box-shadow` | ❌ | Stripped |
153
+ | `filter` | ❌ | Stripped |
154
+ | `transform` | ❌ | Stripped |
155
+ | `transition` | ❌ | Stripped |
156
+ | `animation` | ❌ | Stripped |
157
+ | `opacity` | ❌ | Use `rgba()` colors instead |
158
+ | `gap` | ❌ | Use `margin` on children |
159
+
160
+ ---
161
+
162
+ ## See Also
163
+
164
+ - [HTML Allowlist](./HTML-Allowlist.md) — Master reference for all allowed tags and properties
165
+ - [RCE Limitations And Workarounds](./RCE-Limitations-and-Workarounds.md) — Edge cases and institutional escalations
166
+ - [Component Library](../03-design-systems/Component-Library.md) — Pre-built components using only allowed CSS