diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index acf8aa9..e679da8 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -2,6 +2,7 @@ @import "tailwindcss/components"; @import "tailwindcss/utilities"; +@import "components/animations"; @import "components/base"; @import "components/buttons"; @import "components/dashboard_services"; diff --git a/app/assets/stylesheets/components/animations.css b/app/assets/stylesheets/components/animations.css new file mode 100644 index 0000000..23b7664 --- /dev/null +++ b/app/assets/stylesheets/components/animations.css @@ -0,0 +1,16 @@ +@keyframes scaleIn { + from { + transform: scale(0.5); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +.animate-scale-in { + animation-name: scaleIn; + animation-duration: 0.15s; + animation-timing-function: cubic-bezier(0.2, 0, 0.13, 1); +} diff --git a/app/components/modal_component.html.erb b/app/components/modal_component.html.erb new file mode 100644 index 0000000..81702ab --- /dev/null +++ b/app/components/modal_component.html.erb @@ -0,0 +1,15 @@ + diff --git a/app/components/modal_component.rb b/app/components/modal_component.rb new file mode 100644 index 0000000..249ec37 --- /dev/null +++ b/app/components/modal_component.rb @@ -0,0 +1,2 @@ +class ModalComponent < ViewComponent::Base +end diff --git a/app/components/qr_code_modal_component.html.erb b/app/components/qr_code_modal_component.html.erb new file mode 100644 index 0000000..7d02637 --- /dev/null +++ b/app/components/qr_code_modal_component.html.erb @@ -0,0 +1,6 @@ +<%= render ModalComponent.new do %> + <% if @descripton.present? %> +

<%= @description %>

+ <% end %> +

<%= raw @qr_code_svg %>

+<% end %> diff --git a/app/components/qr_code_modal_component.rb b/app/components/qr_code_modal_component.rb new file mode 100644 index 0000000..5b2f7b6 --- /dev/null +++ b/app/components/qr_code_modal_component.rb @@ -0,0 +1,24 @@ +require "rqrcode" + +class QrCodeModalComponent < ViewComponent::Base + def initialize(qr_content:, description: nil) + @description = description + @qr_code_svg = qr_code_svg(qr_content) + end + + private + + def qr_code_svg(content) + qr_code = RQRCode::QRCode.new(content) + qr_code.as_svg( + color: "000", + shape_rendering: "crispEdges", + module_size: 6, + standalone: true, + use_path: true, + svg_attributes: { + class: 'inline-block' + } + ) + end +end diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js index 1213e85..97645a6 100644 --- a/app/javascript/controllers/application.js +++ b/app/javascript/controllers/application.js @@ -1,7 +1,10 @@ import { Application } from "@hotwired/stimulus" +import { Modal } from "tailwindcss-stimulus-components" const application = Application.start() +application.register('modal', Modal) + // Configure Stimulus development experience application.debug = false window.Stimulus = application diff --git a/app/views/icons/_qr_code.html.erb b/app/views/icons/_qr_code.html.erb new file mode 100644 index 0000000..fba7fa5 --- /dev/null +++ b/app/views/icons/_qr_code.html.erb @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/views/invitations/index.html.erb b/app/views/invitations/index.html.erb index b2c5a22..e54ee68 100644 --- a/app/views/invitations/index.html.erb +++ b/app/views/invitations/index.html.erb @@ -8,20 +8,25 @@

diff --git a/config/importmap.rb b/config/importmap.rb index 17d5cd6..605cf26 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -6,3 +6,4 @@ pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers" pin "bech32" # @2.0.0 +pin "tailwindcss-stimulus-components" # @3.0.4 diff --git a/tailwind.config.js b/tailwind.config.js index a86d1b2..a3ba1c4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -5,7 +5,8 @@ module.exports = { './app/components/**/*.rb', './app/views/**/*.html.erb', './app/helpers/**/*.rb', - './app/javascript/**/*.js' + './app/javascript/**/*.js', + './vendor/javascript/tailwindcss-stimulus-components.js' ], safelist: [ 'bg-gray-100', 'text-gray-800', diff --git a/vendor/javascript/tailwindcss-stimulus-components.js b/vendor/javascript/tailwindcss-stimulus-components.js new file mode 100644 index 0000000..e877767 --- /dev/null +++ b/vendor/javascript/tailwindcss-stimulus-components.js @@ -0,0 +1,2 @@ +import{Controller as t}from"@hotwired/stimulus";class s extends t{initialize(){this.hide()}connect(){setTimeout((()=>{this.show()}),this.showDelayValue),this.hasDismissAfterValue&&setTimeout((()=>{this.close()}),this.dismissAfterValue)}close(){this.hide(),setTimeout((()=>{this.element.remove()}),this.removeDelayValue)}show(){this.element.classList.add(...this.showClasses),this.element.classList.remove(...this.hideClasses)}hide(){this.element.classList.add(...this.hideClasses),this.element.classList.remove(...this.showClasses)}}s.values={dismissAfter:Number,showDelay:{type:Number,default:200},removeDelay:{type:Number,default:1100}},s.classes=["show","hide"];class e extends t{connect(){this.timeout=null,this.duration=this.data.get("duration")||1e3}save(){clearTimeout(this.timeout),this.timeout=setTimeout((()=>{this.statusTarget.textContent="Saving...",Rails.fire(this.formTarget,"submit")}),this.duration)}success(){this.setStatus("Saved!")}error(){this.setStatus("Unable to save!")}setStatus(t){this.statusTarget.textContent=t,this.timeout=setTimeout((()=>{this.statusTarget.textContent=""}),2e3)}}e.targets=["form","status"];class i extends t{constructor(...t){super(...t),this._onMenuButtonKeydown=t=>{switch(t.keyCode){case 13:case 32:t.preventDefault(),this.toggle()}}}connect(){this.toggleClass=this.data.get("class")||"hidden",this.visibleClass=this.data.get("visibleClass")||null,this.invisibleClass=this.data.get("invisibleClass")||null,this.activeClass=this.data.get("activeClass")||null,this.enteringClass=this.data.get("enteringClass")||null,this.leavingClass=this.data.get("leavingClass")||null,this.hasButtonTarget&&this.buttonTarget.addEventListener("keydown",this._onMenuButtonKeydown),this.element.setAttribute("aria-haspopup","true")}disconnect(){this.hasButtonTarget&&this.buttonTarget.removeEventListener("keydown",this._onMenuButtonKeydown)}toggle(){this.openValue=!this.openValue}openValueChanged(){this.openValue?this._show():this._hide()}_show(t){setTimeout((()=>{this.menuTarget.classList.remove(this.toggleClass),this.element.setAttribute("aria-expanded","true"),this._enteringClassList[0].forEach((t=>{this.menuTarget.classList.add(t)}).bind(this)),this._activeClassList[0].forEach((t=>{this.activeTarget.classList.add(t)})),this._invisibleClassList[0].forEach((t=>this.menuTarget.classList.remove(t))),this._visibleClassList[0].forEach((t=>{this.menuTarget.classList.add(t)})),setTimeout((()=>{this._enteringClassList[0].forEach((t=>this.menuTarget.classList.remove(t)))}).bind(this),this.enterTimeout[0]),"function"==typeof t&&t()}).bind(this))}_hide(t){setTimeout((()=>{this.element.setAttribute("aria-expanded","false"),this._invisibleClassList[0].forEach((t=>this.menuTarget.classList.add(t))),this._visibleClassList[0].forEach((t=>this.menuTarget.classList.remove(t))),this._activeClassList[0].forEach((t=>this.activeTarget.classList.remove(t))),this._leavingClassList[0].forEach((t=>this.menuTarget.classList.add(t))),setTimeout((()=>{this._leavingClassList[0].forEach((t=>this.menuTarget.classList.remove(t))),"function"==typeof t&&t(),this.menuTarget.classList.add(this.toggleClass)}).bind(this),this.leaveTimeout[0])}).bind(this))}show(){this.openValue=!0}hide(t){!1===this.element.contains(t.target)&&this.openValue&&(this.openValue=!1)}get activeTarget(){return this.data.has("activeTarget")?document.querySelector(this.data.get("activeTarget")):this.element}get _activeClassList(){return this.activeClass?this.activeClass.split(",").map((t=>t.split(" "))):[[],[]]}get _visibleClassList(){return this.visibleClass?this.visibleClass.split(",").map((t=>t.split(" "))):[[],[]]}get _invisibleClassList(){return this.invisibleClass?this.invisibleClass.split(",").map((t=>t.split(" "))):[[],[]]}get _enteringClassList(){return this.enteringClass?this.enteringClass.split(",").map((t=>t.split(" "))):[[],[]]}get _leavingClassList(){return this.leavingClass?this.leavingClass.split(",").map((t=>t.split(" "))):[[],[]]}get enterTimeout(){return(this.data.get("enterTimeout")||"0,0").split(",").map((t=>parseInt(t)))}get leaveTimeout(){return(this.data.get("leaveTimeout")||"0,0").split(",").map((t=>parseInt(t)))}}i.targets=["menu","button"],i.values={open:Boolean};class a extends t{connect(){this.toggleClass=this.data.get("class")||"hidden",this.backgroundId=this.data.get("backgroundId")||"modal-background",this.backgroundHtml=this.data.get("backgroundHtml")||this._backgroundHTML(),this.allowBackgroundClose="true"===(this.data.get("allowBackgroundClose")||"true"),this.preventDefaultActionOpening="true"===(this.data.get("preventDefaultActionOpening")||"true"),this.preventDefaultActionClosing="true"===(this.data.get("preventDefaultActionClosing")||"true")}disconnect(){this.close()}open(t){this.preventDefaultActionOpening&&t.preventDefault(),t.target.blur&&t.target.blur(),this.lockScroll(),this.containerTarget.classList.remove(this.toggleClass),this.data.get("disable-backdrop")||(document.body.insertAdjacentHTML("beforeend",this.backgroundHtml),this.background=document.querySelector(`#${this.backgroundId}`))}close(t){t&&this.preventDefaultActionClosing&&t.preventDefault(),this.unlockScroll(),this.containerTarget.classList.add(this.toggleClass),this.background&&this.background.remove()}closeBackground(t){this.allowBackgroundClose&&t.target===this.containerTarget&&this.close(t)}closeWithKeyboard(t){27!==t.keyCode||this.containerTarget.classList.contains(this.toggleClass)||this.close(t)}_backgroundHTML(){return`
`}lockScroll(){const t=window.innerWidth-document.documentElement.clientWidth;document.body.style.paddingRight=`${t}px`,this.saveScrollPosition(),document.body.classList.add("fixed","inset-x-0","overflow-hidden"),document.body.style.top=`-${this.scrollPosition}px`}unlockScroll(){document.body.style.paddingRight=null,document.body.classList.remove("fixed","inset-x-0","overflow-hidden"),this.restoreScrollValue&&this.restoreScrollPosition(),document.body.style.top=null}saveScrollPosition(){this.scrollPosition=window.pageYOffset||document.body.scrollTop}restoreScrollPosition(){void 0!==this.scrollPosition&&(document.documentElement.scrollTop=this.scrollPosition)}}a.targets=["container"],a.values={backdropColor:{type:String,default:"rgba(0, 0, 0, 0.8)"},restoreScroll:{type:Boolean,default:!0}};class l extends t{connect(){this.activeTabClasses=(this.data.get("activeTab")||"active").split(" "),this.inactiveTabClasses=(this.data.get("inactiveTab")||"inactive").split(" "),this.anchor&&(this.index=this.tabTargets.findIndex((t=>t.id===this.anchor))),this.showTab()}change(t){t.preventDefault(),this.index=t.currentTarget.dataset.index?t.currentTarget.dataset.index:t.currentTarget.dataset.id?this.tabTargets.findIndex((d=>d.id==t.currentTarget.dataset.id)):this.tabTargets.indexOf(t.currentTarget),window.dispatchEvent(new CustomEvent("tsc:tab-change"))}showTab(){this.tabTargets.forEach(((t,d)=>{const c=this.panelTargets[d];d===this.index?(c.classList.remove("hidden"),t.classList.remove(...this.inactiveTabClasses),t.classList.add(...this.activeTabClasses),t.id&&(location.hash=t.id)):(c.classList.add("hidden"),t.classList.remove(...this.activeTabClasses),t.classList.add(...this.inactiveTabClasses))}))}get index(){return parseInt(this.data.get("index")||0)}set index(t){this.data.set("index",t>=0?t:0),this.showTab()}get anchor(){return document.URL.split("#").length>1?document.URL.split("#")[1]:null}}l.targets=["tab","panel"];class o extends t{connect(){this.toggleClass=this.data.get("class")||"hidden"}toggle(t){t.preventDefault(),this.openValue=!this.openValue}hide(t){t.preventDefault(),this.openValue=!1}show(t){t.preventDefault(),this.openValue=!0}openValueChanged(){this.toggleClass&&this.toggleableTargets.forEach((t=>{t.classList.toggle(this.toggleClass)}))}}o.targets=["toggleable"],o.values={open:Boolean};class n extends t{initialize(){this.contentTarget.setAttribute("style",`transform:translate(${this.data.get("translateX")}, ${this.data.get("translateY")});`)}mouseOver(){this.contentTarget.classList.remove("hidden")}mouseOut(){this.contentTarget.classList.add("hidden")}toggle(){this.contentTarget.classList.contains("hidden")?this.contentTarget.classList.remove("hidden"):this.contentTarget.classList.add("hidden")}}n.targets=["content"];class r extends i{_show(){this.overlayTarget.classList.remove(this.toggleClass),super._show((()=>{this._activeClassList[1].forEach((t=>this.overlayTarget.classList.add(t))),this._invisibleClassList[1].forEach((t=>this.overlayTarget.classList.remove(t))),this._visibleClassList[1].forEach((t=>this.overlayTarget.classList.add(t))),setTimeout((()=>{this._enteringClassList[1].forEach((t=>this.overlayTarget.classList.remove(t)))}).bind(this),this.enterTimeout[1])}).bind(this))}_hide(){this._leavingClassList[1].forEach((t=>this.overlayTarget.classList.add(t))),super._hide((()=>{setTimeout((()=>{this._visibleClassList[1].forEach((t=>this.overlayTarget.classList.remove(t))),this._invisibleClassList[1].forEach((t=>this.overlayTarget.classList.add(t))),this._activeClassList[1].forEach((t=>this.overlayTarget.classList.remove(t))),this._leavingClassList[1].forEach((t=>this.overlayTarget.classList.remove(t))),this.overlayTarget.classList.add(this.toggleClass)}).bind(this),this.leaveTimeout[1])}).bind(this))}}r.targets=["menu","overlay"];class h extends t{connect(){this.styleProperty=this.data.get("style")||"backgroundColor"}update(){this.preview=this.color}set preview(t){this.previewTarget.style[this.styleProperty]=t;const d=this._getContrastYIQ(t);"color"===this.styleProperty?this.previewTarget.style.backgroundColor=d:this.previewTarget.style.color=d}get color(){return this.colorTarget.value}_getContrastYIQ(t){return t=t.replace("#",""),(299*parseInt(t.substr(0,2),16)+587*parseInt(t.substr(2,2),16)+114*parseInt(t.substr(4,2),16))/1e3>=128?"#000":"#fff"}}h.targets=["preview","color"];export{s as Alert,e as Autosave,h as ColorPreview,i as Dropdown,a as Modal,n as Popover,r as Slideover,l as Tabs,o as Toggle}; +