trestle 0.10.0.pre2 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +4 -0
  3. data/Gemfile +2 -2
  4. data/README.md +1 -1
  5. data/app/assets/bundle/trestle/admin.css +9 -9
  6. data/app/assets/bundle/trestle/admin.js +13 -13
  7. data/app/assets/bundle/trestle/fa-brands-400.ttf +0 -0
  8. data/app/assets/bundle/trestle/fa-brands-400.woff2 +0 -0
  9. data/app/assets/bundle/trestle/fa-regular-400.ttf +0 -0
  10. data/app/assets/bundle/trestle/fa-regular-400.woff2 +0 -0
  11. data/app/assets/bundle/trestle/fa-solid-900.ttf +0 -0
  12. data/app/assets/bundle/trestle/fa-solid-900.woff2 +0 -0
  13. data/app/assets/bundle/trestle/photoswipe-2d522a3abaa59f8a8f73.digested.js +6 -0
  14. data/app/assets/sprockets/trestle/icons/font-awesome.css.erb +1 -1
  15. data/app/controllers/concerns/trestle/controller/modal.rb +3 -1
  16. data/app/helpers/trestle/avatar_helper.rb +20 -14
  17. data/app/helpers/trestle/card_helper.rb +27 -9
  18. data/app/helpers/trestle/container_helper.rb +37 -6
  19. data/app/helpers/trestle/display_helper.rb +11 -0
  20. data/app/helpers/trestle/flash_helper.rb +1 -10
  21. data/app/helpers/trestle/form_helper.rb +32 -18
  22. data/app/helpers/trestle/format_helper.rb +47 -17
  23. data/app/helpers/trestle/gravatar_helper.rb +48 -0
  24. data/app/helpers/trestle/grid_helper.rb +12 -14
  25. data/app/helpers/trestle/headings_helper.rb +2 -23
  26. data/app/helpers/trestle/i18n_helper.rb +1 -0
  27. data/app/helpers/trestle/icon_helper.rb +16 -3
  28. data/app/helpers/trestle/layout_helper.rb +1 -0
  29. data/app/helpers/trestle/modal_helper.rb +21 -2
  30. data/app/helpers/trestle/navigation_helper.rb +1 -0
  31. data/app/helpers/trestle/pagination_helper.rb +1 -0
  32. data/app/helpers/trestle/params_helper.rb +32 -0
  33. data/app/helpers/trestle/sort_helper.rb +38 -7
  34. data/app/helpers/trestle/status_helper.rb +19 -3
  35. data/app/helpers/trestle/tab_helper.rb +42 -7
  36. data/app/helpers/trestle/table_helper.rb +23 -23
  37. data/app/helpers/trestle/timestamp_helper.rb +18 -25
  38. data/app/helpers/trestle/title_helper.rb +2 -0
  39. data/app/helpers/trestle/toolbars_helper.rb +2 -1
  40. data/app/helpers/trestle/turbo/frame_helper.rb +25 -14
  41. data/app/helpers/trestle/url_helper.rb +124 -54
  42. data/app/views/kaminari/trestle/_first_page.html.erb +1 -2
  43. data/app/views/kaminari/trestle/_gap.html.erb +0 -1
  44. data/app/views/kaminari/trestle/_last_page.html.erb +1 -2
  45. data/app/views/kaminari/trestle/_page.html.erb +1 -2
  46. data/app/views/kaminari/trestle/_paginator.html.erb +0 -1
  47. data/app/views/layouts/trestle/admin.html.erb +3 -3
  48. data/app/views/layouts/trestle/modal.html.erb +2 -2
  49. data/app/views/trestle/application/_layout.html.erb +22 -18
  50. data/app/views/trestle/application/_tabs.html.erb +1 -1
  51. data/app/views/trestle/flash/_alert.html.erb +3 -1
  52. data/app/views/trestle/flash/_flash.html.erb +7 -4
  53. data/app/views/trestle/resource/_scopes.html.erb +3 -3
  54. data/app/views/trestle/resource/create.turbo_stream.erb +1 -0
  55. data/app/views/trestle/resource/destroy.turbo_stream.erb +2 -0
  56. data/app/views/trestle/resource/index.html.erb +10 -12
  57. data/app/views/trestle/resource/update.turbo_stream.erb +1 -0
  58. data/app/views/trestle/shared/_sidebar.html.erb +8 -8
  59. data/app/views/trestle/table/_table.html.erb +2 -2
  60. data/config/locales/pt-BR.yml +13 -13
  61. data/frontend/css/components/_scopes.scss +6 -7
  62. data/frontend/css/core/_theme.scss +3 -3
  63. data/frontend/css/layout/_sidebar.scss +9 -5
  64. data/frontend/css/variables/_trestle.scss +3 -0
  65. data/frontend/js/controllers/confirm_delete_controller.js +4 -4
  66. data/frontend/js/controllers/flatpickr_controller.js +2 -2
  67. data/frontend/js/controllers/gallery_controller.js +2 -0
  68. data/frontend/js/controllers/lightbox_controller.js +3 -5
  69. data/frontend/js/controllers/modal_trigger_controller.js +2 -2
  70. data/frontend/js/controllers/sidebar_controller.js +13 -3
  71. data/frontend/js/controllers/tab_errors_controller.js +2 -2
  72. data/frontend/js/core/backdrop.js +30 -28
  73. data/frontend/js/core/error_modal.js +7 -9
  74. data/frontend/js/core/fetch.js +2 -0
  75. data/lib/trestle/admin.rb +9 -2
  76. data/lib/trestle/configuration.rb +3 -0
  77. data/lib/trestle/engine.rb +1 -1
  78. data/lib/trestle/evaluation_context.rb +2 -4
  79. data/lib/trestle/form/automatic.rb +1 -1
  80. data/lib/trestle/form/field.rb +1 -1
  81. data/lib/trestle/form/fields/check_box.rb +1 -1
  82. data/lib/trestle/form/fields/collection_check_boxes.rb +1 -1
  83. data/lib/trestle/form/fields/collection_radio_buttons.rb +1 -1
  84. data/lib/trestle/form/fields/date_select.rb +1 -1
  85. data/lib/trestle/form/fields/datetime_select.rb +1 -1
  86. data/lib/trestle/form/fields/form_control.rb +2 -2
  87. data/lib/trestle/form/fields/form_group.rb +4 -4
  88. data/lib/trestle/form/fields/radio_button.rb +1 -1
  89. data/lib/trestle/form/fields/static_field.rb +1 -1
  90. data/lib/trestle/form/fields/time_select.rb +1 -1
  91. data/lib/trestle/form/renderer.rb +3 -5
  92. data/lib/trestle/hook/helpers.rb +21 -0
  93. data/lib/trestle/navigation/block.rb +8 -15
  94. data/lib/trestle/navigation/group.rb +2 -2
  95. data/lib/trestle/navigation/item.rb +21 -4
  96. data/lib/trestle/registry.rb +14 -11
  97. data/lib/trestle/resource/builder.rb +9 -6
  98. data/lib/trestle/resource/toolbar.rb +5 -5
  99. data/lib/trestle/resource.rb +7 -5
  100. data/lib/trestle/scopes/block.rb +8 -12
  101. data/lib/trestle/scopes/definition.rb +6 -2
  102. data/lib/trestle/scopes/scope.rb +13 -10
  103. data/lib/trestle/tab.rb +2 -2
  104. data/lib/trestle/table/column.rb +4 -3
  105. data/lib/trestle/table/row.rb +1 -1
  106. data/lib/trestle/toolbar/builder.rb +6 -6
  107. data/lib/trestle/toolbar/context.rb +2 -4
  108. data/lib/trestle/toolbar/item.rb +10 -19
  109. data/lib/trestle/toolbar/menu.rb +9 -9
  110. data/lib/trestle/version.rb +1 -1
  111. data/lib/trestle.rb +2 -2
  112. data/package.json +7 -7
  113. data/trestle.gemspec +1 -1
  114. data/yarn.lock +751 -796
  115. metadata +7 -7
  116. data/app/assets/bundle/trestle/photoswipe-7aa1aec9c3c1fd65c382.digested.js +0 -6
  117. data/app/views/layouts/trestle/admin.turbo_stream.erb +0 -4
