Refactors UI components with new card header structure
Replaces `swp-section-label` with standardized `swp-card-header` and `swp-card-title` Improves component consistency across multiple features: - Adds structured card headers - Introduces more semantic HTML elements - Enhances layout and readability of card components Updates CSS and component styles to support new structure
This commit is contained in:
parent
33c338345e
commit
c1d2df9327
31 changed files with 250 additions and 149 deletions
|
|
@ -75,29 +75,58 @@ Standard icon wrapper (40×40px cirkel):
|
|||
| `swp-page-title` | Titel-wrapper med h1 og p | h1 + subtitle |
|
||||
| `swp-page-actions` | Action buttons i header | Flex gap |
|
||||
| `swp-card` | Standard card wrapper | Border, padding, rounded |
|
||||
| `swp-section-label` | Card section label | Uppercase, 11px, border-bottom |
|
||||
| `swp-section-header` | Wrapper for label + action | Flex, space-between |
|
||||
| `swp-section-action` | Action link i section header | Teal, clickable |
|
||||
| `swp-card-header` | Card header wrapper | Flex, space-between, border-bottom |
|
||||
| `swp-card-title` | Card title med ikon | Flex, icon + text |
|
||||
| `swp-section-action` | Action link i header | Teal, clickable |
|
||||
| `swp-section-label` | Subsection label (inde i card) | Uppercase, 11px, border-bottom |
|
||||
| `swp-card-content` | Card indhold | Block |
|
||||
|
||||
### Card Header Eksempler
|
||||
|
||||
**Simpel label (uden action):**
|
||||
**Standard card header (ANBEFALET):**
|
||||
```html
|
||||
<swp-card>
|
||||
<swp-section-label>Kontakter</swp-section-label>
|
||||
<swp-card-content>...</swp-card-content>
|
||||
<swp-card-header>
|
||||
<swp-card-title>Kontakter</swp-card-title>
|
||||
</swp-card-header>
|
||||
<!-- content -->
|
||||
</swp-card>
|
||||
```
|
||||
|
||||
**Label med action:**
|
||||
**Card header med ikon:**
|
||||
```html
|
||||
<swp-card>
|
||||
<swp-section-header>
|
||||
<swp-section-label>Dagens bookinger</swp-section-label>
|
||||
<swp-card-header>
|
||||
<swp-card-title>
|
||||
<i class="ph ph-envelope"></i>
|
||||
Email
|
||||
</swp-card-title>
|
||||
</swp-card-header>
|
||||
<!-- content -->
|
||||
</swp-card>
|
||||
```
|
||||
|
||||
**Card header med action:**
|
||||
```html
|
||||
<swp-card>
|
||||
<swp-card-header>
|
||||
<swp-card-title>Dagens bookinger</swp-card-title>
|
||||
<swp-section-action>Se alle</swp-section-action>
|
||||
</swp-section-header>
|
||||
<swp-card-content>...</swp-card-content>
|
||||
</swp-card-header>
|
||||
<!-- content -->
|
||||
</swp-card>
|
||||
```
|
||||
|
||||
**Subsection label (inde i card):**
|
||||
```html
|
||||
<swp-card>
|
||||
<swp-card-header>
|
||||
<swp-card-title>Grundlæggende</swp-card-title>
|
||||
</swp-card-header>
|
||||
<!-- first section content -->
|
||||
|
||||
<swp-section-label class="spaced">Interne noter</swp-section-label>
|
||||
<!-- second section content -->
|
||||
</swp-card>
|
||||
```
|
||||
|
||||
|
|
@ -434,7 +463,9 @@ Bruger `swp-data-table` med `.salary-history` context class.
|
|||
|
||||
```html
|
||||
<swp-card class="salary-history">
|
||||
<swp-section-label>Lønhistorik</swp-section-label>
|
||||
<swp-card-header>
|
||||
<swp-card-title>Lønhistorik</swp-card-title>
|
||||
</swp-card-header>
|
||||
<swp-data-table>
|
||||
<swp-data-table-header>
|
||||
<swp-data-table-cell>Periode</swp-data-table-cell>
|
||||
|
|
|
|||
|
|
@ -57,15 +57,9 @@ swp-filter-spacer {
|
|||
/* ===========================================
|
||||
ACTION BAR (Table Header)
|
||||
=========================================== */
|
||||
swp-action-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-6) var(--spacing-8);
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
swp-action-bar.grid-top {
|
||||
border-bottom: none;
|
||||
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
swp-selection-info {
|
||||
|
|
@ -279,20 +273,6 @@ swp-row-arrow {
|
|||
}
|
||||
}
|
||||
|
||||
/* ===========================================
|
||||
TWO-COLUMN GRID (Detail View)
|
||||
=========================================== */
|
||||
swp-cash-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-12);
|
||||
}
|
||||
|
||||
swp-cash-column {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
/* ===========================================
|
||||
DATA TABLE (Dagens Tal)
|
||||
=========================================== */
|
||||
|
|
@ -690,12 +670,6 @@ swp-system-note {
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
swp-cash-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
swp-filter-bar {
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -570,6 +570,7 @@ swp-card-title {
|
|||
gap: var(--spacing-3);
|
||||
font-size: var(--font-size-md);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
text-transform: uppercase;
|
||||
color: var(--color-text);
|
||||
|
||||
& i {
|
||||
|
|
@ -1322,12 +1323,17 @@ swp-back-link {
|
|||
swp-detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--spacing-8);
|
||||
gap: var(--card-gap);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
/* ===========================================
|
||||
CARD COLUMN (Stacked cards container)
|
||||
=========================================== */
|
||||
swp-card-column {
|
||||
display: grid;
|
||||
gap: var(--card-gap);
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
|
@ -1582,9 +1588,3 @@ swp-two-column-grid {
|
|||
}
|
||||
}
|
||||
|
||||
/* Stacked cards in a grid column */
|
||||
.stacked-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--card-gap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ swp-stats-grid {
|
|||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: var(--card-gap);
|
||||
margin-bottom: var(--section-gap);
|
||||
|
||||
}
|
||||
|
||||
swp-stats-row {
|
||||
|
|
|
|||
|
|
@ -88,10 +88,31 @@ export class CashController {
|
|||
toBankInput.addEventListener('input', calculate);
|
||||
actualCashInput.addEventListener('input', calculate);
|
||||
|
||||
// Setup Enter key navigation between fields
|
||||
this.setupEnterNavigation([payoutsInput, toBankInput, actualCashInput]);
|
||||
|
||||
// Initial calculation
|
||||
calculate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Enter key to move focus to next input field
|
||||
*/
|
||||
private setupEnterNavigation(inputs: HTMLInputElement[]): void {
|
||||
inputs.forEach((input, index) => {
|
||||
input.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const nextIndex = index + 1;
|
||||
if (nextIndex < inputs.length) {
|
||||
inputs[nextIndex].focus();
|
||||
inputs[nextIndex].select();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate expected cash and difference
|
||||
*/
|
||||
|
|
@ -113,13 +134,13 @@ export class CashController {
|
|||
}
|
||||
|
||||
// Calculate and display difference
|
||||
this.updateDifference(actual, expectedCash, actualCashInput.value);
|
||||
this.updateDifference(actual, expectedCash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update difference box with color coding
|
||||
*/
|
||||
private updateDifference(actual: number, expected: number, rawValue: string): void {
|
||||
private updateDifference(actual: number, expected: number): void {
|
||||
const box = document.getElementById('differenceBox');
|
||||
const value = document.getElementById('differenceValue');
|
||||
if (!box || !value) return;
|
||||
|
|
@ -129,11 +150,7 @@ export class CashController {
|
|||
// Remove all state classes
|
||||
box.classList.remove('positive', 'negative', 'neutral');
|
||||
|
||||
if (actual === 0 && rawValue === '') {
|
||||
// No input yet
|
||||
value.textContent = '– kr';
|
||||
box.classList.add('neutral');
|
||||
} else if (diff > 0) {
|
||||
if (diff > 0) {
|
||||
// More cash than expected
|
||||
value.textContent = '+' + this.formatNumber(diff) + ' kr';
|
||||
box.classList.add('positive');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue