Skip to content

Commit ec73050

Browse files
committed
Stable Alert Component CSS/JS
1 parent 487071f commit ec73050

File tree

4 files changed

+130
-117
lines changed

4 files changed

+130
-117
lines changed

demo.html

Lines changed: 7 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -51,79 +51,15 @@
5151
<h2 class="font-lg text-primary my-4">Alert Component Showcase</h2>
5252

5353
<!-- Success Alerts -->
54-
<div class="alert" data-variant="success" data-size="default" data-shape="rounded">
55-
<span class="alert-icon"></span>
56-
<div class="alert-content">
57-
<p class="alert-title">Success Alert</p>
58-
<p class="alert-body">This is a standard success alert with rounded borders.</p>
59-
</div>
60-
<button class="alert-close" aria-label="Close alert">&times;</button>
61-
</div>
62-
63-
<div class="alert" data-variant="success" data-size="large" data-shape="circle">
64-
<span class="alert-icon"></span>
65-
<div class="alert-content">
66-
<p class="alert-title">Large Success Alert</p>
67-
<p class="alert-body">A large, circular success alert for important messages.</p>
68-
</div>
69-
<button class="alert-close" aria-label="Close alert">&times;</button>
70-
</div>
71-
72-
<!-- Warning Alerts -->
73-
<div class="alert" data-variant="warning" data-size="compact" data-shape="rounded">
74-
<span class="alert-icon"></span>
75-
<div class="alert-content">
76-
<p class="alert-title">Compact Warning Alert</p>
77-
<p class="alert-body">This warning alert is compact and uses rounded corners.</p>
78-
</div>
79-
<button class="alert-close" aria-label="Close alert">&times;</button>
80-
</div>
81-
82-
<div class="alert" data-variant="warning" data-size="large" data-shape="default">
83-
<span class="alert-icon"></span>
84-
<div class="alert-content">
85-
<p class="alert-title">Large Warning Alert</p>
86-
<p class="alert-body">This is a large warning alert with the default shape.</p>
87-
</div>
88-
<button class="alert-close" aria-label="Close alert">&times;</button>
89-
</div>
90-
91-
<!-- Danger Alerts -->
92-
<div class="alert" data-variant="danger" data-size="default" data-shape="rounded">
93-
<span class="alert-icon"></span>
94-
<div class="alert-content">
95-
<p class="alert-title">Danger Alert</p>
96-
<p class="alert-body">A standard danger alert with rounded borders for alerts.</p>
97-
</div>
98-
<button class="alert-close" aria-label="Close alert">&times;</button>
99-
</div>
100-
101-
<div class="alert" data-variant="danger" data-size="compact" data-shape="circle">
102-
<span class="alert-icon"></span>
103-
<div class="alert-content">
104-
<p class="alert-title">Compact Danger Alert</p>
105-
<p class="alert-body">This is a compact danger alert with a circular shape.</p>
106-
</div>
107-
<button class="alert-close" aria-label="Close alert">&times;</button>
108-
</div>
109-
110-
<!-- Info Alerts -->
111-
<div class="alert" data-variant="info" data-size="large" data-shape="default">
112-
<span class="alert-icon"></span>
113-
<div class="alert-content">
114-
<p class="alert-title">Large Info Alert</p>
115-
<p class="alert-body">An info alert in large size, suitable for informative messages.</p>
116-
</div>
117-
<button class="alert-close" aria-label="Close alert">&times;</button>
118-
</div>
54+
<div class="kroma-alert" data-variant="success" data-size="large" data-shape="rounded" data-title="Alert!" data-body="This is the alert content."></div>
11955

120-
<div class="alert" data-variant="info" data-size="default" data-shape="rounded">
121-
<span class="alert-icon"></span>
122-
<div class="alert-content">
123-
<p class="alert-title">Standard Info Alert</p>
124-
<p class="alert-body">A standard info alert with rounded corners for general use.</p>
56+
<div class="kroma-alert" data-variant="success" data-size="large" data-shape="circle">
57+
<span class="kroma-alert-icon"></span>
58+
<div class="kroma-alert-content">
59+
<p class="kroma-alert-title">Large Success Alert</p>
60+
<p class="kroma-alert-body">A large, circular success alert for important messages.</p>
12561
</div>
126-
<button class="alert-close" aria-label="Close alert">&times;</button>
62+
<button class="kroma-alert-close" aria-label="Close alert">&times;</button>
12763
</div>
12864

12965
</section>