@@ -0,0 +1,6 @@
1
+ "use strict";(self.webpackChunkTrestle=self.webpackChunkTrestle||[]).push([[641],{8300:function(t,i,e){
2
+ /*!
3
+ * PhotoSwipe 5.4.4 - https://photoswipe.com
4
+ * (c) 2024 Dmytro Semenov
5
+ */
6
+ function s(t,i,e){const s=document.createElement(i);return t&&(s.className=t),e&&e.appendChild(s),s}function n(t,i){return t.x=i.x,t.y=i.y,void 0!==i.id&&(t.id=i.id),t}function o(t){t.x=Math.round(t.x),t.y=Math.round(t.y)}function a(t,i){const e=Math.abs(t.x-i.x),s=Math.abs(t.y-i.y);return Math.sqrt(e*e+s*s)}function h(t,i){return t.x===i.x&&t.y===i.y}function r(t,i,e){return Math.min(Math.max(t,i),e)}function l(t,i,e){let s=`translate3d(${t}px,${i||0}px,0)`;return void 0!==e&&(s+=` scale3d(${e},${e},1)`),s}function p(t,i,e,s){t.style.transform=l(i,e,s)}e.r(i),e.d(i,{default:function(){return rt}});function d(t,i,e,s){t.style.transition=i?`${i} ${e}ms ${s||"cubic-bezier(.4,0,.22,1)"}`:"none"}function c(t,i,e){t.style.width="number"==typeof i?`${i}px`:i,t.style.height="number"==typeof e?`${e}px`:e}const m="idle",u="loading",v="loaded",_="error";function g(){return!(!navigator.vendor||!navigator.vendor.match(/apple/i))}let y=!1;try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:()=>{y=!0}}))}catch(t){}class f{constructor(){this._pool=[]}add(t,i,e,s){this._toggleListener(t,i,e,s)}remove(t,i,e,s){this._toggleListener(t,i,e,s,!0)}removeAll(){this._pool.forEach((t=>{this._toggleListener(t.target,t.type,t.listener,t.passive,!0,!0)})),this._pool=[]}_toggleListener(t,i,e,s,n,o){if(!t)return;const a=n?"removeEventListener":"addEventListener";i.split(" ").forEach((i=>{if(i){o||(n?this._pool=this._pool.filter((s=>s.type!==i||s.listener!==e||s.target!==t)):this._pool.push({target:t,type:i,listener:e,passive:s}));const h=!!y&&{passive:s||!1};t[a](i,e,h)}}))}}function w(t,i){if(t.getViewportSizeFn){const e=t.getViewportSizeFn(t,i);if(e)return e}return{x:document.documentElement.clientWidth,y:window.innerHeight}}function x(t,i,e,s,n){let o=0;if(i.paddingFn)o=i.paddingFn(e,s,n)[t];else if(i.padding)o=i.padding[t];else{const e="padding"+t[0].toUpperCase()+t.slice(1);i[e]&&(o=i[e])}return Number(o)||0}function P(t,i,e,s){return{x:i.x-x("left",t,i,e,s)-x("right",t,i,e,s),y:i.y-x("top",t,i,e,s)-x("bottom",t,i,e,s)}}class S{constructor(t){this.slide=t,this.currZoomLevel=1,this.center={x:0,y:0},this.max={x:0,y:0},this.min={x:0,y:0}}update(t){this.currZoomLevel=t,this.slide.width?(this._updateAxis("x"),this._updateAxis("y"),this.slide.pswp.dispatch("calcBounds",{slide:this.slide})):this.reset()}_updateAxis(t){const{pswp:i}=this.slide,e=this.slide["x"===t?"width":"height"]*this.currZoomLevel,s=x("x"===t?"left":"top",i.options,i.viewportSize,this.slide.data,this.slide.index),n=this.slide.panAreaSize[t];this.center[t]=Math.round((n-e)/2)+s,this.max[t]=e>n?Math.round(n-e)+s:this.center[t],this.min[t]=e>n?s:this.center[t]}reset(){this.center.x=0,this.center.y=0,this.max.x=0,this.max.y=0,this.min.x=0,this.min.y=0}correctPan(t,i){return r(i,this.max[t],this.min[t])}}class b{constructor(t,i,e,s){this.pswp=s,this.options=t,this.itemData=i,this.index=e,this.panAreaSize=null,this.elementSize=null,this.fit=1,this.fill=1,this.vFill=1,this.initial=1,this.secondary=1,this.max=1,this.min=1}update(t,i,e){const s={x:t,y:i};this.elementSize=s,this.panAreaSize=e;const n=e.x/s.x,o=e.y/s.y;this.fit=Math.min(1,n<o?n:o),this.fill=Math.min(1,n>o?n:o),this.vFill=Math.min(1,o),this.initial=this._getInitial(),this.secondary=this._getSecondary(),this.max=Math.max(this.initial,this.secondary,this._getMax()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}_parseZoomLevelOption(t){const i=t+"ZoomLevel",e=this.options[i];if(e)return"function"==typeof e?e(this):"fill"===e?this.fill:"fit"===e?this.fit:Number(e)}_getSecondary(){let t=this._parseZoomLevelOption("secondary");return t||(t=Math.min(1,3*this.fit),this.elementSize&&t*this.elementSize.x>4e3&&(t=4e3/this.elementSize.x),t)}_getInitial(){return this._parseZoomLevelOption("initial")||this.fit}_getMax(){return this._parseZoomLevelOption("max")||Math.max(1,4*this.fit)}}class z{constructor(t,i,e){this.data=t,this.index=i,this.pswp=e,this.isActive=i===e.currIndex,this.currentResolution=0,this.panAreaSize={x:0,y:0},this.pan={x:0,y:0},this.isFirstSlide=this.isActive&&!e.opener.isOpen,this.zoomLevels=new b(e.options,t,i,e),this.pswp.dispatch("gettingData",{slide:this,data:this.data,index:i}),this.content=this.pswp.contentLoader.getContentBySlide(this),this.container=s("pswp__zoom-wrap","div"),this.holderElement=null,this.currZoomLevel=1,this.width=this.content.width,this.height=this.content.height,this.heavyAppended=!1,this.bounds=new S(this),this.prevDisplayedWidth=-1,this.prevDisplayedHeight=-1,this.pswp.dispatch("slideInit",{slide:this})}setIsActive(t){t&&!this.isActive?this.activate():!t&&this.isActive&&this.deactivate()}append(t){this.holderElement=t,this.container.style.transformOrigin="0 0",this.data&&(this.calculateSize(),this.load(),this.updateContentSize(),this.appendHeavy(),this.holderElement.appendChild(this.container),this.zoomAndPanToInitial(),this.pswp.dispatch("firstZoomPan",{slide:this}),this.applyCurrentZoomPan(),this.pswp.dispatch("afterSetContent",{slide:this}),this.isActive&&this.activate())}load(){this.content.load(!1),this.pswp.dispatch("slideLoad",{slide:this})}appendHeavy(){const{pswp:t}=this;!this.heavyAppended&&t.opener.isOpen&&!t.mainScroll.isShifted()&&(this.isActive,1)&&(this.pswp.dispatch("appendHeavy",{slide:this}).defaultPrevented||(this.heavyAppended=!0,this.content.append(),this.pswp.dispatch("appendHeavyContent",{slide:this})))}activate(){this.isActive=!0,this.appendHeavy(),this.content.activate(),this.pswp.dispatch("slideActivate",{slide:this})}deactivate(){this.isActive=!1,this.content.deactivate(),this.currZoomLevel!==this.zoomLevels.initial&&this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize(),this.pswp.dispatch("slideDeactivate",{slide:this})}destroy(){this.content.hasSlide=!1,this.content.remove(),this.container.remove(),this.pswp.dispatch("slideDestroy",{slide:this})}resize(){this.currZoomLevel!==this.zoomLevels.initial&&this.isActive?(this.calculateSize(),this.bounds.update(this.currZoomLevel),this.panTo(this.pan.x,this.pan.y)):(this.calculateSize(),this.currentResolution=0,this.zoomAndPanToInitial(),this.applyCurrentZoomPan(),this.updateContentSize())}updateContentSize(t){const i=this.currentResolution||this.zoomLevels.initial;if(!i)return;const e=Math.round(this.width*i)||this.pswp.viewportSize.x,s=Math.round(this.height*i)||this.pswp.viewportSize.y;(this.sizeChanged(e,s)||t)&&this.content.setDisplayedSize(e,s)}sizeChanged(t,i){return(t!==this.prevDisplayedWidth||i!==this.prevDisplayedHeight)&&(this.prevDisplayedWidth=t,this.prevDisplayedHeight=i,!0)}getPlaceholderElement(){var t;return null===(t=this.content.placeholder)||void 0===t?void 0:t.element}zoomTo(t,i,e,s){const{pswp:n}=this;if(!this.isZoomable()||n.mainScroll.isShifted())return;n.dispatch("beforeZoomTo",{destZoomLevel:t,centerPoint:i,transitionDuration:e}),n.animations.stopAllPan();const a=this.currZoomLevel;s||(t=r(t,this.zoomLevels.min,this.zoomLevels.max)),this.setZoomLevel(t),this.pan.x=this.calculateZoomToPanOffset("x",i,a),this.pan.y=this.calculateZoomToPanOffset("y",i,a),o(this.pan);const h=()=>{this._setResolution(t),this.applyCurrentZoomPan()};e?n.animations.startTransition({isPan:!0,name:"zoomTo",target:this.container,transform:this.getCurrentTransform(),onComplete:h,duration:e,easing:n.options.easing}):h()}toggleZoom(t){this.zoomTo(this.currZoomLevel===this.zoomLevels.initial?this.zoomLevels.secondary:this.zoomLevels.initial,t,this.pswp.options.zoomAnimationDuration)}setZoomLevel(t){this.currZoomLevel=t,this.bounds.update(this.currZoomLevel)}calculateZoomToPanOffset(t,i,e){if(0===this.bounds.max[t]-this.bounds.min[t])return this.bounds.center[t];i||(i=this.pswp.getViewportCenterPoint()),e||(e=this.zoomLevels.initial);const s=this.currZoomLevel/e;return this.bounds.correctPan(t,(this.pan[t]-i[t])*s+i[t])}panTo(t,i){this.pan.x=this.bounds.correctPan("x",t),this.pan.y=this.bounds.correctPan("y",i),this.applyCurrentZoomPan()}isPannable(){return Boolean(this.width)&&this.currZoomLevel>this.zoomLevels.fit}isZoomable(){return Boolean(this.width)&&this.content.isZoomable()}applyCurrentZoomPan(){this._applyZoomTransform(this.pan.x,this.pan.y,this.currZoomLevel),this===this.pswp.currSlide&&this.pswp.dispatch("zoomPanUpdate",{slide:this})}zoomAndPanToInitial(){this.currZoomLevel=this.zoomLevels.initial,this.bounds.update(this.currZoomLevel),n(this.pan,this.bounds.center),this.pswp.dispatch("initialZoomPan",{slide:this})}_applyZoomTransform(t,i,e){e/=this.currentResolution||this.zoomLevels.initial,p(this.container,t,i,e)}calculateSize(){const{pswp:t}=this;n(this.panAreaSize,P(t.options,t.viewportSize,this.data,this.index)),this.zoomLevels.update(this.width,this.height,this.panAreaSize),t.dispatch("calcSlideSize",{slide:this})}getCurrentTransform(){const t=this.currZoomLevel/(this.currentResolution||this.zoomLevels.initial);return l(this.pan.x,this.pan.y,t)}_setResolution(t){t!==this.currentResolution&&(this.currentResolution=t,this.updateContentSize(),this.pswp.dispatch("resolutionChanged"))}}class C{constructor(t){this.gestures=t,this.pswp=t.pswp,this.startPan={x:0,y:0}}start(){this.pswp.currSlide&&n(this.startPan,this.pswp.currSlide.pan),this.pswp.animations.stopAll()}change(){const{p1:t,prevP1:i,dragAxis:e}=this.gestures,{currSlide:s}=this.pswp;if("y"===e&&this.pswp.options.closeOnVerticalDrag&&s&&s.currZoomLevel<=s.zoomLevels.fit&&!this.gestures.isMultitouch){const e=s.pan.y+(t.y-i.y);if(!this.pswp.dispatch("verticalDrag",{panY:e}).defaultPrevented){this._setPanWithFriction("y",e,.6);const t=1-Math.abs(this._getVerticalDragRatio(s.pan.y));this.pswp.applyBgOpacity(t),s.applyCurrentZoomPan()}}else{this._panOrMoveMainScroll("x")||(this._panOrMoveMainScroll("y"),s&&(o(s.pan),s.applyCurrentZoomPan()))}}end(){const{velocity:t}=this.gestures,{mainScroll:i,currSlide:e}=this.pswp;let s=0;if(this.pswp.animations.stopAll(),i.isShifted()){const e=(i.x-i.getCurrSlideX())/this.pswp.viewportSize.x;t.x<-.5&&e<0||t.x<.1&&e<-.5?(s=1,t.x=Math.min(t.x,0)):(t.x>.5&&e>0||t.x>-.1&&e>.5)&&(s=-1,t.x=Math.max(t.x,0)),i.moveIndexBy(s,!0,t.x)}e&&e.currZoomLevel>e.zoomLevels.max||this.gestures.isMultitouch?this.gestures.zoomLevels.correctZoomPan(!0):(this._finishPanGestureForAxis("x"),this._finishPanGestureForAxis("y"))}_finishPanGestureForAxis(t){const{velocity:i}=this.gestures,{currSlide:e}=this.pswp;if(!e)return;const{pan:s,bounds:n}=e,o=s[t],a=this.pswp.bgOpacity<1&&"y"===t,h=o+function(t,i){return t*i/(1-i)}(i[t],.995);if(a){const t=this._getVerticalDragRatio(o),i=this._getVerticalDragRatio(h);if(t<0&&i<-.4||t>0&&i>.4)return void this.pswp.close()}const l=n.correctPan(t,h);if(o===l)return;const p=l===h?1:.82,d=this.pswp.bgOpacity,c=l-o;this.pswp.animations.startSpring({name:"panGesture"+t,isPan:!0,start:o,end:l,velocity:i[t],dampingRatio:p,onUpdate:i=>{if(a&&this.pswp.bgOpacity<1){const t=1-(l-i)/c;this.pswp.applyBgOpacity(r(d+(1-d)*t,0,1))}s[t]=Math.floor(i),e.applyCurrentZoomPan()}})}_panOrMoveMainScroll(t){const{p1:i,dragAxis:e,prevP1:s,isMultitouch:n}=this.gestures,{currSlide:o,mainScroll:a}=this.pswp,h=i[t]-s[t],r=a.x+h;if(!h||!o)return!1;if("x"===t&&!o.isPannable()&&!n)return a.moveTo(r,!0),!0;const{bounds:l}=o,p=o.pan[t]+h;if(this.pswp.options.allowPanToNext&&"x"===e&&"x"===t&&!n){const i=a.getCurrSlideX(),e=a.x-i,s=h>0,n=!s;if(p>l.min[t]&&s){if(l.min[t]<=this.startPan[t])return a.moveTo(r,!0),!0;this._setPanWithFriction(t,p)}else if(p<l.max[t]&&n){if(this.startPan[t]<=l.max[t])return a.moveTo(r,!0),!0;this._setPanWithFriction(t,p)}else if(0!==e){if(e>0)return a.moveTo(Math.max(r,i),!0),!0;if(e<0)return a.moveTo(Math.min(r,i),!0),!0}else this._setPanWithFriction(t,p)}else"y"===t&&(a.isShifted()||l.min.y===l.max.y)||this._setPanWithFriction(t,p);return!1}_getVerticalDragRatio(t){var i,e;return(t-(null!==(i=null===(e=this.pswp.currSlide)||void 0===e?void 0:e.bounds.center.y)&&void 0!==i?i:0))/(this.pswp.viewportSize.y/3)}_setPanWithFriction(t,i,e){const{currSlide:s}=this.pswp;if(!s)return;const{pan:n,bounds:o}=s;if(o.correctPan(t,i)!==i||e){const s=Math.round(i-n[t]);n[t]+=s*(e||.35)}else n[t]=i}}function I(t,i,e){return t.x=(i.x+e.x)/2,t.y=(i.y+e.y)/2,t}class L{constructor(t){this.gestures=t,this._startPan={x:0,y:0},this._startZoomPoint={x:0,y:0},this._zoomPoint={x:0,y:0},this._wasOverFitZoomLevel=!1,this._startZoomLevel=1}start(){const{currSlide:t}=this.gestures.pswp;t&&(this._startZoomLevel=t.currZoomLevel,n(this._startPan,t.pan)),this.gestures.pswp.animations.stopAllPan(),this._wasOverFitZoomLevel=!1}change(){const{p1:t,startP1:i,p2:e,startP2:s,pswp:n}=this.gestures,{currSlide:o}=n;if(!o)return;const h=o.zoomLevels.min,r=o.zoomLevels.max;if(!o.isZoomable()||n.mainScroll.isShifted())return;I(this._startZoomPoint,i,s),I(this._zoomPoint,t,e);let l=1/a(i,s)*a(t,e)*this._startZoomLevel;if(l>o.zoomLevels.initial+o.zoomLevels.initial/15&&(this._wasOverFitZoomLevel=!0),l<h)if(n.options.pinchToClose&&!this._wasOverFitZoomLevel&&this._startZoomLevel<=o.zoomLevels.initial){const t=1-(h-l)/(h/1.2);n.dispatch("pinchClose",{bgOpacity:t}).defaultPrevented||n.applyBgOpacity(t)}else l=h-.15*(h-l);else l>r&&(l=r+.05*(l-r));o.pan.x=this._calculatePanForZoomLevel("x",l),o.pan.y=this._calculatePanForZoomLevel("y",l),o.setZoomLevel(l),o.applyCurrentZoomPan()}end(){const{pswp:t}=this.gestures,{currSlide:i}=t;(!i||i.currZoomLevel<i.zoomLevels.initial)&&!this._wasOverFitZoomLevel&&t.options.pinchToClose?t.close():this.correctZoomPan()}_calculatePanForZoomLevel(t,i){const e=i/this._startZoomLevel;return this._zoomPoint[t]-(this._startZoomPoint[t]-this._startPan[t])*e}correctZoomPan(t){const{pswp:i}=this.gestures,{currSlide:e}=i;if(null==e||!e.isZoomable())return;0===this._zoomPoint.x&&(t=!0);const s=e.currZoomLevel;let o,a=!0;s<e.zoomLevels.initial?o=e.zoomLevels.initial:s>e.zoomLevels.max?o=e.zoomLevels.max:(a=!1,o=s);const l=i.bgOpacity,p=i.bgOpacity<1,d=n({x:0,y:0},e.pan);let c=n({x:0,y:0},d);t&&(this._zoomPoint.x=0,this._zoomPoint.y=0,this._startZoomPoint.x=0,this._startZoomPoint.y=0,this._startZoomLevel=s,n(this._startPan,d)),a&&(c={x:this._calculatePanForZoomLevel("x",o),y:this._calculatePanForZoomLevel("y",o)}),e.setZoomLevel(o),c={x:e.bounds.correctPan("x",c.x),y:e.bounds.correctPan("y",c.y)},e.setZoomLevel(s);const m=!h(c,d);if(!m&&!a&&!p)return e._setResolution(o),void e.applyCurrentZoomPan();i.animations.stopAllPan(),i.animations.startSpring({isPan:!0,start:0,end:1e3,velocity:0,dampingRatio:1,naturalFrequency:40,onUpdate:t=>{if(t/=1e3,m||a){if(m&&(e.pan.x=d.x+(c.x-d.x)*t,e.pan.y=d.y+(c.y-d.y)*t),a){const i=s+(o-s)*t;e.setZoomLevel(i)}e.applyCurrentZoomPan()}p&&i.bgOpacity<1&&i.applyBgOpacity(r(l+(1-l)*t,0,1))},onComplete:()=>{e._setResolution(o),e.applyCurrentZoomPan()}})}}function A(t){return!!t.target.closest(".pswp__container")}class T{constructor(t){this.gestures=t}click(t,i){const e=i.target.classList,s=e.contains("pswp__img"),n=e.contains("pswp__item")||e.contains("pswp__zoom-wrap");s?this._doClickOrTapAction("imageClick",t,i):n&&this._doClickOrTapAction("bgClick",t,i)}tap(t,i){A(i)&&this._doClickOrTapAction("tap",t,i)}doubleTap(t,i){A(i)&&this._doClickOrTapAction("doubleTap",t,i)}_doClickOrTapAction(t,i,e){var s;const{pswp:n}=this.gestures,{currSlide:o}=n,a=t+"Action",h=n.options[a];if(!n.dispatch(a,{point:i,originalEvent:e}).defaultPrevented)if("function"!=typeof h)switch(h){case"close":case"next":n[h]();break;case"zoom":null==o||o.toggleZoom(i);break;case"zoom-or-close":null!=o&&o.isZoomable()&&o.zoomLevels.secondary!==o.zoomLevels.initial?o.toggleZoom(i):n.options.clickToCloseNonZoomable&&n.close();break;case"toggle-controls":null===(s=this.gestures.pswp.element)||void 0===s||s.classList.toggle("pswp--ui-visible")}else h.call(n,i,e)}}class Z{constructor(t){this.pswp=t,this.dragAxis=null,this.p1={x:0,y:0},this.p2={x:0,y:0},this.prevP1={x:0,y:0},this.prevP2={x:0,y:0},this.startP1={x:0,y:0},this.startP2={x:0,y:0},this.velocity={x:0,y:0},this._lastStartP1={x:0,y:0},this._intervalP1={x:0,y:0},this._numActivePoints=0,this._ongoingPointers=[],this._touchEventEnabled="ontouchstart"in window,this._pointerEventEnabled=!!window.PointerEvent,this.supportsTouch=this._touchEventEnabled||this._pointerEventEnabled&&navigator.maxTouchPoints>1,this._numActivePoints=0,this._intervalTime=0,this._velocityCalculated=!1,this.isMultitouch=!1,this.isDragging=!1,this.isZooming=!1,this.raf=null,this._tapTimer=null,this.supportsTouch||(t.options.allowPanToNext=!1),this.drag=new C(this),this.zoomLevels=new L(this),this.tapHandler=new T(this),t.on("bindEvents",(()=>{t.events.add(t.scrollWrap,"click",this._onClick.bind(this)),this._pointerEventEnabled?this._bindEvents("pointer","down","up","cancel"):this._touchEventEnabled?(this._bindEvents("touch","start","end","cancel"),t.scrollWrap&&(t.scrollWrap.ontouchmove=()=>{},t.scrollWrap.ontouchend=()=>{})):this._bindEvents("mouse","down","up")}))}_bindEvents(t,i,e,s){const{pswp:n}=this,{events:o}=n,a=s?t+s:"";o.add(n.scrollWrap,t+i,this.onPointerDown.bind(this)),o.add(window,t+"move",this.onPointerMove.bind(this)),o.add(window,t+e,this.onPointerUp.bind(this)),a&&o.add(n.scrollWrap,a,this.onPointerUp.bind(this))}onPointerDown(t){const i="mousedown"===t.type||"mouse"===t.pointerType;if(i&&t.button>0)return;const{pswp:e}=this;e.opener.isOpen?e.dispatch("pointerDown",{originalEvent:t}).defaultPrevented||(i&&(e.mouseDetected(),this._preventPointerEventBehaviour(t,"down")),e.animations.stopAll(),this._updatePoints(t,"down"),1===this._numActivePoints&&(this.dragAxis=null,n(this.startP1,this.p1)),this._numActivePoints>1?(this._clearTapTimer(),this.isMultitouch=!0):this.isMultitouch=!1):t.preventDefault()}onPointerMove(t){this._preventPointerEventBehaviour(t,"move"),this._numActivePoints&&(this._updatePoints(t,"move"),this.pswp.dispatch("pointerMove",{originalEvent:t}).defaultPrevented||(1!==this._numActivePoints||this.isDragging?this._numActivePoints>1&&!this.isZooming&&(this._finishDrag(),this.isZooming=!0,this._updateStartPoints(),this.zoomLevels.start(),this._rafStopLoop(),this._rafRenderLoop()):(this.dragAxis||this._calculateDragDirection(),this.dragAxis&&!this.isDragging&&(this.isZooming&&(this.isZooming=!1,this.zoomLevels.end()),this.isDragging=!0,this._clearTapTimer(),this._updateStartPoints(),this._intervalTime=Date.now(),this._velocityCalculated=!1,n(this._intervalP1,this.p1),this.velocity.x=0,this.velocity.y=0,this.drag.start(),this._rafStopLoop(),this._rafRenderLoop()))))}_finishDrag(){this.isDragging&&(this.isDragging=!1,this._velocityCalculated||this._updateVelocity(!0),this.drag.end(),this.dragAxis=null)}onPointerUp(t){this._numActivePoints&&(this._updatePoints(t,"up"),this.pswp.dispatch("pointerUp",{originalEvent:t}).defaultPrevented||(0===this._numActivePoints&&(this._rafStopLoop(),this.isDragging?this._finishDrag():this.isZooming||this.isMultitouch||this._finishTap(t)),this._numActivePoints<2&&this.isZooming&&(this.isZooming=!1,this.zoomLevels.end(),1===this._numActivePoints&&(this.dragAxis=null,this._updateStartPoints()))))}_rafRenderLoop(){(this.isDragging||this.isZooming)&&(this._updateVelocity(),this.isDragging?h(this.p1,this.prevP1)||this.drag.change():h(this.p1,this.prevP1)&&h(this.p2,this.prevP2)||this.zoomLevels.change(),this._updatePrevPoints(),this.raf=requestAnimationFrame(this._rafRenderLoop.bind(this)))}_updateVelocity(t){const i=Date.now(),e=i-this._intervalTime;e<50&&!t||(this.velocity.x=this._getVelocity("x",e),this.velocity.y=this._getVelocity("y",e),this._intervalTime=i,n(this._intervalP1,this.p1),this._velocityCalculated=!0)}_finishTap(t){const{mainScroll:i}=this.pswp;if(i.isShifted())return void i.moveIndexBy(0,!0);if(t.type.indexOf("cancel")>0)return;if("mouseup"===t.type||"mouse"===t.pointerType)return void this.tapHandler.click(this.startP1,t);const e=this.pswp.options.doubleTapAction?300:0;this._tapTimer?(this._clearTapTimer(),a(this._lastStartP1,this.startP1)<25&&this.tapHandler.doubleTap(this.startP1,t)):(n(this._lastStartP1,this.startP1),this._tapTimer=setTimeout((()=>{this.tapHandler.tap(this.startP1,t),this._clearTapTimer()}),e))}_clearTapTimer(){this._tapTimer&&(clearTimeout(this._tapTimer),this._tapTimer=null)}_getVelocity(t,i){const e=this.p1[t]-this._intervalP1[t];return Math.abs(e)>1&&i>5?e/i:0}_rafStopLoop(){this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}_preventPointerEventBehaviour(t,i){this.pswp.applyFilters("preventPointerEvent",!0,t,i)&&t.preventDefault()}_updatePoints(t,i){if(this._pointerEventEnabled){const e=t,s=this._ongoingPointers.findIndex((t=>t.id===e.pointerId));"up"===i&&s>-1?this._ongoingPointers.splice(s,1):"down"===i&&-1===s?this._ongoingPointers.push(this._convertEventPosToPoint(e,{x:0,y:0})):s>-1&&this._convertEventPosToPoint(e,this._ongoingPointers[s]),this._numActivePoints=this._ongoingPointers.length,this._numActivePoints>0&&n(this.p1,this._ongoingPointers[0]),this._numActivePoints>1&&n(this.p2,this._ongoingPointers[1])}else{const e=t;this._numActivePoints=0,e.type.indexOf("touch")>-1?e.touches&&e.touches.length>0&&(this._convertEventPosToPoint(e.touches[0],this.p1),this._numActivePoints++,e.touches.length>1&&(this._convertEventPosToPoint(e.touches[1],this.p2),this._numActivePoints++)):(this._convertEventPosToPoint(t,this.p1),"up"===i?this._numActivePoints=0:this._numActivePoints++)}}_updatePrevPoints(){n(this.prevP1,this.p1),n(this.prevP2,this.p2)}_updateStartPoints(){n(this.startP1,this.p1),n(this.startP2,this.p2),this._updatePrevPoints()}_calculateDragDirection(){if(this.pswp.mainScroll.isShifted())this.dragAxis="x";else{const t=Math.abs(this.p1.x-this.startP1.x)-Math.abs(this.p1.y-this.startP1.y);if(0!==t){const i=t>0?"x":"y";Math.abs(this.p1[i]-this.startP1[i])>=10&&(this.dragAxis=i)}}}_convertEventPosToPoint(t,i){return i.x=t.pageX-this.pswp.offset.x,i.y=t.pageY-this.pswp.offset.y,"pointerId"in t?i.id=t.pointerId:void 0!==t.identifier&&(i.id=t.identifier),i}_onClick(t){this.pswp.mainScroll.isShifted()&&(t.preventDefault(),t.stopPropagation())}}class O{constructor(t){this.pswp=t,this.x=0,this.slideWidth=0,this._currPositionIndex=0,this._prevPositionIndex=0,this._containerShiftIndex=-1,this.itemHolders=[]}resize(t){const{pswp:i}=this,e=Math.round(i.viewportSize.x+i.viewportSize.x*i.options.spacing),s=e!==this.slideWidth;s&&(this.slideWidth=e,this.moveTo(this.getCurrSlideX())),this.itemHolders.forEach(((i,e)=>{s&&p(i.el,(e+this._containerShiftIndex)*this.slideWidth),t&&i.slide&&i.slide.resize()}))}resetPosition(){this._currPositionIndex=0,this._prevPositionIndex=0,this.slideWidth=0,this._containerShiftIndex=-1}appendHolders(){this.itemHolders=[];for(let t=0;t<3;t++){const i=s("pswp__item","div",this.pswp.container);i.setAttribute("role","group"),i.setAttribute("aria-roledescription","slide"),i.setAttribute("aria-hidden","true"),i.style.display=1===t?"block":"none",this.itemHolders.push({el:i})}}canBeSwiped(){return this.pswp.getNumItems()>1}moveIndexBy(t,i,e){const{pswp:s}=this;let n=s.potentialIndex+t;const o=s.getNumItems();if(s.canLoop()){n=s.getLoopedIndex(n);const i=(t+o)%o;t=i<=o/2?i:i-o}else n<0?n=0:n>=o&&(n=o-1),t=n-s.potentialIndex;s.potentialIndex=n,this._currPositionIndex-=t,s.animations.stopMainScroll();const a=this.getCurrSlideX();if(i){s.animations.startSpring({isMainScroll:!0,start:this.x,end:a,velocity:e||0,naturalFrequency:30,dampingRatio:1,onUpdate:t=>{this.moveTo(t)},onComplete:()=>{this.updateCurrItem(),s.appendHeavy()}});let t=s.potentialIndex-s.currIndex;if(s.canLoop()){const i=(t+o)%o;t=i<=o/2?i:i-o}Math.abs(t)>1&&this.updateCurrItem()}else this.moveTo(a),this.updateCurrItem();return Boolean(t)}getCurrSlideX(){return this.slideWidth*this._currPositionIndex}isShifted(){return this.x!==this.getCurrSlideX()}updateCurrItem(){var t;const{pswp:i}=this,e=this._prevPositionIndex-this._currPositionIndex;if(!e)return;this._prevPositionIndex=this._currPositionIndex,i.currIndex=i.potentialIndex;let s,n=Math.abs(e);n>=3&&(this._containerShiftIndex+=e+(e>0?-3:3),n=3,this.itemHolders.forEach((t=>{var i;null===(i=t.slide)||void 0===i||i.destroy(),t.slide=void 0})));for(let t=0;t<n;t++)e>0?(s=this.itemHolders.shift(),s&&(this.itemHolders[2]=s,this._containerShiftIndex++,p(s.el,(this._containerShiftIndex+2)*this.slideWidth),i.setContent(s,i.currIndex-n+t+2))):(s=this.itemHolders.pop(),s&&(this.itemHolders.unshift(s),this._containerShiftIndex--,p(s.el,this._containerShiftIndex*this.slideWidth),i.setContent(s,i.currIndex+n-t-2)));Math.abs(this._containerShiftIndex)>50&&!this.isShifted()&&(this.resetPosition(),this.resize()),i.animations.stopAllPan(),this.itemHolders.forEach(((t,i)=>{t.slide&&t.slide.setIsActive(1===i)})),i.currSlide=null===(t=this.itemHolders[1])||void 0===t?void 0:t.slide,i.contentLoader.updateLazy(e),i.currSlide&&i.currSlide.applyCurrentZoomPan(),i.dispatch("change")}moveTo(t,i){if(!this.pswp.canLoop()&&i){let i=(this.slideWidth*this._currPositionIndex-t)/this.slideWidth;i+=this.pswp.currIndex;const e=Math.round(t-this.x);(i<0&&e>0||i>=this.pswp.getNumItems()-1&&e<0)&&(t=this.x+.35*e)}this.x=t,this.pswp.container&&p(this.pswp.container,t),this.pswp.dispatch("moveMainScroll",{x:t,dragging:null!=i&&i})}}const D={Escape:27,z:90,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Tab:9},E=(t,i)=>i?t:D[t];class M{constructor(t){this.pswp=t,this._wasFocused=!1,t.on("bindEvents",(()=>{t.options.trapFocus&&(t.options.initialPointerPos||this._focusRoot(),t.events.add(document,"focusin",this._onFocusIn.bind(this))),t.events.add(document,"keydown",this._onKeyDown.bind(this))}));const i=document.activeElement;t.on("destroy",(()=>{t.options.returnFocus&&i&&this._wasFocused&&i.focus()}))}_focusRoot(){!this._wasFocused&&this.pswp.element&&(this.pswp.element.focus(),this._wasFocused=!0)}_onKeyDown(t){const{pswp:i}=this;if(i.dispatch("keydown",{originalEvent:t}).defaultPrevented)return;if(function(t){return"button"in t&&1===t.button||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey}(t))return;let e,s,n=!1;const o="key"in t;switch(o?t.key:t.keyCode){case E("Escape",o):i.options.escKey&&(e="close");break;case E("z",o):e="toggleZoom";break;case E("ArrowLeft",o):s="x";break;case E("ArrowUp",o):s="y";break;case E("ArrowRight",o):s="x",n=!0;break;case E("ArrowDown",o):n=!0,s="y";break;case E("Tab",o):this._focusRoot()}if(s){t.preventDefault();const{currSlide:o}=i;i.options.arrowKeys&&"x"===s&&i.getNumItems()>1?e=n?"next":"prev":o&&o.currZoomLevel>o.zoomLevels.fit&&(o.pan[s]+=n?-80:80,o.panTo(o.pan.x,o.pan.y))}e&&(t.preventDefault(),i[e]())}_onFocusIn(t){const{template:i}=this.pswp;i&&document!==t.target&&i!==t.target&&!i.contains(t.target)&&i.focus()}}const F="cubic-bezier(.4,0,.22,1)";class B{constructor(t){var i;this.props=t;const{target:e,onComplete:s,transform:n,onFinish:o=()=>{},duration:a=333,easing:h=F}=t;this.onFinish=o;const r=n?"transform":"opacity",l=null!==(i=t[r])&&void 0!==i?i:"";this._target=e,this._onComplete=s,this._finished=!1,this._onTransitionEnd=this._onTransitionEnd.bind(this),this._helperTimeout=setTimeout((()=>{d(e,r,a,h),this._helperTimeout=setTimeout((()=>{e.addEventListener("transitionend",this._onTransitionEnd,!1),e.addEventListener("transitioncancel",this._onTransitionEnd,!1),this._helperTimeout=setTimeout((()=>{this._finalizeAnimation()}),a+500),e.style[r]=l}),30)}),0)}_onTransitionEnd(t){t.target===this._target&&this._finalizeAnimation()}_finalizeAnimation(){this._finished||(this._finished=!0,this.onFinish(),this._onComplete&&this._onComplete())}destroy(){this._helperTimeout&&clearTimeout(this._helperTimeout),d(this._target),this._target.removeEventListener("transitionend",this._onTransitionEnd,!1),this._target.removeEventListener("transitioncancel",this._onTransitionEnd,!1),this._finished||this._finalizeAnimation()}}class R{constructor(t,i,e){this.velocity=1e3*t,this._dampingRatio=i||.75,this._naturalFrequency=e||12,this._dampedFrequency=this._naturalFrequency,this._dampingRatio<1&&(this._dampedFrequency*=Math.sqrt(1-this._dampingRatio*this._dampingRatio))}easeFrame(t,i){let e,s=0;i/=1e3;const n=Math.E**(-this._dampingRatio*this._naturalFrequency*i);if(1===this._dampingRatio)e=this.velocity+this._naturalFrequency*t,s=(t+e*i)*n,this.velocity=s*-this._naturalFrequency+e*n;else if(this._dampingRatio<1){e=1/this._dampedFrequency*(this._dampingRatio*this._naturalFrequency*t+this.velocity);const o=Math.cos(this._dampedFrequency*i),a=Math.sin(this._dampedFrequency*i);s=n*(t*o+e*a),this.velocity=s*-this._naturalFrequency*this._dampingRatio+n*(-this._dampedFrequency*t*a+this._dampedFrequency*e*o)}return s}}class k{constructor(t){this.props=t,this._raf=0;const{start:i,end:e,velocity:s,onUpdate:n,onComplete:o,onFinish:a=()=>{},dampingRatio:h,naturalFrequency:r}=t;this.onFinish=a;const l=new R(s,h,r);let p=Date.now(),d=i-e;const c=()=>{this._raf&&(d=l.easeFrame(d,Date.now()-p),Math.abs(d)<1&&Math.abs(l.velocity)<50?(n(e),o&&o(),this.onFinish()):(p=Date.now(),n(d+e),this._raf=requestAnimationFrame(c)))};this._raf=requestAnimationFrame(c)}destroy(){this._raf>=0&&cancelAnimationFrame(this._raf),this._raf=0}}class H{constructor(){this.activeAnimations=[]}startSpring(t){this._start(t,!0)}startTransition(t){this._start(t)}_start(t,i){const e=i?new k(t):new B(t);return this.activeAnimations.push(e),e.onFinish=()=>this.stop(e),e}stop(t){t.destroy();const i=this.activeAnimations.indexOf(t);i>-1&&this.activeAnimations.splice(i,1)}stopAll(){this.activeAnimations.forEach((t=>{t.destroy()})),this.activeAnimations=[]}stopAllPan(){this.activeAnimations=this.activeAnimations.filter((t=>!t.props.isPan||(t.destroy(),!1)))}stopMainScroll(){this.activeAnimations=this.activeAnimations.filter((t=>!t.props.isMainScroll||(t.destroy(),!1)))}isPanRunning(){return this.activeAnimations.some((t=>t.props.isPan))}}class W{constructor(t){this.pswp=t,t.events.add(t.element,"wheel",this._onWheel.bind(this))}_onWheel(t){t.preventDefault();const{currSlide:i}=this.pswp;let{deltaX:e,deltaY:s}=t;if(i&&!this.pswp.dispatch("wheel",{originalEvent:t}).defaultPrevented)if(t.ctrlKey||this.pswp.options.wheelToZoom){if(i.isZoomable()){let e=-s;1===t.deltaMode?e*=.05:e*=t.deltaMode?1:.002,e=2**e;const n=i.currZoomLevel*e;i.zoomTo(n,{x:t.clientX,y:t.clientY})}}else i.isPannable()&&(1===t.deltaMode&&(e*=18,s*=18),i.panTo(i.pan.x-e,i.pan.y-s))}}class N{constructor(t,i){var e;const n=i.name||i.className;let o=i.html;if(!1===t.options[n])return;"string"==typeof t.options[n+"SVG"]&&(o=t.options[n+"SVG"]),t.dispatch("uiElementCreate",{data:i});let a="";i.isButton?(a+="pswp__button ",a+=i.className||`pswp__button--${i.name}`):a+=i.className||`pswp__${i.name}`;let h=i.isButton?i.tagName||"button":i.tagName||"div";h=h.toLowerCase();const r=s(a,h);if(i.isButton){"button"===h&&(r.type="button");let{title:e}=i;const{ariaLabel:s}=i;"string"==typeof t.options[n+"Title"]&&(e=t.options[n+"Title"]),e&&(r.title=e);const o=s||e;o&&r.setAttribute("aria-label",o)}r.innerHTML=function(t){if("string"==typeof t)return t;if(!t||!t.isCustomSVG)return"";const i=t;let e='<svg aria-hidden="true" class="pswp__icn" viewBox="0 0 %d %d" width="%d" height="%d">';return e=e.split("%d").join(i.size||32),i.outlineID&&(e+='<use class="pswp__icn-shadow" xlink:href="#'+i.outlineID+'"/>'),e+=i.inner,e+="</svg>",e}(o),i.onInit&&i.onInit(r,t),i.onClick&&(r.onclick=e=>{"string"==typeof i.onClick?t[i.onClick]():"function"==typeof i.onClick&&i.onClick(e,r,t)});const l=i.appendTo||"bar";let p=t.element;"bar"===l?(t.topBar||(t.topBar=s("pswp__top-bar pswp__hide-on-close","div",t.scrollWrap)),p=t.topBar):(r.classList.add("pswp__hide-on-close"),"wrapper"===l&&(p=t.scrollWrap)),null===(e=p)||void 0===e||e.appendChild(t.applyFilters("uiElement",r,i))}}function V(t,i,e){t.classList.add("pswp__button--arrow"),t.setAttribute("aria-controls","pswp__items"),i.on("change",(()=>{i.options.loop||(t.disabled=e?!(i.currIndex<i.getNumItems()-1):!(i.currIndex>0))}))}const q={name:"arrowPrev",className:"pswp__button--arrow--prev",title:"Previous",order:10,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'<path d="M29 43l-3 3-16-16 16-16 3 3-13 13 13 13z" id="pswp__icn-arrow"/>',outlineID:"pswp__icn-arrow"},onClick:"prev",onInit:V},U={name:"arrowNext",className:"pswp__button--arrow--next",title:"Next",order:11,isButton:!0,appendTo:"wrapper",html:{isCustomSVG:!0,size:60,inner:'<use xlink:href="#pswp__icn-arrow"/>',outlineID:"pswp__icn-arrow"},onClick:"next",onInit:(t,i)=>{V(t,i,!0)}},G={name:"close",title:"Close",order:20,isButton:!0,html:{isCustomSVG:!0,inner:'<path d="M24 10l-2-2-6 6-6-6-2 2 6 6-6 6 2 2 6-6 6 6 2-2-6-6z" id="pswp__icn-close"/>',outlineID:"pswp__icn-close"},onClick:"close"},K={name:"zoom",title:"Zoom",order:10,isButton:!0,html:{isCustomSVG:!0,inner:'<path d="M17.426 19.926a6 6 0 1 1 1.5-1.5L23 22.5 21.5 24l-4.074-4.074z" id="pswp__icn-zoom"/><path fill="currentColor" class="pswp__zoom-icn-bar-h" d="M11 16v-2h6v2z"/><path fill="currentColor" class="pswp__zoom-icn-bar-v" d="M13 12h2v6h-2z"/>',outlineID:"pswp__icn-zoom"},onClick:"toggleZoom"},$={name:"preloader",appendTo:"bar",order:7,html:{isCustomSVG:!0,inner:'<path fill-rule="evenodd" clip-rule="evenodd" d="M21.2 16a5.2 5.2 0 1 1-5.2-5.2V8a8 8 0 1 0 8 8h-2.8Z" id="pswp__icn-loading"/>',outlineID:"pswp__icn-loading"},onInit:(t,i)=>{let e,s=null;const n=i=>{var s,n;e!==i&&(e=i,s="active",n=i,t.classList.toggle("pswp__preloader--"+s,n))},o=()=>{var t;if(null===(t=i.currSlide)||void 0===t||!t.content.isLoading())return n(!1),void(s&&(clearTimeout(s),s=null));s||(s=setTimeout((()=>{var t;n(Boolean(null===(t=i.currSlide)||void 0===t?void 0:t.content.isLoading())),s=null}),i.options.preloaderDelay))};i.on("change",o),i.on("loadComplete",(t=>{i.currSlide===t.slide&&o()})),i.ui&&(i.ui.updatePreloaderVisibility=o)}},X={name:"counter",order:5,onInit:(t,i)=>{i.on("change",(()=>{t.innerText=i.currIndex+1+i.options.indexIndicatorSep+i.getNumItems()}))}};function Y(t,i){t.classList.toggle("pswp--zoomed-in",i)}class j{constructor(t){this.pswp=t,this.isRegistered=!1,this.uiElementsData=[],this.items=[],this.updatePreloaderVisibility=()=>{},this._lastUpdatedZoomLevel=void 0}init(){const{pswp:t}=this;this.isRegistered=!1,this.uiElementsData=[G,q,U,K,$,X],t.dispatch("uiRegister"),this.uiElementsData.sort(((t,i)=>(t.order||0)-(i.order||0))),this.items=[],this.isRegistered=!0,this.uiElementsData.forEach((t=>{this.registerElement(t)})),t.on("change",(()=>{var i;null===(i=t.element)||void 0===i||i.classList.toggle("pswp--one-slide",1===t.getNumItems())})),t.on("zoomPanUpdate",(()=>this._onZoomPanUpdate()))}registerElement(t){this.isRegistered?this.items.push(new N(this.pswp,t)):this.uiElementsData.push(t)}_onZoomPanUpdate(){const{template:t,currSlide:i,options:e}=this.pswp;if(this.pswp.opener.isClosing||!t||!i)return;let{currZoomLevel:s}=i;if(this.pswp.opener.isOpen||(s=i.zoomLevels.initial),s===this._lastUpdatedZoomLevel)return;this._lastUpdatedZoomLevel=s;const n=i.zoomLevels.initial-i.zoomLevels.secondary;if(Math.abs(n)<.01||!i.isZoomable())return Y(t,!1),void t.classList.remove("pswp--zoom-allowed");t.classList.add("pswp--zoom-allowed");Y(t,(s===i.zoomLevels.initial?i.zoomLevels.secondary:i.zoomLevels.initial)<=s),"zoom"!==e.imageClickAction&&"zoom-or-close"!==e.imageClickAction||t.classList.add("pswp--click-to-zoom")}}class J{constructor(t,i){this.type=t,this.defaultPrevented=!1,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class Q{constructor(){this._listeners={},this._filters={},this.pswp=void 0,this.options=void 0}addFilter(t,i,e=100){var s,n,o;this._filters[t]||(this._filters[t]=[]),null===(s=this._filters[t])||void 0===s||s.push({fn:i,priority:e}),null===(n=this._filters[t])||void 0===n||n.sort(((t,i)=>t.priority-i.priority)),null===(o=this.pswp)||void 0===o||o.addFilter(t,i,e)}removeFilter(t,i){this._filters[t]&&(this._filters[t]=this._filters[t].filter((t=>t.fn!==i))),this.pswp&&this.pswp.removeFilter(t,i)}applyFilters(t,...i){var e;return null===(e=this._filters[t])||void 0===e||e.forEach((t=>{i[0]=t.fn.apply(this,i)})),i[0]}on(t,i){var e,s;this._listeners[t]||(this._listeners[t]=[]),null===(e=this._listeners[t])||void 0===e||e.push(i),null===(s=this.pswp)||void 0===s||s.on(t,i)}off(t,i){var e;this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter((t=>i!==t))),null===(e=this.pswp)||void 0===e||e.off(t,i)}dispatch(t,i){var e;if(this.pswp)return this.pswp.dispatch(t,i);const s=new J(t,i);return null===(e=this._listeners[t])||void 0===e||e.forEach((t=>{t.call(this,s)})),s}}class tt{constructor(t,i){if(this.element=s("pswp__img pswp__img--placeholder",t?"img":"div",i),t){const i=this.element;i.decoding="async",i.alt="",i.src=t,i.setAttribute("role","presentation")}this.element.setAttribute("aria-hidden","true")}setDisplayedSize(t,i){this.element&&("IMG"===this.element.tagName?(c(this.element,250,"auto"),this.element.style.transformOrigin="0 0",this.element.style.transform=l(0,0,t/250)):c(this.element,t,i))}destroy(){var t;null!==(t=this.element)&&void 0!==t&&t.parentNode&&this.element.remove(),this.element=null}}class it{constructor(t,i,e){this.instance=i,this.data=t,this.index=e,this.element=void 0,this.placeholder=void 0,this.slide=void 0,this.displayedImageWidth=0,this.displayedImageHeight=0,this.width=Number(this.data.w)||Number(this.data.width)||0,this.height=Number(this.data.h)||Number(this.data.height)||0,this.isAttached=!1,this.hasSlide=!1,this.isDecoding=!1,this.state=m,this.data.type?this.type=this.data.type:this.data.src?this.type="image":this.type="html",this.instance.dispatch("contentInit",{content:this})}removePlaceholder(){this.placeholder&&!this.keepPlaceholder()&&setTimeout((()=>{this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0)}),1e3)}load(t,i){if(this.slide&&this.usePlaceholder())if(this.placeholder){const t=this.placeholder.element;t&&!t.parentElement&&this.slide.container.prepend(t)}else{const t=this.instance.applyFilters("placeholderSrc",!(!this.data.msrc||!this.slide.isFirstSlide)&&this.data.msrc,this);this.placeholder=new tt(t,this.slide.container)}this.element&&!i||this.instance.dispatch("contentLoad",{content:this,isLazy:t}).defaultPrevented||(this.isImageContent()?(this.element=s("pswp__img","img"),this.displayedImageWidth&&this.loadImage(t)):(this.element=s("pswp__content","div"),this.element.innerHTML=this.data.html||""),i&&this.slide&&this.slide.updateContentSize(!0))}loadImage(t){var i,e;if(!this.isImageContent()||!this.element||this.instance.dispatch("contentLoadImage",{content:this,isLazy:t}).defaultPrevented)return;const s=this.element;this.updateSrcsetSizes(),this.data.srcset&&(s.srcset=this.data.srcset),s.src=null!==(i=this.data.src)&&void 0!==i?i:"",s.alt=null!==(e=this.data.alt)&&void 0!==e?e:"",this.state=u,s.complete?this.onLoaded():(s.onload=()=>{this.onLoaded()},s.onerror=()=>{this.onError()})}setSlide(t){this.slide=t,this.hasSlide=!0,this.instance=t.pswp}onLoaded(){this.state=v,this.slide&&this.element&&(this.instance.dispatch("loadComplete",{slide:this.slide,content:this}),this.slide.isActive&&this.slide.heavyAppended&&!this.element.parentNode&&(this.append(),this.slide.updateContentSize(!0)),this.state!==v&&this.state!==_||this.removePlaceholder())}onError(){this.state=_,this.slide&&(this.displayError(),this.instance.dispatch("loadComplete",{slide:this.slide,isError:!0,content:this}),this.instance.dispatch("loadError",{slide:this.slide,content:this}))}isLoading(){return this.instance.applyFilters("isContentLoading",this.state===u,this)}isError(){return this.state===_}isImageContent(){return"image"===this.type}setDisplayedSize(t,i){if(this.element&&(this.placeholder&&this.placeholder.setDisplayedSize(t,i),!this.instance.dispatch("contentResize",{content:this,width:t,height:i}).defaultPrevented&&(c(this.element,t,i),this.isImageContent()&&!this.isError()))){const e=!this.displayedImageWidth&&t;this.displayedImageWidth=t,this.displayedImageHeight=i,e?this.loadImage(!1):this.updateSrcsetSizes(),this.slide&&this.instance.dispatch("imageSizeChange",{slide:this.slide,width:t,height:i,content:this})}}isZoomable(){return this.instance.applyFilters("isContentZoomable",this.isImageContent()&&this.state!==_,this)}updateSrcsetSizes(){if(!this.isImageContent()||!this.element||!this.data.srcset)return;const t=this.element,i=this.instance.applyFilters("srcsetSizesWidth",this.displayedImageWidth,this);(!t.dataset.largestUsedSize||i>parseInt(t.dataset.largestUsedSize,10))&&(t.sizes=i+"px",t.dataset.largestUsedSize=String(i))}usePlaceholder(){return this.instance.applyFilters("useContentPlaceholder",this.isImageContent(),this)}lazyLoad(){this.instance.dispatch("contentLazyLoad",{content:this}).defaultPrevented||this.load(!0)}keepPlaceholder(){return this.instance.applyFilters("isKeepingPlaceholder",this.isLoading(),this)}destroy(){this.hasSlide=!1,this.slide=void 0,this.instance.dispatch("contentDestroy",{content:this}).defaultPrevented||(this.remove(),this.placeholder&&(this.placeholder.destroy(),this.placeholder=void 0),this.isImageContent()&&this.element&&(this.element.onload=null,this.element.onerror=null,this.element=void 0))}displayError(){if(this.slide){var t,i;let e=s("pswp__error-msg","div");e.innerText=null!==(t=null===(i=this.instance.options)||void 0===i?void 0:i.errorMsg)&&void 0!==t?t:"",e=this.instance.applyFilters("contentErrorElement",e,this),this.element=s("pswp__content pswp__error-msg-container","div"),this.element.appendChild(e),this.slide.container.innerText="",this.slide.container.appendChild(this.element),this.slide.updateContentSize(!0),this.removePlaceholder()}}append(){if(this.isAttached||!this.element)return;if(this.isAttached=!0,this.state===_)return void this.displayError();if(this.instance.dispatch("contentAppend",{content:this}).defaultPrevented)return;const t="decode"in this.element;this.isImageContent()?t&&this.slide&&(!this.slide.isActive||g())?(this.isDecoding=!0,this.element.decode().catch((()=>{})).finally((()=>{this.isDecoding=!1,this.appendImage()}))):this.appendImage():this.slide&&!this.element.parentNode&&this.slide.container.appendChild(this.element)}activate(){!this.instance.dispatch("contentActivate",{content:this}).defaultPrevented&&this.slide&&(this.isImageContent()&&this.isDecoding&&!g()?this.appendImage():this.isError()&&this.load(!1,!0),this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","false"))}deactivate(){this.instance.dispatch("contentDeactivate",{content:this}),this.slide&&this.slide.holderElement&&this.slide.holderElement.setAttribute("aria-hidden","true")}remove(){this.isAttached=!1,this.instance.dispatch("contentRemove",{content:this}).defaultPrevented||(this.element&&this.element.parentNode&&this.element.remove(),this.placeholder&&this.placeholder.element&&this.placeholder.element.remove())}appendImage(){this.isAttached&&(this.instance.dispatch("contentAppendImage",{content:this}).defaultPrevented||(this.slide&&this.element&&!this.element.parentNode&&this.slide.container.appendChild(this.element),this.state!==v&&this.state!==_||this.removePlaceholder()))}}function et(t,i,e){const s=i.createContentFromData(t,e);let n;const{options:o}=i;if(o){let a;n=new b(o,t,-1),a=i.pswp?i.pswp.viewportSize:w(o,i);const h=P(o,a,t,e);n.update(s.width,s.height,h)}return s.lazyLoad(),n&&s.setDisplayedSize(Math.ceil(s.width*n.initial),Math.ceil(s.height*n.initial)),s}class st{constructor(t){this.pswp=t,this.limit=Math.max(t.options.preload[0]+t.options.preload[1]+1,5),this._cachedItems=[]}updateLazy(t){const{pswp:i}=this;if(i.dispatch("lazyLoad").defaultPrevented)return;const{preload:e}=i.options,s=void 0===t||t>=0;let n;for(n=0;n<=e[1];n++)this.loadSlideByIndex(i.currIndex+(s?n:-n));for(n=1;n<=e[0];n++)this.loadSlideByIndex(i.currIndex+(s?-n:n))}loadSlideByIndex(t){const i=this.pswp.getLoopedIndex(t);let e=this.getContentByIndex(i);e||(e=function(t,i){const e=i.getItemData(t);if(!i.dispatch("lazyLoadSlide",{index:t,itemData:e}).defaultPrevented)return et(e,i,t)}(i,this.pswp),e&&this.addToCache(e))}getContentBySlide(t){let i=this.getContentByIndex(t.index);return i||(i=this.pswp.createContentFromData(t.data,t.index),this.addToCache(i)),i.setSlide(t),i}addToCache(t){if(this.removeByIndex(t.index),this._cachedItems.push(t),this._cachedItems.length>this.limit){const t=this._cachedItems.findIndex((t=>!t.isAttached&&!t.hasSlide));if(-1!==t){this._cachedItems.splice(t,1)[0].destroy()}}}removeByIndex(t){const i=this._cachedItems.findIndex((i=>i.index===t));-1!==i&&this._cachedItems.splice(i,1)}getContentByIndex(t){return this._cachedItems.find((i=>i.index===t))}destroy(){this._cachedItems.forEach((t=>t.destroy())),this._cachedItems=[]}}class nt extends Q{getNumItems(){var t;let i=0;const e=null===(t=this.options)||void 0===t?void 0:t.dataSource;e&&"length"in e?i=e.length:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),e.items&&(i=e.items.length));const s=this.dispatch("numItems",{dataSource:e,numItems:i});return this.applyFilters("numItems",s.numItems,e)}createContentFromData(t,i){return new it(t,this,i)}getItemData(t){var i;const e=null===(i=this.options)||void 0===i?void 0:i.dataSource;let s={};Array.isArray(e)?s=e[t]:e&&"gallery"in e&&(e.items||(e.items=this._getGalleryDOMElements(e.gallery)),s=e.items[t]);let n=s;n instanceof Element&&(n=this._domElementToItemData(n));const o=this.dispatch("itemData",{itemData:n||{},index:t});return this.applyFilters("itemData",o.itemData,t)}_getGalleryDOMElements(t){var i,e;return null!==(i=this.options)&&void 0!==i&&i.children||null!==(e=this.options)&&void 0!==e&&e.childSelector?function(t,i,e=document){let s=[];if(t instanceof Element)s=[t];else if(t instanceof NodeList||Array.isArray(t))s=Array.from(t);else{const n="string"==typeof t?t:i;n&&(s=Array.from(e.querySelectorAll(n)))}return s}(this.options.children,this.options.childSelector,t)||[]:[t]}_domElementToItemData(t){const i={element:t},e="A"===t.tagName?t:t.querySelector("a");if(e){i.src=e.dataset.pswpSrc||e.href,e.dataset.pswpSrcset&&(i.srcset=e.dataset.pswpSrcset),i.width=e.dataset.pswpWidth?parseInt(e.dataset.pswpWidth,10):0,i.height=e.dataset.pswpHeight?parseInt(e.dataset.pswpHeight,10):0,i.w=i.width,i.h=i.height,e.dataset.pswpType&&(i.type=e.dataset.pswpType);const n=t.querySelector("img");var s;if(n)i.msrc=n.currentSrc||n.src,i.alt=null!==(s=n.getAttribute("alt"))&&void 0!==s?s:"";(e.dataset.pswpCropped||e.dataset.cropped)&&(i.thumbCropped=!0)}return this.applyFilters("domItemData",i,t,e)}lazyLoadData(t,i){return et(t,this,i)}}const ot=.003;class at{constructor(t){this.pswp=t,this.isClosed=!0,this.isOpen=!1,this.isClosing=!1,this.isOpening=!1,this._duration=void 0,this._useAnimation=!1,this._croppedZoom=!1,this._animateRootOpacity=!1,this._animateBgOpacity=!1,this._placeholder=void 0,this._opacityElement=void 0,this._cropContainer1=void 0,this._cropContainer2=void 0,this._thumbBounds=void 0,this._prepareOpen=this._prepareOpen.bind(this),t.on("firstZoomPan",this._prepareOpen)}open(){this._prepareOpen(),this._start()}close(){if(this.isClosed||this.isClosing||this.isOpening)return;const t=this.pswp.currSlide;this.isOpen=!1,this.isOpening=!1,this.isClosing=!0,this._duration=this.pswp.options.hideAnimationDuration,t&&t.currZoomLevel*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps(),setTimeout((()=>{this._start()}),this._croppedZoom?30:0)}_prepareOpen(){if(this.pswp.off("firstZoomPan",this._prepareOpen),!this.isOpening){const t=this.pswp.currSlide;this.isOpening=!0,this.isClosing=!1,this._duration=this.pswp.options.showAnimationDuration,t&&t.zoomLevels.initial*t.width>=this.pswp.options.maxWidthToAnimate&&(this._duration=0),this._applyStartProps()}}_applyStartProps(){const{pswp:t}=this,i=this.pswp.currSlide,{options:e}=t;var s,n;("fade"===e.showHideAnimationType?(e.showHideOpacity=!0,this._thumbBounds=void 0):"none"===e.showHideAnimationType?(e.showHideOpacity=!1,this._duration=0,this._thumbBounds=void 0):this.isOpening&&t._initialThumbBounds?this._thumbBounds=t._initialThumbBounds:this._thumbBounds=this.pswp.getThumbBounds(),this._placeholder=null==i?void 0:i.getPlaceholderElement(),t.animations.stopAll(),this._useAnimation=Boolean(this._duration&&this._duration>50),this._animateZoom=Boolean(this._thumbBounds)&&(null==i?void 0:i.content.usePlaceholder())&&(!this.isClosing||!t.mainScroll.isShifted()),this._animateZoom)?this._animateRootOpacity=null!==(s=e.showHideOpacity)&&void 0!==s&&s:(this._animateRootOpacity=!0,this.isOpening&&i&&(i.zoomAndPanToInitial(),i.applyCurrentZoomPan()));if(this._animateBgOpacity=!this._animateRootOpacity&&this.pswp.options.bgOpacity>ot,this._opacityElement=this._animateRootOpacity?t.element:t.bg,!this._useAnimation)return this._duration=0,this._animateZoom=!1,this._animateBgOpacity=!1,this._animateRootOpacity=!0,void(this.isOpening&&(t.element&&(t.element.style.opacity=String(ot)),t.applyBgOpacity(1)));this._animateZoom&&this._thumbBounds&&this._thumbBounds.innerRect?(this._croppedZoom=!0,this._cropContainer1=this.pswp.container,this._cropContainer2=null===(n=this.pswp.currSlide)||void 0===n?void 0:n.holderElement,t.container&&(t.container.style.overflow="hidden",t.container.style.width=t.viewportSize.x+"px")):this._croppedZoom=!1;this.isOpening?(this._animateRootOpacity?(t.element&&(t.element.style.opacity=String(ot)),t.applyBgOpacity(1)):(this._animateBgOpacity&&t.bg&&(t.bg.style.opacity=String(ot)),t.element&&(t.element.style.opacity="1")),this._animateZoom&&(this._setClosedStateZoomPan(),this._placeholder&&(this._placeholder.style.willChange="transform",this._placeholder.style.opacity=String(ot)))):this.isClosing&&(t.mainScroll.itemHolders[0]&&(t.mainScroll.itemHolders[0].el.style.display="none"),t.mainScroll.itemHolders[2]&&(t.mainScroll.itemHolders[2].el.style.display="none"),this._croppedZoom&&0!==t.mainScroll.x&&(t.mainScroll.resetPosition(),t.mainScroll.resize()))}_start(){this.isOpening&&this._useAnimation&&this._placeholder&&"IMG"===this._placeholder.tagName?new Promise((t=>{let i=!1,e=!0;var s;(s=this._placeholder,"decode"in s?s.decode().catch((()=>{})):s.complete?Promise.resolve(s):new Promise(((t,i)=>{s.onload=()=>t(s),s.onerror=i}))).finally((()=>{i=!0,e||t(!0)})),setTimeout((()=>{e=!1,i&&t(!0)}),50),setTimeout(t,250)})).finally((()=>this._initiate())):this._initiate()}_initiate(){var t,i;null===(t=this.pswp.element)||void 0===t||t.style.setProperty("--pswp-transition-duration",this._duration+"ms"),this.pswp.dispatch(this.isOpening?"openingAnimationStart":"closingAnimationStart"),this.pswp.dispatch("initialZoom"+(this.isOpening?"In":"Out")),null===(i=this.pswp.element)||void 0===i||i.classList.toggle("pswp--ui-visible",this.isOpening),this.isOpening?(this._placeholder&&(this._placeholder.style.opacity="1"),this._animateToOpenState()):this.isClosing&&this._animateToClosedState(),this._useAnimation||this._onAnimationComplete()}_onAnimationComplete(){const{pswp:t}=this;if(this.isOpen=this.isOpening,this.isClosed=this.isClosing,this.isOpening=!1,this.isClosing=!1,t.dispatch(this.isOpen?"openingAnimationEnd":"closingAnimationEnd"),t.dispatch("initialZoom"+(this.isOpen?"InEnd":"OutEnd")),this.isClosed)t.destroy();else if(this.isOpen){var i;this._animateZoom&&t.container&&(t.container.style.overflow="visible",t.container.style.width="100%"),null===(i=t.currSlide)||void 0===i||i.applyCurrentZoomPan()}}_animateToOpenState(){const{pswp:t}=this;this._animateZoom&&(this._croppedZoom&&this._cropContainer1&&this._cropContainer2&&(this._animateTo(this._cropContainer1,"transform","translate3d(0,0,0)"),this._animateTo(this._cropContainer2,"transform","none")),t.currSlide&&(t.currSlide.zoomAndPanToInitial(),this._animateTo(t.currSlide.container,"transform",t.currSlide.getCurrentTransform()))),this._animateBgOpacity&&t.bg&&this._animateTo(t.bg,"opacity",String(t.options.bgOpacity)),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","1")}_animateToClosedState(){const{pswp:t}=this;this._animateZoom&&this._setClosedStateZoomPan(!0),this._animateBgOpacity&&t.bgOpacity>.01&&t.bg&&this._animateTo(t.bg,"opacity","0"),this._animateRootOpacity&&t.element&&this._animateTo(t.element,"opacity","0")}_setClosedStateZoomPan(t){if(!this._thumbBounds)return;const{pswp:i}=this,{innerRect:e}=this._thumbBounds,{currSlide:s,viewportSize:o}=i;if(this._croppedZoom&&e&&this._cropContainer1&&this._cropContainer2){const i=-o.x+(this._thumbBounds.x-e.x)+e.w,s=-o.y+(this._thumbBounds.y-e.y)+e.h,n=o.x-e.w,a=o.y-e.h;t?(this._animateTo(this._cropContainer1,"transform",l(i,s)),this._animateTo(this._cropContainer2,"transform",l(n,a))):(p(this._cropContainer1,i,s),p(this._cropContainer2,n,a))}s&&(n(s.pan,e||this._thumbBounds),s.currZoomLevel=this._thumbBounds.w/s.width,t?this._animateTo(s.container,"transform",s.getCurrentTransform()):s.applyCurrentZoomPan())}_animateTo(t,i,e){if(!this._duration)return void(t.style[i]=e);const{animations:s}=this.pswp,n={duration:this._duration,easing:this.pswp.options.easing,onComplete:()=>{s.activeAnimations.length||this._onAnimationComplete()},target:t};n[i]=e,s.startTransition(n)}}const ht={allowPanToNext:!0,spacing:.1,loop:!0,pinchToClose:!0,closeOnVerticalDrag:!0,hideAnimationDuration:333,showAnimationDuration:333,zoomAnimationDuration:333,escKey:!0,arrowKeys:!0,trapFocus:!0,returnFocus:!0,maxWidthToAnimate:4e3,clickToCloseNonZoomable:!0,imageClickAction:"zoom-or-close",bgClickAction:"close",tapAction:"toggle-controls",doubleTapAction:"zoom",indexIndicatorSep:" / ",preloaderDelay:2e3,bgOpacity:.8,index:0,errorMsg:"The image cannot be loaded",preload:[1,2],easing:"cubic-bezier(.4,0,.22,1)"};class rt extends nt{constructor(t){super(),this.options=this._prepareOptions(t||{}),this.offset={x:0,y:0},this._prevViewportSize={x:0,y:0},this.viewportSize={x:0,y:0},this.bgOpacity=1,this.currIndex=0,this.potentialIndex=0,this.isOpen=!1,this.isDestroying=!1,this.hasMouse=!1,this._initialItemData={},this._initialThumbBounds=void 0,this.topBar=void 0,this.element=void 0,this.template=void 0,this.container=void 0,this.scrollWrap=void 0,this.currSlide=void 0,this.events=new f,this.animations=new H,this.mainScroll=new O(this),this.gestures=new Z(this),this.opener=new at(this),this.keyboard=new M(this),this.contentLoader=new st(this)}init(){if(this.isOpen||this.isDestroying)return!1;this.isOpen=!0,this.dispatch("init"),this.dispatch("beforeOpen"),this._createMainStructure();let t="pswp--open";return this.gestures.supportsTouch&&(t+=" pswp--touch"),this.options.mainClass&&(t+=" "+this.options.mainClass),this.element&&(this.element.className+=" "+t),this.currIndex=this.options.index||0,this.potentialIndex=this.currIndex,this.dispatch("firstUpdate"),this.scrollWheel=new W(this),(Number.isNaN(this.currIndex)||this.currIndex<0||this.currIndex>=this.getNumItems())&&(this.currIndex=0),this.gestures.supportsTouch||this.mouseDetected(),this.updateSize(),this.offset.y=window.pageYOffset,this._initialItemData=this.getItemData(this.currIndex),this.dispatch("gettingData",{index:this.currIndex,data:this._initialItemData,slide:void 0}),this._initialThumbBounds=this.getThumbBounds(),this.dispatch("initialLayout"),this.on("openingAnimationEnd",(()=>{const{itemHolders:t}=this.mainScroll;t[0]&&(t[0].el.style.display="block",this.setContent(t[0],this.currIndex-1)),t[2]&&(t[2].el.style.display="block",this.setContent(t[2],this.currIndex+1)),this.appendHeavy(),this.contentLoader.updateLazy(),this.events.add(window,"resize",this._handlePageResize.bind(this)),this.events.add(window,"scroll",this._updatePageScrollOffset.bind(this)),this.dispatch("bindEvents")})),this.mainScroll.itemHolders[1]&&this.setContent(this.mainScroll.itemHolders[1],this.currIndex),this.dispatch("change"),this.opener.open(),this.dispatch("afterInit"),!0}getLoopedIndex(t){const i=this.getNumItems();return this.options.loop&&(t>i-1&&(t-=i),t<0&&(t+=i)),r(t,0,i-1)}appendHeavy(){this.mainScroll.itemHolders.forEach((t=>{var i;null===(i=t.slide)||void 0===i||i.appendHeavy()}))}goTo(t){this.mainScroll.moveIndexBy(this.getLoopedIndex(t)-this.potentialIndex)}next(){this.goTo(this.potentialIndex+1)}prev(){this.goTo(this.potentialIndex-1)}zoomTo(...t){var i;null===(i=this.currSlide)||void 0===i||i.zoomTo(...t)}toggleZoom(){var t;null===(t=this.currSlide)||void 0===t||t.toggleZoom()}close(){this.opener.isOpen&&!this.isDestroying&&(this.isDestroying=!0,this.dispatch("close"),this.events.removeAll(),this.opener.close())}destroy(){var t;if(!this.isDestroying)return this.options.showHideAnimationType="none",void this.close();this.dispatch("destroy"),this._listeners={},this.scrollWrap&&(this.scrollWrap.ontouchmove=null,this.scrollWrap.ontouchend=null),null===(t=this.element)||void 0===t||t.remove(),this.mainScroll.itemHolders.forEach((t=>{var i;null===(i=t.slide)||void 0===i||i.destroy()})),this.contentLoader.destroy(),this.events.removeAll()}refreshSlideContent(t){this.contentLoader.removeByIndex(t),this.mainScroll.itemHolders.forEach(((i,e)=>{var s,n;let o=(null!==(s=null===(n=this.currSlide)||void 0===n?void 0:n.index)&&void 0!==s?s:0)-1+e;var a;(this.canLoop()&&(o=this.getLoopedIndex(o)),o===t)&&(this.setContent(i,t,!0),1===e&&(this.currSlide=i.slide,null===(a=i.slide)||void 0===a||a.setIsActive(!0)))})),this.dispatch("change")}setContent(t,i,e){if(this.canLoop()&&(i=this.getLoopedIndex(i)),t.slide){if(t.slide.index===i&&!e)return;t.slide.destroy(),t.slide=void 0}if(!this.canLoop()&&(i<0||i>=this.getNumItems()))return;const s=this.getItemData(i);t.slide=new z(s,i,this),i===this.currIndex&&(this.currSlide=t.slide),t.slide.append(t.el)}getViewportCenterPoint(){return{x:this.viewportSize.x/2,y:this.viewportSize.y/2}}updateSize(t){if(this.isDestroying)return;const i=w(this.options,this);!t&&h(i,this._prevViewportSize)||(n(this._prevViewportSize,i),this.dispatch("beforeResize"),n(this.viewportSize,this._prevViewportSize),this._updatePageScrollOffset(),this.dispatch("viewportSize"),this.mainScroll.resize(this.opener.isOpen),!this.hasMouse&&window.matchMedia("(any-hover: hover)").matches&&this.mouseDetected(),this.dispatch("resize"))}applyBgOpacity(t){this.bgOpacity=Math.max(t,0),this.bg&&(this.bg.style.opacity=String(this.bgOpacity*this.options.bgOpacity))}mouseDetected(){var t;this.hasMouse||(this.hasMouse=!0,null===(t=this.element)||void 0===t||t.classList.add("pswp--has_mouse"))}_handlePageResize(){this.updateSize(),/iPhone|iPad|iPod/i.test(window.navigator.userAgent)&&setTimeout((()=>{this.updateSize()}),500)}_updatePageScrollOffset(){this.setScrollOffset(0,window.pageYOffset)}setScrollOffset(t,i){this.offset.x=t,this.offset.y=i,this.dispatch("updateScrollOffset")}_createMainStructure(){this.element=s("pswp","div"),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.template=this.element,this.bg=s("pswp__bg","div",this.element),this.scrollWrap=s("pswp__scroll-wrap","section",this.element),this.container=s("pswp__container","div",this.scrollWrap),this.scrollWrap.setAttribute("aria-roledescription","carousel"),this.container.setAttribute("aria-live","off"),this.container.setAttribute("id","pswp__items"),this.mainScroll.appendHolders(),this.ui=new j(this),this.ui.init(),(this.options.appendToEl||document.body).appendChild(this.element)}getThumbBounds(){return function(t,i,e){const s=e.dispatch("thumbBounds",{index:t,itemData:i,instance:e});if(s.thumbBounds)return s.thumbBounds;const{element:n}=i;let o,a;if(n&&!1!==e.options.thumbSelector){const t=e.options.thumbSelector||"img";a=n.matches(t)?n:n.querySelector(t)}return a=e.applyFilters("thumbEl",a,i,t),a&&(o=i.thumbCropped?function(t,i,e){const s=t.getBoundingClientRect(),n=s.width/i,o=s.height/e,a=n>o?n:o,h=(s.width-i*a)/2,r=(s.height-e*a)/2,l={x:s.left+h,y:s.top+r,w:i*a};return l.innerRect={w:s.width,h:s.height,x:h,y:r},l}(a,i.width||i.w||0,i.height||i.h||0):function(t){const i=t.getBoundingClientRect();return{x:i.left,y:i.top,w:i.width}}(a)),e.applyFilters("thumbBounds",o,i,t)}(this.currIndex,this.currSlide?this.currSlide.data:this._initialItemData,this)}canLoop(){return this.options.loop&&this.getNumItems()>2}_prepareOptions(t){return window.matchMedia("(prefers-reduced-motion), (update: slow)").matches&&(t.showHideAnimationType="none",t.zoomAnimationDuration=0),{...ht,...t}}}}}]);
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
2
+ * Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
3
3
  * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4
