Redesign homepage: navy and pink 'sentence is the layout' direction
Complete rebuild of the single page from the design-taste-frontend skill (direction: sentence-as-layout, seed 1084447843). CSS and JS moved out of the markup into css/site.css and js/site.js. - navy field #1a2039 with pink ink #f9a3c0: no Odoo plum, no teal, no violet - hero headline carries a 1689 world map inside the sentence - claims as full-bleed switchable bands, tips table, module picker - four archival Wikimedia pictures, credited in the footer - inspector: 0 FAIL at 1440 / 768 / 390 (lint clean)
This commit is contained in:
1 parent
ed6d3c747b
commit
94eb541ac3
9 files changed
+1192
-790
No files matched your search
+148
@@ -0,0 +1,148 @@
|
||||
/* The OC Guy — page behaviour.
|
||||
Everything here degrades: without JS the page still reads, the bands still
|
||||
show their titles, the tips still list, the form still shows. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var doc = document.documentElement;
|
||||
doc.classList.add('js');
|
||||
|
||||
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
/* ---------- signature move: the shutter on the hero photograph ---------- */
|
||||
var hero = document.querySelector('.hero-line');
|
||||
if (hero) {
|
||||
if (reduce) {
|
||||
hero.classList.add('shutter');
|
||||
} else {
|
||||
requestAnimationFrame(function () {
|
||||
setTimeout(function () { hero.classList.add('shutter'); }, 120);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- entrance for the parts of every section ---------- */
|
||||
var targets = [];
|
||||
document.querySelectorAll('.intro .statement, .open h2, .open p, .map-figure figcaption, .tips h2, .tips-note, .picker, .tips-list li, .about h2, .bio, .about-facts, .ask-line, .ask-note, .band-text, .foot-invite, .foot-links').forEach(function (el) {
|
||||
targets.push(el);
|
||||
});
|
||||
|
||||
if (!reduce && 'IntersectionObserver' in window) {
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
entry.target.classList.add('rv-in');
|
||||
io.unobserve(entry.target);
|
||||
});
|
||||
}, { rootMargin: '0px 0px -12% 0px', threshold: 0.12 });
|
||||
|
||||
targets.forEach(function (el, i) {
|
||||
el.setAttribute('data-rv', String((i % 4) + 1));
|
||||
io.observe(el);
|
||||
});
|
||||
} else {
|
||||
targets.forEach(function (el) { el.classList.add('rv-in'); });
|
||||
}
|
||||
|
||||
/* ---------- switches: five claims ---------- */
|
||||
document.querySelectorAll('.band-switch').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var band = btn.closest('.band');
|
||||
var on = btn.getAttribute('aria-checked') === 'true';
|
||||
btn.setAttribute('aria-checked', String(!on));
|
||||
band.setAttribute('data-on', String(!on));
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- the live thing: pick what the company does ---------- */
|
||||
var chips = Array.prototype.slice.call(document.querySelectorAll('.chip'));
|
||||
var out = document.querySelector('.picker-out');
|
||||
var installOrder = ['Sales', 'CRM', 'Purchase', 'Manufacturing', 'Inventory', 'Project', 'Timesheets', 'Expenses', 'Invoicing', 'Accounting'];
|
||||
|
||||
function render(mods) {
|
||||
if (!mods.length) {
|
||||
out.textContent = 'Choose one, or several. The modules stack in the order you would install them.';
|
||||
return;
|
||||
}
|
||||
out.innerHTML = '';
|
||||
mods.forEach(function (name, i) {
|
||||
var span = document.createElement('span');
|
||||
span.className = 'mod';
|
||||
span.textContent = name;
|
||||
out.appendChild(span);
|
||||
if (i < mods.length - 1) {
|
||||
var arrow = document.createElement('span');
|
||||
arrow.className = 'arrow';
|
||||
arrow.textContent = ' → ';
|
||||
out.appendChild(arrow);
|
||||
}
|
||||
});
|
||||
var note = document.createElement('span');
|
||||
note.className = 'arrow';
|
||||
note.textContent = ' — that order, top to bottom.';
|
||||
out.appendChild(note);
|
||||
}
|
||||
|
||||
chips.forEach(function (chip) {
|
||||
chip.setAttribute('aria-pressed', 'false');
|
||||
chip.addEventListener('click', function () {
|
||||
var pressed = chip.getAttribute('aria-pressed') === 'true';
|
||||
chip.setAttribute('aria-pressed', String(!pressed));
|
||||
|
||||
var picked = chips.filter(function (c) { return c.getAttribute('aria-pressed') === 'true'; })
|
||||
.reduce(function (all, c) {
|
||||
c.dataset.modules.split(',').forEach(function (m) {
|
||||
var name = m.trim();
|
||||
if (all.indexOf(name) === -1) all.push(name);
|
||||
});
|
||||
return all;
|
||||
}, []);
|
||||
|
||||
picked.sort(function (a, b) { return installOrder.indexOf(a) - installOrder.indexOf(b); });
|
||||
render(picked);
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- ask: one question, by mail ---------- */
|
||||
var send = document.querySelector('.ask-send');
|
||||
var mail = document.getElementById('ask-mail');
|
||||
if (send && mail) {
|
||||
send.addEventListener('click', function () {
|
||||
var addr = (mail.value || '').trim();
|
||||
var body = 'My question about Odoo Community:\n\n\n';
|
||||
if (addr) body += '\n— reply to: ' + addr + '\n';
|
||||
var href = 'mailto:o.arnold@projektbox.de'
|
||||
+ '?subject=' + encodeURIComponent('Odoo Community question')
|
||||
+ '&body=' + encodeURIComponent(body);
|
||||
if (addr && addr.indexOf('@') === -1) {
|
||||
mail.focus();
|
||||
mail.setAttribute('aria-invalid', 'true');
|
||||
return;
|
||||
}
|
||||
mail.removeAttribute('aria-invalid');
|
||||
window.location.href = href;
|
||||
});
|
||||
mail.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Enter') send.click();
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- one moving picture: the world map drifts against the scroll ---------- */
|
||||
var map = document.getElementById('worldmap');
|
||||
if (map && !reduce) {
|
||||
var ticking = false;
|
||||
var update = function () {
|
||||
var rect = map.getBoundingClientRect();
|
||||
var vh = window.innerHeight || 800;
|
||||
if (rect.bottom > -200 && rect.top < vh + 200) {
|
||||
var progress = (rect.top + rect.height / 2 - vh / 2) / vh;
|
||||
map.style.transform = 'translate3d(0,' + (progress * -26).toFixed(2) + 'px,0) scale(1.06)';
|
||||
}
|
||||
ticking = false;
|
||||
};
|
||||
window.addEventListener('scroll', function () {
|
||||
if (!ticking) { ticking = true; requestAnimationFrame(update); }
|
||||
}, { passive: true });
|
||||
update();
|
||||
}
|
||||
})();
|
||||
Reference in new issue
Block a user