notify2t
Version:
A versatile UI notification, alert, and modal library with unique Ant Design inspired look.
533 lines (472 loc) • 18.4 kB
CSS
/* --- Global Variables & Base Styles --- */
:root {
/* Colors - Inspired by modern, slightly muted palette */
--ui-success: #4CAF50; /* Green: rgb(76, 175, 80) */
--ui-success-rgb: 76, 175, 80; /* Thêm biến RGB */
--ui-error: #F44336; /* Red: rgb(244, 67, 54) */
--ui-error-rgb: 244, 67, 54; /* Thêm biến RGB */
--ui-warning: #FFC107; /* Amber: rgb(255, 193, 7) */
--ui-warning-rgb: 255, 193, 7; /* Thêm biến RGB */
--ui-info: #2196F3; /* Blue: rgb(33, 150, 243) */
--ui-info-rgb: 33, 150, 243; /* Thêm biến RGB */
--ui-primary-text: #333;
--ui-secondary-text: #666;
--ui-light-text: #fff;
--ui-bg-light: rgba(255, 255, 255, 0.95); /* Slightly transparent white for glass effect */
--ui-bg-dark-overlay: rgba(0, 0, 0, 0.6); /* Darker overlay for modals */
--ui-border-light: rgba(0, 0, 0, 0.1);
--ui-shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.15);
--ui-shadow-deep: 0 8px 24px rgba(0, 0, 0, 0.25);
/* Spacing */
--ui-gap-sm: 8px;
--ui-gap-md: 16px;
--ui-gap-lg: 24px;
/* Border Radii */
--ui-radius-sm: 6px;
--ui-radius-md: 12px;
--ui-radius-lg: 24px; /* For more unique shapes */
/* Z-index */
--ui-z-notification: 9999;
--ui-z-modal-backdrop: 10000;
--ui-z-modal: 10001;
/* Fonts (Example - you'd link via @font-face) */
--ui-font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
}
body {
font-family: var(--ui-font-family);
color: var(--ui-primary-text);
}
/* Base Icon Styles */
.ui-icon-base {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5em; /* Slightly larger icons */
flex-shrink: 0;
}
.ui-icon-base svg {
width: 1em;
height: 1em;
filter: drop-shadow(0px 0px 3px rgba(0,0,0,0.1)); /* Subtle shadow for icons */
}
/* --- Notification Styles --- */
.ui-notification-container {
position: fixed;
z-index: var(--ui-z-notification);
display: flex;
flex-direction: column;
pointer-events: none; /* Allow clicks through container */
}
/* Position adjustments - slightly more margin */
.ui-notification-container.top-left { top: var(--ui-gap-lg); left: var(--ui-gap-lg); align-items: flex-start; }
.ui-notification-container.top-right { top: var(--ui-gap-lg); right: var(--ui-gap-lg); align-items: flex-end; }
.ui-notification-container.bottom-left { bottom: var(--ui-gap-lg); left: var(--ui-gap-lg); align-items: flex-start; }
.ui-notification-container.bottom-right { bottom: var(--ui-gap-lg); right: var(--ui-gap-lg); align-items: flex-end; }
.ui-notification-wrapper {
background-color: var(--ui-bg-light);
/* Glassmorphism/Asymmetrical Borders */
border-radius: var(--ui-radius-md) var(--ui-radius-lg) var(--ui-radius-md) var(--ui-radius-sm); /* Unique shape */
backdrop-filter: blur(8px); /* Glass effect */
-webkit-backdrop-filter: blur(8px); /* Safari compatibility */
box-shadow: var(--ui-shadow-soft); /* Soft shadow */
overflow: hidden; /* For progress bar and smooth content transition */
padding: var(--ui-gap-md);
margin-bottom: var(--ui-gap-sm);
display: flex;
align-items: flex-start; /* Align icon/title to top */
width: 320px; /* Slightly adjusted width */
max-width: calc(100vw - var(--ui-gap-lg) * 2);
box-sizing: border-box;
pointer-events: auto; /* Allow interaction with content */
/* Custom Entry/Exit Animation */
opacity: 0;
transform: translateX(100px) scale(0.8); /* Start off-screen, smaller */
transform-origin: top right; /* For right-aligned notifications */
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); /* Smooth, slightly elastic entry */
position: relative; /* For progress bar */
border: 1px solid rgba(255, 255, 255, 0.2); /* Subtle white border for glass effect */
/* Glow Effect (using pseudo-element for a subtle outer glow based on type) */
&::before { /* Note: This is SCSS/LESS syntax for nesting. For plain CSS, remove &::before and use .ui-notification-wrapper::before */
content: '';
position: absolute;
top: -2px; left: -2px; right: -2px; bottom: -2px;
z-index: -1;
border-radius: inherit; /* Inherit rounded corners */
/* FIX: Using rgba with rgb variables for the glow effect */
background: radial-gradient(circle at center, transparent 0%, transparent 70%, rgba(var(--ui-info-rgb), 0.5) 100%); /* Default to info glow */
background-size: 200% 200%;
opacity: 0.3;
filter: blur(8px); /* Soft glow */
pointer-events: none;
transition: opacity 0.3s ease;
}
}
/* Adjust transform origin for left-aligned notifications */
.ui-notification-container.top-left .ui-notification-wrapper,
.ui-notification-container.bottom-left .ui-notification-wrapper {
transform-origin: top left;
transform: translateX(-100px) scale(0.8);
}
.ui-notification-wrapper.show {
opacity: 1;
transform: translateX(0) scale(1);
}
.ui-notification-wrapper.hide {
opacity: 0;
transform: translateX(100px) scale(0.8); /* Slide out to the right */
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
height: 0; /* Collapse height */
min-height: 0; /* Ensure it collapses */
overflow: hidden;
transition: all 0.4s cubic-bezier(0.55, 0.055, 0.675, 0.19); /* Quicker, sharper exit */
}
.ui-notification-container.top-left .ui-notification-wrapper.hide,
.ui-notification-container.bottom-left .ui-notification-wrapper.hide {
transform: translateX(-100px) scale(0.8); /* Slide out to the left for left positions */
}
/* Icon Animation & Position */
.ui-notification-wrapper > .ui-notification-icon {
margin-right: var(--ui-gap-sm);
position: relative;
top: -2px; /* Slightly raise icon for better vertical alignment with text */
}
/* Micro-animation for icons on show */
.ui-notification-wrapper.show > .ui-notification-icon {
animation: iconBounce 0.6s ease-out;
}
@keyframes iconBounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-3px); }
}
.ui-notification-wrapper > .ui-notification-content {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.ui-notification-wrapper > .ui-notification-content > .ui-notification-title {
font-weight: 600; /* Slightly bolder */
font-size: 1rem; /* Base font size */
line-height: 1.4;
margin-bottom: 4px;
color: var(--ui-primary-text);
}
.ui-notification-wrapper > .ui-notification-content > .ui-notification-message {
font-size: 0.875rem; /* Smaller font for message */
line-height: 1.5;
color: var(--ui-secondary-text);
word-wrap: break-word;
/* For expandable notifications */
max-height: 3em; /* Limit to 2 lines initially (assuming 1.5em line-height) */
overflow: hidden;
text-overflow: ellipsis; /* For non-expandable long messages */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
transition: max-height 0.3s ease-out;
}
.ui-notification-wrapper.expanded .ui-notification-message {
max-height: 150px; /* Expand to show more content */
-webkit-line-clamp: unset;
}
.ui-notification-wrapper .ui-expand-btn {
font-size: 0.8em;
color: var(--ui-info);
cursor: pointer;
text-align: right;
margin-top: 4px;
display: none; /* Hide by default, JS will show if needed */
}
/* Custom Close Button */
.ui-notification-wrapper > .ui-notification-close-btn {
position: absolute;
top: var(--ui-gap-sm);
right: var(--ui-gap-sm);
width: 24px;
height: 24px;
border-radius: 50%; /* Circular button */
background-color: transparent;
border: none;
font-size: 1.5rem; /* Larger 'x' */
color: rgba(0, 0, 0, 0.45);
cursor: pointer;
transition: background-color 0.2s ease, color 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
.ui-notification-wrapper > .ui-notification-close-btn:hover {
background-color: rgba(0, 0, 0, 0.05);
color: rgba(0, 0, 0, 0.85);
}
/* Mini Progress Bar */
.ui-notification-wrapper .ui-progress-bar {
position: absolute;
bottom: 0;
left: 0;
height: 3px; /* Thin progress bar */
width: 0%; /* Will be animated via JS */
background-color: currentColor; /* Inherits color from type */
transition: width linear; /* Animated by JS, this just ensures smooth visual */
opacity: 0.7;
border-radius: 0 0 var(--ui-radius-md) var(--ui-radius-sm); /* Matches notification shape */
}
/* Notification Type Colors */
/* FIX: Use rgba with rgb variables for the glow effect */
.ui-notification-wrapper.success::before { background: radial-gradient(circle at center, transparent 0%, transparent 70%, rgba(var(--ui-success-rgb), 0.5) 100%); }
.ui-notification-wrapper.success .ui-progress-bar { background-color: var(--ui-success); }
.ui-notification-wrapper.success .ui-notification-icon svg { fill: var(--ui-success); }
.ui-notification-wrapper.error::before { background: radial-gradient(circle at center, transparent 0%, transparent 70%, rgba(var(--ui-error-rgb), 0.5) 100%); }
.ui-notification-wrapper.error .ui-progress-bar { background-color: var(--ui-error); }
.ui-notification-wrapper.error .ui-notification-icon svg { fill: var(--ui-error); }
.ui-notification-wrapper.warning::before { background: radial-gradient(circle at center, transparent 0%, transparent 70%, rgba(var(--ui-warning-rgb), 0.5) 100%); }
.ui-notification-wrapper.warning .ui-progress-bar { background-color: var(--ui-warning); }
.ui-notification-wrapper.warning .ui-notification-icon svg { fill: var(--ui-warning); }
.ui-notification-wrapper.info::before { background: radial-gradient(circle at center, transparent 0%, transparent 70%, rgba(var(--ui-info-rgb), 0.5) 100%); }
.ui-notification-wrapper.info .ui-progress-bar { background-color: var(--ui-info); }
.ui-notification-wrapper.info .ui-notification-icon svg { fill: var(--ui-info); }
/* --- Modal Styles --- */
.ui-modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: var(--ui-z-modal-backdrop);
/* Gradient Backdrop */
background: linear-gradient(45deg, var(--ui-bg-dark-overlay), rgba(0, 0, 0, 0.7));
opacity: 0;
transition: opacity 0.3s ease;
}
.ui-modal-backdrop.show {
opacity: 1;
}
.ui-modal-wrapper {
background-color: var(--ui-bg-light);
border-radius: var(--ui-radius-md); /* Softer corners */
box-shadow: var(--ui-shadow-deep); /* More pronounced shadow for depth */
width: 500px; /* Slightly adjusted default width */
max-width: calc(100% - var(--ui-gap-lg) * 2);
max-height: calc(100% - var(--ui-gap-lg) * 2);
display: flex;
flex-direction: column;
overflow: hidden;
/* Float/Depth animation */
transform: translateY(50px) scale(0.95); /* Start slightly off-center and smaller */
opacity: 0;
transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.4s ease-out; /* Smooth entry */
}
.ui-modal-backdrop.show .ui-modal-wrapper {
transform: translateY(0) scale(1);
opacity: 1;
}
.ui-modal-header {
padding: var(--ui-gap-md) var(--ui-gap-lg);
border-bottom: 1px solid var(--ui-border-light);
font-size: 1.25rem; /* Larger header font */
font-weight: 600;
color: var(--ui-primary-text);
display: flex;
justify-content: space-between;
align-items: center;
position: relative; /* For custom header elements if needed */
}
.ui-modal-header .ui-modal-close-btn {
background: none;
border: none;
font-size: 2rem; /* Larger 'x' */
cursor: pointer;
color: rgba(0, 0, 0, 0.45);
transition: color 0.2s ease, transform 0.2s ease;
padding: 0;
line-height: 1;
border-radius: 50%; /* Circular hit area */
width: 30px; height: 30px;
display: flex; justify-content: center; align-items: center;
}
.ui-modal-header .ui-modal-close-btn:hover {
color: var(--ui-error); /* Red on hover */
transform: rotate(90deg); /* Rotate on hover */
}
.ui-modal-body {
padding: var(--ui-gap-lg);
font-size: 0.95rem;
line-height: 1.6;
word-wrap: break-word;
flex-grow: 1;
overflow-y: auto;
color: var(--ui-secondary-text);
}
.ui-modal-footer {
padding: var(--ui-gap-sm) var(--ui-gap-lg);
border-top: 1px solid var(--ui-border-light);
display: flex;
justify-content: flex-end;
gap: var(--ui-gap-sm);
background-color: rgba(255, 255, 255, 0.8); /* Slightly less transparent footer */
}
.ui-modal-footer button {
padding: 8px 20px;
font-size: 0.9rem;
border-radius: var(--ui-radius-sm);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
font-weight: 500;
}
.ui-modal-footer .modal-ok-btn {
background-color: var(--ui-info);
color: var(--ui-light-text);
border: 1px solid var(--ui-info);
/* FIX: Using rgba with rgb variables for box-shadow */
box-shadow: 0 2px 4px rgba(var(--ui-info-rgb), 0.3);
}
.ui-modal-footer .modal-ok-btn:hover {
background-color: #1a78d0; /* Darker blue */
border-color: #1a78d0;
/* FIX: Using rgba with rgb variables for box-shadow */
box-shadow: 0 3px 6px rgba(var(--ui-info-rgb), 0.4);
transform: translateY(-1px); /* Subtle lift */
}
.ui-modal-footer .modal-cancel-btn {
background-color: transparent;
color: var(--ui-primary-text);
border: 1px solid var(--ui-border-light);
}
.ui-modal-footer .modal-cancel-btn:hover {
color: var(--ui-info);
border-color: var(--ui-info);
/* FIX: Using rgba with rgb variables for background-color */
background-color: rgba(var(--ui-info-rgb), 0.05); /* Light blue background on hover */
}
/* --- Alert Styles --- */
.ui-alert-wrapper {
position: relative;
padding: var(--ui-gap-md);
border: 1px solid transparent; /* Default transparent border */
border-radius: var(--ui-radius-md); /* Softer corners for alert */
display: flex;
align-items: flex-start; /* Align content to the top */
font-size: 0.95rem;
line-height: 1.5;
margin-bottom: var(--ui-gap-md);
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
opacity: 1;
box-sizing: border-box;
/* Subtle background pattern/texture (example) */
background-image: radial-gradient(circle at 100% 100%, rgba(255,255,255,0.05) 1px, transparent 1px);
background-size: 8px 8px;
background-position: 0 0;
}
.ui-alert-wrapper.hide {
opacity: 0;
padding-top: 0;
padding-bottom: 0;
margin-top: 0;
margin-bottom: 0;
height: 0;
min-height: 0;
overflow: hidden;
}
.ui-alert-wrapper .ui-alert-icon {
margin-right: var(--ui-gap-sm);
padding-top: 2px;
}
.ui-alert-wrapper .ui-alert-content {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.ui-alert-wrapper .ui-alert-content .ui-alert-title {
font-weight: 600;
margin-bottom: 4px;
color: var(--ui-primary-text);
}
.ui-alert-wrapper .ui-alert-content .ui-alert-message {
color: var(--ui-secondary-text);
/* For expandable alerts */
max-height: 3em; /* Limit to 2 lines initially */
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
transition: max-height 0.3s ease-out;
}
.ui-alert-wrapper.expanded .ui-alert-message {
max-height: 150px; /* Expand to show more content */
-webkit-line-clamp: unset;
}
.ui-alert-wrapper .ui-expand-btn {
font-size: 0.8em;
color: var(--ui-info);
cursor: pointer;
text-align: right;
margin-top: 4px;
display: none; /* Hide by default, JS will show if needed */
}
/* Custom Close Button for Alert */
.ui-alert-wrapper .ui-alert-close-btn {
background: none;
border: none;
font-size: 1.2rem;
cursor: pointer;
color: rgba(0, 0, 0, 0.45);
transition: color 0.2s ease, transform 0.2s ease;
padding: 0;
line-height: 1;
position: absolute;
top: var(--ui-gap-sm);
right: var(--ui-gap-sm);
border-radius: 50%;
width: 24px; height: 24px;
display: flex; justify-content: center; align-items: center;
}
.ui-alert-wrapper .ui-alert-close-btn:hover {
color: var(--ui-error);
transform: rotate(90deg);
}
/* Alert Type Colors and Backgrounds */
/* FIX: Using rgba with rgb variables for background-color */
.ui-alert-wrapper.success {
background-color: rgba(var(--ui-success-rgb), 0.08); /* Light green tint */
border-color: var(--ui-success);
color: var(--ui-success);
}
.ui-alert-wrapper.success .ui-alert-icon svg { fill: var(--ui-success); }
.ui-alert-wrapper.error {
background-color: rgba(var(--ui-error-rgb), 0.08);
border-color: var(--ui-error);
color: var(--ui-error);
}
.ui-alert-wrapper.error .ui-alert-icon svg { fill: var(--ui-error); }
.ui-alert-wrapper.warning {
background-color: rgba(var(--ui-warning-rgb), 0.08);
border-color: var(--ui-warning);
color: var(--ui-warning);
}
.ui-alert-wrapper.warning .ui-alert-icon svg { fill: var(--ui-warning); }
.ui-alert-wrapper.info {
background-color: rgba(var(--ui-info-rgb), 0.08);
border-color: var(--ui-info);
color: var(--ui-info);
}
.ui-alert-wrapper.info .ui-alert-icon svg { fill: var(--ui-info); }
/* Hide icon for alerts if showIcon is false */
.ui-alert-wrapper:not(.show-icon) .ui-alert-icon {
display: none;
}
/* Adjust spacing if icon is not shown */
.ui-alert-wrapper:not(.show-icon) .ui-alert-content {
margin-left: -12px; /* Pull content back if no icon */
}
/* General button styling */
.ui-modal-footer button,
.ui-alert-wrapper .ui-expand-btn {
/* Basic button styles */
font-family: var(--ui-font-family);
}