4
  * Copyright 2024 Fonticons, Inc.
5
5
  */
@@ -11,7 +11,9 @@ module Trestle
11
11
 
12
12
  protected
13
13
  def modal_request?
14
- request.headers["X-Trestle-Modal"] || request.headers["X-Trestle-Dialog"]
14
+ turbo_frame_request_id == "modal" ||
15
+ request.headers["X-Trestle-Modal"] ||
16
+ request.headers["X-Trestle-Dialog"]
15
17
  end
16
18
 
17
19
  def dialog_request?
@@ -1,23 +1,29 @@
1
1
  module Trestle
2
2
  module AvatarHelper
3
- def avatar(options={})
4
- fallback = options.delete(:fallback) if options[:fallback]
5
-
6
- content_tag(:div, default_avatar_options.merge(options)) do
7
- concat content_tag(:span, fallback, class: "avatar-fallback") if fallback
3
+ # Renders an avatar (or similar image) styled as a circle typically designed to
4
+ # represent a user (though not limited to that). The avatar helper accepts a block
5
+ # within which the image should be provided, which will be resized to fit.
6
+ #
7
+ # fallback - Optional short text (2-3 characters) shown when no image is available
8
+ # attributes - Additional HTML attributes to add to the <div> tag
9
+ #
10
+ # Examples
11
+ #
12
+ # <%= avatar { image_tag("person.jpg") } %>
13
+ #
14
+ # <%= avatar(fallback: "SP", class: "avatar-lg") { gravatar("sam@trestle.io") } %>
15
+ #
16
+ # <%= avatar(style: "--avatar-size: 3rem") { gravatar("sam@trestle.io") }
17
+ #
18
+ # Return the HTML div containing the avatar image.
19
+ def avatar(fallback: nil, **attributes, &block)
20
+ tag.div(**default_avatar_options.merge(attributes)) do
21
+ concat tag.span(fallback, class: "avatar-fallback") if fallback
8
22
  concat yield if block_given?
