From 48a601f58d1e362f7b2c41afb5c75f3c6ff8bfb0 Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Sun, 27 Apr 2025 08:21:30 -0500 Subject: [PATCH] wip: ajax notifications w/ php-flasher --- .env.dist | 1 + .../controllers/download_button_controller.js | 6 +- build.xml | 1 + composer.json | 1 + composer.lock | 137 +++++++++++++++++- config/bundles.php | 1 + config/packages/flasher.yaml | 48 ++++++ importmap.php | 3 + public/vendor/flasher/flasher.min.css | 2 + public/vendor/flasher/flasher.min.js | 1 + public/vendor/flasher/manifest.json | 4 + symfony.lock | 3 + 12 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 config/packages/flasher.yaml create mode 100644 public/vendor/flasher/flasher.min.css create mode 100644 public/vendor/flasher/flasher.min.js create mode 100644 public/vendor/flasher/manifest.json diff --git a/.env.dist b/.env.dist index a020e84..2142be1 100644 --- a/.env.dist +++ b/.env.dist @@ -1,3 +1,4 @@ +APP_SECRET="%%app_secret%%" DATABASE_URL="%%db_url%%" DOWNLOAD_DIR=%%download_dir%% REAL_DEBRID_KEY="%%rd_key%%" diff --git a/assets/controllers/download_button_controller.js b/assets/controllers/download_button_controller.js index 7459173..4344a9e 100644 --- a/assets/controllers/download_button_controller.js +++ b/assets/controllers/download_button_controller.js @@ -1,5 +1,5 @@ import { Controller } from '@hotwired/stimulus'; - +import flasher from '@flasher/flasher' /* * The following line makes this controller "lazy": it won't be downloaded until needed * See https://github.com/symfony/stimulus-bridge#lazy-controllers @@ -31,7 +31,7 @@ export default class extends Controller { }) .then(res => res.json()) .then(json => { - console.log(json) - }) + flasher.success(json.message); + }) } } diff --git a/build.xml b/build.xml index e52569f..c4f2c0e 100644 --- a/build.xml +++ b/build.xml @@ -24,6 +24,7 @@ + diff --git a/composer.json b/composer.json index f3e544a..db8032a 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "nihilarr/parse-torrent-name": "^0.0.1", "nyholm/psr7": "*", "p3k/emoji-detector": "^1.2", + "php-flasher/flasher-symfony": "^2.1", "php-tmdb/api": "^4.1", "symfony/asset": "7.2.*", "symfony/console": "7.2.*", diff --git a/composer.lock b/composer.lock index 2d4799d..2766ddc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "09d927397449bd08c7c2b96e35d2bd60", + "content-hash": "02f1ff0023fc6fb23a0307520495e75c", "packages": [ { "name": "1tomany/data-uri", @@ -1780,6 +1780,141 @@ }, "time": "2024-02-19T18:29:05+00:00" }, + { + "name": "php-flasher/flasher", + "version": "v2.1.6", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher.git", + "reference": "054a209515d2eb1bb72467023d8614a29b5d2e60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher/zipball/054a209515d2eb1bb72467023d8614a29b5d2e60", + "reference": "054a209515d2eb1bb72467023d8614a29b5d2e60", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "files": [ + "functions.php", + "helpers.php" + ], + "psr-4": { + "Flasher\\Prime\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes ENNAJI", + "email": "younes.ennaji.pro@gmail.com", + "homepage": "https://www.linkedin.com/in/younes--ennaji/", + "role": "Developer" + } + ], + "description": "The foundational PHP library for PHPFlasher, enabling the creation of framework-agnostic flash notifications. Ideal for building custom integrations or for use in PHP projects.", + "homepage": "https://php-flasher.io", + "keywords": [ + "custom-integrations", + "flash-notifications", + "flasher-core", + "framework-agnostic", + "open-source", + "php" + ], + "support": { + "issues": "https://github.com/php-flasher/php-flasher/issues", + "source": "https://github.com/php-flasher/php-flasher" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://github.com/yoeunes", + "type": "github" + } + ], + "time": "2025-02-21T20:05:00+00:00" + }, + { + "name": "php-flasher/flasher-symfony", + "version": "v2.1.6", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher-symfony.git", + "reference": "14bd1ba6bbd1184bde0300a5b02455e886845cea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher-symfony/zipball/14bd1ba6bbd1184bde0300a5b02455e886845cea", + "reference": "14bd1ba6bbd1184bde0300a5b02455e886845cea", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "php-flasher/flasher": "^2.1.6", + "symfony/config": "^7.0", + "symfony/console": "^7.0", + "symfony/dependency-injection": "^7.0", + "symfony/http-kernel": "^7.0" + }, + "suggest": { + "symfony/translation": "To translate flash messages, title and presets", + "symfony/ux-twig-component": "To utilize and interact with flash messages components in Twig templates" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Flasher\\Symfony\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes ENNAJI", + "email": "younes.ennaji.pro@gmail.com", + "homepage": "https://www.linkedin.com/in/younes--ennaji/", + "role": "Developer" + } + ], + "description": "Integrate flash notifications into Symfony projects effortlessly with PHPFlasher. Improve user experience and application feedback loops easily.", + "homepage": "https://php-flasher.io", + "keywords": [ + "flash-notifications", + "open-source", + "php", + "phpflasher", + "symfony", + "user-feedback" + ], + "support": { + "issues": "https://github.com/php-flasher/php-flasher/issues", + "source": "https://github.com/php-flasher/php-flasher" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://github.com/yoeunes", + "type": "github" + } + ], + "time": "2025-02-21T20:05:00+00:00" + }, { "name": "php-http/discovery", "version": "1.20.0", diff --git a/config/bundles.php b/config/bundles.php index 2adc20d..3e1c567 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -14,4 +14,5 @@ return [ Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true], + Flasher\Symfony\FlasherSymfonyBundle::class => ['all' => true], ]; diff --git a/config/packages/flasher.yaml b/config/packages/flasher.yaml new file mode 100644 index 0000000..1f472bc --- /dev/null +++ b/config/packages/flasher.yaml @@ -0,0 +1,48 @@ +flasher: + # Default notification library (e.g., 'flasher', 'toastr', 'noty', 'notyf', 'sweetalert') + default: flasher + + # Path to the main PHPFlasher JavaScript file + main_script: '/vendor/flasher/flasher.min.js' + + # List of CSS files to style your notifications + styles: + - '/vendor/flasher/flasher.min.css' + + # Set global options for all notifications (optional) + # options: + # # Time in milliseconds before the notification disappears + # timeout: 5000 + # # Where the notification appears on the screen + # position: 'top-right' + + # Automatically inject JavaScript and CSS assets into your HTML pages + inject_assets: true + + # Enable message translation using Symfony's translation service + translate: true + + # URL patterns to exclude from asset injection and flash_bag conversion + excluded_paths: + - '/^\/_profiler/' + - '/^\/_fragment/' + + # Map Symfony flash message keys to notification types + flash_bag: + success: ['success'] + error: ['error', 'danger'] + warning: ['warning', 'alarm'] + info: ['info', 'notice', 'alert'] + + # Set criteria to filter which notifications are displayed (optional) + # filter: + # # Maximum number of notifications to show at once + # limit: 5 + + # Define notification presets to simplify notification creation (optional) + # presets: + # # Example preset: + # entity_saved: + # type: 'success' + # title: 'Entity saved' + # message: 'Entity saved successfully' diff --git a/importmap.php b/importmap.php index 176ca69..9e3c6b8 100644 --- a/importmap.php +++ b/importmap.php @@ -25,4 +25,7 @@ return [ '@symfony/ux-live-component' => [ 'path' => './vendor/symfony/ux-live-component/assets/dist/live_controller.js', ], + '@flasher/flasher' => [ + 'version' => '2.1.5', + ], ]; diff --git a/public/vendor/flasher/flasher.min.css b/public/vendor/flasher/flasher.min.css new file mode 100644 index 0000000..188be96 --- /dev/null +++ b/public/vendor/flasher/flasher.min.css @@ -0,0 +1,2 @@ +:root{--background-color:#fff;--text-color:#4b5563;--dark-background-color:#0f172a;--dark-text-color:#fff;--success-color:#10b981;--info-color:#3b82f6;--warning-color:#f59e0b;--error-color:#ef4444;--success-color-light:#d4f7eb;--info-color-light:#d4e1f7;--warning-color-light:#fce8cf;--error-color-light:#f9d2d2}.fl-wrapper{position:fixed;-webkit-transition:all 1s ease-in-out;-moz-transition:all 1s ease-in-out;transition:all 1s ease-in-out;width:24em;z-index:10}@media only screen and (width <= 480px){.fl-wrapper{left:5%;right:5%;width:90%}}.fl-wrapper[data-position^=top-]{top:.5em}.fl-wrapper[data-position^=bottom-]{bottom:.5em}.fl-wrapper[data-position$=-right]{right:.5em}.fl-wrapper[data-position$=-right] .fl-container{-webkit-transform:translateX(110%);-moz-transform:translateX(110%);-ms-transform:translateX(110%);transform:translateX(110%)}.fl-wrapper[data-position$=-left]{left:.5em}.fl-wrapper[data-position$=-left] .fl-container{-webkit-transform:translateX(-110%);-moz-transform:translateX(-110%);-ms-transform:translateX(-110%);transform:translateX(-110%)}.fl-wrapper[data-position$=-center]{left:50%;-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.fl-wrapper[data-position=top-center] .fl-container{-webkit-transform:translateY(-100vh);-moz-transform:translateY(-100vh);-ms-transform:translateY(-100vh);transform:translateY(-100vh)}.fl-wrapper[data-position=bottom-center] .fl-container{-webkit-transform:translateY(100vh);-moz-transform:translateY(100vh);-ms-transform:translateY(100vh);transform:translateY(100vh)}.fl-container{color:var(--text-color);opacity:0;-webkit-transform:translateY(-20px);-moz-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;transition:all .5s ease-in-out}.fl-container.fl-show{opacity:1;-webkit-transform:translate(0)!important;-moz-transform:translate(0)!important;-ms-transform:translate(0)!important;transform:translate(0)!important}.fl-container.fl-rtl{direction:rtl}.fl-icon{border-radius:50%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;color:#fff;display:inline-block;height:1em;margin:0;min-height:1em;min-width:1em;position:relative;-webkit-transition:all 1s;-moz-transition:all 1s;transition:all 1s;width:1em}.fl-icon:after,.fl-icon:before{border-width:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;content:"";position:absolute;-webkit-transition:all 1s;-moz-transition:all 1s;transition:all 1s}.fl-success .fl-icon:after,.fl-success .fl-icon:before{background-color:currentcolor;border-radius:.1em;height:.6em;left:.35em;top:.6em;-webkit-transform:rotate(-135deg);-moz-transform:rotate(-135deg);-ms-transform:rotate(-135deg);transform:rotate(-135deg);-webkit-transform-origin:.08em .08em;-moz-transform-origin:.08em .08em;-ms-transform-origin:.08em .08em;transform-origin:.08em .08em;width:.16em}.fl-success .fl-icon:after{height:.16em;width:.4em}.fl-info .fl-icon:after,.fl-info .fl-icon:before{background-color:currentcolor;border-radius:.03em;left:50%;-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:.15em}.fl-info .fl-icon:before{height:.38em;top:.4em}.fl-info .fl-icon:after{-webkit-box-shadow:-.06em .19em,-.06em .44em,.06em .44em;box-shadow:-.06em .19em,-.06em .44em,.06em .44em;height:.13em;top:.21em}.fl-warning .fl-icon:after,.fl-warning .fl-icon:before{background-color:currentcolor;border-radius:.03em;left:50%;-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:.15em}.fl-warning .fl-icon:before{height:.38em;top:.21em}.fl-warning .fl-icon:after{height:.13em;top:.65em}.fl-error .fl-icon:after,.fl-error .fl-icon:before{background-color:currentcolor;border-radius:.1em;height:.7em;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) rotate(-135deg);-moz-transform:translate(-50%,-50%) rotate(-135deg);-ms-transform:translate(-50%,-50%) rotate(-135deg);transform:translate(-50%,-50%) rotate(-135deg);width:.16em}.fl-error .fl-icon:after{-webkit-transform:translate(-50%,-50%) rotate(-45deg);-moz-transform:translate(-50%,-50%) rotate(-45deg);-ms-transform:translate(-50%,-50%) rotate(-45deg);transform:translate(-50%,-50%) rotate(-45deg)}.fl-success .fl-icon{background-color:var(--success-color)}.fl-info .fl-icon{background-color:var(--info-color)}.fl-warning .fl-icon{background-color:var(--warning-color)}.fl-error .fl-icon{background-color:var(--error-color)}.fl-progress-bar{bottom:0;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:flex;height:.125em;left:0;position:absolute;right:0}.fl-success .fl-progress-bar{background-color:var(--success-color-light)}.fl-success .fl-progress-bar .fl-progress{background-color:var(--success-color)}.fl-info .fl-progress-bar{background-color:var(--info-color-light)}.fl-info .fl-progress-bar .fl-progress{background-color:var(--info-color)}.fl-warning .fl-progress-bar{background-color:var(--warning-color-light)}.fl-warning .fl-progress-bar .fl-progress{background-color:var(--warning-color)}.fl-error .fl-progress-bar{background-color:var(--error-color-light)}.fl-error .fl-progress-bar .fl-progress{background-color:var(--error-color)} +body.fl-dark .fl-flasher,html.fl-dark .fl-flasher{--background-color:var(--dark-background-color);--text-color:var(--dark-text-color)}.fl-flasher{background-color:var(--background-color);border-bottom:none;-webkit-box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);color:var(--text-color);line-height:1.5;margin:.75em 0;padding:.75em;position:relative;word-break:break-word}.fl-flasher.fl-rtl{border-radius:0 .375em .375em 0}.fl-flasher:not(.fl-rtl){border-radius:.375em 0 0 .375em}.fl-flasher .fl-content{-webkit-box-align:center;-webkit-align-items:center;-moz-box-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:flex}.fl-flasher .fl-icon{font-size:2.5em}.fl-flasher .fl-message,.fl-flasher .fl-title{display:block;line-height:1.25em;margin-left:1em;margin-right:1em}.fl-flasher .fl-title{font-size:1em;font-weight:700}.fl-flasher .fl-message{font-size:.875em;margin-top:.25em}.fl-flasher .fl-close{-webkit-box-align:center;-webkit-align-items:center;-moz-box-align:center;align-items:center;background-color:transparent;border:none;color:#a8aaab;cursor:pointer;display:-webkit-inline-box;display:-webkit-inline-flex;display:-moz-inline-box;display:inline-flex;font-size:25px;-webkit-box-pack:center;-webkit-justify-content:center;-moz-box-pack:center;justify-content:center;line-height:0;margin:-.5rem;padding:.5rem;position:absolute;right:.5rem;top:1rem;-webkit-transition:color .3s ease,-webkit-transform .3s ease;transition:color .3s ease,-webkit-transform .3s ease;-moz-transition:color .3s ease,transform .3s ease,-moz-transform .3s ease;transition:color .3s ease,transform .3s ease;transition:color .3s ease,transform .3s ease,-webkit-transform .3s ease,-moz-transform .3s ease}.fl-flasher .fl-close:hover{color:#8e9192;-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}.fl-flasher.fl-rtl .fl-close{left:.5rem;right:auto}.fl-flasher.fl-success{border-left:.8em solid var(--success-color)}.fl-flasher.fl-success.fl-rtl{border-left:none;border-right:.8em solid var(--success-color)}.fl-flasher.fl-success:not(.fl-rtl){border-left:.8em solid var(--success-color);border-right:none}.fl-flasher.fl-success .fl-title{color:var(--success-color)}.fl-flasher.fl-info{border-left:.8em solid var(--info-color)}.fl-flasher.fl-info.fl-rtl{border-left:none;border-right:.8em solid var(--info-color)}.fl-flasher.fl-info:not(.fl-rtl){border-left:.8em solid var(--info-color);border-right:none}.fl-flasher.fl-info .fl-title{color:var(--info-color)}.fl-flasher.fl-warning{border-left:.8em solid var(--warning-color)}.fl-flasher.fl-warning.fl-rtl{border-left:none;border-right:.8em solid var(--warning-color)}.fl-flasher.fl-warning:not(.fl-rtl){border-left:.8em solid var(--warning-color);border-right:none}.fl-flasher.fl-warning .fl-title{color:var(--warning-color)}.fl-flasher.fl-error{border-left:.8em solid var(--error-color)}.fl-flasher.fl-error.fl-rtl{border-left:none;border-right:.8em solid var(--error-color)}.fl-flasher.fl-error:not(.fl-rtl){border-left:.8em solid var(--error-color);border-right:none}.fl-flasher.fl-error .fl-title{color:var(--error-color)} \ No newline at end of file diff --git a/public/vendor/flasher/flasher.min.js b/public/vendor/flasher/flasher.min.js new file mode 100644 index 0000000..2804f95 --- /dev/null +++ b/public/vendor/flasher/flasher.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).flasher=t()}(this,(function(){"use strict";function e(e,t,s,n){return new(s||(s=Promise))((function(o,i){function r(e){try{a(n.next(e))}catch(e){i(e)}}function l(e){try{a(n.throw(e))}catch(e){i(e)}}function a(e){var t;e.done?o(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(r,l)}a((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class t{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,n){if("object"==typeof e?(e=(n=e).type,t=n.message,s=n.title):"object"==typeof t?(t=(n=t).message,s=n.title):"object"==typeof s&&(s=(n=s).title),void 0===t)throw new Error("message option is required");const o={type:e,message:t,title:s||e,options:n||{},metadata:{plugin:""}};this.renderOptions(n||{}),this.renderEnvelopes([o])}}class s extends t{constructor(e){super(),this.options={timeout:null,timeouts:{success:5e3,info:5e3,error:5e3,warning:5e3},fps:30,position:"top-right",direction:"top",rtl:!1,style:{},escapeHtml:!1},this.theme=e}renderEnvelopes(e){const t=()=>e.forEach((e=>{var t,s,n,o;const i=null!==(s=null!==(t=this.options.timeout)&&void 0!==t?t:this.options.timeouts[e.type])&&void 0!==s?s:5e3,r=Object.assign(Object.assign(Object.assign({},this.options),e.options),{timeout:null!==(n=e.options.timeout)&&void 0!==n?n:i,escapeHtml:null!==(o=e.options.escapeHtml)&&void 0!==o?o:this.options.escapeHtml});this.addToContainer(this.createContainer(r),e,r)}));"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}renderOptions(e){this.options=Object.assign(Object.assign({},this.options),e)}createContainer(e){let t=document.querySelector(`.fl-wrapper[data-position="${e.position}"]`);return t||(t=document.createElement("div"),t.className="fl-wrapper",t.dataset.position=e.position,Object.entries(e.style).forEach((([e,s])=>t.style.setProperty(e,s))),document.body.appendChild(t)),t.dataset.turboTemporary="",t}addToContainer(e,t,s){var n;s.escapeHtml&&(t.title=this.escapeHtml(t.title),t.message=this.escapeHtml(t.message));const o=this.stringToHTML(this.theme.render(t));o.classList.add(...("fl-container"+(s.rtl?" fl-rtl":"")).split(" ")),"bottom"===s.direction?e.append(o):e.prepend(o),requestAnimationFrame((()=>o.classList.add("fl-show"))),null===(n=o.querySelector(".fl-close"))||void 0===n||n.addEventListener("click",(e=>{e.stopPropagation(),this.removeNotification(o)})),this.addProgressBar(o,s)}addProgressBar(e,{timeout:t,fps:s}){if(t<=0||s<=0)return;const n=e.querySelector(".fl-progress-bar");if(!n)return;const o=document.createElement("span");o.classList.add("fl-progress"),n.append(o);const i=1e3/s;let r=0;const l=()=>{r+=1;const s=100*(1-i*(r/t));o.style.width=`${s}%`,s<=0&&(clearInterval(a),this.removeNotification(e))};let a=window.setInterval(l,i);e.addEventListener("mouseout",(()=>a=window.setInterval(l,i))),e.addEventListener("mouseover",(()=>clearInterval(a)))}removeNotification(e){e.classList.remove("fl-show"),e.ontransitionend=()=>{var t,s;!(null===(t=e.parentElement)||void 0===t?void 0:t.hasChildNodes())&&(null===(s=e.parentElement)||void 0===s||s.remove()),e.remove()}}stringToHTML(e){const t=document.createElement("template");return t.innerHTML=e.trim(),t.content.firstElementChild}escapeHtml(e){return null==e?"":e.replace(/[&<>"'`=\/]/g,(e=>({"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","=":"=","/":"/"}[e])))}}const n=new class extends t{constructor(){super(...arguments),this.defaultPlugin="flasher",this.plugins=new Map,this.themes=new Map}render(t){return e(this,void 0,void 0,(function*(){const e=this.resolveResponse(t);yield this.addAssets([{urls:e.styles,nonce:e.context.csp_style_nonce,type:"style"},{urls:e.scripts,nonce:e.context.csp_script_nonce,type:"script"}]),this.renderOptions(e.options),this.renderEnvelopes(e.envelopes)}))}renderEnvelopes(e){const t={};e.forEach((e=>{const s=this.resolvePluginAlias(e.metadata.plugin);t[s]=t[s]||[],t[s].push(e)})),Object.entries(t).forEach((([e,t])=>{this.use(e).renderEnvelopes(t)}))}renderOptions(e){Object.entries(e).forEach((([e,t])=>{this.use(e).renderOptions(t)}))}addPlugin(e,t){this.plugins.set(e,t)}addTheme(e,t){this.themes.set(e,t)}use(e){e=this.resolvePluginAlias(e),this.resolvePlugin(e);const t=this.plugins.get(e);if(!t)throw new Error(`Unable to resolve "${e}" plugin, did you forget to register it?`);return t}create(e){return this.use(e)}resolveResponse(e){const t=Object.assign({envelopes:[],options:{},scripts:[],styles:[],context:{}},e);return Object.entries(t.options).forEach((([e,s])=>{t.options[e]=this.resolveOptions(s)})),t.context.csp_style_nonce=t.context.csp_style_nonce||"",t.context.csp_script_nonce=t.context.csp_script_nonce||"",t.envelopes.forEach((s=>{s.metadata=s.metadata||{},s.metadata.plugin=this.resolvePluginAlias(s.metadata.plugin),this.addThemeStyles(t,s.metadata.plugin),s.options=this.resolveOptions(s.options),s.context=e.context})),t}resolveOptions(e){return Object.entries(e).forEach((([t,s])=>{e[t]=this.resolveFunction(s)})),e}resolveFunction(e){var t,s;if("string"!=typeof e)return e;const n=e.match(/^function\s*(\w*)\s*\(([^)]*)\)\s*\{([\s\S]*)\}$/)||e.match(/^\s*(\(([^)]*)\)|[^=]+)\s*=>\s*([\s\S]+)$/);if(!n)return e;const o=null!==(s=null===(t=n[2])||void 0===t?void 0:t.split(",").map((e=>e.trim())))&&void 0!==s?s:[];let i=n[3].trim();i.startsWith("{")||(i=`{ return ${i}; }`);try{return new Function(...o,i)}catch(t){return console.error("Error converting string to function:",t),e}}resolvePlugin(e){if(this.plugins.get(e)||!e.includes("theme."))return;const t=this.themes.get(e.replace("theme.",""));t&&this.addPlugin(e,new s(t))}resolvePluginAlias(e){return"flasher"===(e=e||this.defaultPlugin)?"theme.flasher":e}addAssets(t){return e(this,void 0,void 0,(function*(){for(const{urls:e,nonce:s,type:n}of t)for(const t of e)yield this.loadAsset(t,s,n)}))}loadAsset(t,s,n){return e(this,void 0,void 0,(function*(){if(document.querySelector(`${"style"===n?"link":"script"}[src="${t}"]`))return;const e=document.createElement("style"===n?"link":"script");return"style"===n?(e.rel="stylesheet",e.href=t):(e.type="text/javascript",e.src=t),s&&e.setAttribute("nonce",s),document.head.appendChild(e),new Promise(((s,n)=>{e.onload=()=>s(),e.onerror=()=>n(new Error(`Failed to load ${t}`))}))}))}addThemeStyles(e,t){var s;if("flasher"!==t&&!t.includes("theme."))return;t=t.replace("theme.","");const n=(null===(s=this.themes.get(t))||void 0===s?void 0:s.styles)||[];e.styles=Array.from(new Set([...e.styles,...n]))}};return n.addTheme("flasher",{render:e=>{const{type:t,title:s,message:n}=e,o="error"===t||"warning"===t;return`\n
\n
\n
\n
\n ${s}\n ${n}\n
\n \n
\n \n
`}}),n})); diff --git a/public/vendor/flasher/manifest.json b/public/vendor/flasher/manifest.json new file mode 100644 index 0000000..0f6df8a --- /dev/null +++ b/public/vendor/flasher/manifest.json @@ -0,0 +1,4 @@ +{ + "/vendor/flasher/flasher.min.js": "/vendor/flasher/flasher.min.js?id=9a255a6680873c0d5fc3d394a2ba3195", + "/vendor/flasher/flasher.min.css": "/vendor/flasher/flasher.min.css?id=7a96e40c68626198d5128ad2fb5d77e0" +} \ No newline at end of file diff --git a/symfony.lock b/symfony.lock index e7027e6..2e51988 100644 --- a/symfony.lock +++ b/symfony.lock @@ -29,6 +29,9 @@ "migrations/.gitignore" ] }, + "php-flasher/flasher-symfony": { + "version": "v2.1.6" + }, "php-http/discovery": { "version": "1.20", "recipe": {