src/css/components/alert.css

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Base Alert Styles */
2-
.alert {
2+
.kroma-alert {
33
display: flex;
44
flex-direction: column;
55
align-items: flex-start;
@@ -9,79 +9,83 @@
99
box-shadow: var(--shadow-md);
1010
font-size: clamp(0.875rem, 1vw + 0.5rem, 1rem);
1111
position: relative;
12-
transition: var(--transition-all);
12+
transition: max-height 0.5s ease-in-out, opacity 0.4s ease-in-out;
13+
opacity: 1;
1314
background-color: var(--neutral-50);
1415
color: var(--neutral-900);
1516
gap: var(--space-3);
1617
overflow: hidden;
18+
max-height: 500px; /* Set an arbitrary large value to allow transition */
19+
overflow: hidden; /* Prevent overflow during the transition */
1720
}
1821

19-
/* Variant Styles (Dynamic) */
20-
.alert[data-variant] {
22+
/* Variant Styles */
23+
.kroma-alert[data-variant] {
2124
background-color: var(--variant-bg);
2225
color: var(--variant-text);
2326
box-shadow: var(--variant-shadow);
2427
border: 1px solid var(--variant-border);
2528
}
26-
.alert[data-variant]:hover {
29+
30+
.kroma-alert[data-variant]:hover {
2731
background-color: var(--variant-hover-bg);
2832
}
2933

3034
/* Size Modifiers */
31-
.alert[data-size="large"] {
35+
.kroma-alert[data-size="large"] {
3236
padding: clamp(var(--space-6), 1vw + var(--space-4), var(--space-8));
3337
font-size: clamp(1rem, 1vw + 0.75rem, 1.25rem);
3438
}
3539

36-
.alert[data-size="compact"] {
40+
.kroma-alert[data-size="compact"] {
3741
padding: clamp(var(--space-3), 1vw + var(--space-2), var(--space-4));
3842
gap: var(--space-2);
3943
flex-direction: row;
4044
align-items: center;
4145
}
4246

4347
/* Shape Modifiers */
44-
.alert[data-shape="rounded"] {
48+
.kroma-alert[data-shape="rounded"] {
4549
border-radius: var(--radius-xl);
4650
}
4751

48-
.alert[data-shape="circle"] {
52+
.kroma-alert[data-shape="circle"] {
4953
border-radius: var(--radius-full);
5054
padding: var(--space-4);
5155
}
5256

5357
/* Icon */
54-
.alert-icon {
58+
.kroma-alert-icon {
5559
font-size: clamp(1.5rem, 2vw, 2rem);
5660
margin-right: var(--space-4);
5761
flex-shrink: 0;
5862
color: inherit;
5963
}
6064

6165
/* Content and Title */
62-
.alert-content {
66+
.kroma-alert-content {
6367
flex: 1;
6468
}
6569

66-
.alert-title {
70+
.kroma-alert-title {
6771
font-weight: 600;
6872
font-size: clamp(1rem, 1vw + 0.5rem, 1.25rem);
6973
margin-bottom: var(--space-2);
7074
}
7175

72-
.alert-body {
76+
.kroma-alert-body {
7377
margin-top: var(--space-1);
7478
line-height: 1.4;
7579
}
7680

77-
.alert-footer {
81+
.kroma-alert-footer {
7882
font-size: 0.75rem;
7983
color: var(--neutral-500);
8084
margin-top: var(--space-3);
8185
}
8286

8387
/* Close Button */
84-
.alert-close {
88+
.kroma-alert-close {
8589
position: absolute;
8690
top: var(--space-2);
8791
right: var(--space-2);
@@ -93,33 +97,29 @@
9397
transition: var(--transition-colors);
9498
}
9599

96-
.alert[data-shape="rounded"] .alert-close {
97-
top: var(--space-4);
98-
right: var(--space-4);
99-
}
100-
101-
.alert[data-shape="circle"] .alert-close {
100+
.kroma-alert[data-shape="rounded"] .kroma-alert-close,
101+
.kroma-alert[data-shape="circle"] .kroma-alert-close {
102102
top: var(--space-4);
103103
right: var(--space-4);
104104
}
105105

106-
.alert-close:hover {
106+
.kroma-alert-close:hover {
107107
color: var(--neutral-700);
108108
}
109109

110110
/* Fade-out with Smooth Collapse */
111-
.alert.fade-out {
111+
.kroma-alert.fade-out {
112112
opacity: 0;
113113
transform: translateY(-10px);
114114
max-height: 0;
115115
padding: 0;
116116
margin: 0;
117-
transition: opacity 0.4s, transform 0.4s, max-height 0.4s ease-out, padding 0.4s, margin 0.4s;
117+
transition: opacity 0.3s, transform 0.6s, max-height 0.6s linear, padding 0.6s, margin 0.6s;
118118
}
119119

120120
/* Responsive Design */
121121
@media (min-width: 600px) {
122-
.alert {
122+
.kroma-alert {
123123
flex-direction: row;
124124
align-items: center;
125125
}

src/js/components/alert.js

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,99 @@
1-
document.querySelectorAll('.alert .alert-close').forEach(button => {
2-
button.addEventListener('click', event => {
3-
const alert = button.closest('.alert');
4-
alert.style.maxHeight = alert.scrollHeight + 'px'; // Set max-height to element's height for smooth collapse
1+
document.addEventListener('DOMContentLoaded', () => {
2+
initializeAlerts(document);
3+
});
4+
5+
/**
6+
* Initialize all alerts within a container
7+
* @param {HTMLElement} container - The container with alerts to initialize
8+
*/
9+
function initializeAlerts(container) {
10+
const alerts = container.querySelectorAll('.kroma-alert');
11+
alerts.forEach(alert => initializeAlert(alert));
12+
}
13+
14+
/**
15+
* Initialize a single alert
16+
* @param {HTMLElement} alert - The alert element
17+
*/
18+
function initializeAlert(alert) {
19+
const iconMap = {
20+
success: '✔',
21+
error: '❌',
22+
warning: '⚠',
23+
info: 'ℹ',
24+
};
25+
26+
// Ensure the icon is present
27+
let iconElement = alert.querySelector('.kroma-alert-icon');
28+
if (!iconElement) {
29+
iconElement = document.createElement('span');
30+
iconElement.classList.add('kroma-alert-icon');
31+
iconElement.textContent = alert.dataset.icon || iconMap[alert.dataset.variant] || '';
32+
alert.prepend(iconElement); // Insert icon at the beginning
33+
}
34+
35+
// Ensure the content wrapper is present
36+
let contentElement = alert.querySelector('.kroma-alert-content');
37+
if (!contentElement) {
38+
contentElement = document.createElement('div');
39+
contentElement.classList.add('kroma-alert-content');
40+
alert.appendChild(contentElement);
41+
}
42+
43+
// Ensure the title is present
44+
if (alert.dataset.title) {
45+
let titleElement = contentElement.querySelector('.kroma-alert-title');
46+
if (!titleElement) {
47+
titleElement = document.createElement('p');
48+
titleElement.classList.add('kroma-alert-title');
49+
titleElement.textContent = alert.dataset.title;
50+
contentElement.appendChild(titleElement);
51+
}
52+
}
53+
54+
// Ensure the body is present
55+
if (alert.dataset.body) {
56+
let bodyElement = contentElement.querySelector('.kroma-alert-body');
57+
if (!bodyElement) {
58+
bodyElement = document.createElement('p');
59+
bodyElement.classList.add('kroma-alert-body');
60+
bodyElement.textContent = alert.dataset.body;
61+
contentElement.appendChild(bodyElement);
62+
}
63+
}
64+
65+
// Ensure the close button is present
66+
let closeButton = alert.querySelector('.kroma-alert-close');
67+
if (!closeButton) {
68+
closeButton = document.createElement('button');
69+
closeButton.classList.add('kroma-alert-close');
70+
closeButton.setAttribute('aria-label', 'Close alert');
71+
closeButton.innerHTML = '&times;';
72+
alert.appendChild(closeButton);
73+
}
74+
75+
// Add close button functionality
76+
closeButton.addEventListener('click', () => handleAlertClose(alert));
77+
}
78+
79+
/**
80+
* Handle alert close functionality
81+
* @param {HTMLElement} alert - The alert to close
82+
*/
83+
function handleAlertClose(alert) {
84+
if (!alert) return;
85+
86+
// Set the initial height for smooth transition
87+
alert.style.maxHeight = `${alert.scrollHeight}px`;
88+
89+
// Trigger the transition
90+
requestAnimationFrame(() => {
591
alert.classList.add('fade-out');
6-
alert.addEventListener('transitionend', () => {
7-
if (alert.parentNode) alert.remove();
8-
});
92+
alert.style.maxHeight = '0';
993
});
10-
});
94+
95+
// Remove the alert after the animation ends
96+
alert.addEventListener('transitionend', () => {
97+
if (alert.parentNode) alert.remove();
98+
}, { once: true });
99+
}

src/js/main.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Import components
2+
import { } from './components/alert.js';
23
import { toggleAccordion } from './components/accordion.js';
34
import { showHologram } from './components/hologram.js';
45
import { showTabContent } from './components/tabs.js';
@@ -29,19 +30,6 @@ document.addEventListener("DOMContentLoaded", () => {
2930

3031
initializeCodeblock();
3132

32-
// Initialize other components, if applicable
33-
document.querySelectorAll('.alert .alert-close').forEach(button => {
34-
button.addEventListener('click', event => {
35-
const alert = button.closest('.alert');
36-
alert.style.maxHeight = alert.scrollHeight + 'px';
37-
alert.classList.add('fade-out');
38-
alert.addEventListener('transitionend', () => {
39-
if (alert.parentNode) alert.remove();
40-
});
41-
});
42-
});
43-
44-
4533
});
4634

4735
// Export functions globally if needed

0 commit comments

Comments
 (0)