9
23
  end
10
24
  end
11
25
 
12
- def gravatar(email, options={})
13
- options = { d: "mp" }.merge(options)
14
-
15
- url = "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email.to_s.downcase)}.png"
16
- url << "?#{options.to_query}" if options.any?
17
-
18
- image_tag(url)
19
- end
20
-
26
+ protected
21
27
  def default_avatar_options
22
28
  Trestle::Options.new(class: ["avatar"])
23
29
  end
@@ -1,23 +1,41 @@
1
1
  module Trestle
2
2
  module CardHelper
3
- def card(options={}, &block)
4
- content_tag(:div, options.slice(:id, :data).merge(class: ["card", options[:class]].compact)) do
3
+ # Renders a card container element (sometimes also known as a panel or well), based on
4
+ # Bootstrap's card element (https://getbootstrap.com/docs/5.3/components/card/).
5
+ #
6
+ # header - Optional header to add within a .card-header
7
+ # footer - Optional footer to add within a .card-footer
8
+ # attributes - Additional HTML attributes to add to the container <div> tag
9
+ #
10
+ # Examples
11
+ #
12
+ # <%= card do %>
13
+ # <p>Card content here...</p>
14
+ # <% end %>
15
+ #
16
+ # <%= card header: "Header", footer: "Footer", class: "text-bg-primary" do %>...
17
+ #
18
+ # Returns a HTML-safe String.
19
+ def card(header: nil, footer: nil, **attributes, &block)
20
+ tag.div(**attributes.merge(class: ["card", attributes[:class]])) do
5
21
  safe_join([
6
- (content_tag(:div, options[:header], class: "card-header") if options[:header]),
7
- content_tag(:div, class: "card-body", &block),
8
- (content_tag(:div, options[:footer], class: "card-footer") if options[:footer])
22
+ (tag.header(header, class: "card-header") if header),
23
+ tag.div(class: "card-body", &block),
24
+ (tag.footer(footer, class: "card-footer") if footer)
9
25
  ].compact)
