-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtraining-portal.js
More file actions
246 lines (214 loc) · 9.97 KB
/
Copy pathtraining-portal.js
File metadata and controls
246 lines (214 loc) · 9.97 KB
1
2
3
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*
* Tigera Labs theme — Training Portal surface.
*
* Loaded at end-of-body by the upstream training-portal Django base
* template (training-portal/src/project/templates/project-base.html).
* That template auto-links ONLY training-portal.css and this file —
* it has no hook to inject training-portal.html into <head>, so the
* core token stylesheet and `window.TigeraTheme` global must be
* bootstrapped from here. Without this, every var(--*) in
* training-portal.css resolves to nothing and the page renders white.
*/
(function () {
'use strict';
var THEME_BASE = '/static/workshops/theme/';
// Bootstrap the shared core stylesheet + script that training-portal.html
// would normally have linked from <head>. The CSS goes in first so paint
// applies tokens as soon as the file lands; the JS is what defines
// window.TigeraTheme, so the rest of this surface waits on its load.
injectCoreStylesheet();
injectCoreScript(startSurface);
function injectCoreStylesheet() {
if (document.querySelector('link[data-tigera-core]')) return;
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = THEME_BASE + 'tigera-theme-core.css';
link.setAttribute('data-tigera-core', '');
// Prepend so per-surface training-portal.css (already linked from
// <head>) keeps its cascade priority for overrides.
var head = document.head || document.getElementsByTagName('head')[0];
head.insertBefore(link, head.firstChild);
}
function injectCoreScript(onReadyFn) {
if (window.TigeraTheme) { onReadyFn(); return; }
var existing = document.querySelector('script[data-tigera-core]');
if (existing) {
existing.addEventListener('load', onReadyFn);
return;
}
var s = document.createElement('script');
s.src = THEME_BASE + 'tigera-theme-core.js';
s.setAttribute('data-tigera-core', '');
s.onload = onReadyFn;
(document.head || document.getElementsByTagName('head')[0]).appendChild(s);
}
function startSurface() {
document.documentElement.classList.add('tigera-labs');
if (document.body) document.body.classList.add('tigera-labs');
// Keep the toggle's icon and aria-label in sync with the theme.
TigeraTheme.onApplyTheme(function (theme) {
var t = document.getElementById('tigera-theme-toggle');
if (!t) return;
t.innerHTML = theme === 'dark' ? TigeraTheme.svgSun() : TigeraTheme.svgMoon();
t.setAttribute('aria-label', theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
});
// Auth pages: tag <body> for CSS scoping + inject the side hero.
if (location.pathname.indexOf('/accounts/login/') !== -1 ||
location.pathname.indexOf('/accounts/register/') !== -1) {
onReady(function () {
document.body.classList.add('tigera-labs-auth');
injectAuthHero();
});
}
onReady(function () {
swapPlatformLogo();
injectThemeToggle();
injectCatalogHero();
injectAccessNotice();
renameStartButtons();
injectFooter();
TigeraTheme.injectSlackHelp();
});
}
function onReady(fn) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fn);
} else {
fn();
}
}
// -------------------------------------------------------------------
// Surface helpers
// -------------------------------------------------------------------
// Visual replacement of the upstream logo is handled by CSS
// `content: url(...)` so it applies before paint and avoids the
// flash this function used to cause. We only update alt text here
// for accessibility — the original src stays untouched.
function swapPlatformLogo() {
var imgs = document.querySelectorAll('.portal-logo, .navbar-brand img');
imgs.forEach(function (img) {
img.alt = 'Calico';
});
}
function injectThemeToggle() {
var nav = document.querySelector('nav.navbar.navbar-fixed-top, nav.navbar.bg-dark');
if (!nav) return;
if (nav.querySelector('#tigera-theme-toggle')) return;
var btn = document.createElement('button');
btn.id = 'tigera-theme-toggle';
btn.type = 'button';
btn.innerHTML = ''; // icon set by the hook below
btn.addEventListener('click', TigeraTheme.toggleTheme);
nav.appendChild(btn);
// Re-fire hooks now that the button exists, so the icon paints
// for the initial state.
TigeraTheme.applyTheme(document.documentElement.getAttribute('data-theme') || 'light');
}
function injectAuthHero() {
var card = document.querySelector('.login, .register');
if (!card) return;
if (card.parentElement && card.parentElement.classList.contains('tigera-auth-grid')) return;
var isRegister = card.classList.contains('register');
var grid = document.createElement('div');
grid.className = 'tigera-auth-grid';
var hero = document.createElement('aside');
hero.className = 'tigera-auth-hero';
hero.innerHTML = isRegister ? heroRegisterCopy() : heroLoginCopy();
var parent = card.parentElement;
parent.insertBefore(grid, card);
grid.appendChild(hero);
grid.appendChild(card);
}
function heroLoginCopy() {
return [
'<div class="stamp">Tigera Labs</div>',
'<h1>Hands-on <span class="accent">cloud-native</span> security</h1>',
'<p>Master Calico, Kubernetes networking, and AI workload governance through real environments. Sign in to continue your session.</p>',
'<ul class="features">',
' <li>Per-session isolated Kubernetes clusters</li>',
' <li>Live terminal, editor, and console panes</li>',
' <li>Real Calico CRDs & network-policy enforcement</li>',
'</ul>',
].join('');
}
function heroRegisterCopy() {
return [
'<div class="stamp">Tigera Labs</div>',
'<h1>Create your <span class="accent">Tigera Labs</span> account</h1>',
'<p>One account — resume any workshop session if your browser exits, switch devices mid-lab, and track your progress across sessions.</p>',
'<ul class="features">',
' <li>No personal data retained beyond the training period</li>',
' <li>Resume in-progress sessions from any browser</li>',
' <li>Free access to the Tigera Labs catalog</li>',
'</ul>',
].join('');
}
function injectCatalogHero() {
var container = document.querySelector('.jumbotron .container');
if (!container) return;
if (container.querySelector('.tigera-hero-banner')) return;
if (document.querySelector('.login, .register')) return;
if (!document.querySelector('.card .start-workshop, .card .btn.start-workshop')) return;
var cardCount = document.querySelectorAll('.card').length;
var labWord = cardCount === 1 ? 'lab' : 'labs';
var hero = document.createElement('div');
hero.className = 'tigera-hero-banner';
hero.innerHTML = [
'<div class="meta-row">',
' <div class="stamp">Tigera Labs</div>',
' <div class="meta"><strong>' + cardCount + '</strong> ' + labWord + ' available</div>',
'</div>',
'<h1>Hands-on <span class="accent">cloud-native</span> security</h1>',
'<p>Master Calico, Kubernetes networking, and AI workload governance through real environments. Deploy, secure, and monitor production-grade clusters.</p>',
].join('');
container.insertBefore(hero, container.firstChild);
}
// /workshops/access/ — invite-only gate. Educates' upstream template
// is just an h1 + form; we prepend a Tigera-styled hero panel that
// explains the gating and surfaces the Slack recovery channel.
function injectAccessNotice() {
if (location.pathname.indexOf('/workshops/access/') === -1) return;
var container = document.querySelector('.jumbotron .container');
if (!container) return;
if (container.querySelector('.tigera-access-notice')) return;
var notice = document.createElement('div');
notice.className = 'tigera-hero-banner tigera-access-notice';
notice.innerHTML = [
'<div class="meta-row">',
' <div class="stamp">Invite-only lab</div>',
'</div>',
'<h1>This lab is <span class="accent">invite only</span></h1>',
'<p>Lost your invite or need access restored? Reach out to us on Slack and we’ll help you get back in.</p>',
'<div class="tigera-access-actions">',
' <a class="btn btn-primary" href="https://slack.projectcalico.org/" target="_blank" rel="noopener noreferrer">',
' <svg class="tigera-access-slack-icon" width="18" height="18" viewBox="0 0 24 24" aria-hidden="true">',
' <path fill="currentColor" d="M5.04 15.16a2.04 2.04 0 1 1-2.04-2.04h2.04v2.04zm1.03 0a2.04 2.04 0 0 1 4.07 0v5.11a2.04 2.04 0 1 1-4.07 0v-5.11zm2.04-10.12a2.04 2.04 0 1 1-2.04-2.04v2.04H8.11zm0 1.03a2.04 2.04 0 0 1 0 4.07H3a2.04 2.04 0 1 1 0-4.07h5.11zm10.85 3.77a2.04 2.04 0 1 1 2.04 2.04h-2.04V9.84zm-1.03 0a2.04 2.04 0 0 1-4.07 0V4.73a2.04 2.04 0 1 1 4.07 0v5.11zm-3.04 9.12a2.04 2.04 0 1 1-2.04 2.04v-2.04h2.04zm0-1.03a2.04 2.04 0 0 1 0-4.07H21a2.04 2.04 0 1 1 0 4.07h-5.11z"/>',
' </svg>',
' Recover access on Slack',
' </a>',
'</div>',
].join('');
container.insertBefore(notice, container.firstChild);
}
function renameStartButtons() {
document.querySelectorAll('.btn.start-workshop').forEach(function (btn) {
btn.textContent = 'Start Lab';
});
}
function injectFooter() {
if (!document.querySelector('.jumbotron')) return;
if (document.querySelector('.tigera-footer')) return;
var year = new Date().getFullYear();
var footer = document.createElement('footer');
footer.className = 'tigera-footer';
footer.innerHTML = [
'<div>© ' + year + ' TIGERA, INC. ALL RIGHTS RESERVED.</div>',
'<div>',
' <a href="https://www.tigera.io/privacy-policy/" target="_blank" rel="noopener">Privacy</a>',
' <a href="https://www.tigera.io/legal/" target="_blank" rel="noopener">Terms</a>',
' <a href="https://docs.tigera.io" target="_blank" rel="noopener">Docs</a>',
'</div>',
].join('');
document.body.appendChild(footer);
}
})();