fix: add modal

This commit is contained in:
Tim Rijkse
2026-01-16 09:45:38 +01:00
parent 5755d43cfc
commit 626a304169
8 changed files with 814 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
/**
* Content Tabs Component
* Tabbed interface for displaying different content sections
*/
class ContentTabs extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.activeTab = 0;
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
get tabs() {
const tabsAttr = this.getAttribute("tabs");
return tabsAttr ? tabsAttr.split(",").map((t) => t.trim()) : [];
}
setupEventListeners() {
const tabButtons = this.shadowRoot.querySelectorAll(".tab-button");
tabButtons.forEach((button, index) => {
button.addEventListener("click", () => {
this.setActiveTab(index);
});
});
}
setActiveTab(index) {
this.activeTab = index;
this.updateTabs();
this.dispatchEvent(
new CustomEvent("tab-change", {
bubbles: true,
composed: true,
detail: { index, tab: this.tabs[index] },
})
);
}
updateTabs() {
// Update tab buttons
const tabButtons = this.shadowRoot.querySelectorAll(".tab-button");
tabButtons.forEach((button, index) => {
button.classList.toggle("active", index === this.activeTab);
});
// Update panels
const panels = this.querySelectorAll("[slot^='panel-']");
panels.forEach((panel, index) => {
panel.style.display = index === this.activeTab ? "block" : "none";
});
}
render() {
const tabsHtml = this.tabs
.map(
(tab, index) => `
<button
class="tab-button ${index === this.activeTab ? "active" : ""}"
type="button"
role="tab"
aria-selected="${index === this.activeTab}"
>
${tab}
</button>
`
)
.join("");
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
.tabs-container {
display: flex;
flex-direction: column;
}
.tab-list {
display: flex;
gap: var(--spacing-lg, 1.5rem);
border-bottom: 1px solid var(--color-border, #e2e8f0);
margin-bottom: var(--spacing-md, 1rem);
}
.tab-button {
padding: var(--spacing-sm, 0.5rem) 0;
background: none;
border: none;
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: var(--color-purple, #951d51);
text-decoration: underline;
text-underline-offset: 3px;
cursor: pointer;
transition: opacity var(--transition-fast, 150ms ease);
position: relative;
}
.tab-button:first-child {
color: var(--color-text, #1e293b);
text-decoration: none;
font-weight: 400;
}
.tab-button.active {
color: var(--color-text, #1e293b);
text-decoration: none;
font-weight: 400;
}
.tab-button:hover {
opacity: 0.7;
}
.tab-panels {
min-height: 100px;
}
</style>
<div class="tabs-container">
<div class="tab-list" role="tablist">
${tabsHtml}
</div>
<div class="tab-panels">
<slot name="panel-0"></slot>
<slot name="panel-1"></slot>
<slot name="panel-2"></slot>
</div>
</div>
`;
// Initialize panel visibility
setTimeout(() => this.updateTabs(), 0);
}
}
customElements.define("content-tabs", ContentTabs);