10
26
  end
11
27
  end
12
28
 
13
- def panel(options={}, &block)
29
+ # [DEPRECATED] Alias for card
30
+ def panel(**attributes, &block)
14
31
  Trestle.deprecator.warn("The panel helper is deprecated and will be removed in future versions of Trestle. Please use the card helper instead.")
15
- card(options.merge(header: options[:title]), &block)
32
+ card(**attributes.merge(header: attributes[:title]), &block)
16
33
  end
17
34
 
18
- def well(options={}, &block)
35
+ # [DEPRECATED] Alias for card
36
+ def well(**attributes, &block)
19
37
  Trestle.deprecator.warn("The well helper is deprecated and will be removed in future versions of Trestle. Please use the card helper instead.")
20
- card(options, &block)
38
+ card(**attributes, &block)
21
39
  end
22
40
  end
23
41
  end
@@ -1,11 +1,35 @@
1
1
  module Trestle
2
2
  module ContainerHelper
3
- def container(&block)
3
+ # Renders a content container with an optional sidebar, which can
4
+ # be useful when creating an admin or dashboard with a custom view.
5
+ #
6
+ # This helper accepts a block (within which the main content is provided),
7
+ # which yields a `Context` capture object. The Context object has one important
8
+ # method -- `sidebar(**attributes, &block)` which captures the sidebar content
9
+ # to be rendered after the main content.
10
+ #
11
+ # attributes - Additional HTML attributes to add to the <div> tag
12
+ #
13
+ # Examples
14
+ #
15
+ # <%= container do |c| %>
16
+ # This content will be wrapped in a .main-content-container > .main-content div.
17
+ # <% end %>
18
+ #
19
+ # <%= container do |c| %>
20
+ # <% c.sidebar class: "order-first" %>
21
+ # Sidebar content...
22
+ # <% end %>
23
+ # Main content...
24
+ # <% end %>
25
+ #
26
+ # Returns a HTML-safe String.
27
+ def container(**attributes, &block)
4
28
  context = Context.new(self)
