You've already forked php-flasher
mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-04-05 12:32:55 +01:00
add crystal theme
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @file PHPFlasher Crystal Theme Styles
|
||||
* @description CSS styling for the elegant Crystal theme
|
||||
* @author yoeunes
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHPFlasher - Crystal Theme
|
||||
*
|
||||
* A clean, elegant notification theme with subtle animations
|
||||
* and a focus on simplicity and readability.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Theme-specific variables
|
||||
* Define the color palette and styling attributes for Crystal theme
|
||||
*/
|
||||
.fl-crystal {
|
||||
/* Base colors for light and dark modes */
|
||||
--crystal-bg-light: #ffffff; /* Pure white background in light mode */
|
||||
--crystal-bg-dark: rgba(30, 30, 30, 0.95); /* Near-black in dark mode */
|
||||
--crystal-text-light: #2c3e50; /* Deep blue-gray text for light mode */
|
||||
--crystal-text-dark: rgba(255, 255, 255, 0.95); /* Off-white text for dark mode */
|
||||
|
||||
/* Shadow colors for animations and effects */
|
||||
--crystal-shadow: rgba(0, 0, 0, 0.08); /* Subtle shadow for light mode */
|
||||
--crystal-shadow-dark: rgba(0, 0, 0, 0.25); /* Stronger shadow for dark mode */
|
||||
}
|
||||
|
||||
/**
|
||||
* Entrance animation
|
||||
* Slides in from the top with a fade effect
|
||||
*/
|
||||
@keyframes crystalIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px); /* Start above final position */
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0); /* End at natural position */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hover animation
|
||||
* Creates a subtle pulsing shadow effect
|
||||
*/
|
||||
@keyframes crystalPulse {
|
||||
0% {
|
||||
box-shadow: 0 2px 8px var(--crystal-shadow); /* Start with normal shadow */
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 4px 12px var(--crystal-shadow); /* Peak with larger shadow */
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 2px 8px var(--crystal-shadow); /* Return to normal shadow */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Crystal theme styling
|
||||
*/
|
||||
.fl-crystal {
|
||||
position: relative;
|
||||
background: var(--crystal-bg-light, var(--fl-bg-light));
|
||||
margin: 0 0 1rem 0; /* Space between stacked notifications */
|
||||
font-family: var(--fl-font), serif;
|
||||
animation: crystalIn 0.3s ease-out; /* Entrance animation */
|
||||
box-shadow: 0 2px 8px var(--crystal-shadow); /* Default shadow */
|
||||
max-width: 380px; /* Limit width for readability */
|
||||
border-radius: var(--fl-border-radius, 4px); /* Rounded corners */
|
||||
will-change: transform, opacity; /* Optimize for animation performance */
|
||||
transition: box-shadow 0.3s ease; /* Smooth transition for shadow changes */
|
||||
|
||||
/**
|
||||
* Hover effect
|
||||
* Applies pulsing animation when notification is hovered
|
||||
*/
|
||||
&:hover {
|
||||
animation: crystalPulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove margin from last notification in a stack
|
||||
*/
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content container
|
||||
* Holds the message and close button
|
||||
*/
|
||||
.fl-content {
|
||||
padding: 1rem 2.5rem 1rem 1rem; /* Space for close button on right */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem; /* Space between elements */
|
||||
}
|
||||
|
||||
/**
|
||||
* Text container
|
||||
* Holds the message paragraph
|
||||
*/
|
||||
.fl-text {
|
||||
flex: 1; /* Take available space */
|
||||
}
|
||||
|
||||
/**
|
||||
* Message styling
|
||||
* The primary notification text
|
||||
*/
|
||||
.fl-message {
|
||||
margin: 0;
|
||||
font-size: 0.9375rem; /* 15px at default font size */
|
||||
line-height: 1.4; /* Improved readability */
|
||||
color: var(--crystal-text-light, var(--fl-text-light));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close button styling
|
||||
* Positioned absolutely to maintain consistent layout
|
||||
*/
|
||||
.fl-close {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%; /* Center vertically */
|
||||
transform: translateY(-50%); /* Fine-tune vertical centering */
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1;
|
||||
padding: 0.25rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.5; /* Subtle appearance by default */
|
||||
transition: all 0.2s ease;
|
||||
color: currentColor; /* Inherit color from parent */
|
||||
touch-action: manipulation; /* Better touch behavior */
|
||||
|
||||
&:hover, &:focus {
|
||||
opacity: 1; /* Full opacity on interaction */
|
||||
transform: translateY(-50%) scale(1.1); /* Slight grow effect */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress bar container
|
||||
* Holds the animated progress indicator
|
||||
*/
|
||||
.fl-progress-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
/**
|
||||
* Progress indicator
|
||||
* Animated by JavaScript to show remaining time
|
||||
*/
|
||||
.fl-progress {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform-origin: left center; /* Animation starts from left */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-specific styling
|
||||
* Each notification type gets its own text color
|
||||
*/
|
||||
&.fl-success {
|
||||
color: var(--success-color, var(--fl-success));
|
||||
.fl-message { color: var(--success-color, var(--fl-success)); }
|
||||
}
|
||||
|
||||
&.fl-error {
|
||||
color: var(--error-color, var(--fl-error));
|
||||
.fl-message { color: var(--error-color, var(--fl-error)); }
|
||||
}
|
||||
|
||||
&.fl-warning {
|
||||
color: var(--warning-color, var(--fl-warning));
|
||||
.fl-message { color: var(--warning-color, var(--fl-warning)); }
|
||||
}
|
||||
|
||||
&.fl-info {
|
||||
color: var(--info-color, var(--fl-info));
|
||||
.fl-message { color: var(--info-color, var(--fl-info)); }
|
||||
}
|
||||
|
||||
/**
|
||||
* RTL support
|
||||
* Right-to-left language direction support
|
||||
*/
|
||||
&.fl-rtl {
|
||||
direction: rtl;
|
||||
|
||||
.fl-content {
|
||||
padding: 1rem 1rem 1rem 2.5rem; /* Swap padding for close button on left */
|
||||
}
|
||||
|
||||
.fl-close {
|
||||
right: auto;
|
||||
left: 0.75rem; /* Move close button to left side */
|
||||
}
|
||||
|
||||
.fl-progress .fl-progress {
|
||||
transform-origin: right center; /* Animation starts from right */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessibility
|
||||
* Respects reduced motion preferences
|
||||
*/
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none; /* Disable entrance animation */
|
||||
|
||||
&:hover {
|
||||
animation: none; /* Disable pulse animation */
|
||||
box-shadow: 0 2px 8px var(--crystal-shadow); /* Keep default shadow */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dark mode support
|
||||
* Different styling when in dark mode
|
||||
*/
|
||||
body.fl-dark .fl-crystal,
|
||||
html.fl-dark .fl-crystal,
|
||||
.fl-crystal.fl-auto-dark {
|
||||
background-color: var(--crystal-bg-dark, var(--fl-bg-dark));
|
||||
box-shadow: 0 2px 8px var(--crystal-shadow-dark);
|
||||
|
||||
.fl-message {
|
||||
color: var(--crystal-text-dark, var(--fl-text-dark));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
animation: none; /* Disable pulse in dark mode */
|
||||
box-shadow: 0 4px 16px var(--crystal-shadow-dark); /* Use static enhanced shadow instead */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file PHPFlasher Crystal Theme Implementation
|
||||
* @description Clean, elegant notification theme with subtle animations
|
||||
* @author yoeunes
|
||||
*/
|
||||
import './crystal.scss'
|
||||
import type { Envelope } from '../../types'
|
||||
|
||||
/**
|
||||
* Crystal notification theme for PHPFlasher.
|
||||
*
|
||||
* The Crystal theme provides a clean, elegant design with distinct features:
|
||||
* - Monochromatic design with colored text for each notification type
|
||||
* - Subtle entrance animation
|
||||
* - Gentle pulsing shadow effect on hover
|
||||
* - Minimalist structure that emphasizes message content
|
||||
* - Smooth transitions and animations
|
||||
* - Accessible structure and interactions
|
||||
*
|
||||
* This theme aims to be understated yet elegant, providing notifications
|
||||
* that are noticeable without being distracting.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import flasher from '@flasher/flasher';
|
||||
* import { crystalTheme } from '@flasher/flasher/themes';
|
||||
*
|
||||
* // Register the theme (if not already registered)
|
||||
* flasher.addTheme('crystal', crystalTheme);
|
||||
*
|
||||
* // Use the theme
|
||||
* flasher.use('theme.crystal').success('Document saved successfully');
|
||||
* ```
|
||||
*/
|
||||
export const crystalTheme = {
|
||||
/**
|
||||
* Renders a notification envelope as HTML.
|
||||
*
|
||||
* Creates a clean, elegant notification with minimal elements:
|
||||
* - Message text
|
||||
* - Close button
|
||||
* - Progress indicator
|
||||
*
|
||||
* The Crystal theme uses colored text rather than backgrounds to indicate
|
||||
* notification type, creating a more subtle visual distinction.
|
||||
*
|
||||
* @param envelope - The notification envelope to render
|
||||
* @returns HTML string representation of the notification
|
||||
*/
|
||||
render: (envelope: Envelope): string => {
|
||||
const { type, message } = envelope
|
||||
|
||||
// Set appropriate ARIA roles based on notification type
|
||||
const isAlert = type === 'error' || type === 'warning'
|
||||
const role = isAlert ? 'alert' : 'status'
|
||||
const ariaLive = isAlert ? 'assertive' : 'polite'
|
||||
|
||||
return `
|
||||
<div class="fl-crystal fl-${type}" role="${role}" aria-live="${ariaLive}" aria-atomic="true">
|
||||
<div class="fl-content">
|
||||
<div class="fl-text">
|
||||
<p class="fl-message">${message}</p>
|
||||
</div>
|
||||
<button class="fl-close" aria-label="Close ${type} message">×</button>
|
||||
</div>
|
||||
<div class="fl-progress-bar">
|
||||
<div class="fl-progress"></div>
|
||||
</div>
|
||||
</div>`
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file PHPFlasher Crystal Theme Registration
|
||||
* @description Registers the Crystal theme with PHPFlasher
|
||||
* @author yoeunes
|
||||
*/
|
||||
import flasher from '../../index'
|
||||
import { crystalTheme } from './crystal'
|
||||
|
||||
/**
|
||||
* Register the Crystal theme.
|
||||
*
|
||||
* This theme provides an elegant notification style with subtle animations
|
||||
* and a clean, minimal design.
|
||||
*
|
||||
* The registration makes the theme available under the name 'crystal'.
|
||||
*
|
||||
* The Crystal theme can be used by calling:
|
||||
* ```typescript
|
||||
* flasher.use('theme.crystal').success('Your document has been saved');
|
||||
* ```
|
||||
*
|
||||
* Key features:
|
||||
* - Clean, white background with colored text
|
||||
* - Subtle pulsing shadow effect on hover
|
||||
* - Smooth entrance animation
|
||||
* - Progress indicator
|
||||
* - Minimalist design that focuses on the message
|
||||
*/
|
||||
flasher.addTheme('crystal', crystalTheme)
|
||||
Reference in New Issue
Block a user