456 lines
20 KiB
HTML
456 lines
20 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Styleguide – Data Display</title>
|
||
<link rel="stylesheet" href="../styleguide.css">
|
||
</head>
|
||
<body>
|
||
|
||
<h1 class="sg-main-heading">Components – Data Display</h1>
|
||
|
||
<!-- ========================================================= -->
|
||
<!-- Components -->
|
||
<!-- ========================================================= -->
|
||
|
||
<!-- Component: Data Table -->
|
||
<section id="component-data-table">
|
||
|
||
<p class="sg-preview-label">Component: Data Table</p>
|
||
|
||
<table class="sg-data-table" aria-label="Beispiel Kennzahlen-Tabelle" data-component="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th data-component-part="data-table-header-cell">Kennzahl</th>
|
||
<th data-component-part="data-table-header-cell">Wert</th>
|
||
<th data-component-part="data-table-header-cell">Peer-Median</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE <span class="sg-data-table__help-icon" aria-label="Hilfetext" data-component="help-icon" data-component-context="data-table">?</span></td>
|
||
<td class="sg-data-table__value" data-component-part="data-table-value-cell">7.7</td>
|
||
<td data-component-part="data-table-reference-cell">11.7</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PE Forward <span class="sg-data-table__help-icon" aria-label="Hilfetext" data-component="help-icon" data-component-context="data-table">?</span></td>
|
||
<td class="sg-data-table__value" data-component-part="data-table-value-cell">8.6</td>
|
||
<td data-component-part="data-table-reference-cell">9.7</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sg-data-table__label" data-component-part="data-table-label-cell">PEG Forward <span class="sg-data-table__help-icon" aria-label="Hilfetext" data-component="help-icon" data-component-context="data-table">?</span></td>
|
||
<td class="sg-data-table__value sg-data-table__value--warning" data-component-part="data-table-value-cell" data-component-state="warning">1.23</td>
|
||
<td data-component-part="data-table-reference-cell">1.43</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
</section>
|
||
|
||
<!-- Component: Data Columns -->
|
||
<section id="component-data-columns">
|
||
|
||
<p class="sg-preview-label">Component: Data Columns</p>
|
||
|
||
<table class="sg-data-table" aria-label="Beispiel Kennzahlen-Spalten" data-component="data-columns">
|
||
<tbody>
|
||
<tr>
|
||
<td class="sg-data-table__value" data-component-part="data-columns-value-cell">7.7</td>
|
||
<td data-component-part="data-columns-reference-cell">11.7</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sg-data-table__value" data-component-part="data-columns-value-cell">8.6</td>
|
||
<td data-component-part="data-columns-reference-cell">9.7</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sg-data-table__value sg-data-table__value--warning" data-component-part="data-columns-value-cell" data-component-state="warning">1.23</td>
|
||
<td data-component-part="data-columns-reference-cell">1.43</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
</section>
|
||
|
||
<!-- Component: Large Table -->
|
||
<section id="component-large-table">
|
||
|
||
<p class="sg-preview-label">Component: Large Table</p>
|
||
|
||
<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-strong">Large Table</div>
|
||
<span class="sg-search-field-row" data-component="search-field">
|
||
<span class="sg-input-single-line-wrap" data-has-value="false" data-component="single-line-input" data-component-state="inactive-selectable">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
|
||
type="text"
|
||
placeholder="Suche"
|
||
aria-label="Suchfeld ohne Eingabe"
|
||
data-large-table-search
|
||
>
|
||
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen">×</button>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--header" role="row" data-component-part="large-table-header-row">
|
||
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="0">
|
||
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 1 sortieren">
|
||
<span class="sg-large-table__sort-label">Spalte 1</span>
|
||
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
|
||
</button>
|
||
</div>
|
||
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="1">
|
||
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 2 sortieren">
|
||
<span class="sg-large-table__sort-label">Spalte 2</span>
|
||
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
|
||
</button>
|
||
</div>
|
||
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="2">
|
||
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 3 sortieren">
|
||
<span class="sg-large-table__sort-label">Spalte 3</span>
|
||
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
|
||
</button>
|
||
</div>
|
||
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="3">
|
||
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 4 sortieren">
|
||
<span class="sg-large-table__sort-label">Spalte 4</span>
|
||
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
|
||
</button>
|
||
</div>
|
||
<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader" aria-sort="none" data-sort-key="4">
|
||
<button class="sg-large-table__sort-button" type="button" aria-label="Spalte 5 sortieren">
|
||
<span class="sg-large-table__sort-label">Spalte 5</span>
|
||
<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="ascending"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A1</div>
|
||
<div class="sg-large-table__cell" role="cell">B1</div>
|
||
<div class="sg-large-table__cell" role="cell">C1</div>
|
||
<div class="sg-large-table__cell" role="cell">D1</div>
|
||
<div class="sg-large-table__cell" role="cell">E1</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A2</div>
|
||
<div class="sg-large-table__cell" role="cell">B2</div>
|
||
<div class="sg-large-table__cell" role="cell">C2</div>
|
||
<div class="sg-large-table__cell" role="cell">D2</div>
|
||
<div class="sg-large-table__cell" role="cell">E2</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A3</div>
|
||
<div class="sg-large-table__cell" role="cell">B3</div>
|
||
<div class="sg-large-table__cell" role="cell">C3</div>
|
||
<div class="sg-large-table__cell" role="cell">D3</div>
|
||
<div class="sg-large-table__cell" role="cell">E3</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A4</div>
|
||
<div class="sg-large-table__cell" role="cell">B4</div>
|
||
<div class="sg-large-table__cell" role="cell">C4</div>
|
||
<div class="sg-large-table__cell" role="cell">D4</div>
|
||
<div class="sg-large-table__cell" role="cell">E4</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A5</div>
|
||
<div class="sg-large-table__cell" role="cell">B5</div>
|
||
<div class="sg-large-table__cell" role="cell">C5</div>
|
||
<div class="sg-large-table__cell" role="cell">D5</div>
|
||
<div class="sg-large-table__cell" role="cell">E5</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A6</div>
|
||
<div class="sg-large-table__cell" role="cell">B6</div>
|
||
<div class="sg-large-table__cell" role="cell">C6</div>
|
||
<div class="sg-large-table__cell" role="cell">D6</div>
|
||
<div class="sg-large-table__cell" role="cell">E6</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A7</div>
|
||
<div class="sg-large-table__cell" role="cell">B7</div>
|
||
<div class="sg-large-table__cell" role="cell">C7</div>
|
||
<div class="sg-large-table__cell" role="cell">D7</div>
|
||
<div class="sg-large-table__cell" role="cell">E7</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A8</div>
|
||
<div class="sg-large-table__cell" role="cell">B8</div>
|
||
<div class="sg-large-table__cell" role="cell">C8</div>
|
||
<div class="sg-large-table__cell" role="cell">D8</div>
|
||
<div class="sg-large-table__cell" role="cell">E8</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A9</div>
|
||
<div class="sg-large-table__cell" role="cell">B9</div>
|
||
<div class="sg-large-table__cell" role="cell">C9</div>
|
||
<div class="sg-large-table__cell" role="cell">D9</div>
|
||
<div class="sg-large-table__cell" role="cell">E9</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row">
|
||
<div class="sg-large-table__cell" role="cell">A10</div>
|
||
<div class="sg-large-table__cell" role="cell">B10</div>
|
||
<div class="sg-large-table__cell" role="cell">C10</div>
|
||
<div class="sg-large-table__cell" role="cell">D10</div>
|
||
<div class="sg-large-table__cell" role="cell">E10</div>
|
||
</div>
|
||
|
||
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row" data-large-table-load-more-row="true">
|
||
<div class="sg-large-table__cell sg-large-table__cell--load-more" role="cell">
|
||
<div class="sg-navigation-card-layout sg-large-table__load-more-layout">
|
||
<div class="sg-navigation-card-block">
|
||
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
|
||
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
|
||
<div class="sg-navigation-card-center">
|
||
<a class="sg-hyperlink" href="#" data-component="hyperlink" data-large-table-load-more-trigger="true">Mehr laden</a>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
</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>
|
||
</html>
|