5
- content = capture(context, &block)
29
+ content = capture(context, &block) if block_given?
6
30
 
7
- content_tag(:div, class: "main-content-container") do
8
- concat content_tag(:div, content, class: "main-content")
31
+ tag.div(**attributes.merge(class: ["main-content-container", attributes[:class]])) do
32
+ concat tag.div(content, class: "main-content")
9
33
  concat context.sidebar if context.sidebar
10
34
  end
11
35
  end
@@ -15,15 +39,22 @@ module Trestle
15
39
  @template = template
16
40
  end
17
41
 
18
- def sidebar(options={}, &block)
42
+ # Captures or renders the sidebar for a container block.
43
+ #
44
+ # When passed a block, the block content is captured as the sidebar content, and nil is returned.
45
+ # When no block is provided, the sidebar tag is returned (if defined).
46
+ #
47
+ # attributes - Additional HTML attributes to add to the <div> tag
48
+ def sidebar(**attributes, &block)
19
49
  if block_given?
20
- @sidebar = @template.content_tag(:aside, default_sidebar_options.merge(options), &block)
50
+ @sidebar = @template.tag.aside(**default_sidebar_options.merge(attributes), &block)
21
51
  nil
22
52
  else
23
53
  @sidebar
24
54
  end
25
55
  end
