From 0db7312aafe144000606e545f12d8089ef7ade6c Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Wed, 30 Sep 2026 23:06:17 -0700 Subject: [PATCH] =?UTF-8?q?thomaslawson:=20TL=20refresh=20v1.6.0=20live,?= =?UTF-8?q?=20v1.6.1=20built=20=E2=80=94=20F=C3=ADa's=202026-09-30=20meeti?= =?UTF-8?q?ng=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.6.0 (live via sftp): Valise recent-work carousel on Home, In the Studio opens on a recent Valise work, new 2020–2022 + 2022–present periods served from Valise, Beyond the Studio as an index with previews (Curatorial Projects door removed), Deirdre film, Slimane spelling, Portrait of New York singular, REALLIFE 15 link, About lightbox, Art School captions, News grid with the Law & Order find. deploy-plugin.sh gains TL_MEDIA_DIR uploads. v1.6.1 (built, not uploaded): singular Portrait of New York sitewide, the section moved above Memory Lingers Here, Deirdre spelling, Early New York before Painted Installations — from Tom's Jan 2026 notes. --- .../refresh-2026-09-27/build-plugin.mjs | 138 +++- .../refresh-2026-09-27/deploy-plugin.sh | 7 + .../plugin/tl-design-refresh.zip | Bin 32177 -> 40495 bytes .../tl-design-refresh/tl-design-refresh.php | 739 +++++++++++++++++- .../refresh-2026-09-27/refresh.css | 202 +++++ .../refresh-2026-09-27/refresh.js | 395 +++++++++- 6 files changed, 1414 insertions(+), 67 deletions(-) diff --git a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/build-plugin.mjs b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/build-plugin.mjs index 7c6b3be3cb..0ea2be718a 100644 --- a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/build-plugin.mjs +++ b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/build-plugin.mjs @@ -49,13 +49,15 @@ function tl_refresh_cv_slug() { $path = isset($_SERVER['REQUEST_URI']) ? (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : ''; $slug = trim($path, '/'); $pages = tl_refresh_cv_pages(); - return isset($pages[$slug]) ? $slug : null; + if (isset($pages[$slug])) { return $slug; } + return isset(tl_refresh_recent_periods()[$slug]) ? $slug : null; } function tl_refresh_cv_route() { $slug = tl_refresh_cv_slug(); if (!$slug || !is_404()) { return; } $pages = tl_refresh_cv_pages(); - $page = $pages[$slug]; + $page = isset($pages[$slug]) ? $pages[$slug] : tl_refresh_recent_page($slug); + if (!$page) { return; } global $wp_query; $wp_query->is_404 = false; status_header(200); @@ -129,12 +131,144 @@ function tl_refresh_valise_works() { return $out; } + +/* ---- Recent work from Valise (Fía + Tom, 2026-09-30) ---- + Every Valise artwork dated 2020 or later that has a photograph, newest + first: the home carousel, the In the Studio opening image, and the two + new periods (2020–2022, 2022–present). Server-side key, cached 12h; + an admin can append ?valise_refresh=1 to rebuild. */ +function tl_refresh_valise_recent() { + static $memo = null; + if ($memo !== null) { return $memo; } + if (!function_exists('tl_valise_api_key') || !tl_valise_api_key()) { return $memo = array(); } + $cached = get_transient('tl_refresh_recent_v1'); + if ($cached !== false && !(current_user_can('manage_options') && isset($_GET['valise_refresh']))) { return $memo = $cached; } + $out = array(); $url = TL_VALISE_API_BASE . '/artworks?limit=100'; $guard = 0; + while ($url && $guard < 40) { + $resp = wp_remote_get($url, array('headers' => array('Authorization' => 'Bearer ' . tl_valise_api_key(), 'Accept' => 'application/json'), 'timeout' => 20)); + if (is_wp_error($resp) || wp_remote_retrieve_response_code($resp) !== 200) { break; } + $body = json_decode(wp_remote_retrieve_body($resp), true); + if (empty($body['data']) || !is_array($body['data'])) { break; } + foreach ($body['data'] as $w) { + $t = isset($w['title']) ? trim((string) $w['title']) : ''; + $ys = isset($w['year']) ? trim((string) $w['year']) : ''; + if ($t === '' || empty($w['images'][0]['url']) || !preg_match('/(?:19|20)\\d\\d/', $ys, $m)) { continue; } + $y = intval($m[0]); + if ($y < 2020) { continue; } + $im = $w['images'][0]; + $out[] = array( + 't' => $t, + 'y' => $y, + 'ys' => $ys, + 'm' => isset($w['medium']) ? trim((string) $w['medium']) : '', + 'd' => isset($w['dimensions']) ? trim((string) $w['dimensions']) : '', + 'u' => tl_valise_img_url($w, 1600), + 'w' => isset($im['width']) ? intval($im['width']) : 0, + 'h' => isset($im['height']) ? intval($im['height']) : 0, + ); + } + $url = isset($body['page']['next']) ? $body['page']['next'] : null; + $guard++; + } + /* Newest first; keep Valise's own order within a year. */ + foreach ($out as $i => &$row) { $row['i'] = $i; } unset($row); + usort($out, function ($a, $b) { return $a['y'] === $b['y'] ? $a['i'] - $b['i'] : $b['y'] - $a['y']; }); + foreach ($out as &$row) { unset($row['i']); } unset($row); + set_transient('tl_refresh_recent_v1', $out, $out ? 12 * HOUR_IN_SECONDS : 10 * MINUTE_IN_SECONDS); + return $memo = $out; +} + +/* The two new In the Studio periods. A work dated 2022 belongs to the later one. */ +function tl_refresh_recent_periods() { + return array( + 'inthestudio_2022-present' => array('title' => '2022 – present', 'from' => 2022, 'to' => 9999), + 'inthestudio_2020-2022' => array('title' => '2020 – 2022', 'from' => 2020, 'to' => 2021), + ); +} +function tl_refresh_recent_in($from, $to) { + return array_values(array_filter(tl_refresh_valise_recent(), function ($w) use ($from, $to) { return $w['y'] >= $from && $w['y'] <= $to; })); +} +function tl_refresh_valise_size($u, $width) { + return preg_replace('#/rs:fit:\\d+:\\d+/#', '/rs:fit:' . intval($width) . ':0/', $u); +} +function tl_refresh_recent_page($slug) { + $periods = tl_refresh_recent_periods(); + if (!isset($periods[$slug])) { return null; } + $p = $periods[$slug]; + $works = tl_refresh_recent_in($p['from'], $p['to']); + if (!$works) { return null; } + $lead = $works[0]; + $ar = ($lead['w'] && $lead['h']) ? $lead['w'] . '/' . $lead['h'] : '4/3'; + $h = '
'; + $h .= '
' . esc_attr($lead['t']) . '
'; + $h .= '
In the Studio

' . esc_html($p['title']) . '

'; + $h .= '

' . count($works) . ' ' . (count($works) === 1 ? 'work' : 'works') . '.

'; + $h .= '
'; + foreach ($works as $w) { + $cap = array_filter(array($w['ys'], $w['m'], $w['d'])); + $h .= '
'; + $h .= '' . esc_attr($w['t']) . ''; + $h .= '
' . esc_html($w['t']) . '' . ($cap ? '' . esc_html(implode(', ', $cap)) . '' : '') . '
'; + } + $h .= '
'; + return array('title' => 'In the Studio ' . str_replace(' – ', '–', $p['title']), 'html' => $h); +} + +/* Beyond the Studio as an index (Fía, 2026-09-30): each project's first + paragraph and a strip of its pictures, read from the project page. */ +function tl_refresh_bts_index() { + $cached = get_transient('tl_refresh_bts_v1'); + if ($cached !== false && !(current_user_can('manage_options') && isset($_GET['valise_refresh']))) { return $cached; } + $out = array(); + $pages = get_posts(array('post_type' => 'page', 'post_status' => 'publish', 'numberposts' => 50, 'orderby' => 'menu_order', 'order' => 'ASC')); + foreach ($pages as $pg) { + if (strpos($pg->post_name, 'beyond-the-studio-') !== 0) { continue; } + $raw = (string) get_post_meta($pg->ID, '_elementor_data', true) . ' ' . (string) $pg->post_content; + $raw = str_replace('\\/', '/', $raw); + preg_match_all('#https?://[^"\\'\\s\\\\\\\\]+/wp-content/uploads/[^"\\'\\s\\\\\\\\]+?\\.(?:jpe?g|png)#i', $raw, $mm); + $imgs = array(); $seen = array(); + foreach ($mm[0] as $u) { + $base = preg_replace('#-\\d+x\\d+(\\.\\w+)$#', '$1', preg_replace('#-scaled(\\.\\w+)$#', '$1', $u)); + if (isset($seen[$base])) { continue; } + $seen[$base] = true; + $id = attachment_url_to_postid($base); + if (!$id) { $id = attachment_url_to_postid($u); } + $thumb = $id ? wp_get_attachment_image_url($id, 'medium') : $u; + if ($thumb) { $imgs[] = $thumb; } + if (count($imgs) >= 8) { break; } + } + $text = ''; + $plain = wp_strip_all_tags(preg_replace('#<(p|div|h\\d)[^>]*>#i', "\\n", (string) $pg->post_content)); + foreach (preg_split('/\\n+/', html_entity_decode($plain, ENT_QUOTES, 'UTF-8')) as $line) { + $line = trim(preg_replace('/\\s+/u', ' ', $line)); + if (mb_strlen($line) > 120) { $text = $line; break; } + } + if ($text && mb_strlen($text) > 230) { $cut = mb_substr($text, 0, 230); $sp = strrpos($cut, ' '); $text = rtrim($sp ? substr($cut, 0, $sp) : $cut) . '…'; } + $out[$pg->post_name] = array('imgs' => $imgs, 'text' => $text); + } + set_transient('tl_refresh_bts_v1', $out, 12 * HOUR_IN_SECONDS); + return $out; +} + function tl_refresh_js() { if (in_array('tl-studio-detail', get_body_class(), true)) { $works = tl_refresh_valise_works(); echo '\n"; echo '\n"; } + $classes = get_body_class(); + if (is_front_page() || in_array('page-id-140', $classes, true)) { + $recent = tl_refresh_valise_recent(); + $periods = array(); + foreach (tl_refresh_recent_periods() as $slug => $p) { + $ws = tl_refresh_recent_in($p['from'], $p['to']); + if ($ws) { $periods[] = array('slug' => $slug, 'title' => $p['title'], 'works' => array_slice($ws, 0, 3)); } + } + echo '\n"; + } + if (in_array('page-id-1177', $classes, true)) { + echo '\n"; + } ?> "; echo ' +"; + } + $classes = get_body_class(); + if (is_front_page() || in_array('page-id-140', $classes, true)) { + $recent = tl_refresh_valise_recent(); + $periods = array(); + foreach (tl_refresh_recent_periods() as $slug => $p) { + $ws = tl_refresh_recent_in($p['from'], $p['to']); + if ($ws) { $periods[] = array('slug' => $slug, 'title' => $p['title'], 'works' => array_slice($ws, 0, 3)); } + } + echo ' +"; + } + if (in_array('page-id-1177', $classes, true)) { + echo ' "; } ?> @@ -1189,6 +1527,92 @@ window.TL_CV = {"curatorial":{"n":8,"from":1981,"to":2016,"img":"https://www.tho return (value || '').replace(/[​-‍]/g, '').replace(/\s+/g, ' ').trim(); } + /* ---- 0. Fixes from the 2026-09-30 meeting (Fía). They run first, so the + sections below see the corrected words and links. ---- */ + var UP = 'https://www.thomaslawson.com/wp-content/uploads/'; + var MEDIA = UP + 'tl-refresh/'; + var main = document.querySelector('main') || document.getElementById('content') || body; + function on(id) { return body.classList.contains('page-id-' + id); } + function retext(root, re, to) { + var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); + var node; + while ((node = walker.nextNode())) { + if (re.test(node.nodeValue)) node.nodeValue = node.nodeValue.replace(re, to); + re.lastIndex = 0; + } + } + function el(tag, cls, text) { + var e = document.createElement(tag); + if (cls) e.className = cls; + if (text) e.textContent = text; + return e; + } + /* Hedi Slimane's name. */ + retext(main, /Silmane/g, 'Slimane'); + /* The Municipal Building mural is one portrait of the city. */ + /* Fía: "Portrait of New York" is singular wherever it appears. */ + retext(body, /Portraits of New York/g, 'Portrait of New York'); + if (on(1622)) { + /* Tom's notes: Portrait of New York (1989) comes before Memory Lingers + Here, which opens "As I was completing the New York project". */ + var tops = Array.prototype.slice.call(main.querySelectorAll('.elementor-top-section')); + var textOf = function (sec) { var t = sec.querySelector('.elementor-widget-text-editor'); return t ? t.textContent : ''; }; + var memIdx = tops.findIndex(function (sec) { return /As I was completing the New York project/.test(textOf(sec)); }); + var porIdx = tops.findIndex(function (sec) { return /knowing I could rely on Russell Rainbolt/.test(textOf(sec)); }); + if (memIdx > -1 && porIdx > memIdx && !main.querySelector('.tl-moved')) { + tops.slice(porIdx).forEach(function (sec) { + sec.classList.add('tl-moved'); + tops[memIdx].parentNode.insertBefore(sec, tops[memIdx]); + }); + } + } + /* Yeats's Deirdre (Tom's notes: "fix spelling"). */ + if (on(1660)) retext(main, /\bDeidre\b/g, 'Deirdre'); + /* REALLIFE 15 pointed at an unrelated East of Borneo article; until its + scan is uploaded, the cover opens the cover. */ + if (on(1819)) { + var r15 = window.TL_SHELVES && window.TL_SHELVES['reallife-15-cover.jpg']; + if (r15) r15.h = UP + '2023/12/REALLIFE-15-cover.jpg'; + main.querySelectorAll('a[href*="the-journey-west"]').forEach(function (a) { + var col = a.closest('.elementor-column'); + if (col && col.querySelector('img[src*="REALLIFE-15-cover"]')) a.href = UP + '2023/12/REALLIFE-15-cover.jpg'; + }); + } + /* Deirdre: Tom's opening film of birds, beside the paragraph about it. */ + if (on(1660) && !document.querySelector('.tl-video')) { + var birds = Array.prototype.find.call(main.querySelectorAll('.elementor-widget-text-editor'), function (t) { + return /video of birds/i.test(t.textContent); + }); + if (birds) { + var vf = el('figure', 'tl-video'); + var v = document.createElement('video'); + v.controls = true; v.preload = 'none'; v.setAttribute('playsinline', ''); + v.poster = MEDIA + 'deirdre-birds-poster.jpg'; + v.setAttribute('aria-label', 'Birds, the opening film for Deirdre'); + var vs = document.createElement('source'); + vs.src = MEDIA + 'deirdre-birds.mp4'; vs.type = 'video/mp4'; + v.appendChild(vs); + vf.appendChild(v); + vf.appendChild(el('figcaption', '', 'Birds, the opening film for Deirdre')); + birds.parentNode.insertBefore(vf, birds.nextSibling); + } + } + /* Art School: the last four items had paragraph captions; give them the + same label as every other item, and name the Sohrab Mohebbi interview. */ + if (on(1878)) { + main.querySelectorAll('.elementor-widget-image + .elementor-widget-text-editor').forEach(function (t) { + var text = clean(t.textContent); + if (!text || text.length > 200) return; + if (/Sohrab Mohebbi/.test(text)) text = 'Sohrab Mohebbi Interview'; + var w = el('div', 'elementor-element elementor-widget elementor-widget-heading tl-caption-label'); + var c = el('div', 'elementor-widget-container'); + var h = el('h5', 'elementor-heading-title elementor-size-default', text); + h.setAttribute('data-tl-role', 'caption'); + c.appendChild(h); w.appendChild(c); + t.replaceWith(w); + }); + } + /* ---- 1. All-caps labels → title case (authored caps, not CSS). ---- */ var KEEP = /^(REALLIFE|MOCA|LACE|LAXART|CAE|PS1|P\.S\.1|USA|UK|US|LA|NY|NYC|TV|BBC|CCA|SVA|UCLA|ICA|II|III|IV|VI|VII|VIII|IX|XI|XII|TL|DJ)$/; var SMALL = /^(a|an|and|as|at|by|for|from|in|into|of|on|or|the|to|with)$/; @@ -1544,9 +1968,17 @@ window.TL_CV = {"curatorial":{"n":8,"from":1981,"to":2016,"img":"https://www.tho widgets move into the new column so nothing is duplicated. ar fallback proportions until the image reports its own m phone crop (portraits only), with its focal point */ + /* Recent work from Valise (window.TL_RECENT, newest first, printed by the + plugin on Home and In the Studio). */ + var RECENT = (window.TL_RECENT || []).filter(function (w) { return w && w.u; }); + function valiseSize(u, width) { return u.replace(/\/rs:fit:\d+:\d+\//, '/rs:fit:' + width + ':0/'); } + function recentLead() { + /* The newest landscape picture reads best beside the intro. */ + return RECENT.filter(function (w) { return w.w && w.h && w.w >= w.h; })[0] || RECENT[0] || null; + } var SPLIT = { 'page-id-68': { sel: '.elementor-element-3d58b5f', title: 'About' }, - 'page-id-140': { sel: '.elementor-element-71fa6aa', ar: '720/556', bg: 'https://www.thomaslawson.com/wp-content/uploads/2022/09/2010_Tree_HR.jpg' }, + 'page-id-140': { sel: '.elementor-element-71fa6aa', ar: '720/556', recent: true, bg: 'https://www.thomaslawson.com/wp-content/uploads/2022/09/2010_Tree_HR.jpg' }, 'page-id-1177': { sel: '.elementor-element-1b54d5a' }, 'page-id-1147': { sel: '.elementor-element-ba54885' }, 'page-id-808': { sel: '.elementor-element-825b6e9', m: '4/5', focus: '50% 42%' }, @@ -1571,7 +2003,12 @@ window.TL_CV = {"curatorial":{"n":8,"from":1981,"to":2016,"img":"https://www.tho if (!section) return true; var src = '', alt = '', ar = cfg.ar || ''; var srcImg = section.querySelector('.elementor-widget-image img'); - if (srcImg) { + var lead = cfg.recent && recentLead(); + if (lead) { + src = valiseSize(lead.u, 1400); + alt = lead.t + (lead.ys ? ', ' + lead.ys : ''); + if (lead.w && lead.h) ar = lead.w + '/' + lead.h; + } else if (srcImg) { src = bestSrc(srcImg); alt = srcImg.getAttribute('alt') || ''; var w = parseInt(srcImg.getAttribute('width'), 10), h = parseInt(srcImg.getAttribute('height'), 10); @@ -1615,36 +2052,270 @@ window.TL_CV = {"curatorial":{"n":8,"from":1981,"to":2016,"img":"https://www.tho return true; }); - /* ---- 10. Beyond the Studio → Curatorial Projects + Exhibitions (Fía, 2026-09-28). - Two doors under the header, to the pages the plugin builds from Tom's - CV (window.TL_CV, counts generated by build-cv.mjs). ---- */ - var CV = window.TL_CV; - if (CV && body.classList.contains('page-id-1177') && !document.querySelector('.tl-bts-doors')) { - var dash = ' – '; - var doors = [ - ['/curatorial-projects/', 'Curatorial Projects', CV.curatorial.n + ' exhibitions curated, ' + CV.curatorial.from + dash + CV.curatorial.to, CV.curatorial.img], - ['/exhibitions/', 'Exhibitions', CV.exhibitions.solo + ' solo, ' + CV.exhibitions.group + ' group, ' + CV.exhibitions.from + dash + CV.exhibitions.to, CV.exhibitions.img] - ]; - var nav = document.createElement('nav'); - nav.className = 'tl-bts-doors'; - nav.setAttribute('aria-label', 'Beyond the Studio'); - doors.forEach(function (d) { - var a = document.createElement('a'); - a.className = 'tl-bts-door'; - a.href = d[0]; - var im = document.createElement('img'); - im.src = d[3]; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; - var t = document.createElement('span'); - t.className = 'tl-bts-door-title'; - t.textContent = d[1]; - var s = document.createElement('span'); - s.className = 'tl-bts-door-meta'; - s.textContent = d[2]; - a.appendChild(im); a.appendChild(t); a.appendChild(s); - nav.appendChild(a); + /* ---- 10. Beyond the Studio as an index (Fía, 2026-09-30). ---- + One row per project: title, its opening lines, and a strip of its + pictures (window.TL_BTS, read from each project page by the plugin). + Exhibitions leads the list; Curatorial Projects is gone from here, + since Art in a Broader Context already holds those shows. ---- */ + if (on(1177) && !document.querySelector('.tl-bts-index')) { + var BTS = window.TL_BTS || {}; + var CVS = window.TL_CV; + var cards = [], seen = {}, holders = []; + main.querySelectorAll('a[href*="/beyond-the-studio-"]').forEach(function (a) { + if (a.closest('.tl-split')) return; + var m = a.getAttribute('href').match(/\/(beyond-the-studio-[^\/?#]+)/); + if (!m || seen[m[1]]) return; + seen[m[1]] = true; + var col = a.closest('.elementor-column') || a.parentElement; + var img = col.querySelector('img'); + cards.push({ slug: m[1], href: a.getAttribute('href'), title: clean(col.textContent), img: img && (img.currentSrc || img.src) }); + var sec = a.closest('.elementor-top-section'); + if (sec && holders.indexOf(sec) < 0) holders.push(sec); + }); + /* Tom's notes: Early New York before Painted Installations, as it happened. */ + var iE = cards.findIndex(function (c) { return /early-new-york/.test(c.slug); }); + var iP = cards.findIndex(function (c) { return /painted-installations/.test(c.slug); }); + if (iE > -1 && iP > -1 && iP < iE) cards.splice(iP, 0, cards.splice(iE, 1)[0]); + if (cards.length) { + var list = el('ol', 'tl-bts-index'); + var row = function (href, title, text, imgs, n) { + var li = el('li', 'tl-bts-row'); + var a = el('a', 'tl-bts-row-link'); + a.href = href; + var head = el('span', 'tl-bts-row-head'); + head.appendChild(el('span', 'tl-bts-row-n', n)); + head.appendChild(el('span', 'tl-bts-row-title', title)); + a.appendChild(head); + if (text) a.appendChild(el('span', 'tl-bts-row-text', text)); + if (imgs.length) { + var strip = el('span', 'tl-bts-row-strip'); + imgs.slice(0, 6).forEach(function (u) { + var im = document.createElement('img'); + im.src = u; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; + strip.appendChild(im); + }); + a.appendChild(strip); + } + li.appendChild(a); + return li; + }; + var n = 0; + var pad = function (i) { return (i < 10 ? '0' : '') + i; }; + if (CVS && CVS.exhibitions) { + var ex = CVS.exhibitions; + list.appendChild(row('/exhibitions/', 'Exhibitions', ex.solo + ' solo and ' + ex.group + ' group exhibitions, ' + ex.from + ' – ' + ex.to + '.', [ex.img], pad(++n))); + } + cards.forEach(function (c) { + var d = BTS[c.slug] || {}; + var imgs = (d.imgs && d.imgs.length) ? d.imgs : (c.img ? [c.img] : []); + list.appendChild(row(c.href, c.title, d.text || '', imgs, pad(++n))); + }); + var first = holders[0]; + first.parentNode.insertBefore(list, first); + holders.forEach(function (h) { h.classList.add('tl-bts-source'); h.setAttribute('aria-hidden', 'true'); }); + } + } + + /* ---- 11. A small lightbox: About's pictures and the new studio + periods open full size (Fía, 2026-09-30). ---- */ + function lightbox(src, caption, opener) { + var ov = el('div', 'tl-lb'); + ov.setAttribute('role', 'dialog'); + ov.setAttribute('aria-modal', 'true'); + ov.setAttribute('aria-label', caption || 'Image'); + var im = document.createElement('img'); + im.src = src; im.alt = caption || ''; + var fig = el('figure', 'tl-lb-figure'); + fig.appendChild(im); + if (caption) fig.appendChild(el('figcaption', 'tl-lb-caption', caption)); + var close = el('button', 'tl-lb-close', '×'); + close.type = 'button'; + close.setAttribute('aria-label', 'Close'); + ov.appendChild(fig); ov.appendChild(close); + function shut() { + ov.remove(); + document.removeEventListener('keydown', key); + document.documentElement.classList.remove('tl-lb-open'); + if (opener && opener.focus) opener.focus(); + } + function key(e) { if (e.key === 'Escape') shut(); } + ov.addEventListener('click', function (e) { if (e.target !== im) shut(); }); + document.addEventListener('keydown', key); + document.documentElement.classList.add('tl-lb-open'); + body.appendChild(ov); + close.focus(); + } + function largest(img) { + var best = { url: img.currentSrc || img.src, w: 0 }; + (img.getAttribute('srcset') || '').split(',').forEach(function (s) { + var p = s.trim().split(/\s+/), w = parseInt(p[1], 10) || 0; + if (p[0] && w > best.w && w <= 2600) best = { url: p[0], w: w }; + }); + return best.url; + } + if (on(68)) { + main.querySelectorAll('.elementor-widget-image img').forEach(function (img) { + if (img.closest('.tl-split, .tl-split-source, a')) return; + var col = img.closest('.elementor-column'); + var label = col ? Array.prototype.map.call(col.querySelectorAll('.elementor-heading-title'), function (h) { return clean(h.textContent); }).filter(function (t) { return t && t !== '-' && t !== '–'; }).join(', ') : ''; + img.classList.add('tl-zoomable'); + img.tabIndex = 0; + img.setAttribute('role', 'button'); + img.setAttribute('aria-label', 'Enlarge' + (label ? ': ' + label : '')); + var open = function () { lightbox(largest(img), label, img); }; + img.addEventListener('click', open); + img.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }); + }); + } + document.querySelectorAll('a.tl-zoom').forEach(function (a) { + a.addEventListener('click', function (e) { + if (e.metaKey || e.ctrlKey || e.shiftKey) return; + e.preventDefault(); + lightbox(a.href, a.getAttribute('data-caption') || '', a); + }); + }); + + /* ---- 12. In the Studio: the two newest periods, from Valise + (window.TL_PERIODS), above 2017 – 2020. ---- */ + var PERIODS = window.TL_PERIODS || []; + if (on(140) && PERIODS.length && !document.querySelector('.tl-period')) { + var oldest = main.querySelector('.elementor-top-section img[src*="2019_Head-in-Hands"]'); + var before = oldest && oldest.closest('.elementor-top-section'); + if (before) { + PERIODS.forEach(function (p) { + var sec = el('section', 'tl-period'); + var a = el('a', 'tl-period-link'); + a.href = '/' + p.slug + '/'; + a.setAttribute('aria-label', p.title); + var lab = el('span', 'tl-period-label'); + lab.appendChild(el('span', 'tl-period-range', p.title)); + a.appendChild(lab); + var works = el('span', 'tl-period-works'); + p.works.forEach(function (w) { + var im = document.createElement('img'); + im.src = valiseSize(w.u, 700); im.alt = w.t; im.loading = 'lazy'; im.decoding = 'async'; + if (w.w && w.h) { im.width = w.w; im.height = w.h; } + works.appendChild(im); + }); + a.appendChild(works); + sec.appendChild(a); + before.parentNode.insertBefore(sec, before); + }); + } + } + + /* ---- 13. Home: a carousel of recent work from Valise. ---- */ + function mountCarousel(tries) { + if (document.querySelector('.tl-carousel')) return; + /* The polish plugin builds .tl-home-artwork around the painting. */ + var holder = document.querySelector('.tl-home-artwork'); + if (!holder) { if (tries < 30) setTimeout(function () { mountCarousel(tries + 1); }, 100); return; } + { + var slides = RECENT.slice(0, 12); + var car = el('section', 'tl-carousel'); + car.setAttribute('aria-roledescription', 'carousel'); + car.setAttribute('aria-label', 'Recent work'); + var stage = el('div', 'tl-carousel-stage'); + var cap = el('p', 'tl-carousel-caption'); + cap.setAttribute('aria-live', 'polite'); + var figs = slides.map(function (w, i) { + var a = el('a', 'tl-carousel-slide'); + a.href = '/' + (w.y >= 2022 ? 'inthestudio_2022-present' : 'inthestudio_2020-2022') + '/'; + a.setAttribute('aria-roledescription', 'slide'); + a.setAttribute('aria-label', (i + 1) + ' of ' + slides.length + ': ' + w.t); + var im = document.createElement('img'); + im.src = valiseSize(w.u, 1200); im.alt = w.t; im.decoding = 'async'; + if (i > 1) im.loading = 'lazy'; + a.appendChild(im); + stage.appendChild(a); + return a; + }); + var prev = el('button', 'tl-carousel-btn tl-carousel-prev', '←'); + var next = el('button', 'tl-carousel-btn tl-carousel-next', '→'); + prev.type = next.type = 'button'; + prev.setAttribute('aria-label', 'Previous work'); + next.setAttribute('aria-label', 'Next work'); + var foot = el('div', 'tl-carousel-foot'); + foot.appendChild(cap); + var ctl = el('span', 'tl-carousel-controls'); + ctl.appendChild(prev); ctl.appendChild(next); + foot.appendChild(ctl); + car.appendChild(stage); car.appendChild(foot); + var cur = 0, timer = null; + var still = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches; + var show = function (i) { + cur = (i + figs.length) % figs.length; + figs.forEach(function (f, j) { + f.classList.toggle('is-on', j === cur); + f.tabIndex = j === cur ? 0 : -1; + f.setAttribute('aria-hidden', j === cur ? 'false' : 'true'); + }); + var w = slides[cur]; + cap.textContent = w.t + (w.ys ? ', ' + w.ys : ''); + }; + var stop = function () { clearInterval(timer); timer = null; }; + var go = function () { if (!still && !timer) timer = setInterval(function () { show(cur + 1); }, 5000); }; + prev.addEventListener('click', function () { stop(); show(cur - 1); }); + next.addEventListener('click', function () { stop(); show(cur + 1); }); + car.addEventListener('mouseenter', stop); + car.addEventListener('mouseleave', go); + car.addEventListener('focusin', stop); + var x0 = null; + stage.addEventListener('touchstart', function (e) { x0 = e.touches[0].clientX; }, { passive: true }); + stage.addEventListener('touchend', function (e) { + if (x0 === null) return; + var dx = e.changedTouches[0].clientX - x0; x0 = null; + if (Math.abs(dx) > 40) { stop(); show(cur + (dx < 0 ? 1 : -1)); } + }); + show(0); + holder.innerHTML = ''; + holder.appendChild(car); + go(); + } + } + if (on(10) && RECENT.length > 1) mountCarousel(0); + + /* ---- 14. News: one grid, newest first, with Tom's find from a JetBlue + screen — the Portrait of New York mural behind a Law & Order scene. ---- */ + if (on(1898) && !document.querySelector('.tl-news-grid')) { + var items = [], secs = []; + main.querySelectorAll('.elementor-top-section').forEach(function (sec) { + if (sec.closest('.tl-split') || sec.classList.contains('tl-split-source')) return; + var cols = sec.querySelectorAll('.elementor-top-column'); + var got = false; + cols.forEach(function (col) { + var img = col.querySelector('.elementor-widget-image img'); + var title = col.querySelector('.elementor-heading-title'); + if (!img || !title) return; + var link = img.closest('a') || col.querySelector('a'); + items.push({ href: link ? link.href : '', ext: link ? link.target === '_blank' : false, src: largest(img), title: clean(title.textContent) }); + got = true; + }); + if (got) secs.push(sec); }); - var anchor = document.querySelector('.tl-split'); - if (anchor) anchor.parentNode.insertBefore(nav, anchor.nextSibling); + if (secs.length) { + items.unshift({ href: '/beyond-the-studio-portraits-of-new-york/', ext: false, src: MEDIA + 'law-and-order-portrait-of-new-york.jpg', title: 'Portrait of New York, spotted behind a scene of Law & Order (early 1990s)' }); + var grid = el('section', 'tl-news-grid'); + items.forEach(function (it) { + var art = el('article', 'tl-news-item'); + var a = el('a', 'tl-news-cover'); + if (it.href) a.href = it.href; + if (it.ext) { a.target = '_blank'; a.rel = 'noopener'; } + var im = document.createElement('img'); + im.src = it.src; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; + a.appendChild(im); + art.appendChild(a); + var h = el('h2', 'tl-news-title'); + var ha = el('a', '', it.title); + if (it.href) ha.href = it.href; + if (it.ext) { ha.target = '_blank'; ha.rel = 'noopener'; ha.className = 'tl-opens'; } + h.appendChild(ha); + art.appendChild(h); + grid.appendChild(art); + }); + secs[0].parentNode.insertBefore(grid, secs[0]); + secs.forEach(function (sx) { sx.classList.add('tl-news-source'); sx.setAttribute('aria-hidden', 'true'); }); + } } })(); diff --git a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.css b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.css index 6a36aee0c2..48ac8e37b1 100644 --- a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.css +++ b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.css @@ -912,3 +912,205 @@ body.tl-refresh:not(#tl) .tl-cv-month::before { content: " \00b7 "; } body.tl-refresh:not(#tl) .tl-bts-doors { grid-template-columns: minmax(0, 1fr); } body.tl-refresh:not(#tl) .tl-cv-row { grid-template-columns: 3.25rem minmax(0, 1fr); } } + +/* ------------------------------------------------------------------ * + * 16. Fía, 2026-09-30 — the meeting's fixes. + * ------------------------------------------------------------------ */ +body.tl-refresh:not(#tl) :is(.tl-bts-source, .tl-news-source) { display: none !important; } + +/* Beyond the Studio: an index — title, opening lines, a strip of pictures. */ +body.tl-refresh:not(#tl) .tl-bts-index { + order: -198; + list-style: none !important; + width: min(var(--tl-wide), 100vw - 2 * var(--tl-gutter)); + margin: 0 auto clamp(3rem, 6vw, 5rem) !important; + padding: 0 !important; + border-top: 1px solid var(--tl-rule); + box-sizing: border-box; +} +body.tl-refresh:not(#tl) .tl-bts-row { margin: 0 !important; border-bottom: 1px solid var(--tl-rule); } +body.tl-refresh:not(#tl) .tl-bts-row-link { + display: grid; + grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); + grid-template-areas: "head text" "head strip"; + column-gap: clamp(1.25rem, 4vw, 3rem); + row-gap: 0.9rem; + padding: clamp(1.25rem, 2.5vw, 1.75rem) 0; + color: var(--tl-ink) !important; +} +body.tl-refresh:not(#tl) .tl-bts-row-head { grid-area: head; display: flex; gap: 0.9rem; align-items: baseline; } +body.tl-refresh:not(#tl) .tl-bts-row-n { + font-family: var(--tl-sans); + font-size: var(--tl-fs-small); + color: var(--tl-muted); + font-variant-numeric: tabular-nums; +} +body.tl-refresh:not(#tl) .tl-bts-row-title { + font-family: var(--tl-sans); + font-size: var(--tl-fs-title); + font-weight: 500; + line-height: 1.18; + letter-spacing: -0.018em; +} +body.tl-refresh:not(#tl) .tl-bts-row-link:hover .tl-bts-row-title { color: var(--tl-accent); } +body.tl-refresh:not(#tl) .tl-bts-row-text { + grid-area: text; + max-width: var(--tl-measure); + font-family: var(--tl-serif); + font-size: var(--tl-fs-body); + line-height: 1.5; + color: var(--tl-ink); +} +body.tl-refresh:not(#tl) .tl-bts-row-strip { + grid-area: strip; + display: flex; + gap: 0.5rem; + overflow: hidden; +} +body.tl-refresh:not(#tl) .tl-bts-row-strip img { + display: block; + height: clamp(64px, 8vw, 104px); + width: auto; + max-width: none; + flex: none; + object-fit: cover; + transition: opacity 0.2s; +} +body.tl-refresh:not(#tl) .tl-bts-row-link:hover .tl-bts-row-strip img { opacity: 0.88; } + +/* Deirdre's film. */ +body.tl-refresh:not(#tl) .tl-video { margin: 1.5rem 0 2rem !important; max-width: 46rem; } +body.tl-refresh:not(#tl) .tl-video video { display: block; width: 100%; height: auto; background: #000; aspect-ratio: 704 / 480; } +body.tl-refresh:not(#tl) .tl-video figcaption { + margin-top: 0.5rem; + font-family: var(--tl-sans); + font-size: var(--tl-fs-small); + color: var(--tl-muted); +} + +/* Lightbox (About, recent periods). */ +body.tl-refresh:not(#tl) .tl-zoomable { cursor: zoom-in; } +body.tl-refresh:not(#tl) .tl-zoomable:focus-visible { outline: 2px solid var(--tl-accent); outline-offset: 3px; } +html.tl-lb-open { overflow: hidden; } +.tl-lb { + position: fixed; inset: 0; z-index: 100000; + display: flex; align-items: center; justify-content: center; + padding: clamp(1rem, 4vw, 3rem); + background: rgba(255, 249, 239, 0.97); + cursor: zoom-out; +} +.tl-lb-figure { margin: 0; display: flex; flex-direction: column; align-items: center; max-height: 100%; } +.tl-lb-figure img { max-width: 100%; max-height: calc(100vh - 7rem); width: auto; height: auto; object-fit: contain; cursor: default; } +.tl-lb-caption { margin-top: 0.75rem; font: 400 14px/1.4 "Inter", "Helvetica Neue", Arial, sans-serif; color: #6c665d; text-align: center; } +.tl-lb-close { + position: absolute; top: 0.75rem; right: 1rem; + border: 0 !important; background: none !important; padding: 0.25rem 0.5rem !important; + font: 300 34px/1 "Inter", "Helvetica Neue", Arial, sans-serif; color: #1d1c1a !important; cursor: pointer; +} + +/* In the Studio: the two newest periods, styled like the rows below. */ +body.tl-refresh:not(#tl) .tl-period { + width: min(var(--tl-wide), 100vw - 2 * var(--tl-gutter)); + margin: 0 auto clamp(2rem, 4vw, 3rem); + box-sizing: border-box; +} +body.tl-refresh:not(#tl) .tl-period-link { display: block; color: var(--tl-ink) !important; } +body.tl-refresh:not(#tl) .tl-period-label { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem; } +body.tl-refresh:not(#tl) .tl-period-label::after { content: ""; flex: 1; border-top: 1px solid var(--tl-rule); } +body.tl-refresh:not(#tl) .tl-period-range { + font-family: var(--tl-sans); + font-size: var(--tl-fs-label); + font-variant-numeric: tabular-nums; +} +body.tl-refresh:not(#tl) .tl-period-link:hover .tl-period-range { color: var(--tl-accent); } +body.tl-refresh:not(#tl) .tl-period-works { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: clamp(1rem, 3vw, 2.5rem); + align-items: center; +} +body.tl-refresh:not(#tl) .tl-period-works img { + display: block; + width: 100%; + height: clamp(150px, 18vw, 240px); + object-fit: contain; +} + +/* Recent periods: the work grid. */ +body.tl-refresh:not(#tl) .tl-recent-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); + gap: clamp(1.5rem, 3.5vw, 3rem); + align-items: end; + width: min(var(--tl-wide), 100vw - 2 * var(--tl-gutter)); + margin: clamp(2rem, 5vw, 4rem) auto clamp(3rem, 6vw, 5rem); + box-sizing: border-box; +} +body.tl-refresh:not(#tl) .tl-recent-work { margin: 0 !important; } +body.tl-refresh:not(#tl) .tl-recent-work a { display: block; cursor: zoom-in; } +body.tl-refresh:not(#tl) .tl-recent-work img { display: block; width: 100%; height: auto; } +body.tl-refresh:not(#tl) .tl-recent-work figcaption { margin-top: 0.6rem; font-family: var(--tl-sans); line-height: 1.4; } +body.tl-refresh:not(#tl) .tl-recent-title { display: block; font-size: var(--tl-fs-label); color: var(--tl-ink); } +body.tl-refresh:not(#tl) .tl-recent-meta { display: block; font-size: var(--tl-fs-small); color: var(--tl-muted); } + +/* Home: recent work from Valise. */ +body.tl-refresh:not(#tl) .tl-carousel { width: 100%; } +body.tl-refresh:not(#tl) .tl-carousel-stage { position: relative; aspect-ratio: 720 / 556; } +body.tl-refresh:not(#tl) .tl-carousel-slide { + position: absolute; inset: 0; + display: flex; align-items: center; justify-content: center; + opacity: 0; visibility: hidden; + transition: opacity 0.9s ease, visibility 0s linear 0.9s; +} +body.tl-refresh:not(#tl) .tl-carousel-slide.is-on { opacity: 1; visibility: visible; transition: opacity 0.9s ease; } +body.tl-refresh:not(#tl) .tl-carousel-slide img { max-width: 100%; max-height: 100%; width: auto !important; height: auto !important; aspect-ratio: auto !important; object-fit: contain; } +body.tl-refresh:not(#tl) .tl-carousel-foot { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; margin-top: 0.75rem; } +body.tl-refresh:not(#tl) .tl-carousel-caption { + margin: 0 !important; + font-family: var(--tl-sans); + font-size: var(--tl-fs-small); + color: var(--tl-muted); +} +body.tl-refresh:not(#tl) .tl-carousel-controls { display: flex; gap: 0.25rem; flex: none; } +body.tl-refresh:not(#tl) .tl-carousel-btn { + border: 0 !important; background: none !important; + padding: 0.2rem 0.45rem !important; + font: 400 18px/1 var(--tl-sans) !important; + color: var(--tl-ink) !important; + cursor: pointer; +} +body.tl-refresh:not(#tl) .tl-carousel-btn:hover { color: var(--tl-accent) !important; } +@media (prefers-reduced-motion: reduce) { + body.tl-refresh:not(#tl) .tl-carousel-slide { transition: none; } +} + +/* News: one grid. */ +body.tl-refresh:not(#tl) .tl-news-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: clamp(2rem, 4vw, 3.5rem) clamp(1.25rem, 3vw, 2.5rem); + align-items: start; + width: min(var(--tl-wide), 100vw - 2 * var(--tl-gutter)); + margin: clamp(2rem, 5vw, 4rem) auto clamp(3rem, 6vw, 5rem); + box-sizing: border-box; +} +body.tl-refresh:not(#tl) .tl-news-item { margin: 0; } +body.tl-refresh:not(#tl) .tl-news-cover { display: block; line-height: 0; } +body.tl-refresh:not(#tl) .tl-news-cover img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: contain; } +body.tl-refresh:not(#tl) .tl-news-title { + margin: 0.75rem 0 0 !important; + font-family: var(--tl-sans) !important; + font-size: var(--tl-fs-label) !important; + font-weight: 400 !important; + line-height: 1.4 !important; + letter-spacing: 0 !important; +} +body.tl-refresh:not(#tl) .tl-news-title a { color: var(--tl-ink) !important; } +body.tl-refresh:not(#tl) .tl-news-title a:hover { color: var(--tl-accent) !important; } + +@media (max-width: 767px) { + body.tl-refresh:not(#tl) .tl-bts-row-link { grid-template-columns: minmax(0, 1fr); grid-template-areas: "head" "text" "strip"; } + body.tl-refresh:not(#tl) .tl-news-grid { grid-template-columns: minmax(0, 1fr); } + body.tl-refresh:not(#tl) .tl-period-works { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.75rem; } + body.tl-refresh:not(#tl) .tl-period-works img { height: 110px; } +} diff --git a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.js b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.js index 45de63ded2..2f81975a6c 100644 --- a/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.js +++ b/gigs/thomaslawson.com/work-fia-edits/refresh-2026-09-27/refresh.js @@ -11,6 +11,92 @@ return (value || '').replace(/[​-‍]/g, '').replace(/\s+/g, ' ').trim(); } + /* ---- 0. Fixes from the 2026-09-30 meeting (Fía). They run first, so the + sections below see the corrected words and links. ---- */ + var UP = 'https://www.thomaslawson.com/wp-content/uploads/'; + var MEDIA = UP + 'tl-refresh/'; + var main = document.querySelector('main') || document.getElementById('content') || body; + function on(id) { return body.classList.contains('page-id-' + id); } + function retext(root, re, to) { + var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); + var node; + while ((node = walker.nextNode())) { + if (re.test(node.nodeValue)) node.nodeValue = node.nodeValue.replace(re, to); + re.lastIndex = 0; + } + } + function el(tag, cls, text) { + var e = document.createElement(tag); + if (cls) e.className = cls; + if (text) e.textContent = text; + return e; + } + /* Hedi Slimane's name. */ + retext(main, /Silmane/g, 'Slimane'); + /* The Municipal Building mural is one portrait of the city. */ + /* Fía: "Portrait of New York" is singular wherever it appears. */ + retext(body, /Portraits of New York/g, 'Portrait of New York'); + if (on(1622)) { + /* Tom's notes: Portrait of New York (1989) comes before Memory Lingers + Here, which opens "As I was completing the New York project". */ + var tops = Array.prototype.slice.call(main.querySelectorAll('.elementor-top-section')); + var textOf = function (sec) { var t = sec.querySelector('.elementor-widget-text-editor'); return t ? t.textContent : ''; }; + var memIdx = tops.findIndex(function (sec) { return /As I was completing the New York project/.test(textOf(sec)); }); + var porIdx = tops.findIndex(function (sec) { return /knowing I could rely on Russell Rainbolt/.test(textOf(sec)); }); + if (memIdx > -1 && porIdx > memIdx && !main.querySelector('.tl-moved')) { + tops.slice(porIdx).forEach(function (sec) { + sec.classList.add('tl-moved'); + tops[memIdx].parentNode.insertBefore(sec, tops[memIdx]); + }); + } + } + /* Yeats's Deirdre (Tom's notes: "fix spelling"). */ + if (on(1660)) retext(main, /\bDeidre\b/g, 'Deirdre'); + /* REALLIFE 15 pointed at an unrelated East of Borneo article; until its + scan is uploaded, the cover opens the cover. */ + if (on(1819)) { + var r15 = window.TL_SHELVES && window.TL_SHELVES['reallife-15-cover.jpg']; + if (r15) r15.h = UP + '2023/12/REALLIFE-15-cover.jpg'; + main.querySelectorAll('a[href*="the-journey-west"]').forEach(function (a) { + var col = a.closest('.elementor-column'); + if (col && col.querySelector('img[src*="REALLIFE-15-cover"]')) a.href = UP + '2023/12/REALLIFE-15-cover.jpg'; + }); + } + /* Deirdre: Tom's opening film of birds, beside the paragraph about it. */ + if (on(1660) && !document.querySelector('.tl-video')) { + var birds = Array.prototype.find.call(main.querySelectorAll('.elementor-widget-text-editor'), function (t) { + return /video of birds/i.test(t.textContent); + }); + if (birds) { + var vf = el('figure', 'tl-video'); + var v = document.createElement('video'); + v.controls = true; v.preload = 'none'; v.setAttribute('playsinline', ''); + v.poster = MEDIA + 'deirdre-birds-poster.jpg'; + v.setAttribute('aria-label', 'Birds, the opening film for Deirdre'); + var vs = document.createElement('source'); + vs.src = MEDIA + 'deirdre-birds.mp4'; vs.type = 'video/mp4'; + v.appendChild(vs); + vf.appendChild(v); + vf.appendChild(el('figcaption', '', 'Birds, the opening film for Deirdre')); + birds.parentNode.insertBefore(vf, birds.nextSibling); + } + } + /* Art School: the last four items had paragraph captions; give them the + same label as every other item, and name the Sohrab Mohebbi interview. */ + if (on(1878)) { + main.querySelectorAll('.elementor-widget-image + .elementor-widget-text-editor').forEach(function (t) { + var text = clean(t.textContent); + if (!text || text.length > 200) return; + if (/Sohrab Mohebbi/.test(text)) text = 'Sohrab Mohebbi Interview'; + var w = el('div', 'elementor-element elementor-widget elementor-widget-heading tl-caption-label'); + var c = el('div', 'elementor-widget-container'); + var h = el('h5', 'elementor-heading-title elementor-size-default', text); + h.setAttribute('data-tl-role', 'caption'); + c.appendChild(h); w.appendChild(c); + t.replaceWith(w); + }); + } + /* ---- 1. All-caps labels → title case (authored caps, not CSS). ---- */ var KEEP = /^(REALLIFE|MOCA|LACE|LAXART|CAE|PS1|P\.S\.1|USA|UK|US|LA|NY|NYC|TV|BBC|CCA|SVA|UCLA|ICA|II|III|IV|VI|VII|VIII|IX|XI|XII|TL|DJ)$/; var SMALL = /^(a|an|and|as|at|by|for|from|in|into|of|on|or|the|to|with)$/; @@ -366,9 +452,17 @@ widgets move into the new column so nothing is duplicated. ar fallback proportions until the image reports its own m phone crop (portraits only), with its focal point */ + /* Recent work from Valise (window.TL_RECENT, newest first, printed by the + plugin on Home and In the Studio). */ + var RECENT = (window.TL_RECENT || []).filter(function (w) { return w && w.u; }); + function valiseSize(u, width) { return u.replace(/\/rs:fit:\d+:\d+\//, '/rs:fit:' + width + ':0/'); } + function recentLead() { + /* The newest landscape picture reads best beside the intro. */ + return RECENT.filter(function (w) { return w.w && w.h && w.w >= w.h; })[0] || RECENT[0] || null; + } var SPLIT = { 'page-id-68': { sel: '.elementor-element-3d58b5f', title: 'About' }, - 'page-id-140': { sel: '.elementor-element-71fa6aa', ar: '720/556', bg: 'https://www.thomaslawson.com/wp-content/uploads/2022/09/2010_Tree_HR.jpg' }, + 'page-id-140': { sel: '.elementor-element-71fa6aa', ar: '720/556', recent: true, bg: 'https://www.thomaslawson.com/wp-content/uploads/2022/09/2010_Tree_HR.jpg' }, 'page-id-1177': { sel: '.elementor-element-1b54d5a' }, 'page-id-1147': { sel: '.elementor-element-ba54885' }, 'page-id-808': { sel: '.elementor-element-825b6e9', m: '4/5', focus: '50% 42%' }, @@ -393,7 +487,12 @@ if (!section) return true; var src = '', alt = '', ar = cfg.ar || ''; var srcImg = section.querySelector('.elementor-widget-image img'); - if (srcImg) { + var lead = cfg.recent && recentLead(); + if (lead) { + src = valiseSize(lead.u, 1400); + alt = lead.t + (lead.ys ? ', ' + lead.ys : ''); + if (lead.w && lead.h) ar = lead.w + '/' + lead.h; + } else if (srcImg) { src = bestSrc(srcImg); alt = srcImg.getAttribute('alt') || ''; var w = parseInt(srcImg.getAttribute('width'), 10), h = parseInt(srcImg.getAttribute('height'), 10); @@ -437,35 +536,269 @@ return true; }); - /* ---- 10. Beyond the Studio → Curatorial Projects + Exhibitions (Fía, 2026-09-28). - Two doors under the header, to the pages the plugin builds from Tom's - CV (window.TL_CV, counts generated by build-cv.mjs). ---- */ - var CV = window.TL_CV; - if (CV && body.classList.contains('page-id-1177') && !document.querySelector('.tl-bts-doors')) { - var dash = ' – '; - var doors = [ - ['/curatorial-projects/', 'Curatorial Projects', CV.curatorial.n + ' exhibitions curated, ' + CV.curatorial.from + dash + CV.curatorial.to, CV.curatorial.img], - ['/exhibitions/', 'Exhibitions', CV.exhibitions.solo + ' solo, ' + CV.exhibitions.group + ' group, ' + CV.exhibitions.from + dash + CV.exhibitions.to, CV.exhibitions.img] - ]; - var nav = document.createElement('nav'); - nav.className = 'tl-bts-doors'; - nav.setAttribute('aria-label', 'Beyond the Studio'); - doors.forEach(function (d) { - var a = document.createElement('a'); - a.className = 'tl-bts-door'; - a.href = d[0]; - var im = document.createElement('img'); - im.src = d[3]; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; - var t = document.createElement('span'); - t.className = 'tl-bts-door-title'; - t.textContent = d[1]; - var s = document.createElement('span'); - s.className = 'tl-bts-door-meta'; - s.textContent = d[2]; - a.appendChild(im); a.appendChild(t); a.appendChild(s); - nav.appendChild(a); + /* ---- 10. Beyond the Studio as an index (Fía, 2026-09-30). ---- + One row per project: title, its opening lines, and a strip of its + pictures (window.TL_BTS, read from each project page by the plugin). + Exhibitions leads the list; Curatorial Projects is gone from here, + since Art in a Broader Context already holds those shows. ---- */ + if (on(1177) && !document.querySelector('.tl-bts-index')) { + var BTS = window.TL_BTS || {}; + var CVS = window.TL_CV; + var cards = [], seen = {}, holders = []; + main.querySelectorAll('a[href*="/beyond-the-studio-"]').forEach(function (a) { + if (a.closest('.tl-split')) return; + var m = a.getAttribute('href').match(/\/(beyond-the-studio-[^\/?#]+)/); + if (!m || seen[m[1]]) return; + seen[m[1]] = true; + var col = a.closest('.elementor-column') || a.parentElement; + var img = col.querySelector('img'); + cards.push({ slug: m[1], href: a.getAttribute('href'), title: clean(col.textContent), img: img && (img.currentSrc || img.src) }); + var sec = a.closest('.elementor-top-section'); + if (sec && holders.indexOf(sec) < 0) holders.push(sec); + }); + /* Tom's notes: Early New York before Painted Installations, as it happened. */ + var iE = cards.findIndex(function (c) { return /early-new-york/.test(c.slug); }); + var iP = cards.findIndex(function (c) { return /painted-installations/.test(c.slug); }); + if (iE > -1 && iP > -1 && iP < iE) cards.splice(iP, 0, cards.splice(iE, 1)[0]); + if (cards.length) { + var list = el('ol', 'tl-bts-index'); + var row = function (href, title, text, imgs, n) { + var li = el('li', 'tl-bts-row'); + var a = el('a', 'tl-bts-row-link'); + a.href = href; + var head = el('span', 'tl-bts-row-head'); + head.appendChild(el('span', 'tl-bts-row-n', n)); + head.appendChild(el('span', 'tl-bts-row-title', title)); + a.appendChild(head); + if (text) a.appendChild(el('span', 'tl-bts-row-text', text)); + if (imgs.length) { + var strip = el('span', 'tl-bts-row-strip'); + imgs.slice(0, 6).forEach(function (u) { + var im = document.createElement('img'); + im.src = u; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; + strip.appendChild(im); + }); + a.appendChild(strip); + } + li.appendChild(a); + return li; + }; + var n = 0; + var pad = function (i) { return (i < 10 ? '0' : '') + i; }; + if (CVS && CVS.exhibitions) { + var ex = CVS.exhibitions; + list.appendChild(row('/exhibitions/', 'Exhibitions', ex.solo + ' solo and ' + ex.group + ' group exhibitions, ' + ex.from + ' – ' + ex.to + '.', [ex.img], pad(++n))); + } + cards.forEach(function (c) { + var d = BTS[c.slug] || {}; + var imgs = (d.imgs && d.imgs.length) ? d.imgs : (c.img ? [c.img] : []); + list.appendChild(row(c.href, c.title, d.text || '', imgs, pad(++n))); + }); + var first = holders[0]; + first.parentNode.insertBefore(list, first); + holders.forEach(function (h) { h.classList.add('tl-bts-source'); h.setAttribute('aria-hidden', 'true'); }); + } + } + + /* ---- 11. A small lightbox: About's pictures and the new studio + periods open full size (Fía, 2026-09-30). ---- */ + function lightbox(src, caption, opener) { + var ov = el('div', 'tl-lb'); + ov.setAttribute('role', 'dialog'); + ov.setAttribute('aria-modal', 'true'); + ov.setAttribute('aria-label', caption || 'Image'); + var im = document.createElement('img'); + im.src = src; im.alt = caption || ''; + var fig = el('figure', 'tl-lb-figure'); + fig.appendChild(im); + if (caption) fig.appendChild(el('figcaption', 'tl-lb-caption', caption)); + var close = el('button', 'tl-lb-close', '×'); + close.type = 'button'; + close.setAttribute('aria-label', 'Close'); + ov.appendChild(fig); ov.appendChild(close); + function shut() { + ov.remove(); + document.removeEventListener('keydown', key); + document.documentElement.classList.remove('tl-lb-open'); + if (opener && opener.focus) opener.focus(); + } + function key(e) { if (e.key === 'Escape') shut(); } + ov.addEventListener('click', function (e) { if (e.target !== im) shut(); }); + document.addEventListener('keydown', key); + document.documentElement.classList.add('tl-lb-open'); + body.appendChild(ov); + close.focus(); + } + function largest(img) { + var best = { url: img.currentSrc || img.src, w: 0 }; + (img.getAttribute('srcset') || '').split(',').forEach(function (s) { + var p = s.trim().split(/\s+/), w = parseInt(p[1], 10) || 0; + if (p[0] && w > best.w && w <= 2600) best = { url: p[0], w: w }; + }); + return best.url; + } + if (on(68)) { + main.querySelectorAll('.elementor-widget-image img').forEach(function (img) { + if (img.closest('.tl-split, .tl-split-source, a')) return; + var col = img.closest('.elementor-column'); + var label = col ? Array.prototype.map.call(col.querySelectorAll('.elementor-heading-title'), function (h) { return clean(h.textContent); }).filter(function (t) { return t && t !== '-' && t !== '–'; }).join(', ') : ''; + img.classList.add('tl-zoomable'); + img.tabIndex = 0; + img.setAttribute('role', 'button'); + img.setAttribute('aria-label', 'Enlarge' + (label ? ': ' + label : '')); + var open = function () { lightbox(largest(img), label, img); }; + img.addEventListener('click', open); + img.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }); + }); + } + document.querySelectorAll('a.tl-zoom').forEach(function (a) { + a.addEventListener('click', function (e) { + if (e.metaKey || e.ctrlKey || e.shiftKey) return; + e.preventDefault(); + lightbox(a.href, a.getAttribute('data-caption') || '', a); }); - var anchor = document.querySelector('.tl-split'); - if (anchor) anchor.parentNode.insertBefore(nav, anchor.nextSibling); + }); + + /* ---- 12. In the Studio: the two newest periods, from Valise + (window.TL_PERIODS), above 2017 – 2020. ---- */ + var PERIODS = window.TL_PERIODS || []; + if (on(140) && PERIODS.length && !document.querySelector('.tl-period')) { + var oldest = main.querySelector('.elementor-top-section img[src*="2019_Head-in-Hands"]'); + var before = oldest && oldest.closest('.elementor-top-section'); + if (before) { + PERIODS.forEach(function (p) { + var sec = el('section', 'tl-period'); + var a = el('a', 'tl-period-link'); + a.href = '/' + p.slug + '/'; + a.setAttribute('aria-label', p.title); + var lab = el('span', 'tl-period-label'); + lab.appendChild(el('span', 'tl-period-range', p.title)); + a.appendChild(lab); + var works = el('span', 'tl-period-works'); + p.works.forEach(function (w) { + var im = document.createElement('img'); + im.src = valiseSize(w.u, 700); im.alt = w.t; im.loading = 'lazy'; im.decoding = 'async'; + if (w.w && w.h) { im.width = w.w; im.height = w.h; } + works.appendChild(im); + }); + a.appendChild(works); + sec.appendChild(a); + before.parentNode.insertBefore(sec, before); + }); + } + } + + /* ---- 13. Home: a carousel of recent work from Valise. ---- */ + function mountCarousel(tries) { + if (document.querySelector('.tl-carousel')) return; + /* The polish plugin builds .tl-home-artwork around the painting. */ + var holder = document.querySelector('.tl-home-artwork'); + if (!holder) { if (tries < 30) setTimeout(function () { mountCarousel(tries + 1); }, 100); return; } + { + var slides = RECENT.slice(0, 12); + var car = el('section', 'tl-carousel'); + car.setAttribute('aria-roledescription', 'carousel'); + car.setAttribute('aria-label', 'Recent work'); + var stage = el('div', 'tl-carousel-stage'); + var cap = el('p', 'tl-carousel-caption'); + cap.setAttribute('aria-live', 'polite'); + var figs = slides.map(function (w, i) { + var a = el('a', 'tl-carousel-slide'); + a.href = '/' + (w.y >= 2022 ? 'inthestudio_2022-present' : 'inthestudio_2020-2022') + '/'; + a.setAttribute('aria-roledescription', 'slide'); + a.setAttribute('aria-label', (i + 1) + ' of ' + slides.length + ': ' + w.t); + var im = document.createElement('img'); + im.src = valiseSize(w.u, 1200); im.alt = w.t; im.decoding = 'async'; + if (i > 1) im.loading = 'lazy'; + a.appendChild(im); + stage.appendChild(a); + return a; + }); + var prev = el('button', 'tl-carousel-btn tl-carousel-prev', '←'); + var next = el('button', 'tl-carousel-btn tl-carousel-next', '→'); + prev.type = next.type = 'button'; + prev.setAttribute('aria-label', 'Previous work'); + next.setAttribute('aria-label', 'Next work'); + var foot = el('div', 'tl-carousel-foot'); + foot.appendChild(cap); + var ctl = el('span', 'tl-carousel-controls'); + ctl.appendChild(prev); ctl.appendChild(next); + foot.appendChild(ctl); + car.appendChild(stage); car.appendChild(foot); + var cur = 0, timer = null; + var still = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches; + var show = function (i) { + cur = (i + figs.length) % figs.length; + figs.forEach(function (f, j) { + f.classList.toggle('is-on', j === cur); + f.tabIndex = j === cur ? 0 : -1; + f.setAttribute('aria-hidden', j === cur ? 'false' : 'true'); + }); + var w = slides[cur]; + cap.textContent = w.t + (w.ys ? ', ' + w.ys : ''); + }; + var stop = function () { clearInterval(timer); timer = null; }; + var go = function () { if (!still && !timer) timer = setInterval(function () { show(cur + 1); }, 5000); }; + prev.addEventListener('click', function () { stop(); show(cur - 1); }); + next.addEventListener('click', function () { stop(); show(cur + 1); }); + car.addEventListener('mouseenter', stop); + car.addEventListener('mouseleave', go); + car.addEventListener('focusin', stop); + var x0 = null; + stage.addEventListener('touchstart', function (e) { x0 = e.touches[0].clientX; }, { passive: true }); + stage.addEventListener('touchend', function (e) { + if (x0 === null) return; + var dx = e.changedTouches[0].clientX - x0; x0 = null; + if (Math.abs(dx) > 40) { stop(); show(cur + (dx < 0 ? 1 : -1)); } + }); + show(0); + holder.innerHTML = ''; + holder.appendChild(car); + go(); + } + } + if (on(10) && RECENT.length > 1) mountCarousel(0); + + /* ---- 14. News: one grid, newest first, with Tom's find from a JetBlue + screen — the Portrait of New York mural behind a Law & Order scene. ---- */ + if (on(1898) && !document.querySelector('.tl-news-grid')) { + var items = [], secs = []; + main.querySelectorAll('.elementor-top-section').forEach(function (sec) { + if (sec.closest('.tl-split') || sec.classList.contains('tl-split-source')) return; + var cols = sec.querySelectorAll('.elementor-top-column'); + var got = false; + cols.forEach(function (col) { + var img = col.querySelector('.elementor-widget-image img'); + var title = col.querySelector('.elementor-heading-title'); + if (!img || !title) return; + var link = img.closest('a') || col.querySelector('a'); + items.push({ href: link ? link.href : '', ext: link ? link.target === '_blank' : false, src: largest(img), title: clean(title.textContent) }); + got = true; + }); + if (got) secs.push(sec); + }); + if (secs.length) { + items.unshift({ href: '/beyond-the-studio-portraits-of-new-york/', ext: false, src: MEDIA + 'law-and-order-portrait-of-new-york.jpg', title: 'Portrait of New York, spotted behind a scene of Law & Order (early 1990s)' }); + var grid = el('section', 'tl-news-grid'); + items.forEach(function (it) { + var art = el('article', 'tl-news-item'); + var a = el('a', 'tl-news-cover'); + if (it.href) a.href = it.href; + if (it.ext) { a.target = '_blank'; a.rel = 'noopener'; } + var im = document.createElement('img'); + im.src = it.src; im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; + a.appendChild(im); + art.appendChild(a); + var h = el('h2', 'tl-news-title'); + var ha = el('a', '', it.title); + if (it.href) ha.href = it.href; + if (it.ext) { ha.target = '_blank'; ha.rel = 'noopener'; ha.className = 'tl-opens'; } + h.appendChild(ha); + art.appendChild(h); + grid.appendChild(art); + }); + secs[0].parentNode.insertBefore(grid, secs[0]); + secs.forEach(function (sx) { sx.classList.add('tl-news-source'); sx.setAttribute('aria-hidden', 'true'); }); + } } })(); -- 2.51.2