From 7fafa513a2bf9580af22e2f31187a4c10a852e30 Mon Sep 17 00:00:00 2001 From: Younes ENNAJI Date: Sat, 8 Mar 2025 11:41:35 +0000 Subject: [PATCH] refactor flasher theme --- .../assets/themes/flasher/flasher.scss | 139 ++++++++++++------ .../assets/themes/flasher/flasher.ts | 64 ++++++++ .../Resources/assets/themes/flasher/index.ts | 43 +++--- 3 files changed, 176 insertions(+), 70 deletions(-) create mode 100644 src/Prime/Resources/assets/themes/flasher/flasher.ts diff --git a/src/Prime/Resources/assets/themes/flasher/flasher.scss b/src/Prime/Resources/assets/themes/flasher/flasher.scss index b7eda25c..30d816c9 100644 --- a/src/Prime/Resources/assets/themes/flasher/flasher.scss +++ b/src/Prime/Resources/assets/themes/flasher/flasher.scss @@ -1,22 +1,59 @@ -@use "sass:color"; +/** + * @file PHPFlasher Default Theme + * @description Classic bordered notification style with colorful accents + * @author yoeunes + */ -body.fl-dark .fl-flasher, -html.fl-dark .fl-flasher { - --background-color: var(--dark-background-color); - --text-color: var(--dark-text-color); +@use "sass:color"; +@use '../mixins' as *; + +/** + * Animation for flasher theme + * Slides in from the left with a fade effect + */ +@keyframes flasherIn { + from { + opacity: 0; + transform: translateX(-10px); + } + to { + opacity: 1; + transform: translateX(0); + } } + +/** + * Base theme styling + * The default PHPFlasher notification appearance + */ .fl-flasher { + /* Base appearance */ line-height: 1.5; - background-color: var(--background-color); - color: var(--text-color); + background-color: var(--background-color, var(--fl-bg-light)); + color: var(--text-color, var(--fl-text-light)); word-break: break-word; padding: 0.75em; margin: 0.75em 0; position: relative; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); border-bottom: none; + font-family: var(--fl-font), serif; + will-change: transform, opacity; + animation: flasherIn 0.3s ease-out; + transition: transform 0.2s ease; + /* Subtle lift effect on hover */ + &:hover { + transform: translateY(-2px); + } + + /* Remove margin from last notification in a stack */ + &:last-child { + margin-bottom: 0; + } + + /* Border radius handling for RTL and LTR */ &.fl-rtl { border-radius: 0 0.375em 0.375em 0; } @@ -25,15 +62,18 @@ html.fl-dark .fl-flasher { border-radius: 0.375em 0 0 0.375em; } + /* Content layout */ .fl-content { display: flex; align-items: center; } + /* Icon sizing */ .fl-icon { font-size: 2.5em; } + /* Text styling */ .fl-title, .fl-message { display: block; @@ -44,7 +84,7 @@ html.fl-dark .fl-flasher { .fl-title { font-size: 1em; - font-weight: bold; + font-weight: 600; } .fl-message { @@ -52,52 +92,59 @@ html.fl-dark .fl-flasher { font-size: 0.875em; } - .fl-close { - cursor: pointer; - background-color: transparent; - border: none; - position: absolute; - top: 1rem; - right: 0.5rem; - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.5rem; - margin: -0.5rem; - font-size: 25px; - line-height: 0; - color: #a8aaab; - transition: color 0.3s ease, transform 0.3s ease; + /* Apply standard mixins for common functionality */ + @include close-button; + @include rtl-support; - &:hover { - color: color.adjust(#a8aaab, $lightness: -10%); - transform: scale(1.1); + /* Type-specific styling */ + @include variants using($type) { + /* Colored left border */ + border-left: 0.8em solid var(--#{$type}-color, var(--fl-#{$type})); + + /* RTL border handling */ + &.fl-rtl { + border-right: 0.8em solid var(--#{$type}-color, var(--fl-#{$type})); + border-left: none; + } + + &:not(.fl-rtl) { + border-right: none; + border-left: 0.8em solid var(--#{$type}-color, var(--fl-#{$type})); + } + + /* Type-colored title and close button */ + .fl-title { + color: var(--#{$type}-color, var(--fl-#{$type})); + } + + .fl-close { + color: var(--#{$type}-color, var(--fl-#{$type})); + + &:hover, &:focus { + transform: translateY(-50%) scale(1.1); + } } } - &.fl-rtl .fl-close { - right: auto; - left: 0.5rem; + /* Progress bar styling */ + @include progress-bar; + + /* Dark mode support */ + @include dark-mode { + background-color: var(--dark-background-color, var(--fl-bg-dark)); + color: var(--dark-text-color, var(--fl-text-dark)); } + /* Accessibility */ + @media (prefers-reduced-motion: reduce) { + animation: none; - @each $type in success, info, warning, error { - &.fl-#{$type} { - border-left: 0.8em solid var(--#{$type}-color); + &:hover { + transform: none; + } - &.fl-rtl { - border-right: 0.8em solid var(--#{$type}-color); - border-left: none; - } - - &:not(.fl-rtl) { - border-right: none; - border-left: 0.8em solid var(--#{$type}-color); - } - - .fl-title { - color: var(--#{$type}-color); - } + .fl-close:hover, .fl-close:focus { + transform: translateY(-50%); } } } diff --git a/src/Prime/Resources/assets/themes/flasher/flasher.ts b/src/Prime/Resources/assets/themes/flasher/flasher.ts new file mode 100644 index 00000000..aed21102 --- /dev/null +++ b/src/Prime/Resources/assets/themes/flasher/flasher.ts @@ -0,0 +1,64 @@ +/** + * @file PHPFlasher Default Theme + * @description Theme implementation for the default PHPFlasher notification style + * @author yoeunes + */ +import './flasher.scss' +import type { Envelope } from '../../types' + +/** + * The default PHPFlasher theme. + * + * This theme provides a classic bordered notification style with: + * - Colored left border based on notification type + * - Icon representing the notification type + * - Title and message content + * - Close button + * - Progress bar for auto-dismiss + * + * @example + * ```typescript + * import flasher from '@flasher/flasher'; + * import { flasherTheme } from '@flasher/flasher/themes'; + * + * // Register the theme if not already registered + * flasher.addTheme('custom-name', flasherTheme); + * + * // Use the theme + * flasher.use('theme.custom-name').success('Operation completed'); + * ``` + */ +export const flasherTheme = { + /** + * Renders an envelope as HTML. + * + * @param envelope - The notification envelope to render + * @returns HTML string representation of the notification + */ + render: (envelope: Envelope): string => { + const { type, title, 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' + + // Use provided title or capitalize the notification type + const displayTitle = title || type.charAt(0).toUpperCase() + type.slice(1) + + return ` +
+
+
+
+ ${displayTitle} + ${message} +
+ +
+ + + +
` + }, +} diff --git a/src/Prime/Resources/assets/themes/flasher/index.ts b/src/Prime/Resources/assets/themes/flasher/index.ts index d8ab6559..00323ca2 100644 --- a/src/Prime/Resources/assets/themes/flasher/index.ts +++ b/src/Prime/Resources/assets/themes/flasher/index.ts @@ -1,25 +1,20 @@ -import './flasher.scss' +/** + * @file PHPFlasher Default Theme Registration + * @description Registers the default theme with PHPFlasher + * @author yoeunes + */ +import flasher from '../../index' +import { flasherTheme } from './flasher' -import type { Envelope } from '../../types' - -export const flasherTheme = { - render: (envelope: Envelope): string => { - const { type, title, message } = envelope - const isAlert = type === 'error' || type === 'warning' - const role = isAlert ? 'alert' : 'status' - const ariaLive = isAlert ? 'assertive' : 'polite' - - return ` -
-
-
-
- ${title} - ${message} -
- -
- -
` - }, -} +/** + * Register the default "flasher" theme. + * + * This theme is automatically registered when PHPFlasher is initialized + * and is used as the default theme when no specific theme is requested. + * + * The flasher theme is used whenever: + * - You call flasher.success(), flasher.error(), etc. directly + * - You use flasher.use('flasher') explicitly + * - You use flasher.use('theme.flasher') explicitly + */ +flasher.addTheme('flasher', flasherTheme)