26
56
 
57
+ protected
27
58
  def default_sidebar_options
28
59
  Trestle::Options.new(class: ["main-content-sidebar"])
29
60
  end
@@ -1,5 +1,16 @@
1
1
  module Trestle
2
2
  module DisplayHelper
3
+ # Returns a plain-text representation of the given model instance,
4
+ # typically used when rendering an associated object within a table.
5
+ #
6
+ # This helper delegates to Trestle::Display, which works by checking the
7
+ # existence of each method from `Trestle.config.display_methods` in turn
8
+ # and calling the first one it finds.
9
+ #
10
+ # By default this list is set to:
11
+ #
12
+ # [:display_name, :full_name, :name, :title, :username, :login, :email]
13
+ #
3
14
  def display(instance)
4
15
  Trestle::Display.new(instance).to_s
5
16
  end
@@ -1,4 +1,5 @@
1
1
  module Trestle
2
+ # [Internal]
2
3
  module FlashHelper
3
4
  def normalize_flash_alert(flash)
4
5
  flash.is_a?(Hash) ? flash.with_indifferent_access : { message: flash }
@@ -11,15 +12,5 @@ module Trestle
11
12
  def instance_has_errors?
12
13
  instance.errors.any? rescue false
13
14
  end
14
-
15
- def turbo_stream_update_flash
16
- <<-EOF
17
- <turbo-stream action="update" target="flash">
18
- <template>
19
- #{render_to_string(partial: "trestle/flash/flash", formats: [:html])}
20
- </template>
21
- </turbo-stream>
22
- EOF
23
- end
24
15
  end
