Teaser Category
The code below works in all 3 different layouts. It will categorize teasers based on the text that is added after a "|"
- If no "|" character is detected, the teaser will be categorized as "Uncategorized"
- Can be the text of the page or the title text of the teaser
- Accounts for mobile view
- Uses a highlighted color when hovered over
- Creates a count for how many teasers are in the category
- In use on this page
- Must use in HTML block on a page cant add site-wide (yet?)
<style>
/*---------------------------------------*/
/* 1) TAB BAR – keep yours exactly */
/*---------------------------------------*/
.items .tablist {
display: flex;
justify-content: flex-start;
min-width: 100%;
align-items: flex-end;
flex-wrap: wrap;
gap: 1rem;
margin: 0 0 1rem;
padding: 0 1rem;
}
.items .tablist [role="tab"] {
margin-bottom: -2px;
background: #f5f5f5;
border: 1px solid transparent;
border-bottom: none;
border-radius: 4px 4px 0 0;
padding: 0.5em 1em;
cursor: pointer;
transition: background 0.2s;
outline: none;
white-space: nowrap;
}
.items .tablist [role="tab"]:hover {
background: #e0e0e0;
}
.items .tablist [role="tab"][aria-selected="true"] {
background: #fff;
border-color: #ccc;
font-weight: bold;
}
/*---------------------------------------*/
/* 2) PANELS – flex container */
/*---------------------------------------*/
.items .tabpanels [role="tabpanel"] {
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: stretch;
padding: 1rem;
box-sizing: border-box;
}
.items .tabpanels [role="tabpanel"][hidden] {
display: none !important;
}
/*---------------------------------------*/
/* 3) CARD BASE – 2‑column default */
/* (subtract only ONE gap: 1rem) */
/*---------------------------------------*/
.items .tabpanels [role="tabpanel"] .poc-instance {
flex: 0 0 calc((100% - 1rem) / 2);
max-width: calc((100% - 1rem) / 2);
box-sizing: border-box;
}
/*---------------------------------------*/
/* 4) OVERRIDES BASED ON COL NUMBERS */
/*---------------------------------------*/
/* 1‑column */
.poc-layout-one-column .items .tabpanels [role="tabpanel"] .poc-instance {
flex: 0 0 100% ;
max-width: 100% ;
}
/* 2‑column */
.poc-layout-three-column .items .tabpanels [role="tabpanel"] .poc-instance {
flex: 0 0 calc((100% - 1rem) / 2) ;
max-width: calc((100% - 1rem) / 2) ;
}
/* 3‑column */
/* subtract TWO gaps: 1rem * (3‑1) = 2rem */
.poc-layout-three-column .items .tabpanels [role="tabpanel"] .poc-instance {
flex: 0 0 calc((100% - 2rem) / 3) ;
max-width: calc((100% - 2rem) / 3) ;
}
/*---------------------------------------*/
/* 5) COLLAPSE TO ONE‑COLUMN ON MOBILE */
/*---------------------------------------*/
@media (max-width: 600px) {
.items .tabpanels [role="tabpanel"] .poc-instance {
flex: 0 0 100% !important;
max-width: 100% !important;
}
}
/*---------------------------------------*/
/* 6) PHONE‑WRAP TABS (<480px) */
/*---------------------------------------*/
@media (max-width: 480px) {
.items .tablist {
flex-wrap: wrap;
overflow-x: hidden;
}
.items .tablist [role="tab"] {
flex: 0 1 auto;
margin: 0 0.5rem 0.5rem 0;
padding: 0.5em 1em;
white-space: nowrap;
margin-bottom: -2px;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
const container = document.querySelector('.items');
if (!container) return;
// 1️⃣ Grab your original cards
const originals = Array.from(container.querySelectorAll('article.poc-instance'));
if (originals.length === 0) return;
// 2️⃣ Parse category/title from header text
const groupsMap = {}; // category → array of indexes
originals.forEach((card, i) => {
const h3 = card.querySelector('header h3');
if (!h3) return;
const txt = h3.textContent.trim();
let title = txt,
category = 'Uncategorized';
if (txt.includes('|')) {
[title, category] = txt.split('|').map(s => s.trim());
}
// overwrite the displayed title
h3.innerHTML = `<span>${title}</span>`;
// collect into groupsMap
if (!groupsMap[category]) groupsMap[category] = [];
groupsMap[category].push(i);
});
// 3️⃣ Build “All” + other tabs
const types = ['All', ...Object.keys(groupsMap)];
groupsMap['All'] = originals.map((_, i) => i);
// 4️⃣ Clear existing content
container.innerHTML = '';
// 5️⃣ Build the ARIA tablist
const tablist = document.createElement('div');
tablist.className = 'tablist';
tablist.setAttribute('role', 'tablist');
container.appendChild(tablist);
// 6️⃣ Build panels container
const panelsContainer = document.createElement('div');
panelsContainer.className = 'tabpanels';
container.appendChild(panelsContainer);
// 7️⃣ Create each tab + panel
types.forEach((type, idx) => {
// — Tab button
const tab = document.createElement('button');
tab.id = `tab-${idx}`;
tab.setAttribute('role', 'tab');
tab.setAttribute('aria-controls', `panel-${idx}`);
tab.textContent = `${type} (${groupsMap[type].length})`;
tab.setAttribute('aria-selected', idx === 0 ? 'true' : 'false');
if (idx !== 0) tab.setAttribute('tabindex', '-1');
tablist.appendChild(tab);
// — Panel
const panel = document.createElement('div');
panel.id = `panel-${idx}`;
panel.setAttribute('role', 'tabpanel');
panel.setAttribute('aria-labelledby', tab.id);
if (idx !== 0) panel.hidden = true;
panelsContainer.appendChild(panel);
// — Clone & append cards for this group
groupsMap[type].forEach(i => {
panel.appendChild(originals[i].cloneNode(true));
});
// — Click handler
tab.addEventListener('click', () => activateTab(idx));
// — Keyboard nav
tab.addEventListener('keydown', e => {
let newIdx;
if (e.key === 'ArrowRight') newIdx = (idx + 1) % types.length;
else if (e.key === 'ArrowLeft') newIdx = (idx - 1 + types.length) % types.length;
else if (e.key === 'Home') newIdx = 0;
else if (e.key === 'End') newIdx = types.length - 1;
else return;
e.preventDefault();
document.getElementById(`tab-${newIdx}`).focus();
activateTab(newIdx);
});
});
// 8️⃣ Activation logic
function activateTab(activeIndex) {
types.forEach((_, i) => {
const tab = document.getElementById(`tab-${i}`);
const panel = document.getElementById(`panel-${i}`);
const isActive = i === activeIndex;
tab.setAttribute('aria-selected', String(isActive));
if (isActive) tab.removeAttribute('tabindex');
else tab.setAttribute('tabindex', '-1');
panel.hidden = !isActive;
});
}
// 9️⃣ Initialize first tab
activateTab(0);
});
</script>