Add Student Welcome Guide, legal pages, and working newsletter
Student Welcome Guide (Phase 1): - Landing + 5 topic pages (journey, bachelor, master, deadlines, eVS) in EN/SI/MK, reusing the article auto-TOC - New css/pages/_guide.css components and a 3:1 hero image placeholder - Functional client-side "Build my route" tool (student-guide.js) - "Student Welcome Guide" menu link wired site-wide Legal pages: - Trilingual Privacy Policy and Cookie Policy (GDPR-oriented, MailerLite disclosed, IP RS complaint route) - Footer legal strip + Organisation column links wired site-wide, depth-aware, plus header/footer templates Newsletter: - MailerLite subscribe handler in main.js upgrades both form variants on every page: validation, double opt-in, inline trilingual status - Subscribe status styles in css/pages/_projects.css Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bf70a10a14
commit
cee9f1da10
113 files changed
+9043
-346
No files matched your search
@@ -648,10 +648,95 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
/**
|
||||
* ===================================================================
|
||||
* 7. ZAGON FUNKCIJ PO NALOŽITVI STRANI
|
||||
* 7. NEWSLETTER (MailerLite)
|
||||
* ===================================================================
|
||||
*/
|
||||
function setupNewsletter() {
|
||||
// --- MailerLite configuration -----------------------------------
|
||||
// Fill these in from your MailerLite embedded form
|
||||
// (Forms > Embedded forms > your form > Embed code). Both values
|
||||
// appear in the embed's subscribe URL:
|
||||
// https://assets.mailerlite.com/jsonp/<ACCOUNT>/forms/<FORM>/subscribe
|
||||
const ML_ACCOUNT = '1253161';
|
||||
const ML_FORM = '194374752800868123';
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
const forms = document.querySelectorAll('form.subscribe-form, form.subscribe-form-bottom');
|
||||
if (!forms.length) return;
|
||||
|
||||
let lang = (document.documentElement.getAttribute('lang') || 'en').toLowerCase();
|
||||
if (['en', 'si', 'mk'].indexOf(lang) === -1) lang = 'en';
|
||||
|
||||
const T = {
|
||||
invalid: { en: 'Please enter a valid email address.', si: 'Vnesite veljaven e-poštni naslov.', mk: 'Внесете важечка е-адреса.' },
|
||||
sending: { en: 'Sending…', si: 'Pošiljanje…', mk: 'Се испраќа…' },
|
||||
success: { en: 'Thank you! Please check your inbox to confirm your subscription.', si: 'Hvala! Za potrditev naročnine preverite svoj e-poštni predal.', mk: 'Ви благодариме! Проверете го вашето сандаче за да ја потврдите претплатата.' },
|
||||
error: { en: 'Something went wrong. Please try again later.', si: 'Nekaj je šlo narobe. Poskusite znova pozneje.', mk: 'Нешто не успеа. Обидете се повторно подоцна.' },
|
||||
notready: { en: 'The newsletter is being set up. Please check back soon.', si: 'Novice se pravkar nastavljajo. Preverite kmalu znova.', mk: 'Билтенот се поставува. Проверете повторно наскоро.' }
|
||||
};
|
||||
const t = (k) => (T[k][lang] || T[k].en);
|
||||
|
||||
forms.forEach((form) => {
|
||||
const input = form.querySelector('input[type="email"], input[type="text"], input');
|
||||
if (!input) return;
|
||||
input.setAttribute('type', 'email');
|
||||
input.setAttribute('name', 'fields[email]');
|
||||
input.setAttribute('required', '');
|
||||
input.setAttribute('autocomplete', 'email');
|
||||
|
||||
const status = document.createElement('p');
|
||||
status.className = 'subscribe-status';
|
||||
status.setAttribute('role', 'status');
|
||||
status.setAttribute('aria-live', 'polite');
|
||||
status.hidden = true;
|
||||
form.parentNode.insertBefore(status, form.nextSibling);
|
||||
|
||||
const show = (msg, type) => {
|
||||
status.textContent = msg;
|
||||
status.className = 'subscribe-status is-' + type;
|
||||
status.hidden = false;
|
||||
};
|
||||
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const email = (input.value || '').trim();
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
show(t('invalid'), 'error');
|
||||
input.focus();
|
||||
return;
|
||||
}
|
||||
if (!ML_ACCOUNT || !ML_FORM) { show(t('notready'), 'error'); return; }
|
||||
|
||||
const button = form.querySelector('button[type="submit"], button');
|
||||
if (button) button.disabled = true;
|
||||
show(t('sending'), 'info');
|
||||
|
||||
const url = 'https://assets.mailerlite.com/jsonp/' + ML_ACCOUNT + '/forms/' + ML_FORM + '/subscribe';
|
||||
const body = new URLSearchParams();
|
||||
body.append('fields[email]', email);
|
||||
body.append('ml-submit', '1');
|
||||
body.append('anticsrf', 'true');
|
||||
|
||||
fetch(url, { method: 'POST', body: body, mode: 'no-cors' })
|
||||
.then(() => {
|
||||
// Double opt-in: MailerLite emails a confirmation link, so we
|
||||
// optimistically confirm here (the opt-in email is the real check).
|
||||
form.reset();
|
||||
show(t('success'), 'success');
|
||||
})
|
||||
.catch(() => show(t('error'), 'error'))
|
||||
.finally(() => { if (button) button.disabled = false; });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ===================================================================
|
||||
* 8. ZAGON FUNKCIJ PO NALOŽITVI STRANI
|
||||
* ===================================================================
|
||||
*/
|
||||
highlightActiveLink();
|
||||
setupLanguageSwitcher();
|
||||
setupNewsletter();
|
||||
|
||||
});
|
||||
Reference in new issue
Block a user