25
16
  end
@@ -1,22 +1,46 @@
1
1
  module Trestle
2
2
  module FormHelper
3
- IDENTITY_FIELD_ERROR_PROC = Proc.new { |html_tag, instance| html_tag }
4
- DEFAULT_FORM_CONTROLLERS = %w(keyboard-submit form-loading form-error)
5
-
6
- def trestle_form_for(instance, options={}, &block)
3
+ # Generates a form for a resource using Rails' #form_for helper.
4
+ #
5
+ # In addition to delegating to #form_for, this helper method:
6
+ #
7
+ # 1) Sets the default form builder to `Trestle::Form::Builder`.
8
+ # 2) Sets the default :as option to match the parameter name
9
+ # expected by the admin.
10
+ # 3) Sets default Stimulus controllers on the <form> element
11
+ # from `Trestle.config.default_form_controllers`.
12
+ # (defaults to: "keyboard-submit form-loading form-error")
13
+ # 4) Sets a null/identity ActionView::Base.field_error_proc as
14
+ # errors are handled by Trestle::Form::Fields::FormGroup.
15
+ # 5) Exposes the yielded form builder instance via the `form` helper.
16
+ #
17
+ # Examples
18
+ #
19
+ # <%= trestle_form_for(article, url: admin.instance_path(instance, action: :update),
20
+ # method: :patch) do %> ...
21
+ #
22
+ # Returns a HTML-safe String. Yields the form builder instance.
23
+ def trestle_form_for(instance, **options, &block)
7
24
  options[:builder] ||= Form::Builder
8
25
  options[:as] ||= admin.parameter_name
9
26
 
10
27
  options[:data] ||= {}
11
- options[:data][:controller] = (DEFAULT_FORM_CONTROLLERS + Array(options[:data][:controller])).join(" ")
28
+ options[:data][:controller] = (Trestle.config.default_form_controllers + Array(options[:data][:controller])).join(" ")
12
29
 
13
- form_for(instance, options) do |f|
30
+ form_for(instance, **options) do |f|
14
31
  with_identity_field_error_proc do
15
32
  with_form(f) { yield f }
16
33
  end
17
34
  end
18
35
  end
19
36
 
37
+ # Returns the currently scoped Trestle form builder
38
+ # (a subclass of ActionView::Helpers::FormBuilder).
39
+ def form
40
+ @_trestle_form
41
+ end
42
+
43
+ protected
20
44
  def with_form(form)
21
45
  @_trestle_form = form
22
46
  yield form if block_given?
@@ -24,6 +48,8 @@ module Trestle
24
48
  @_trestle_form = nil
25
49
  end
26
50
 
51
+ IDENTITY_FIELD_ERROR_PROC = Proc.new { |html_tag, instance| html_tag }
52
+
27
53
  def with_identity_field_error_proc
28
54
  original_field_error_proc = ::ActionView::Base.field_error_proc
29
55
  ::ActionView::Base.field_error_proc = IDENTITY_FIELD_ERROR_PROC
@@ -32,17 +58,5 @@ module Trestle
32
58
  ensure
33
59
  ::ActionView::Base.field_error_proc = original_field_error_proc
34
60
  end
35
-
36
- def form
37
- @_trestle_form
38
- end
39
-
40
- def sidebar(&block)
41
- content_for(:sidebar, &block)
42
- end
43
-
44
- def render_sidebar_as_tab?
45
- modal_request? && content_for?(:sidebar)
46
- end
47
61
  end
48
62
  end
@@ -1,30 +1,60 @@
1
1
  module Trestle
2
2
  module FormatHelper
3
- def format_value(value, options={})
4
- if options.key?(:format)
5
- format_value_from_options(value, options)
6
- else
7
- autoformat_value(value, options)
8
- end
9
- end
10
-
11
- def format_value_from_options(value, options={})
12
- case options[:format]
3
+ # Formats a value, either with an explicit format (given the :format option)
4
+ # or automatically based on its type using the `autoformat_value` helper.
5
+ #
6
+ # This helper is most commonly called when rendering content within a
7
+ # table cell, but is available to use from any view context.
8
+ #
9
+ # value - Value to format
10
+ # format - Symbol representing format type. Currently supported:
11
+ # :auto, nil - Auto-formats (default)
12
+ # :currency - Formats as currency using `number_to_currency`
13
+ # :tags - Formats an array of Strings as a tag list
14
+ # options - Options hash to pass to `autoformat_value` helper
15
+ #
16
+ # Examples
17
+ #
18
+ # <%= format_value(123.45, format: :currency) %>
19
+ # <%= format_value(article.tags, format: :tags) %>
20
+ #
21
+ # <%= format_value(Time.current) %>
22
+ # <%= format_value(nil, blank: "None") %>
23
+ # <%= format_value(true) %>
24
+ #
25
+ # Returns a HTML-safe String.
26
+ # Raises ArgumentError if an invalid format is given.
27
+ def format_value(value, format: :auto, **options)
28
+ case format
29
+ when :auto, nil
30
+ autoformat_value(value, **options)
13
31
  when :currency
14
32
  number_to_currency(value)
15
33
  when :tags
16
- tags = Array(value).map { |tag| content_tag(:span, tag, class: "tag tag-primary") }
17
- content_tag(:div, safe_join(tags), class: "tag-list")
34
+ tags = Array(value).map { |t| tag.span(t, class: "tag tag-primary") }
35
+ tag.div(safe_join(tags), class: "tag-list")
18
36
  else
19
- value
37
+ raise ArgumentError, "unknown format: #{format}"
20
38
  end
21
39
  end
22
40
 
23
- def autoformat_value(value, options={})
41
+ # Auto-formats a value based on its type.
42
+ #
43
+ # The current implementation of this helper supports Arrays, Time/Datetime,
44
+ # Date, true/false values, nil, String (with optional truncation) or model
45
+ # instance types (using the `display` helper).
46
+ #
47
+ # value - Value to format (multiple types supported)
48
+ # options - Options hash, usage dependent on value type. Currently supported:
49
+ # :blank - text to display for nil values (e.g. "N/A")
50
+ # :truncate - passed to truncate helper for String values
51
+ #
52
+ # Returns a HTML-safe String.
53
+ def autoformat_value(value, **options)
24
54
  case value
25
55
  when Array
26
- content_tag(:ol, safe_join(value.map { |v|
27
- content_tag(:li, v.is_a?(Array) ? v : autoformat_value(v, options)) },
56
+ tag.ol(safe_join(value.map { |v|
57
+ tag.li(v.is_a?(Array) ? v : autoformat_value(v, **options)) },
28
58
  "\n"))
29
59
  when Time, DateTime
30
60
  timestamp(value)
@@ -37,7 +67,7 @@ module Trestle
37
67
  if blank.respond_to?(:call)
38
68
  instance_exec(&blank)
39
69
  else
40
- content_tag(:span, blank, class: "blank")
70
+ tag.span(blank, class: "blank")
41
71
  end
42
72
  when String
43
73
  if value.html_safe? || options[:truncate] == false
@@ -0,0 +1,48 @@
1
+ module Trestle
2
+ module GravatarHelper
3
+ # Returns a Gravatar image tag for a given email address.
4
+ # See https://docs.gravatar.com/api/avatars/images/ for available options.
5
+ #
6
+ # In general, this should be wrapped in an avatar block to apply styling.
7
+ # This method is also aliased as `gravatar`.
8
+ #
9
+ # email - Email address for Gravatar image; will be MD5-hashed to create the URL
10
+ # options - Options to pass to Gravatar API (as query string params)
11
+ #
12
+ # Examples
13
+ #
14
+ # <%= avatar { gravatar_image_tag("sam@trestle.io") } %>
15
+ #
16
+ # <%= avatar { gravatar_image_tag("sam@trestle.io", size: 120, d: "retro") } %>
17
+ #
18
+ # Returns a HTML-safe String.
19
+ def gravatar_image_tag(email, **options)
20
+ image_tag(gravatar_image_url(email, **options))
21
+ end
22
+ alias gravatar gravatar_image_tag
23
+
24
+ # Returns a Gravatar image URL for a given email address.
25
+ # See https://docs.gravatar.com/api/avatars/images/ for available options.
26
+ #
27
+ # email - Email address for Gravatar image; will be MD5-hashed to create the URL
28
+ # options - Options to pass to Gravatar API (as query string params)
29
+ #
30
+ # Example
31
+ #
32
+ # <%= gravatar_image_url("sam@trestle.io", size: 120, d: "retro") %>
33
+ #
34
+ # Returns a HTML-safe String.
35
+ def gravatar_image_url(email, **options)
36
+ options = default_gravatar_options.merge(options)
37
+
38
+ url = "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email.to_s.downcase)}.png"
39
+ url << "?#{options.to_query}" if options.any?
40
+ url
41
+ end
42
+
43
+ protected
44
+ def default_gravatar_options
45
+ { d: "mp" }
46
+ end
47
+ end
48
+ end