trackops 2.0.3 → 2.0.5
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/LICENSE +21 -21
- package/README.md +695 -402
- package/bin/trackops.js +116 -116
- package/lib/config.js +326 -326
- package/lib/control.js +208 -208
- package/lib/env.js +244 -244
- package/lib/init.js +325 -325
- package/lib/locale.js +24 -0
- package/lib/opera-bootstrap.js +941 -874
- package/lib/opera.js +494 -477
- package/lib/preferences.js +74 -74
- package/lib/registry.js +214 -196
- package/lib/release.js +56 -56
- package/lib/runtime-state.js +144 -144
- package/lib/server.js +312 -207
- package/lib/skills.js +74 -57
- package/lib/workspace.js +260 -260
- package/locales/en.json +192 -166
- package/locales/es.json +192 -166
- package/package.json +61 -58
- package/scripts/postinstall-locale.js +21 -21
- package/scripts/skills-marketplace-smoke.js +124 -124
- package/scripts/smoke-tests.js +558 -554
- package/scripts/sync-skill-version.js +21 -21
- package/scripts/validate-skill.js +103 -103
- package/skills/trackops/SKILL.md +126 -122
- package/skills/trackops/agents/openai.yaml +7 -7
- package/skills/trackops/locales/en/SKILL.md +126 -122
- package/skills/trackops/locales/en/references/activation.md +94 -75
- package/skills/trackops/locales/en/references/troubleshooting.md +73 -55
- package/skills/trackops/locales/en/references/workflow.md +55 -32
- package/skills/trackops/references/activation.md +94 -75
- package/skills/trackops/references/troubleshooting.md +73 -55
- package/skills/trackops/references/workflow.md +55 -32
- package/skills/trackops/skill.json +29 -29
- package/templates/hooks/post-checkout +2 -2
- package/templates/hooks/post-commit +2 -2
- package/templates/hooks/post-merge +2 -2
- package/templates/opera/agent.md +28 -27
- package/templates/opera/architecture/dependency-graph.md +24 -24
- package/templates/opera/architecture/runtime-automation.md +24 -24
- package/templates/opera/architecture/runtime-operations.md +34 -34
- package/templates/opera/en/agent.md +22 -21
- package/templates/opera/en/architecture/dependency-graph.md +24 -24
- package/templates/opera/en/architecture/runtime-automation.md +24 -24
- package/templates/opera/en/architecture/runtime-operations.md +34 -34
- package/templates/opera/en/reviews/delivery-audit.md +18 -18
- package/templates/opera/en/reviews/integration-audit.md +18 -18
- package/templates/opera/en/router.md +24 -19
- package/templates/opera/references/autonomy-and-recovery.md +117 -117
- package/templates/opera/references/opera-cycle.md +193 -193
- package/templates/opera/registry.md +28 -28
- package/templates/opera/reviews/delivery-audit.md +18 -18
- package/templates/opera/reviews/integration-audit.md +18 -18
- package/templates/opera/router.md +54 -49
- package/templates/skills/changelog-updater/SKILL.md +69 -69
- package/templates/skills/commiter/SKILL.md +99 -99
- package/templates/skills/opera-contract-auditor/SKILL.md +38 -38
- package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -38
- package/templates/skills/opera-policy-guard/SKILL.md +26 -26
- package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -26
- package/templates/skills/opera-skill/SKILL.md +279 -0
- package/templates/skills/opera-skill/locales/en/SKILL.md +279 -0
- package/templates/skills/opera-skill/locales/en/references/phase-dod.md +138 -0
- package/templates/skills/opera-skill/references/phase-dod.md +138 -0
- package/templates/skills/project-starter-skill/SKILL.md +150 -131
- package/templates/skills/project-starter-skill/locales/en/SKILL.md +143 -105
- package/templates/skills/project-starter-skill/references/opera-cycle.md +195 -193
- package/ui/css/base.css +284 -266
- package/ui/css/charts.css +425 -327
- package/ui/css/components.css +1107 -570
- package/ui/css/onboarding.css +133 -0
- package/ui/css/panels.css +345 -406
- package/ui/css/terminal.css +125 -0
- package/ui/css/timeline.css +58 -0
- package/ui/css/tokens.css +284 -227
- package/ui/favicon.svg +5 -5
- package/ui/index.html +99 -96
- package/ui/js/api.js +49 -13
- package/ui/js/app.js +28 -32
- package/ui/js/charts.js +526 -0
- package/ui/js/console-logger.js +172 -172
- package/ui/js/filters.js +247 -0
- package/ui/js/icons.js +129 -104
- package/ui/js/keyboard.js +229 -0
- package/ui/js/onboarding.js +33 -42
- package/ui/js/router.js +142 -125
- package/ui/js/theme.js +100 -100
- package/ui/js/time-tracker.js +248 -248
- package/ui/js/views/board.js +84 -114
- package/ui/js/views/dashboard.js +870 -0
- package/ui/js/views/flash.js +47 -47
- package/ui/js/views/projects.js +745 -0
- package/ui/js/views/scrum.js +476 -0
- package/ui/js/views/settings.js +153 -203
- package/ui/js/views/sidebar.js +37 -31
- package/ui/js/views/tasks.js +218 -101
- package/ui/js/views/timeline.js +265 -0
- package/ui/js/views/topbar.js +94 -107
- package/ui/app.js +0 -950
- package/ui/js/views/insights.js +0 -340
- package/ui/js/views/overview.js +0 -369
- package/ui/styles.css +0 -688
package/ui/js/icons.js
CHANGED
|
@@ -1,104 +1,129 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* icons.js — SVG paths de
|
|
3
|
-
* Stack vanilla: sin React, sin dependencias externas.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
/**
|
|
2
|
+
* icons.js — SVG paths de Remix Icon (Fill) como constantes
|
|
3
|
+
* Stack vanilla: sin React, sin dependencias externas.
|
|
4
|
+
* Paths SVG tomados de Remix Icon (fill variants), licencia MIT.
|
|
5
|
+
* viewBox 0 0 24 24, fill="currentColor", sin stroke.
|
|
6
|
+
* Uso: icon('dashboard', 20) → <svg>...</svg>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const PATHS = {
|
|
10
|
+
// ── Navegación ──
|
|
11
|
+
dashboard: `<path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/>`,
|
|
12
|
+
tasks: `<path d="M21 2H3c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-9 13l-5-5 1.41-1.41L12 12.17l5.59-5.59L19 8l-7 7z"/>`,
|
|
13
|
+
board: `<path d="M3 3h6v18H3V3zm8 0h6v12h-6V3zm8 0h2v15h-2V3z"/>`,
|
|
14
|
+
execution: `<path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/><path d="M13 19h7v2h-7z"/>`,
|
|
15
|
+
insights: `<path d="M5 9.2h3v10.8H5V9.2zm5.6-5.2h3v16h-3V4zm5.6 8h3v8h-3v-8z"/>`,
|
|
16
|
+
settings: `<path d="M19.14 12.94c.04-.31.06-.63.06-.94 0-.31-.02-.63-.06-.94l2.03-1.58a.49.49 0 00.12-.61l-1.92-3.32a.49.49 0 00-.59-.22l-2.39.96a7.03 7.03 0 00-1.62-.94l-.36-2.54a.48.48 0 00-.48-.41h-3.84a.48.48 0 00-.48.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96a.49.49 0 00-.59.22L2.74 8.87a.48.48 0 00.12.61l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94l-2.03 1.58a.49.49 0 00-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.48-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6A3.6 3.6 0 1112 8.4a3.6 3.6 0 010 7.2z"/>`,
|
|
17
|
+
|
|
18
|
+
// ── General ──
|
|
19
|
+
help: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/>`,
|
|
20
|
+
logout: `<path d="M5 2h14a1 1 0 011 1v18a1 1 0 01-1 1H5a1 1 0 01-1-1v-4h2v3h12V4H7v3H4V3a1 1 0 011-1zm6 7V7l5 5-5 5v-2H4v-6h7z"/>`,
|
|
21
|
+
console: `<path d="M2 4a1 1 0 011-1h18a1 1 0 011 1v16a1 1 0 01-1 1H3a1 1 0 01-1-1V4zm4 13v-2l4-3-4-3V7l6 5-6 5zm6 0h6v-2h-6v2z"/>`,
|
|
22
|
+
infinity: `<path d="M18.6 6.62c-1.44 0-2.8.56-3.77 1.53L12 10.66 9.17 8.15C8.2 7.18 6.84 6.62 5.4 6.62 2.42 6.62 0 9.04 0 12s2.42 5.38 5.4 5.38c1.44 0 2.8-.56 3.77-1.53L12 13.34l2.83 2.51c.97.97 2.33 1.53 3.77 1.53C21.58 17.38 24 14.96 24 12s-2.42-5.38-5.4-5.38zm-13.2 8.56C3.63 15.18 2.2 13.75 2.2 12s1.43-3.18 3.2-3.18c.86 0 1.68.34 2.27.94l2.21 1.96-2.21 2.52c-.59.6-1.41.94-2.27.94zm13.2 0c-.86 0-1.68-.34-2.27-.94l-2.21-1.96 2.21-2.52c.59-.6 1.41-.94 2.27-.94 1.77 0 3.2 1.43 3.2 3.18s-1.43 3.18-3.2 3.18z"/>`,
|
|
23
|
+
|
|
24
|
+
// ── Acciones ──
|
|
25
|
+
plus: `<path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2h6z"/>`,
|
|
26
|
+
check: `<path d="M9.86 18a1 1 0 01-.73-.32l-4.86-5.17a1 1 0 111.46-1.37l4.12 4.39 8.41-9.2a1 1 0 111.48 1.34l-9.14 10a1 1 0 01-.73.33h-.01z"/>`,
|
|
27
|
+
x: `<path d="M12 10.586l4.95-4.95 1.414 1.414L13.414 12l4.95 4.95-1.414 1.414L12 13.414l-4.95 4.95-1.414-1.414L10.586 12 5.636 7.05l1.414-1.414L12 10.586z"/>`,
|
|
28
|
+
edit: `<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>`,
|
|
29
|
+
trash: `<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9zm7.5-5l-1-1h-5l-1 1H5v2h14V4h-3.5z"/>`,
|
|
30
|
+
copy: `<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>`,
|
|
31
|
+
refresh: `<path d="M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>`,
|
|
32
|
+
sync: `<path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46A7.93 7.93 0 0020 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74A7.93 7.93 0 004 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/>`,
|
|
33
|
+
search: `<path d="M15.5 14h-.79l-.28-.27A6.47 6.47 0 0016 9.5 6.5 6.5 0 109.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>`,
|
|
34
|
+
filter: `<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>`,
|
|
35
|
+
sort: `<path d="M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z"/>`,
|
|
36
|
+
menu: `<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>`,
|
|
37
|
+
arrowUp: `<path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/>`,
|
|
38
|
+
arrowDown: `<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"/>`,
|
|
39
|
+
arrowRight: `<path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z"/>`,
|
|
40
|
+
chevronDown: `<path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>`,
|
|
41
|
+
externalLink: `<path d="M19 19H5V5h7V3H5a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>`,
|
|
42
|
+
|
|
43
|
+
// ── Tiempo / cronómetro ──
|
|
44
|
+
clock: `<path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"/>`,
|
|
45
|
+
play: `<path d="M8 5v14l11-7L8 5z"/>`,
|
|
46
|
+
pause: `<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>`,
|
|
47
|
+
stop: `<path d="M6 6h12v12H6z"/>`,
|
|
48
|
+
timer: `<path d="M15 1H9v2h6V1zm-4 13h2V8h-2v6zm8.03-6.61l1.42-1.42c-.43-.51-.9-.99-1.41-1.41l-1.42 1.42A8.962 8.962 0 0012 4c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-2.12-.74-4.07-1.97-5.61zM12 20c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>`,
|
|
49
|
+
|
|
50
|
+
// ── Git / Repo ──
|
|
51
|
+
gitBranch: `<path d="M7 5a2 2 0 100 4 2 2 0 000-4zM7 15a2 2 0 100 4 2 2 0 000-4zM17 5a2 2 0 100 4 2 2 0 000-4zM7 11a4 4 0 00-4 4v0a4 4 0 004 4h0V11zm0 0V9m10-2v2a4 4 0 01-4 4H7"/>`,
|
|
52
|
+
gitCommit: `<path d="M12 16a4 4 0 100-8 4 4 0 000 8zm0-10a6.01 6.01 0 015.917 5H22v2h-4.083A6.01 6.01 0 0112 18a6.01 6.01 0 01-5.917-5H2v-2h4.083A6.01 6.01 0 0112 6z"/>`,
|
|
53
|
+
gitMerge: `<path d="M7.105 8.79A3.001 3.001 0 005 12a3 3 0 002.105 2.862V18a3.001 3.001 0 101.99.001v-3.526A8.01 8.01 0 0015 18h1v-2h-1a6.006 6.006 0 01-5.893-4.876A3.001 3.001 0 007.105 8.79zM8 6a1 1 0 11-2 0 1 1 0 012 0zm0 12a1 1 0 11-2 0 1 1 0 012 0zm0-6a1 1 0 11-2 0 1 1 0 012 0z"/>`,
|
|
54
|
+
|
|
55
|
+
// ── Información / estado ──
|
|
56
|
+
alertCircle: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>`,
|
|
57
|
+
alertTriangle:`<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>`,
|
|
58
|
+
checkCircle: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>`,
|
|
59
|
+
info: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>`,
|
|
60
|
+
shield: `<path d="M12 1l-9 4v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z"/>`,
|
|
61
|
+
zap: `<path d="M11 21h-1l1-7H7.5c-.88 0-.33-.75-.31-.78C8.48 10.94 10.42 7.54 13.01 3h1l-1 7h3.51c.4 0 .62.19.4.66C12.97 17.55 11 21 11 21z"/>`,
|
|
62
|
+
trending: `<path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6h-6z"/>`,
|
|
63
|
+
target: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-14c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm0 10c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
64
|
+
|
|
65
|
+
// ── Ficheros / docs ──
|
|
66
|
+
fileText: `<path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>`,
|
|
67
|
+
folder: `<path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>`,
|
|
68
|
+
download: `<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>`,
|
|
69
|
+
|
|
70
|
+
// ── Layout ──
|
|
71
|
+
maximize: `<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>`,
|
|
72
|
+
columns: `<path d="M10 18h5V5h-5v13zm-6 0h5V5H4v13zM16 5v13h5V5h-5z"/>`,
|
|
73
|
+
terminal2: `<path d="M2 4a1 1 0 011-1h18a1 1 0 011 1v16a1 1 0 01-1 1H3a1 1 0 01-1-1V4zm4 13v-2l4-3-4-3V7l6 5-6 5zm6 0h6v-2h-6v2z"/>`,
|
|
74
|
+
package: `<path d="M20 12V6.5L12 2 4 6.5V12l8 4.5L20 12zM12 4.31l5.74 3.22L12 10.75 6.26 7.53 12 4.31zM6 9.17l5 2.81v5.64l-5-2.81V9.17zm7 8.45v-5.64l5-2.81v5.64l-5 2.81z"/>`,
|
|
75
|
+
|
|
76
|
+
// ── Nuevos iconos ──
|
|
77
|
+
projects: `<path d="M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-2 10H6v-2h12v2zm0-4H6v-2h12v2z"/>`,
|
|
78
|
+
timeline: `<path d="M2 5h6v4H2V5zm0 10h8v4H2v-4zm0-5h10v4H2v-4zm14-5h6v4h-6V5zm-4 10h10v4H12v-4zm2-5h8v4h-8v-4z"/>`,
|
|
79
|
+
velocity: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm1-8.41l2.54 2.53 1.41-1.41-3.54-3.54L12 3v6.59z"/>`,
|
|
80
|
+
calendar: `<path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z"/>`,
|
|
81
|
+
heatmap: `<path d="M4 4h4v4H4V4zm6 0h4v4h-4V4zm6 0h4v4h-4V4zM4 10h4v4H4v-4zm6 0h4v4h-4v-4zm6 0h4v4h-4v-4zM4 16h4v4H4v-4zm6 0h4v4h-4v-4zm6 0h4v4h-4v-4z"/>`,
|
|
82
|
+
keyboard: `<path d="M20 5H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"/>`,
|
|
83
|
+
moon: `<path d="M12.03 4.5C11.44 4.5 10.87 4.56 10.31 4.68 13.31 5.88 15.5 8.88 15.5 12.38c0 3.51-2.19 6.5-5.19 7.7.56.12 1.13.18 1.72.18 4.97 0 9-4.03 9-9s-4.03-9.76-9-9.76z"/>`,
|
|
84
|
+
sun: `<path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/>`,
|
|
85
|
+
user: `<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>`,
|
|
86
|
+
lock: `<path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/>`,
|
|
87
|
+
unlock: `<path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"/>`,
|
|
88
|
+
eye: `<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>`,
|
|
89
|
+
eyeOff: `<path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46A11.8 11.8 0 001 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/>`,
|
|
90
|
+
grip: `<path d="M9 3h2v2H9V3zm4 0h2v2h-2V3zM9 7h2v2H9V7zm4 0h2v2h-2V7zM9 11h2v2H9v-2zm4 0h2v2h-2v-2zM9 15h2v2H9v-2zm4 0h2v2h-2v-2zM9 19h2v2H9v-2zm4 0h2v2h-2v-2z"/>`,
|
|
91
|
+
moreVertical: `<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
92
|
+
moreHorizontal:`<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>`,
|
|
93
|
+
archive: `<path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"/>`,
|
|
94
|
+
star: `<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/>`,
|
|
95
|
+
bookmark: `<path d="M17 3H7c-1.1 0-2 .9-2 2v16l7-3 7 3V5c0-1.1-.9-2-2-2z"/>`,
|
|
96
|
+
link: `<path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/>`,
|
|
97
|
+
globe: `<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>`,
|
|
98
|
+
flag: `<path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6h-5.6z"/>`,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Renderiza un SVG icon (fill-based, Remix Icon style)
|
|
103
|
+
* @param {string} name - nombre del icono
|
|
104
|
+
* @param {number} [size=18] - tamaño en px
|
|
105
|
+
* @param {string} [className=''] - clases adicionales
|
|
106
|
+
* @returns {string} HTML string del SVG
|
|
107
|
+
*/
|
|
108
|
+
export function icon(name, size = 18, className = '') {
|
|
109
|
+
const paths = PATHS[name];
|
|
110
|
+
if (!paths) {
|
|
111
|
+
// Icono fallback: círculo semitransparente
|
|
112
|
+
return `<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="currentColor" class="${className}" aria-hidden="true"><circle cx="12" cy="12" r="10" opacity="0.3"/></svg>`;
|
|
113
|
+
}
|
|
114
|
+
return `<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="currentColor" class="${className}" aria-hidden="true">${paths}</svg>`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Crea un elemento SVG icon insertado en el DOM
|
|
119
|
+
* @param {string} name
|
|
120
|
+
* @param {number} [size=18]
|
|
121
|
+
* @returns {SVGElement}
|
|
122
|
+
*/
|
|
123
|
+
export function iconEl(name, size = 18) {
|
|
124
|
+
const wrapper = document.createElement('span');
|
|
125
|
+
wrapper.innerHTML = icon(name, size);
|
|
126
|
+
return wrapper.firstElementChild;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default { icon, iconEl };
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* keyboard.js — Sistema de atajos de teclado global para TrackOps Dashboard
|
|
3
|
+
* Secuencias de 2 teclas estilo Vim/GitHub (g d = go dashboard).
|
|
4
|
+
* No activo cuando un input/textarea/select tiene foco.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as router from './router.js';
|
|
8
|
+
import * as state from './state.js';
|
|
9
|
+
import { icon } from './icons.js';
|
|
10
|
+
|
|
11
|
+
/** @type {Map<string, {handler: Function, label: string, group: string}>} */
|
|
12
|
+
const _shortcuts = new Map();
|
|
13
|
+
|
|
14
|
+
/** Buffer para secuencias de 2 teclas */
|
|
15
|
+
let _pendingKey = '';
|
|
16
|
+
let _pendingTimer = null;
|
|
17
|
+
const SEQUENCE_TIMEOUT = 600; // ms para completar secuencia
|
|
18
|
+
|
|
19
|
+
/** Elemento del panel de ayuda */
|
|
20
|
+
let _helpVisible = false;
|
|
21
|
+
|
|
22
|
+
// ─────────────────────────────── REGISTRO ────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registrar un atajo de teclado
|
|
26
|
+
* @param {string} keys — Tecla o secuencia ('g o', '/', '?', 'Escape')
|
|
27
|
+
* @param {Function} handler — Callback
|
|
28
|
+
* @param {string} label — Descripcion para el panel de ayuda
|
|
29
|
+
* @param {string} [group='General'] — Grupo en el panel de ayuda
|
|
30
|
+
*/
|
|
31
|
+
export function register(keys, handler, label, group = 'General') {
|
|
32
|
+
_shortcuts.set(keys, { handler, label, group });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─────────────────────────────── DEFAULTS ────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
function _registerDefaults() {
|
|
38
|
+
// Navegacion
|
|
39
|
+
register('g d', () => router.navigate('dashboard'), 'Go to Dashboard', 'Navigation');
|
|
40
|
+
register('g t', () => router.navigate('tasks'), 'Go to Tasks', 'Navigation');
|
|
41
|
+
register('g l', () => router.navigate('timeline'), 'Go to Timeline', 'Navigation');
|
|
42
|
+
register('g e', () => router.navigate('terminal'), 'Go to Terminal', 'Navigation');
|
|
43
|
+
register('g p', () => router.navigate('projects'), 'Go to Projects', 'Navigation');
|
|
44
|
+
register('g s', () => router.navigate('settings'), 'Go to Settings', 'Navigation');
|
|
45
|
+
|
|
46
|
+
// Acciones
|
|
47
|
+
register('/', () => _focusSearch(), 'Focus search', 'Actions');
|
|
48
|
+
register('r', () => _refreshState(), 'Refresh data', 'Actions');
|
|
49
|
+
register('Escape', () => _closeActiveOverlay(), 'Close overlay', 'Actions');
|
|
50
|
+
|
|
51
|
+
// Ayuda
|
|
52
|
+
register('?', () => toggleHelp(), 'Show shortcuts', 'Help');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ─────────────────────────────── HANDLER ─────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
function _onKeyDown(e) {
|
|
58
|
+
// No interceptar si un input tiene foco
|
|
59
|
+
const tag = document.activeElement?.tagName?.toLowerCase();
|
|
60
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select') {
|
|
61
|
+
// Solo Escape escapa de inputs
|
|
62
|
+
if (e.key === 'Escape') {
|
|
63
|
+
document.activeElement.blur();
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// No interceptar si hay modificadores (excepto Shift para ?)
|
|
70
|
+
if (e.ctrlKey || e.altKey || e.metaKey) return;
|
|
71
|
+
|
|
72
|
+
const key = e.key;
|
|
73
|
+
|
|
74
|
+
// Buscar atajo directo (1 tecla)
|
|
75
|
+
if (!_pendingKey) {
|
|
76
|
+
const direct = _shortcuts.get(key);
|
|
77
|
+
if (direct) {
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
direct.handler();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Iniciar secuencia de 2 teclas
|
|
84
|
+
// Solo letras minusculas inician secuencias
|
|
85
|
+
if (/^[a-z]$/.test(key)) {
|
|
86
|
+
_pendingKey = key;
|
|
87
|
+
_pendingTimer = setTimeout(() => {
|
|
88
|
+
_pendingKey = '';
|
|
89
|
+
_pendingTimer = null;
|
|
90
|
+
}, SEQUENCE_TIMEOUT);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Completar secuencia de 2 teclas
|
|
97
|
+
clearTimeout(_pendingTimer);
|
|
98
|
+
const sequence = `${_pendingKey} ${key}`;
|
|
99
|
+
_pendingKey = '';
|
|
100
|
+
_pendingTimer = null;
|
|
101
|
+
|
|
102
|
+
const seq = _shortcuts.get(sequence);
|
|
103
|
+
if (seq) {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
seq.handler();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─────────────────────────────── ACCIONES ────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
function _focusSearch() {
|
|
112
|
+
const input = document.querySelector('.topbar-search input, .topbar-search-input');
|
|
113
|
+
if (input) {
|
|
114
|
+
input.focus();
|
|
115
|
+
input.select();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _refreshState() {
|
|
120
|
+
window.dispatchEvent(new CustomEvent('ops:refresh'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function _closeActiveOverlay() {
|
|
124
|
+
// Cerrar help panel
|
|
125
|
+
if (_helpVisible) {
|
|
126
|
+
toggleHelp();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// Cerrar modal
|
|
130
|
+
const modal = document.querySelector('.modal-overlay:not(.is-hidden)');
|
|
131
|
+
if (modal) {
|
|
132
|
+
modal.classList.add('is-hidden');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Cerrar console panel
|
|
136
|
+
const consolePanel = document.getElementById('console-panel');
|
|
137
|
+
if (consolePanel?.classList.contains('is-open')) {
|
|
138
|
+
consolePanel.classList.remove('is-open');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ─────────────────────────────── HELP PANEL ──────────────────────────────────
|
|
143
|
+
|
|
144
|
+
export function toggleHelp() {
|
|
145
|
+
_helpVisible = !_helpVisible;
|
|
146
|
+
let panel = document.getElementById('keyboard-help-panel');
|
|
147
|
+
|
|
148
|
+
if (!_helpVisible && panel) {
|
|
149
|
+
panel.remove();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (_helpVisible) {
|
|
154
|
+
panel = document.createElement('div');
|
|
155
|
+
panel.id = 'keyboard-help-panel';
|
|
156
|
+
panel.className = 'modal-overlay';
|
|
157
|
+
panel.setAttribute('role', 'dialog');
|
|
158
|
+
panel.setAttribute('aria-modal', 'true');
|
|
159
|
+
panel.setAttribute('aria-label', 'Keyboard shortcuts');
|
|
160
|
+
panel.addEventListener('click', (e) => {
|
|
161
|
+
if (e.target === panel) toggleHelp();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Agrupar shortcuts
|
|
165
|
+
const groups = new Map();
|
|
166
|
+
for (const [keys, { label, group }] of _shortcuts) {
|
|
167
|
+
if (!groups.has(group)) groups.set(group, []);
|
|
168
|
+
groups.get(group).push({ keys, label });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let groupsHtml = '';
|
|
172
|
+
for (const [group, items] of groups) {
|
|
173
|
+
groupsHtml += `
|
|
174
|
+
<div class="kb-help-group">
|
|
175
|
+
<h3 class="kb-help-group-title">${group}</h3>
|
|
176
|
+
<div class="kb-help-items">
|
|
177
|
+
${items.map(({ keys, label }) => `
|
|
178
|
+
<div class="kb-help-item">
|
|
179
|
+
<kbd class="kb-help-key">${_formatKey(keys)}</kbd>
|
|
180
|
+
<span class="kb-help-label">${label}</span>
|
|
181
|
+
</div>
|
|
182
|
+
`).join('')}
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
panel.innerHTML = `
|
|
189
|
+
<div class="modal" style="max-width:520px">
|
|
190
|
+
<div class="modal-header">
|
|
191
|
+
<h2 class="modal-title">${icon('keyboard', 18)} Keyboard shortcuts</h2>
|
|
192
|
+
<button class="modal-close" type="button" aria-label="Close" id="kb-help-close">×</button>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="modal-body" style="padding:var(--space-4) var(--space-6)">
|
|
195
|
+
${groupsHtml}
|
|
196
|
+
</div>
|
|
197
|
+
<div class="modal-footer" style="justify-content:center">
|
|
198
|
+
<p style="font-size:var(--text-xs);color:var(--text-muted)">Press <kbd class="kb-help-key">?</kbd> to toggle this panel</p>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
`;
|
|
202
|
+
|
|
203
|
+
document.body.appendChild(panel);
|
|
204
|
+
panel.querySelector('#kb-help-close')?.addEventListener('click', () => toggleHelp());
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function _formatKey(keys) {
|
|
209
|
+
return keys.split(' ').map(k => {
|
|
210
|
+
if (k === 'Escape') return 'Esc';
|
|
211
|
+
if (k === '/') return '/';
|
|
212
|
+
if (k === '?') return '?';
|
|
213
|
+
return k.toUpperCase();
|
|
214
|
+
}).join(' <span style="opacity:0.4">then</span> ');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ─────────────────────────────── INIT ────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
export function init() {
|
|
220
|
+
_registerDefaults();
|
|
221
|
+
document.addEventListener('keydown', _onKeyDown);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function destroy() {
|
|
225
|
+
document.removeEventListener('keydown', _onKeyDown);
|
|
226
|
+
_shortcuts.clear();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export default { init, destroy, register, toggleHelp };
|