Sync styleguide 2026.05.18.1
This commit is contained in:
@@ -76,6 +76,7 @@
|
|||||||
<section id="component-large-table">
|
<section id="component-large-table">
|
||||||
|
|
||||||
<p class="sg-preview-label">Component: Large Table</p>
|
<p class="sg-preview-label">Component: Large Table</p>
|
||||||
|
<p>Suche, Sortierung und „Mehr laden“ sind hier Demo-Markup. Produktions-Implementierungen müssen Treffer serverseitig neu rendern.</p>
|
||||||
|
|
||||||
<article class="sg-card sg-large-table" data-component="large-table" role="table" aria-label="Beispiel Large Table">
|
<article class="sg-card sg-large-table" data-component="large-table" role="table" aria-label="Beispiel Large Table">
|
||||||
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-large-table__title-segment" data-component-part="large-table-header">
|
<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-large-table__title-segment" data-component-part="large-table-header">
|
||||||
@@ -226,230 +227,5 @@
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
const table = document.querySelector('[data-component="large-table"]');
|
|
||||||
if (!table) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerCells = Array.from(table.querySelectorAll('[role="columnheader"][data-sort-key]'));
|
|
||||||
const headerButtons = headerCells.map((cell) => cell.querySelector('.sg-large-table__sort-button'));
|
|
||||||
const dataRows = Array.from(table.querySelectorAll('[data-component-part="large-table-row"]')).filter((row) => !row.hasAttribute('data-large-table-load-more-row'));
|
|
||||||
const loadMoreRow = table.querySelector('[data-large-table-load-more-row="true"]');
|
|
||||||
const loadMoreTrigger = table.querySelector('[data-large-table-load-more-trigger="true"]');
|
|
||||||
const headerRow = table.querySelector('[data-component-part="large-table-header-row"]');
|
|
||||||
const searchInput = table.querySelector('[data-large-table-search]');
|
|
||||||
const searchFieldWrap = table.querySelector('[data-component="single-line-input"]');
|
|
||||||
const searchClearButton = table.querySelector('.sg-input-clear-button');
|
|
||||||
let searchTimer = null;
|
|
||||||
let loadMoreTimer = null;
|
|
||||||
const totalRows = Array.from({ length: 20 }, (_, index) => {
|
|
||||||
const number = index + 1;
|
|
||||||
return ['A' + number, 'B' + number, 'C' + number, 'D' + number, 'E' + number];
|
|
||||||
});
|
|
||||||
const state = {
|
|
||||||
columnIndex: 0,
|
|
||||||
direction: 'ascending',
|
|
||||||
query: '',
|
|
||||||
loadingSearch: false,
|
|
||||||
loadingMore: false,
|
|
||||||
loadedCount: dataRows.length,
|
|
||||||
};
|
|
||||||
|
|
||||||
function createDataRow(values) {
|
|
||||||
const row = document.createElement('div');
|
|
||||||
row.className = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row';
|
|
||||||
row.setAttribute('role', 'row');
|
|
||||||
row.setAttribute('data-component-part', 'large-table-row');
|
|
||||||
row.setAttribute('data-large-table-data-row', 'true');
|
|
||||||
|
|
||||||
values.forEach((value) => {
|
|
||||||
const cell = document.createElement('div');
|
|
||||||
cell.className = 'sg-large-table__cell';
|
|
||||||
cell.setAttribute('role', 'cell');
|
|
||||||
cell.textContent = value;
|
|
||||||
row.appendChild(cell);
|
|
||||||
});
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setHeaderState(activeIndex, direction) {
|
|
||||||
headerCells.forEach((cell, index) => {
|
|
||||||
const icon = cell.querySelector('.sg-large-table__sort-icon');
|
|
||||||
const isActive = index === activeIndex;
|
|
||||||
|
|
||||||
cell.setAttribute('aria-sort', isActive ? direction : 'none');
|
|
||||||
if (icon) {
|
|
||||||
icon.dataset.direction = isActive ? direction : 'ascending';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
headerButtons.forEach((button, index) => {
|
|
||||||
if (!button) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const label = `Spalte ${index + 1}`;
|
|
||||||
button.setAttribute(
|
|
||||||
'aria-label',
|
|
||||||
index === activeIndex
|
|
||||||
? `${label} ${direction === 'ascending' ? 'aufsteigend' : 'absteigend'} sortiert`
|
|
||||||
: `${label} sortieren`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function compareValues(left, right, direction) {
|
|
||||||
const normalizedLeft = left.trim();
|
|
||||||
const normalizedRight = right.trim();
|
|
||||||
const comparison = normalizedLeft.localeCompare(normalizedRight, 'de', {
|
|
||||||
numeric: true,
|
|
||||||
sensitivity: 'base',
|
|
||||||
});
|
|
||||||
|
|
||||||
return direction === 'ascending' ? comparison : -comparison;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rowMatchesQuery(row, query) {
|
|
||||||
if (!query) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(row.querySelectorAll('[role="cell"]')).some((cell) => {
|
|
||||||
const value = cell.textContent || '';
|
|
||||||
return value.toLowerCase().includes(query);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderRows() {
|
|
||||||
table.setAttribute('aria-busy', state.loadingSearch || state.loadingMore ? 'true' : 'false');
|
|
||||||
const sortedRows = dataRows.slice().sort((leftRow, rightRow) => {
|
|
||||||
const leftCell = leftRow.querySelectorAll('[role="cell"]')[state.columnIndex];
|
|
||||||
const rightCell = rightRow.querySelectorAll('[role="cell"]')[state.columnIndex];
|
|
||||||
const leftValue = leftCell ? leftCell.textContent : '';
|
|
||||||
const rightValue = rightCell ? rightCell.textContent : '';
|
|
||||||
|
|
||||||
return compareValues(leftValue, rightValue, state.direction);
|
|
||||||
});
|
|
||||||
|
|
||||||
let visibleIndex = 0;
|
|
||||||
sortedRows.forEach((row) => {
|
|
||||||
table.appendChild(row);
|
|
||||||
const isVisible = rowMatchesQuery(row, state.query);
|
|
||||||
row.classList.toggle('sg-large-table__row--hidden', !isVisible);
|
|
||||||
row.setAttribute('aria-hidden', isVisible ? 'false' : 'true');
|
|
||||||
row.classList.remove('sg-large-table__row--striped-light');
|
|
||||||
if (isVisible && visibleIndex % 2 === 0) {
|
|
||||||
row.classList.add('sg-large-table__row--striped-light');
|
|
||||||
}
|
|
||||||
if (isVisible) {
|
|
||||||
visibleIndex += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (loadMoreRow) {
|
|
||||||
const hasMoreRows = state.loadedCount < totalRows.length;
|
|
||||||
loadMoreRow.classList.toggle('sg-large-table__row--hidden', !hasMoreRows);
|
|
||||||
loadMoreRow.setAttribute('aria-hidden', hasMoreRows ? 'false' : 'true');
|
|
||||||
table.appendChild(loadMoreRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
setHeaderState(state.columnIndex, state.direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
headerButtons.forEach((button, index) => {
|
|
||||||
if (!button) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
const direction = state.columnIndex === index && state.direction === 'ascending'
|
|
||||||
? 'descending'
|
|
||||||
: 'ascending';
|
|
||||||
|
|
||||||
state.columnIndex = index;
|
|
||||||
state.direction = direction;
|
|
||||||
renderRows();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (searchInput) {
|
|
||||||
searchInput.addEventListener('input', () => {
|
|
||||||
if (searchFieldWrap) {
|
|
||||||
searchFieldWrap.setAttribute('data-has-value', searchInput.value ? 'true' : 'false');
|
|
||||||
}
|
|
||||||
state.loadingSearch = true;
|
|
||||||
renderRows();
|
|
||||||
|
|
||||||
if (searchTimer) {
|
|
||||||
window.clearTimeout(searchTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchTimer = window.setTimeout(() => {
|
|
||||||
state.query = searchInput.value.trim().toLowerCase();
|
|
||||||
state.loadingSearch = false;
|
|
||||||
renderRows();
|
|
||||||
}, 250);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchClearButton && searchInput) {
|
|
||||||
searchClearButton.addEventListener('click', () => {
|
|
||||||
if (searchTimer) {
|
|
||||||
window.clearTimeout(searchTimer);
|
|
||||||
searchTimer = null;
|
|
||||||
}
|
|
||||||
searchInput.value = '';
|
|
||||||
state.query = '';
|
|
||||||
state.loadingSearch = false;
|
|
||||||
if (searchFieldWrap) {
|
|
||||||
searchFieldWrap.setAttribute('data-has-value', 'false');
|
|
||||||
}
|
|
||||||
renderRows();
|
|
||||||
searchInput.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadMoreTrigger) {
|
|
||||||
loadMoreTrigger.addEventListener('click', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (state.loadingMore || state.loadedCount >= totalRows.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadMoreTimer) {
|
|
||||||
window.clearTimeout(loadMoreTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.loadingMore = true;
|
|
||||||
loadMoreTrigger.textContent = 'Lädt ...';
|
|
||||||
renderRows();
|
|
||||||
|
|
||||||
loadMoreTimer = window.setTimeout(() => {
|
|
||||||
const nextCount = Math.min(state.loadedCount + 5, totalRows.length);
|
|
||||||
const nextRows = totalRows.slice(state.loadedCount, nextCount).map((values) => createDataRow(values));
|
|
||||||
|
|
||||||
nextRows.forEach((row) => {
|
|
||||||
dataRows.push(row);
|
|
||||||
});
|
|
||||||
|
|
||||||
state.loadedCount = nextCount;
|
|
||||||
state.loadingMore = false;
|
|
||||||
loadMoreTrigger.textContent = 'Mehr laden';
|
|
||||||
renderRows();
|
|
||||||
}, 350);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headerRow) {
|
|
||||||
setHeaderState(state.columnIndex, state.direction);
|
|
||||||
}
|
|
||||||
renderRows();
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"styleguideVersion": "2026.05.18.1",
|
"styleguideVersion": "2026.05.18.1",
|
||||||
"styleguideCommit": "1ba5b02",
|
"styleguideCommit": "9511e98",
|
||||||
"syncedAtUtc": "2026-06-15T13:05:44Z",
|
"syncedAtUtc": "2026-06-15T14:36:54Z",
|
||||||
"sourceRepo": "/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide",
|
"sourceRepo": "/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide",
|
||||||
"mirroredDocsPath": "docs/styleguide"
|
"mirroredDocsPath": "docs/styleguide"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user