| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // Studio page — vanilla fade-carousel + tab sync + per-slide choreography.
- // Replaces Bootstrap Carousel/Tab, jQuery, and backstretch. Keeps DrawFillSVG
- // (window.DrawFillSVG, self-exposed from the v4-script bundle).
- // --- shared chrome: navbar hide/show on scroll (ported from jQuery dw_hidenav) ---
- (function () {
- const navbar = document.querySelector('.navbar');
- if (!navbar) return;
- const title = document.querySelector('.site-title a');
- const headerHeight = navbar.offsetHeight;
- let previousTop = 0;
- window.addEventListener('scroll', function () {
- const currentTop = window.scrollY;
- if (currentTop < previousTop) {
- if (currentTop > 0 && navbar.classList.contains('fixed')) {
- navbar.classList.add('visible');
- if (title) title.classList.remove('light');
- } else {
- navbar.classList.remove('visible', 'fixed');
- if (title) title.classList.add('light');
- }
- } else {
- navbar.classList.remove('visible');
- if (currentTop > headerHeight && !navbar.classList.contains('fixed')) {
- navbar.classList.add('fixed');
- }
- }
- previousTop = currentTop;
- }, { passive: true });
- })();
- document.querySelectorAll('.nav-toggle').forEach(function (el) {
- el.addEventListener('click', function (e) {
- e.preventDefault();
- el.classList.toggle('active');
- });
- });
- // --- studio fade-carousel ---
- (function () {
- const stage = document.getElementById('studio-caro');
- const caro = document.getElementById('caro');
- if (!stage || !caro) return;
- const slides = Array.from(caro.querySelectorAll('.dw-fade-slide'));
- const tabs = Array.from(document.querySelectorAll('.dw-studio-tab'));
- const panes = Array.from(document.querySelectorAll('#studio-tab .tab-pane'));
- const bg = stage.querySelector('.dw-studio-bg');
- const video = stage.querySelector('.dw-studio-video'); // camera → Media slide
- const tv = stage.querySelector('.dw-studio-tv'); // grayscale → fact intro
- const title = document.querySelector('.site-title a');
- const studioTab = tabs.find((t) => t.getAttribute('href') === '#studio') || tabs[0];
- const GRADS = ['caro-grad', 'caro-grad2', 'caro-grad3', 'caro-grad5'];
- // per slide: gradient class · background image · show video · navbar-title light
- // Slides 0-4 are the tabbed sections; 5-7 the fact intro; 8 the Projects hero.
- const CONFIG = [
- { grad: 'caro-grad5', img: stage.dataset.bg0 || null, video: false, light: true, filter: 'url(#dw-duotone-slate)' }, // 0 Studio (slate-duotone hero)
- { grad: 'caro-grad2', img: null, video: false, light: true }, // 1 Web/Dev (was UX)
- { grad: 'caro-grad3', img: null, video: false, light: false }, // 2 Graphic
- { grad: 'caro-grad5', img: null, video: true, light: true }, // 3 Media
- { grad: 'caro-grad5', img: stage.dataset.bg5 || null, video: false, light: true }, // 4 Art
- { grad: 'caro-grad5', img: null, video: false, tv: true, light: true }, // 5 fact: web sites
- { grad: 'caro-grad5', img: null, video: false, tv: true, light: true }, // 6 fact: stars
- { grad: 'caro-grad5', img: null, video: false, tv: true, light: true }, // 7 fact: brain
- { grad: 'caro-grad5', img: null, video: false, light: true }, // 8 Projects (cards; transparent stage → body shows around the #dadada slide card)
- ];
- const INTERVAL = 5000;
- let index = 0;
- let timer = null;
- function drawSVGs(slide) {
- if (!window.DrawFillSVG) return;
- slide.querySelectorAll('svg[id]').forEach(function (svg) {
- try {
- new window.DrawFillSVG({ elementId: svg.id }).replay();
- } catch (e) {
- /* svg not animatable — skip */
- }
- });
- }
- // Set the hero carousel slide (slide visibility, gradient, bg image, video/tv,
- // navbar-title colour). Does NOT touch the subnav tabs or content panes — those
- // are driven by setActiveTab, so the Wonder auto-cycle and the content-only
- // Projects tab can move the hero and the active tab independently.
- function setHero(i) {
- i = (i + slides.length) % slides.length;
- index = i;
- const cfg = CONFIG[i];
- slides.forEach((s, n) => {
- const on = n === i;
- s.classList.toggle('active', on);
- // reveal the active slide's hidden content (.animac.hide-svg, #brain.hide-svg …)
- if (on) s.querySelectorAll('.hide-svg').forEach((el) => el.classList.remove('hide-svg'));
- });
- GRADS.forEach((g) => stage.classList.remove(g));
- stage.classList.add(cfg.grad);
- if (bg) {
- bg.style.backgroundImage = cfg.img ? 'url("' + cfg.img + '")' : '';
- bg.style.filter = cfg.filter || ''; // slate duotone on the Studio hero only
- }
- if (video) {
- if (cfg.video) {
- video.style.display = 'block';
- video.play().catch(function () {});
- } else {
- video.pause();
- video.style.display = 'none';
- }
- }
- if (tv) {
- if (cfg.tv) {
- tv.style.display = 'block';
- tv.play().catch(function () {});
- } else {
- tv.pause();
- tv.style.display = 'none';
- }
- }
- if (title) title.classList.toggle('light', cfg.light);
- drawSVGs(slides[i]);
- }
- // Mark a subnav tab active and show its matching content pane, matched by the
- // tab's href hash → pane id (#studio → id="studio", #projects → id="projects").
- // Tabs with no pane (Wonder) simply hide every pane.
- function setActiveTab(tab) {
- tabs.forEach((t) => t.classList.toggle('active', t === tab));
- const hash = tab ? tab.getAttribute('href') || '' : '';
- const id = hash.charAt(0) === '#' ? hash.slice(1) : '';
- panes.forEach((p) => p.classList.toggle('active', p.id === id));
- }
- // "Wonder" auto-rotates through the fact slides (6,7,8) then returns to Studio (0)
- // and stops. Every other tab just switches on click — no autoplay.
- const WONDER = [5, 6, 7, 0];
- let wonderTimer = null;
- function stopWonder() { if (wonderTimer) { window.clearTimeout(wonderTimer); wonderTimer = null; } }
- function runWonder() {
- stopWonder();
- let step = 0;
- (function tick() {
- setHero(WONDER[step]);
- step++;
- if (step < WONDER.length) wonderTimer = window.setTimeout(tick, INTERVAL);
- else setActiveTab(studioTab); // cycle ends on the Studio hero → settle the tab there
- })();
- }
- tabs.forEach(function (t) {
- t.addEventListener('click', function (e) {
- e.preventDefault();
- stopWonder();
- setActiveTab(t);
- if (t.classList.contains('dw-studio-wonder')) runWonder();
- else setHero(parseInt(t.dataset.slide, 10) || 0);
- });
- });
- // No autoplay — the carousel advances only on subnav clicks (Wonder runs its own set).
- setActiveTab(studioTab);
- setHero(0);
- })();
|