UNPKG

notify2t

Version:

A versatile UI notification, alert, and modal library with unique Ant Design inspired look.

533 lines (472 loc) 18.4 kB
/* --- 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); }