@forwardimpact/pathway 0.12.0 → 0.14.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.
- package/bin/fit-pathway.js +32 -12
- package/package.json +3 -3
- package/src/commands/build.js +98 -2
- package/src/commands/index.js +1 -0
- package/src/commands/interview.js +52 -14
- package/src/commands/job.js +1 -0
- package/src/commands/questions.js +13 -10
- package/src/commands/stage.js +8 -8
- package/src/commands/update.js +133 -0
- package/src/components/command-prompt.js +85 -0
- package/src/components/nav.js +2 -2
- package/src/components/top-bar.js +97 -0
- package/src/css/bundles/app.css +2 -0
- package/src/css/components/badges.css +41 -11
- package/src/css/components/command-prompt.css +98 -0
- package/src/css/components/layout.css +0 -3
- package/src/css/components/nav.css +121 -81
- package/src/css/components/surfaces.css +1 -1
- package/src/css/components/top-bar.css +180 -0
- package/src/css/pages/agent-builder.css +0 -9
- package/src/css/pages/landing.css +4 -0
- package/src/css/pages/lifecycle.css +5 -2
- package/src/css/reset.css +1 -1
- package/src/css/tokens.css +25 -11
- package/src/css/views/slide-base.css +2 -1
- package/src/formatters/agent/dom.js +0 -26
- package/src/formatters/agent/profile.js +13 -7
- package/src/formatters/agent/skill.js +4 -4
- package/src/formatters/interview/markdown.js +62 -3
- package/src/formatters/interview/shared.js +89 -52
- package/src/formatters/questions/markdown.js +15 -0
- package/src/formatters/questions/shared.js +70 -58
- package/src/formatters/stage/dom.js +13 -10
- package/src/formatters/stage/microdata.js +14 -8
- package/src/formatters/stage/shared.js +4 -4
- package/src/index.html +69 -44
- package/src/lib/cli-command.js +145 -0
- package/src/lib/state.js +2 -0
- package/src/lib/yaml-loader.js +39 -21
- package/src/main.js +47 -26
- package/src/pages/agent-builder.js +0 -28
- package/src/pages/behaviour.js +3 -1
- package/src/pages/discipline.js +3 -1
- package/src/pages/driver.js +6 -1
- package/src/pages/grade.js +6 -1
- package/src/pages/interview.js +61 -5
- package/src/pages/job.js +1 -0
- package/src/pages/landing.js +7 -0
- package/src/pages/skill.js +9 -2
- package/src/pages/track.js +6 -1
- package/src/slides/job.js +1 -0
- package/templates/agent.template.md +17 -10
- package/templates/install.template.sh +33 -0
- package/templates/skill.template.md +15 -7
package/src/index.html
CHANGED
|
@@ -43,56 +43,81 @@
|
|
|
43
43
|
</script>
|
|
44
44
|
</head>
|
|
45
45
|
<body>
|
|
46
|
-
<div id="app">
|
|
47
|
-
<
|
|
48
|
-
<div class="nav-brand">
|
|
49
|
-
<a href="#/">Engineering Pathway</a>
|
|
50
|
-
<span class="brand-tag">#BenchTools</span>
|
|
51
|
-
</div>
|
|
46
|
+
<div id="app" class="drawer-open">
|
|
47
|
+
<header class="top-bar" id="top-bar">
|
|
52
48
|
<button
|
|
53
|
-
class="
|
|
54
|
-
id="
|
|
55
|
-
aria-label="Toggle
|
|
49
|
+
class="top-bar__toggle"
|
|
50
|
+
id="sidebar-toggle"
|
|
51
|
+
aria-label="Toggle sidebar"
|
|
56
52
|
>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
<svg viewBox="0 0 24 24">
|
|
54
|
+
<rect x="3" y="3" width="18" height="18" rx="3" />
|
|
55
|
+
<line x1="9" y1="3" x2="9" y2="21" />
|
|
56
|
+
</svg>
|
|
60
57
|
</button>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<a href="#/career-progress" class="nav-cta">Career Progress</a>
|
|
75
|
-
</li>
|
|
76
|
-
<li>
|
|
77
|
-
<a href="#/self-assessment" class="nav-cta">Self-Assessment</a>
|
|
78
|
-
</li>
|
|
79
|
-
</ul>
|
|
80
|
-
</nav>
|
|
81
|
-
|
|
82
|
-
<main id="app-content">
|
|
83
|
-
<div class="loading">
|
|
84
|
-
<div class="loading-spinner"></div>
|
|
85
|
-
<p>Loading...</p>
|
|
58
|
+
<div class="top-bar__command">
|
|
59
|
+
<span class="top-bar__prompt">$</span>
|
|
60
|
+
<span class="top-bar__command-text" id="cli-command"
|
|
61
|
+
>npx fit-pathway</span
|
|
62
|
+
>
|
|
63
|
+
<button class="top-bar__copy" id="cli-copy" aria-label="Copy command">
|
|
64
|
+
<svg viewBox="0 0 24 24">
|
|
65
|
+
<rect x="9" y="9" width="13" height="13" rx="2" />
|
|
66
|
+
<path
|
|
67
|
+
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
|
|
68
|
+
/>
|
|
69
|
+
</svg>
|
|
70
|
+
</button>
|
|
86
71
|
</div>
|
|
87
|
-
</
|
|
72
|
+
</header>
|
|
88
73
|
|
|
89
|
-
<
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
74
|
+
<aside id="app-drawer">
|
|
75
|
+
<div class="drawer-header">
|
|
76
|
+
<a href="#/" class="nav-brand">
|
|
77
|
+
<span class="brand-emoji">🧭</span>
|
|
78
|
+
<span class="brand-title">Engineering Pathway</span>
|
|
79
|
+
<span class="brand-tag">#BenchTools</span>
|
|
80
|
+
</a>
|
|
81
|
+
</div>
|
|
82
|
+
<nav class="drawer-nav" id="drawer-nav">
|
|
83
|
+
<div class="drawer-section">
|
|
84
|
+
<span class="drawer-section-label">Browse</span>
|
|
85
|
+
<a href="#/discipline">Disciplines</a>
|
|
86
|
+
<a href="#/grade">Grades</a>
|
|
87
|
+
<a href="#/track">Tracks</a>
|
|
88
|
+
<a href="#/behaviour">Behaviours</a>
|
|
89
|
+
<a href="#/skill">Skills</a>
|
|
90
|
+
<a href="#/driver">Drivers</a>
|
|
91
|
+
<a href="#/stage">Stages</a>
|
|
92
|
+
<a href="#/tool">Tools</a>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="drawer-section">
|
|
95
|
+
<span class="drawer-section-label">Work</span>
|
|
96
|
+
<a href="#/job-builder" class="drawer-cta">Build a Job</a>
|
|
97
|
+
<a href="#/agent-builder" class="drawer-cta">Build an Agent</a>
|
|
98
|
+
<a href="#/interview-prep" class="drawer-cta">Interview Prep</a>
|
|
99
|
+
<a href="#/career-progress" class="drawer-cta">Career Progress</a>
|
|
100
|
+
<a href="#/self-assessment" class="drawer-cta">Self-Assessment</a>
|
|
101
|
+
</div>
|
|
94
102
|
</nav>
|
|
95
|
-
</
|
|
103
|
+
</aside>
|
|
104
|
+
|
|
105
|
+
<div class="app-body">
|
|
106
|
+
<main id="app-content">
|
|
107
|
+
<div class="loading">
|
|
108
|
+
<div class="loading-spinner"></div>
|
|
109
|
+
<p>Loading...</p>
|
|
110
|
+
</div>
|
|
111
|
+
</main>
|
|
112
|
+
|
|
113
|
+
<footer id="app-footer">
|
|
114
|
+
<p>Engineering Pathway</p>
|
|
115
|
+
<nav class="footer-links">
|
|
116
|
+
<a href="slides.html">Slides</a>
|
|
117
|
+
<a href="handout.html">Handouts</a>
|
|
118
|
+
</nav>
|
|
119
|
+
</footer>
|
|
120
|
+
</div>
|
|
96
121
|
</div>
|
|
97
122
|
|
|
98
123
|
<script type="module" src="main.js"></script>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Command Mapping
|
|
3
|
+
*
|
|
4
|
+
* Maps hash routes to their equivalent `npx fit-pathway` CLI commands.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Route-to-CLI command rules, checked in order.
|
|
9
|
+
* Each rule has a pattern (regex) and a function that produces the CLI string.
|
|
10
|
+
* @type {Array<{ pattern: RegExp, toCommand: (match: RegExpMatchArray) => string }>}
|
|
11
|
+
*/
|
|
12
|
+
const ROUTE_COMMANDS = [
|
|
13
|
+
// Landing
|
|
14
|
+
{ pattern: /^\/$/, toCommand: () => "npx fit-pathway" },
|
|
15
|
+
|
|
16
|
+
// Entity lists
|
|
17
|
+
{ pattern: /^\/skill$/, toCommand: () => "npx fit-pathway skill" },
|
|
18
|
+
{ pattern: /^\/behaviour$/, toCommand: () => "npx fit-pathway behaviour" },
|
|
19
|
+
{
|
|
20
|
+
pattern: /^\/discipline$/,
|
|
21
|
+
toCommand: () => "npx fit-pathway discipline",
|
|
22
|
+
},
|
|
23
|
+
{ pattern: /^\/track$/, toCommand: () => "npx fit-pathway track" },
|
|
24
|
+
{ pattern: /^\/grade$/, toCommand: () => "npx fit-pathway grade" },
|
|
25
|
+
{ pattern: /^\/driver$/, toCommand: () => "npx fit-pathway driver" },
|
|
26
|
+
{ pattern: /^\/stage$/, toCommand: () => "npx fit-pathway stage" },
|
|
27
|
+
{ pattern: /^\/tool$/, toCommand: () => "npx fit-pathway tool" },
|
|
28
|
+
|
|
29
|
+
// Entity details
|
|
30
|
+
{
|
|
31
|
+
pattern: /^\/skill\/(.+)$/,
|
|
32
|
+
toCommand: (m) => `npx fit-pathway skill ${m[1]}`,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
pattern: /^\/behaviour\/(.+)$/,
|
|
36
|
+
toCommand: (m) => `npx fit-pathway behaviour ${m[1]}`,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
pattern: /^\/discipline\/(.+)$/,
|
|
40
|
+
toCommand: (m) => `npx fit-pathway discipline ${m[1]}`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /^\/track\/(.+)$/,
|
|
44
|
+
toCommand: (m) => `npx fit-pathway track ${m[1]}`,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
pattern: /^\/grade\/(.+)$/,
|
|
48
|
+
toCommand: (m) => `npx fit-pathway grade ${m[1]}`,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
pattern: /^\/driver\/(.+)$/,
|
|
52
|
+
toCommand: (m) => `npx fit-pathway driver ${m[1]}`,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: /^\/stage\/(.+)$/,
|
|
56
|
+
toCommand: (m) => `npx fit-pathway stage ${m[1]}`,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Job builder + detail
|
|
60
|
+
{
|
|
61
|
+
pattern: /^\/job-builder$/,
|
|
62
|
+
toCommand: () => "npx fit-pathway job --list",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
pattern: /^\/job\/([^/]+)\/([^/]+)\/([^/]+)$/,
|
|
66
|
+
toCommand: (m) => `npx fit-pathway job ${m[1]} ${m[2]} --track=${m[3]}`,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
pattern: /^\/job\/([^/]+)\/([^/]+)$/,
|
|
70
|
+
toCommand: (m) => `npx fit-pathway job ${m[1]} ${m[2]}`,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Interview builder + detail
|
|
74
|
+
{
|
|
75
|
+
pattern: /^\/interview-prep$/,
|
|
76
|
+
toCommand: () => "npx fit-pathway interview --list",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
pattern: /^\/interview\/([^/]+)\/([^/]+)\/([^/]+)$/,
|
|
80
|
+
toCommand: (m) =>
|
|
81
|
+
`npx fit-pathway interview ${m[1]} ${m[2]} --track=${m[3]}`,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
pattern: /^\/interview\/([^/]+)\/([^/]+)$/,
|
|
85
|
+
toCommand: (m) => `npx fit-pathway interview ${m[1]} ${m[2]}`,
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
// Career progress builder + detail
|
|
89
|
+
{
|
|
90
|
+
pattern: /^\/career-progress$/,
|
|
91
|
+
toCommand: () => "npx fit-pathway progress --list",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
pattern: /^\/progress\/([^/]+)\/([^/]+)\/([^/]+)$/,
|
|
95
|
+
toCommand: (m) =>
|
|
96
|
+
`npx fit-pathway progress ${m[1]} ${m[2]} --track=${m[3]}`,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
pattern: /^\/progress\/([^/]+)\/([^/]+)$/,
|
|
100
|
+
toCommand: (m) => `npx fit-pathway progress ${m[1]} ${m[2]}`,
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// Self-assessment
|
|
104
|
+
{
|
|
105
|
+
pattern: /^\/self-assessment$/,
|
|
106
|
+
toCommand: () => "npx fit-pathway self-assessment",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pattern: /^\/self-assessment\/results$/,
|
|
110
|
+
toCommand: () => "npx fit-pathway self-assessment",
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
// Agent builder + detail
|
|
114
|
+
{
|
|
115
|
+
pattern: /^\/agent-builder$/,
|
|
116
|
+
toCommand: () => "npx fit-pathway agent --list",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
pattern: /^\/agent\/([^/]+)\/([^/]+)\/([^/]+)$/,
|
|
120
|
+
toCommand: (m) =>
|
|
121
|
+
`npx fit-pathway agent ${m[1]} --track=${m[2]} --stage=${m[3]}`,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
pattern: /^\/agent\/([^/]+)\/([^/]+)$/,
|
|
125
|
+
toCommand: (m) => `npx fit-pathway agent ${m[1]} --track=${m[2]}`,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
pattern: /^\/agent\/([^/]+)$/,
|
|
129
|
+
toCommand: (m) => `npx fit-pathway agent ${m[1]}`,
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the CLI command equivalent for a given hash path
|
|
135
|
+
* @param {string} hashPath - The hash path (without #), e.g. "/skill/testing"
|
|
136
|
+
* @returns {string} The CLI command string
|
|
137
|
+
*/
|
|
138
|
+
export function getCliCommand(hashPath) {
|
|
139
|
+
const path = hashPath.split("?")[0] || "/";
|
|
140
|
+
for (const { pattern, toCommand } of ROUTE_COMMANDS) {
|
|
141
|
+
const match = path.match(pattern);
|
|
142
|
+
if (match) return toCommand(match);
|
|
143
|
+
}
|
|
144
|
+
return "npx fit-pathway";
|
|
145
|
+
}
|
package/src/lib/state.js
CHANGED
|
@@ -132,6 +132,7 @@ export function getFilters(entity) {
|
|
|
132
132
|
* @property {string} title - Application title
|
|
133
133
|
* @property {string} tag - Brand hashtag/tag
|
|
134
134
|
* @property {string} description - Application description
|
|
135
|
+
* @property {string} emojiIcon - Emoji icon for the framework
|
|
135
136
|
*/
|
|
136
137
|
|
|
137
138
|
/**
|
|
@@ -144,5 +145,6 @@ export function getBranding() {
|
|
|
144
145
|
title: framework.title || "Engineering Pathway",
|
|
145
146
|
tag: framework.tag || "#BenchTools",
|
|
146
147
|
description: framework.description || "",
|
|
148
|
+
emojiIcon: framework.emojiIcon || "🧭",
|
|
147
149
|
};
|
|
148
150
|
}
|
package/src/lib/yaml-loader.js
CHANGED
|
@@ -237,35 +237,52 @@ async function loadCapabilitiesFromDir(capabilitiesDir) {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
/**
|
|
240
|
-
* Load questions from folder structure using skill/behaviour IDs
|
|
240
|
+
* Load questions from folder structure using skill/behaviour/capability IDs
|
|
241
241
|
* @param {string} questionsDir - Path to questions directory
|
|
242
242
|
* @param {Array} skills - Skills array (with id property)
|
|
243
243
|
* @param {Array} behaviours - Behaviours array (with id property)
|
|
244
|
+
* @param {Array} capabilities - Capabilities array (with id property)
|
|
244
245
|
* @returns {Promise<Object>}
|
|
245
246
|
*/
|
|
246
|
-
async function loadQuestionFolder(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
247
|
+
async function loadQuestionFolder(
|
|
248
|
+
questionsDir,
|
|
249
|
+
skills,
|
|
250
|
+
behaviours,
|
|
251
|
+
capabilities,
|
|
252
|
+
) {
|
|
253
|
+
const [skillEntries, behaviourEntries, capabilityEntries] = await Promise.all(
|
|
254
|
+
[
|
|
255
|
+
Promise.all(
|
|
256
|
+
skills.map(async (skill) => {
|
|
257
|
+
const content = await tryLoadYamlFile(
|
|
258
|
+
`${questionsDir}/skills/${skill.id}.yaml`,
|
|
259
|
+
);
|
|
260
|
+
return [skill.id, content || {}];
|
|
261
|
+
}),
|
|
262
|
+
),
|
|
263
|
+
Promise.all(
|
|
264
|
+
behaviours.map(async (behaviour) => {
|
|
265
|
+
const content = await tryLoadYamlFile(
|
|
266
|
+
`${questionsDir}/behaviours/${behaviour.id}.yaml`,
|
|
267
|
+
);
|
|
268
|
+
return [behaviour.id, content || {}];
|
|
269
|
+
}),
|
|
270
|
+
),
|
|
271
|
+
Promise.all(
|
|
272
|
+
capabilities.map(async (capability) => {
|
|
273
|
+
const content = await tryLoadYamlFile(
|
|
274
|
+
`${questionsDir}/capabilities/${capability.id}.yaml`,
|
|
275
|
+
);
|
|
276
|
+
return [capability.id, content || {}];
|
|
277
|
+
}),
|
|
278
|
+
),
|
|
279
|
+
],
|
|
280
|
+
);
|
|
265
281
|
|
|
266
282
|
return {
|
|
267
283
|
skillLevels: Object.fromEntries(skillEntries),
|
|
268
284
|
behaviourMaturities: Object.fromEntries(behaviourEntries),
|
|
285
|
+
capabilityLevels: Object.fromEntries(capabilityEntries),
|
|
269
286
|
};
|
|
270
287
|
}
|
|
271
288
|
|
|
@@ -293,11 +310,12 @@ export async function loadAllData(dataDir = "./data") {
|
|
|
293
310
|
loadYamlFile(`${dataDir}/framework.yaml`),
|
|
294
311
|
]);
|
|
295
312
|
|
|
296
|
-
// Load questions using skill/behaviour IDs
|
|
313
|
+
// Load questions using skill/behaviour/capability IDs
|
|
297
314
|
const questions = await loadQuestionFolder(
|
|
298
315
|
`${dataDir}/questions`,
|
|
299
316
|
skills,
|
|
300
317
|
behaviours,
|
|
318
|
+
capabilities,
|
|
301
319
|
);
|
|
302
320
|
|
|
303
321
|
return {
|
package/src/main.js
CHANGED
|
@@ -6,6 +6,8 @@ import { createPagesRouter } from "./lib/router-pages.js";
|
|
|
6
6
|
import { setData, setError, getBranding } from "./lib/state.js";
|
|
7
7
|
import { loadAllData } from "./lib/yaml-loader.js";
|
|
8
8
|
import { render, div, h1, p, showError } from "./lib/render.js";
|
|
9
|
+
import { updateActiveNav } from "./components/nav.js";
|
|
10
|
+
import { setupTopBar, updateCommand } from "./components/top-bar.js";
|
|
9
11
|
|
|
10
12
|
const router = createPagesRouter({
|
|
11
13
|
onNotFound: renderNotFound,
|
|
@@ -41,8 +43,9 @@ import { renderAgentBuilder } from "./pages/agent-builder.js";
|
|
|
41
43
|
* Initialize the application
|
|
42
44
|
*/
|
|
43
45
|
async function init() {
|
|
44
|
-
// Set up
|
|
45
|
-
|
|
46
|
+
// Set up top bar (sidebar toggle + CLI command display)
|
|
47
|
+
setupTopBar();
|
|
48
|
+
setupDrawerOverlay();
|
|
46
49
|
|
|
47
50
|
// Load data
|
|
48
51
|
try {
|
|
@@ -63,6 +66,14 @@ async function init() {
|
|
|
63
66
|
|
|
64
67
|
// Start router
|
|
65
68
|
router.start();
|
|
69
|
+
|
|
70
|
+
// Update active nav link and CLI command on route changes
|
|
71
|
+
const updateNav = () => {
|
|
72
|
+
updateActiveNav(window.location.hash.slice(1) || "/");
|
|
73
|
+
updateCommand();
|
|
74
|
+
};
|
|
75
|
+
window.addEventListener("hashchange", updateNav);
|
|
76
|
+
updateNav();
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
/**
|
|
@@ -175,13 +186,19 @@ function populateBranding() {
|
|
|
175
186
|
// Update document title
|
|
176
187
|
document.title = branding.title;
|
|
177
188
|
|
|
178
|
-
// Update
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
|
|
189
|
+
// Update drawer brand
|
|
190
|
+
const brandTitle = document.querySelector(".nav-brand .brand-title");
|
|
191
|
+
if (brandTitle) {
|
|
192
|
+
brandTitle.textContent = branding.title;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Update drawer brand emoji
|
|
196
|
+
const brandEmoji = document.querySelector(".nav-brand .brand-emoji");
|
|
197
|
+
if (brandEmoji) {
|
|
198
|
+
brandEmoji.textContent = branding.emojiIcon;
|
|
182
199
|
}
|
|
183
200
|
|
|
184
|
-
// Update
|
|
201
|
+
// Update drawer brand tag
|
|
185
202
|
const brandTag = document.querySelector(".nav-brand .brand-tag");
|
|
186
203
|
if (brandTag) {
|
|
187
204
|
brandTag.textContent = branding.tag;
|
|
@@ -195,26 +212,30 @@ function populateBranding() {
|
|
|
195
212
|
}
|
|
196
213
|
|
|
197
214
|
/**
|
|
198
|
-
* Set up mobile
|
|
215
|
+
* Set up drawer overlay for mobile backdrop and auto-close behavior
|
|
199
216
|
*/
|
|
200
|
-
function
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
function setupDrawerOverlay() {
|
|
218
|
+
const app = document.getElementById("app");
|
|
219
|
+
const drawer = document.getElementById("app-drawer");
|
|
220
|
+
|
|
221
|
+
if (!drawer) return;
|
|
222
|
+
|
|
223
|
+
// Create overlay element for mobile backdrop
|
|
224
|
+
const overlay = document.createElement("div");
|
|
225
|
+
overlay.className = "drawer-overlay";
|
|
226
|
+
app.insertBefore(overlay, drawer);
|
|
227
|
+
|
|
228
|
+
// Close drawer when overlay is clicked (mobile)
|
|
229
|
+
overlay.addEventListener("click", () => {
|
|
230
|
+
app.classList.remove("drawer-open");
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Close drawer on mobile when a link is clicked
|
|
234
|
+
drawer.addEventListener("click", (e) => {
|
|
235
|
+
if (e.target.tagName === "A" && window.innerWidth <= 768) {
|
|
236
|
+
app.classList.remove("drawer-open");
|
|
237
|
+
}
|
|
238
|
+
});
|
|
218
239
|
}
|
|
219
240
|
|
|
220
241
|
// Start the app
|
|
@@ -562,9 +562,6 @@ function createAllStagesPreview(context) {
|
|
|
562
562
|
content: createToolkitTable(toolkit),
|
|
563
563
|
})
|
|
564
564
|
: null,
|
|
565
|
-
|
|
566
|
-
// CLI hint
|
|
567
|
-
createCliHint(humanDiscipline.id, humanTrack.id),
|
|
568
565
|
);
|
|
569
566
|
}
|
|
570
567
|
|
|
@@ -687,9 +684,6 @@ function createSingleStagePreview(context, stage) {
|
|
|
687
684
|
content: createToolkitTable(toolkit),
|
|
688
685
|
})
|
|
689
686
|
: null,
|
|
690
|
-
|
|
691
|
-
// CLI hint
|
|
692
|
-
createCliHint(humanDiscipline.id, humanTrack.id, stage.id),
|
|
693
687
|
);
|
|
694
688
|
}
|
|
695
689
|
|
|
@@ -936,29 +930,7 @@ async function importJSZip() {
|
|
|
936
930
|
return module.default;
|
|
937
931
|
}
|
|
938
932
|
|
|
939
|
-
/**
|
|
940
|
-
* Create CLI hint section
|
|
941
|
-
* @param {string} disciplineId - Discipline ID
|
|
942
|
-
* @param {string} trackId - Track ID
|
|
943
|
-
* @param {string} [stageId] - Optional stage ID
|
|
944
|
-
* @returns {HTMLElement}
|
|
945
|
-
*/
|
|
946
|
-
function createCliHint(disciplineId, trackId, stageId) {
|
|
947
|
-
const stageArg = stageId ? ` --stage=${stageId}` : "";
|
|
948
|
-
const command = `npx pathway agent ${disciplineId} ${trackId}${stageArg} --output=.github`;
|
|
949
|
-
|
|
950
|
-
const container = section(
|
|
951
|
-
{ className: "agent-section cli-hint" },
|
|
952
|
-
h2({}, "CLI Alternative"),
|
|
953
|
-
p({}, "Generate this agent from the command line:"),
|
|
954
|
-
createCodeDisplay({
|
|
955
|
-
content: command,
|
|
956
|
-
language: "bash",
|
|
957
|
-
}),
|
|
958
|
-
);
|
|
959
933
|
|
|
960
|
-
return container;
|
|
961
|
-
}
|
|
962
934
|
|
|
963
935
|
/**
|
|
964
936
|
* Create help section explaining how agent builder works
|
package/src/pages/behaviour.js
CHANGED
|
@@ -9,6 +9,7 @@ import { renderNotFound } from "../components/error-page.js";
|
|
|
9
9
|
import { prepareBehavioursList } from "../formatters/behaviour/shared.js";
|
|
10
10
|
import { behaviourToDOM } from "../formatters/behaviour/dom.js";
|
|
11
11
|
import { behaviourToCardConfig } from "../lib/card-mappers.js";
|
|
12
|
+
import { getConceptEmoji } from "@forwardimpact/schema/levels";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Render behaviours list page
|
|
@@ -16,6 +17,7 @@ import { behaviourToCardConfig } from "../lib/card-mappers.js";
|
|
|
16
17
|
export function renderBehavioursList() {
|
|
17
18
|
const { data } = getState();
|
|
18
19
|
const { framework } = data;
|
|
20
|
+
const behaviourEmoji = getConceptEmoji(framework, "behaviour");
|
|
19
21
|
|
|
20
22
|
// Transform data for list view
|
|
21
23
|
const { items } = prepareBehavioursList(data.behaviours);
|
|
@@ -27,7 +29,7 @@ export function renderBehavioursList() {
|
|
|
27
29
|
{ className: "page-header" },
|
|
28
30
|
h1(
|
|
29
31
|
{ className: "page-title" },
|
|
30
|
-
framework.entityDefinitions.behaviour.title
|
|
32
|
+
`${behaviourEmoji} ${framework.entityDefinitions.behaviour.title}`,
|
|
31
33
|
),
|
|
32
34
|
p(
|
|
33
35
|
{ className: "page-description" },
|
package/src/pages/discipline.js
CHANGED
|
@@ -10,6 +10,7 @@ import { renderNotFound } from "../components/error-page.js";
|
|
|
10
10
|
import { prepareDisciplinesList } from "../formatters/discipline/shared.js";
|
|
11
11
|
import { disciplineToDOM } from "../formatters/discipline/dom.js";
|
|
12
12
|
import { disciplineToCardConfig } from "../lib/card-mappers.js";
|
|
13
|
+
import { getConceptEmoji } from "@forwardimpact/schema/levels";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Format discipline group name for display
|
|
@@ -42,6 +43,7 @@ function renderDisciplineGroupHeader(groupName, count) {
|
|
|
42
43
|
export function renderDisciplinesList() {
|
|
43
44
|
const { data } = getState();
|
|
44
45
|
const { framework } = data;
|
|
46
|
+
const disciplineEmoji = getConceptEmoji(framework, "discipline");
|
|
45
47
|
|
|
46
48
|
// Transform data for list view (grouped by professional/management)
|
|
47
49
|
const { groups } = prepareDisciplinesList(data.disciplines);
|
|
@@ -53,7 +55,7 @@ export function renderDisciplinesList() {
|
|
|
53
55
|
{ className: "page-header" },
|
|
54
56
|
h1(
|
|
55
57
|
{ className: "page-title" },
|
|
56
|
-
framework.entityDefinitions.discipline.title
|
|
58
|
+
`${disciplineEmoji} ${framework.entityDefinitions.discipline.title}`,
|
|
57
59
|
),
|
|
58
60
|
p(
|
|
59
61
|
{ className: "page-description" },
|
package/src/pages/driver.js
CHANGED
|
@@ -9,6 +9,7 @@ import { renderNotFound } from "../components/error-page.js";
|
|
|
9
9
|
import { prepareDriversList } from "../formatters/driver/shared.js";
|
|
10
10
|
import { driverToDOM } from "../formatters/driver/dom.js";
|
|
11
11
|
import { driverToCardConfig } from "../lib/card-mappers.js";
|
|
12
|
+
import { getConceptEmoji } from "@forwardimpact/schema/levels";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Render drivers list page
|
|
@@ -16,6 +17,7 @@ import { driverToCardConfig } from "../lib/card-mappers.js";
|
|
|
16
17
|
export function renderDriversList() {
|
|
17
18
|
const { data } = getState();
|
|
18
19
|
const { framework } = data;
|
|
20
|
+
const driverEmoji = getConceptEmoji(framework, "driver");
|
|
19
21
|
|
|
20
22
|
// Transform data for list view
|
|
21
23
|
const { items } = prepareDriversList(data.drivers);
|
|
@@ -25,7 +27,10 @@ export function renderDriversList() {
|
|
|
25
27
|
// Header
|
|
26
28
|
div(
|
|
27
29
|
{ className: "page-header" },
|
|
28
|
-
h1(
|
|
30
|
+
h1(
|
|
31
|
+
{ className: "page-title" },
|
|
32
|
+
`${driverEmoji} ${framework.entityDefinitions.driver.title}`,
|
|
33
|
+
),
|
|
29
34
|
p(
|
|
30
35
|
{ className: "page-description" },
|
|
31
36
|
framework.entityDefinitions.driver.description.trim(),
|
package/src/pages/grade.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createBadge } from "../components/card.js";
|
|
|
8
8
|
import { renderNotFound } from "../components/error-page.js";
|
|
9
9
|
import { prepareGradesList } from "../formatters/grade/shared.js";
|
|
10
10
|
import { gradeToDOM } from "../formatters/grade/dom.js";
|
|
11
|
+
import { getConceptEmoji } from "@forwardimpact/schema/levels";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Render grades list page
|
|
@@ -15,6 +16,7 @@ import { gradeToDOM } from "../formatters/grade/dom.js";
|
|
|
15
16
|
export function renderGradesList() {
|
|
16
17
|
const { data } = getState();
|
|
17
18
|
const { framework } = data;
|
|
19
|
+
const gradeEmoji = getConceptEmoji(framework, "grade");
|
|
18
20
|
|
|
19
21
|
// Transform data for list view
|
|
20
22
|
const { items } = prepareGradesList(data.grades);
|
|
@@ -24,7 +26,10 @@ export function renderGradesList() {
|
|
|
24
26
|
// Header
|
|
25
27
|
div(
|
|
26
28
|
{ className: "page-header" },
|
|
27
|
-
h1(
|
|
29
|
+
h1(
|
|
30
|
+
{ className: "page-title" },
|
|
31
|
+
`${gradeEmoji} ${framework.entityDefinitions.grade.title}`,
|
|
32
|
+
),
|
|
28
33
|
p(
|
|
29
34
|
{ className: "page-description" },
|
|
30
35
|
framework.entityDefinitions.grade.description.trim(),
|