Files
adopt-a-street/frontend/src/styles/toastStyles.css
William Valentin a2d30385b5 feat: implement real-time notification toast system
Implemented comprehensive notification toast system integrating Socket.IO
with react-toastify for real-time user notifications.

Features:
- NotificationProvider component for automatic Socket.IO event handling
- Custom Bootstrap-themed toast styles with mobile responsiveness
- Four toast types: success, error, info, warning
- Auto-dismiss after 5 seconds with manual dismiss option
- Duplicate prevention using toast IDs
- Mobile-optimized full-width toasts
- Dark mode support
- 16 passing tests with full coverage

Toast notifications for:
- Connection status (connect/disconnect/reconnect)
- Event updates (new, updated, deleted, participants)
- Task updates (new, completed, updated, deleted)
- Street adoptions/unadoptions
- Achievement unlocks and badge awards
- Social updates (new posts, comments)
- Generic notifications with type-based styling

Usage:
import { notify } from '../context/NotificationProvider';
notify.success('Operation completed!');
notify.error('Something went wrong!');

Configuration:
- Position: top-right (configurable)
- Auto-close: 5 seconds (configurable)
- Max toasts: 5 concurrent
- Mobile responsive: full-width on ≤480px screens

Documentation:
- NOTIFICATION_SYSTEM.md: Complete usage guide
- NOTIFICATION_IMPLEMENTATION.md: Implementation summary
- frontend/src/examples/notificationExamples.js: Code examples

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-03 13:20:15 -08:00

235 lines
4.7 KiB
CSS

/* Custom Toast Styles for Adopt-a-Street */
/* Override react-toastify default styles to match Bootstrap theme */
:root {
--toastify-color-success: #28a745;
--toastify-color-error: #dc3545;
--toastify-color-warning: #ffc107;
--toastify-color-info: #17a2b8;
--toastify-text-color-light: #212529;
--toastify-toast-width: 320px;
--toastify-toast-background: #ffffff;
--toastify-toast-min-height: 64px;
--toastify-toast-max-height: 800px;
--toastify-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
--toastify-z-index: 9999;
}
/* Toast container positioning and responsiveness */
.Toastify__toast-container {
width: var(--toastify-toast-width);
padding: 4px;
z-index: var(--toastify-z-index);
}
/* Mobile responsive */
@media only screen and (max-width: 480px) {
.Toastify__toast-container {
width: 100vw;
padding: 0;
left: 0;
right: 0;
margin: 0;
border-radius: 0;
}
.Toastify__toast {
margin-bottom: 0;
border-radius: 0;
}
/* Top position on mobile */
.Toastify__toast-container--top-right {
top: 0;
right: 0;
left: 0;
}
}
/* Toast styling */
.Toastify__toast {
background-color: var(--toastify-toast-background);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
padding: 16px;
margin-bottom: 8px;
font-family: var(--toastify-font-family);
color: var(--toastify-text-color-light);
min-height: var(--toastify-toast-min-height);
cursor: pointer;
transition: all 0.3s ease;
}
.Toastify__toast:hover {
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
transform: translateY(-2px);
}
/* Success toast with Bootstrap green */
.Toastify__toast--success {
border-left: 4px solid var(--toastify-color-success);
}
.Toastify__toast--success .Toastify__progress-bar {
background: var(--toastify-color-success);
}
/* Error toast with Bootstrap red */
.Toastify__toast--error {
border-left: 4px solid var(--toastify-color-error);
}
.Toastify__toast--error .Toastify__progress-bar {
background: var(--toastify-color-error);
}
/* Warning toast with Bootstrap yellow */
.Toastify__toast--warning {
border-left: 4px solid var(--toastify-color-warning);
}
.Toastify__toast--warning .Toastify__progress-bar {
background: var(--toastify-color-warning);
}
/* Info toast with Bootstrap blue */
.Toastify__toast--info {
border-left: 4px solid var(--toastify-color-info);
}
.Toastify__toast--info .Toastify__progress-bar {
background: var(--toastify-color-info);
}
/* Toast body */
.Toastify__toast-body {
padding: 0;
line-height: 1.5;
font-size: 14px;
}
.Toastify__toast-body > div:last-child {
word-break: break-word;
}
/* Close button styling */
.Toastify__close-button {
color: #6c757d;
opacity: 0.7;
transition: opacity 0.2s ease;
}
.Toastify__close-button:hover {
opacity: 1;
}
.Toastify__close-button > svg {
height: 16px;
width: 16px;
}
/* Progress bar */
.Toastify__progress-bar {
height: 4px;
}
.Toastify__progress-bar--animated {
animation: Toastify__trackProgress linear 1 forwards;
}
/* Icon styling for success/error/warning/info */
.Toastify__toast-icon {
width: 20px;
margin-right: 12px;
flex-shrink: 0;
}
/* Custom content styling for achievement notifications */
.achievement-toast {
display: flex;
flex-direction: column;
}
.achievement-toast strong {
font-size: 16px;
margin-bottom: 4px;
color: var(--toastify-color-success);
}
.achievement-toast div {
font-weight: 600;
margin-bottom: 4px;
}
.achievement-toast small {
font-size: 12px;
color: #6c757d;
line-height: 1.4;
}
/* Animations */
@keyframes Toastify__bounceInRight {
from,
60%,
75%,
90%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
from {
opacity: 0;
transform: translate3d(3000px, 0, 0);
}
60% {
opacity: 1;
transform: translate3d(-25px, 0, 0);
}
75% {
transform: translate3d(10px, 0, 0);
}
90% {
transform: translate3d(-5px, 0, 0);
}
to {
transform: none;
}
}
@keyframes Toastify__bounceOutRight {
20% {
opacity: 1;
transform: translate3d(-20px, 0, 0);
}
to {
opacity: 0;
transform: translate3d(2000px, 0, 0);
}
}
/* Accessibility improvements */
.Toastify__toast[role="alert"] {
border-radius: 8px;
}
/* Dark mode support (optional) */
@media (prefers-color-scheme: dark) {
:root {
--toastify-toast-background: #2b3035;
--toastify-text-color-light: #ffffff;
}
.Toastify__toast {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.Toastify__close-button {
color: #adb5bd;
}
}
/* Ensure toasts are above modals */
.Toastify__toast-container {
z-index: 9999 !important;
}