diff --git a/app/Console/Commands/Cleanup/DeleteOldUnverifiedUsers.php b/app/Console/Commands/Cleanup/DeleteOldUnverifiedUsers.php index 2b1cb904..e1b6fac6 100644 --- a/app/Console/Commands/Cleanup/DeleteOldUnverifiedUsers.php +++ b/app/Console/Commands/Cleanup/DeleteOldUnverifiedUsers.php @@ -8,18 +8,8 @@ class DeleteOldUnverifiedUsers extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ protected $signature = 'lcm:delete-old-unverified-users'; - /** - * The console command description. - * - * @var string - */ protected $description = 'Removed all unverified users.'; public function handle() diff --git a/app/Console/Commands/UpdateUserCommentsPoints.php b/app/Console/Commands/UpdateUserCommentsPoints.php new file mode 100644 index 00000000..5172be86 --- /dev/null +++ b/app/Console/Commands/UpdateUserCommentsPoints.php @@ -0,0 +1,42 @@ +info('Updating users discussions reputations...'); + + foreach (Discussion::all() as $discussion) { + givePoint(new DiscussionCreated($discussion), $discussion->author); + } + + $this->info('All done!'); + } +} diff --git a/app/Console/Commands/UpdateUserPostsPoints.php b/app/Console/Commands/UpdateUserPostsPoints.php new file mode 100644 index 00000000..6228ee69 --- /dev/null +++ b/app/Console/Commands/UpdateUserPostsPoints.php @@ -0,0 +1,25 @@ +info('Updating users posts reputations...'); + + foreach (Article::all() as $article) { + givePoint(new PostCreated($article), $article->author); + } + + $this->info('All done!'); + } +} diff --git a/app/Console/Commands/UpdateUserRepliesPoints.php b/app/Console/Commands/UpdateUserRepliesPoints.php new file mode 100644 index 00000000..5499713c --- /dev/null +++ b/app/Console/Commands/UpdateUserRepliesPoints.php @@ -0,0 +1,42 @@ +info('Updating users threads reputations...'); + + foreach (Thread::all() as $thread) { + givePoint(new ThreadCreated($thread), $thread->author); + } + + $this->info('All done!'); + } +} diff --git a/app/Gamify/Points/AddPhone.php b/app/Gamify/Points/AddPhone.php new file mode 100644 index 00000000..a0126921 --- /dev/null +++ b/app/Gamify/Points/AddPhone.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Gamify/Points/AddSocialLinks.php b/app/Gamify/Points/AddSocialLinks.php new file mode 100644 index 00000000..dce28aaa --- /dev/null +++ b/app/Gamify/Points/AddSocialLinks.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Gamify/Points/BestReply.php b/app/Gamify/Points/BestReply.php new file mode 100644 index 00000000..6ebb3948 --- /dev/null +++ b/app/Gamify/Points/BestReply.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Gamify/Points/CommentCreated.php b/app/Gamify/Points/CommentCreated.php new file mode 100644 index 00000000..a2b38899 --- /dev/null +++ b/app/Gamify/Points/CommentCreated.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Gamify/Points/DiscussionCreated.php b/app/Gamify/Points/DiscussionCreated.php new file mode 100644 index 00000000..63d3608f --- /dev/null +++ b/app/Gamify/Points/DiscussionCreated.php @@ -0,0 +1,20 @@ +subject = $subject; + } + + public function payee() + { + return $this->getSubject()->author; + } +} diff --git a/app/Gamify/Points/PostCreated.php b/app/Gamify/Points/PostCreated.php new file mode 100644 index 00000000..5b3d7a80 --- /dev/null +++ b/app/Gamify/Points/PostCreated.php @@ -0,0 +1,20 @@ +subject = $subject; + } + + public function payee() + { + return $this->getSubject()->author; + } +} diff --git a/app/Gamify/Points/ReplyCreated.php b/app/Gamify/Points/ReplyCreated.php new file mode 100644 index 00000000..48809921 --- /dev/null +++ b/app/Gamify/Points/ReplyCreated.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Gamify/Points/ThreadCreated.php b/app/Gamify/Points/ThreadCreated.php new file mode 100644 index 00000000..c412ca47 --- /dev/null +++ b/app/Gamify/Points/ThreadCreated.php @@ -0,0 +1,20 @@ +subject = $subject; + } + + public function payee() + { + return $this->getSubject()->author; + } +} diff --git a/app/Gamify/Points/UndoBestReply.php b/app/Gamify/Points/UndoBestReply.php new file mode 100644 index 00000000..2c9ee709 --- /dev/null +++ b/app/Gamify/Points/UndoBestReply.php @@ -0,0 +1,35 @@ +subject = $subject; + } + + /** + * User who will be receive points. + * + * @return mixed + */ + public function payee() + { + return $this->getSubject()->user; + } +} diff --git a/app/Http/Livewire/Articles/Create.php b/app/Http/Livewire/Articles/Create.php index 353b74d3..ad468beb 100644 --- a/app/Http/Livewire/Articles/Create.php +++ b/app/Http/Livewire/Articles/Create.php @@ -2,6 +2,7 @@ namespace App\Http\Livewire\Articles; +use App\Gamify\Points\PostCreated; use App\Models\Article; use App\Models\Tag; use App\Traits\WithArticleAttributes; @@ -60,6 +61,8 @@ public function store() 'user_id' => $user->id, ]); + givePoint(new PostCreated($article)); + if (collect($this->associateTags)->isNotEmpty()) { $article->syncTags($this->associateTags); } diff --git a/app/Http/Livewire/Discussions/Create.php b/app/Http/Livewire/Discussions/Create.php index 85f2d33c..effeb0b0 100644 --- a/app/Http/Livewire/Discussions/Create.php +++ b/app/Http/Livewire/Discussions/Create.php @@ -2,6 +2,7 @@ namespace App\Http\Livewire\Discussions; +use App\Gamify\Points\DiscussionCreated; use App\Models\Discussion; use App\Models\Tag; use App\Notifications\PostDiscussionToTelegram; @@ -43,6 +44,8 @@ public function store() $discussion->syncTags($this->associateTags); } + givePoint(new DiscussionCreated($discussion)); + Auth::user()->notify(new PostDiscussionToTelegram($discussion)); $this->redirectRoute('discussions.show', $discussion); diff --git a/app/Http/Livewire/Forum/CreateThread.php b/app/Http/Livewire/Forum/CreateThread.php index 825faa78..0eab7f31 100644 --- a/app/Http/Livewire/Forum/CreateThread.php +++ b/app/Http/Livewire/Forum/CreateThread.php @@ -3,6 +3,7 @@ namespace App\Http\Livewire\Forum; use App\Events\ThreadWasCreated; +use App\Gamify\Points\ThreadCreated; use App\Models\Channel; use App\Models\Thread; use App\Traits\WithChannelsAssociation; @@ -51,6 +52,8 @@ public function store() $thread->subscribes()->save($subscription); + givePoint(new ThreadCreated($thread)); + event(new ThreadWasCreated($thread)); $this->redirectRoute('forum.show', $thread); diff --git a/app/Http/Resources/ReplyResource.php b/app/Http/Resources/ReplyResource.php index 64027d6b..d97c1dc6 100644 --- a/app/Http/Resources/ReplyResource.php +++ b/app/Http/Resources/ReplyResource.php @@ -15,6 +15,7 @@ public function toArray($request): array 'model_id' => $this->replyable_id, 'created_at' => $this->created_at->getTimestamp(), 'author' => new UserResource($this->author), + 'experience' => $this->author->getPoints(), 'has_replies' => $this->allChildReplies->isNotEmpty(), 'likes_count' => $this->getReactionsSummary()->sum('count'), ]; diff --git a/app/Models/User.php b/app/Models/User.php index b40fc989..6939ec21 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -12,13 +12,15 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Auth; +use QCod\Gamify\Gamify; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable implements MustVerifyEmail, HasMedia { - use HasFactory, + use Gamify, + HasFactory, HasProfilePhoto, HasRoles, InteractsWithMedia, diff --git a/composer.json b/composer.json index 8d336994..068f683e 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "laravel/socialite": "^5.2", "laravel/tinker": "^2.5", "livewire/livewire": "^2.8", - "wireui/wireui": "^0.14.0", + "qcod/laravel-gamify": "^1.0", "ramsey/uuid": "^4.2", "sentry/sentry-laravel": "^2.10", "spatie/laravel-feed": "^4.0", @@ -37,6 +37,7 @@ "torchlight/torchlight-commonmark": "^0.5.2", "wire-elements/modal": "^1.0", "wire-elements/spotlight": "^1.0", + "wireui/wireui": "^0.14.0", "yarri/link-finder": "^2.7" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 44345eb7..a3cc4efc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b6c0ce7151c6041785b80b95732d18fb", + "content-hash": "9e836534fee611238b6b0029b9060e4e", "packages": [ { "name": "abraham/twitteroauth", @@ -5935,6 +5935,74 @@ }, "time": "2021-11-30T14:05:36+00:00" }, + { + "name": "qcod/laravel-gamify", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/qcod/laravel-gamify.git", + "reference": "5746d443ab5ddff4c147e7f4f19d131a8871c9e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/qcod/laravel-gamify/zipball/5746d443ab5ddff4c147e7f4f19d131a8871c9e7", + "reference": "5746d443ab5ddff4c147e7f4f19d131a8871c9e7", + "shasum": "" + }, + "require": { + "laravel/framework": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0|^8.0", + "php": ">=7.3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4 || ~1.0", + "orchestra/testbench": "~3.8|^4.0", + "phpunit/phpunit": "~8.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "QCod\\Gamify\\GamifyServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "QCod\\Gamify\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mohd Saqueib Ansari", + "email": "saquibweb@gmail.com" + } + ], + "description": "Add gamification in laravel app with reputation point and badges support", + "homepage": "https://github.com/qcod/laravel-gamify", + "keywords": [ + "Gamification", + "achivement", + "badge", + "gamify", + "laravel", + "points", + "qcod", + "reputation", + "reward" + ], + "support": { + "issues": "https://github.com/qcod/laravel-gamify/issues", + "source": "https://github.com/qcod/laravel-gamify/tree/1.0.5" + }, + "time": "2020-09-10T15:44:05+00:00" + }, { "name": "ralouphie/getallheaders", "version": "3.0.3", diff --git a/config/gamify.php b/config/gamify.php new file mode 100644 index 00000000..c226532c --- /dev/null +++ b/config/gamify.php @@ -0,0 +1,37 @@ + \App\Models\User::class, + + // Reputation model + 'reputation_model' => '\QCod\Gamify\Reputation', + + // Allow duplicate reputation points + 'allow_reputation_duplicate' => true, + + // Broadcast on private channel + 'broadcast_on_private_channel' => true, + + // Channel name prefix, user id will be suffixed + 'channel_name' => 'user.reputation.', + + // Badge model + 'badge_model' => '\QCod\Gamify\Badge', + + // Where all badges icon stored + 'badge_icon_folder' => 'images/badges/', + + // Extention of badge icons + 'badge_icon_extension' => '.svg', + + // All the levels for badge + 'badge_levels' => [ + 'beginner' => 1, + 'intermediate' => 2, + 'advanced' => 3, + ], + + // Default level + 'badge_default_level' => 1, +]; diff --git a/database/migrations/2022_01_15_201921_add_reputation_field_on_user_table.php b/database/migrations/2022_01_15_201921_add_reputation_field_on_user_table.php new file mode 100644 index 00000000..331a9143 --- /dev/null +++ b/database/migrations/2022_01_15_201921_add_reputation_field_on_user_table.php @@ -0,0 +1,32 @@ +unsignedInteger('reputation')->default(0)->after('remember_token'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('reputation'); + }); + } +} diff --git a/database/migrations/2022_01_15_201921_create_gamify_tables.php b/database/migrations/2022_01_15_201921_create_gamify_tables.php new file mode 100644 index 00000000..bca9ddb2 --- /dev/null +++ b/database/migrations/2022_01_15_201921_create_gamify_tables.php @@ -0,0 +1,58 @@ +id(); + $table->string('name'); + $table->mediumInteger('point', false)->default(0); + $table->bigInteger('subject_id')->nullable(); + $table->string('subject_type')->nullable(); + $table->unsignedBigInteger('payee_id')->nullable(); + $table->text('meta')->nullable(); + $table->timestamps(); + }); + + // badges table + Schema::create('badges', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('description')->nullable(); + $table->string('icon')->nullable(); + $table->tinyInteger('level')->default(config('gamify.badge_default_level', 1)); + $table->timestamps(); + }); + + // user_badges pivot + Schema::create('user_badges', function (Blueprint $table) { + $table->primary(['user_id', 'badge_id']); + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('badge_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_badges'); + Schema::dropIfExists('badges'); + Schema::dropIfExists('reputations'); + } +} diff --git a/public/js/app.js b/public/js/app.js index b9dac889..daf559b6 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,2 +1,2 @@ /*! For license information please see app.js.LICENSE.txt */ -(()=>{var e,t={5513:(e,t,n)=>{"use strict";var i,a,r,o,s=Object.create,l=Object.defineProperty,c=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty,d=Object.getOwnPropertyNames,u=Object.getOwnPropertyDescriptor,p=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),m=p((e=>{function t(e,t){const n=Object.create(null),i=e.split(",");for(let e=0;e!!n[e.toLowerCase()]:e=>!!n[e]}Object.defineProperty(e,"__esModule",{value:!0});var i={1:"TEXT",2:"CLASS",4:"STYLE",8:"PROPS",16:"FULL_PROPS",32:"HYDRATE_EVENTS",64:"STABLE_FRAGMENT",128:"KEYED_FRAGMENT",256:"UNKEYED_FRAGMENT",512:"NEED_PATCH",1024:"DYNAMIC_SLOTS",2048:"DEV_ROOT_FRAGMENT",[-1]:"HOISTED",[-2]:"BAIL"},a={1:"STABLE",2:"DYNAMIC",3:"FORWARDED"},r=t("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt");var o="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",s=t(o),l=t(o+",async,autofocus,autoplay,controls,default,defer,disabled,hidden,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected"),c=/[>/="'\u0009\u000a\u000c\u0020]/,_={};var d=t("animation-iteration-count,border-image-outset,border-image-slice,border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,stroke-miterlimit,stroke-opacity,stroke-width"),u=t("accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap");var p=/;(?![^(]*\))/g,m=/:(.+)/;function g(e){const t={};return e.split(p).forEach((e=>{if(e){const n=e.split(m);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}var E=t("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot"),S=t("svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view"),f=t("area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr"),b=/["'&<>]/;var h=/^-?>||--!>|D(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:w(t)?{[`Set(${t.size})`]:[...t.values()]}:!P(t)||A(t)||F(t)?t:String(t),y=Object.freeze({}),N=Object.freeze([]),O=/^on[^a-z]/,R=Object.assign,I=Object.prototype.hasOwnProperty,A=Array.isArray,D=e=>"[object Map]"===U(e),w=e=>"[object Set]"===U(e),x=e=>e instanceof Date,M=e=>"function"==typeof e,L=e=>"string"==typeof e,P=e=>null!==e&&"object"==typeof e,k=Object.prototype.toString,U=e=>k.call(e),F=e=>"[object Object]"===U(e),B=t(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),G=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Y=/-(\w)/g,H=G((e=>e.replace(Y,((e,t)=>t?t.toUpperCase():"")))),V=/\B([A-Z])/g,q=G((e=>e.replace(V,"-$1").toLowerCase())),z=G((e=>e.charAt(0).toUpperCase()+e.slice(1))),$=G((e=>e?`on${z(e)}`:""));e.EMPTY_ARR=N,e.EMPTY_OBJ=y,e.NO=()=>!1,e.NOOP=()=>{},e.PatchFlagNames=i,e.babelParserDefaultPlugins=["bigInt","optionalChaining","nullishCoalescingOperator"],e.camelize=H,e.capitalize=z,e.def=(e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},e.escapeHtml=function(e){const t=""+e,n=b.exec(t);if(!n)return t;let i,a,r="",o=0;for(a=n.index;a=t){for(let o=e-2;o<=e+2||n>a;o++){if(o<0||o>=i.length)continue;const s=o+1;r.push(`${s}${" ".repeat(Math.max(3-String(s).length,0))}| ${i[o]}`);const l=i[o].length;if(o===e){const e=t-(a-l)+1,i=Math.max(1,n>a?l-e:n-t);r.push(" | "+" ".repeat(e)+"^".repeat(i))}else if(o>e){if(n>a){const e=Math.max(Math.min(n-a,l),1);r.push(" | "+"^".repeat(e))}a+=l+1}}break}return r.join("\n")},e.getGlobalThis=()=>v||(v="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:{}),e.hasChanged=(e,t)=>e!==t&&(e==e||t==t),e.hasOwn=(e,t)=>I.call(e,t),e.hyphenate=q,e.invokeArrayFns=(e,t)=>{for(let n=0;nL(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,e.isKnownAttr=u,e.isMap=D,e.isModelListener=e=>e.startsWith("onUpdate:"),e.isNoUnitNumericStyleProp=d,e.isObject=P,e.isOn=e=>O.test(e),e.isPlainObject=F,e.isPromise=e=>P(e)&&M(e.then)&&M(e.catch),e.isReservedProp=B,e.isSSRSafeAttrName=function(e){if(_.hasOwnProperty(e))return _[e];const t=c.test(e);return t&&console.error(`unsafe attribute name: ${e}`),_[e]=!t},e.isSVGTag=S,e.isSet=w,e.isSpecialBooleanAttr=s,e.isString=L,e.isSymbol=e=>"symbol"==typeof e,e.isVoidTag=f,e.looseEqual=T,e.looseIndexOf=function(e,t){return e.findIndex((e=>T(e,t)))},e.makeMap=t,e.normalizeClass=function e(t){let n="";if(L(t))n=t;else if(A(t))for(let i=0;i{const n=e.indexOf(t);n>-1&&e.splice(n,1)},e.slotFlagsText=a,e.stringifyStyle=function(e){let t="";if(!e)return t;for(const n in e){const i=e[n],a=n.startsWith("--")?n:q(n);(L(i)||"number"==typeof i&&d(a))&&(t+=`${a}:${i};`)}return t},e.toDisplayString=e=>null==e?"":P(e)?JSON.stringify(e,C,2):String(e),e.toHandlerKey=$,e.toNumber=e=>{const t=parseFloat(e);return isNaN(t)?e:t},e.toRawType=e=>U(e).slice(8,-1),e.toTypeString=U})),g=p(((e,t)=>{t.exports=m()})),E=p((e=>{Object.defineProperty(e,"__esModule",{value:!0});var t,n=g(),i=new WeakMap,a=[],r=Symbol("iterate"),o=Symbol("Map key iterate");function s(e,i=n.EMPTY_OBJ){(function(e){return e&&!0===e._isEffect})(e)&&(e=e.raw);const r=function(e,n){const i=function(){if(!i.active)return e();if(!a.includes(i)){c(i);try{return p(),a.push(i),t=i,e()}finally{a.pop(),m(),t=a[a.length-1]}}};return i.id=l++,i.allowRecurse=!!n.allowRecurse,i._isEffect=!0,i.active=!0,i.raw=e,i.deps=[],i.options=n,i}(e,i);return i.lazy||r(),r}var l=0;function c(e){const{deps:t}=e;if(t.length){for(let n=0;n{e&&e.forEach((e=>{(e!==t||e.allowRecurse)&&u.add(e)}))};if("clear"===a)d.forEach(p);else if("length"===s&&n.isArray(e))d.forEach(((e,t)=>{("length"===t||t>=l)&&p(e)}));else switch(void 0!==s&&p(d.get(s)),a){case"add":n.isArray(e)?n.isIntegerKey(s)&&p(d.get("length")):(p(d.get(r)),n.isMap(e)&&p(d.get(o)));break;case"delete":n.isArray(e)||(p(d.get(r)),n.isMap(e)&&p(d.get(o)));break;case"set":n.isMap(e)&&p(d.get(r))}u.forEach((t=>{t.options.onTrigger&&t.options.onTrigger({effect:t,target:e,key:s,type:a,newValue:l,oldValue:c,oldTarget:_}),t.options.scheduler?t.options.scheduler(t):t()}))}var f=n.makeMap("__proto__,__v_isRef,__isVue"),b=new Set(Object.getOwnPropertyNames(Symbol).map((e=>Symbol[e])).filter(n.isSymbol)),h=N(),T=N(!1,!0),v=N(!0),C=N(!0,!0),y={};function N(e=!1,t=!1){return function(i,a,r){if("__v_isReactive"===a)return!e;if("__v_isReadonly"===a)return e;if("__v_raw"===a&&r===(e?t?oe:re:t?ae:ie).get(i))return i;const o=n.isArray(i);if(!e&&o&&n.hasOwn(y,a))return Reflect.get(y,a,r);const s=Reflect.get(i,a,r);if(n.isSymbol(a)?b.has(a):f(a))return s;if(e||E(i,"get",a),t)return s;if(ge(s)){return!o||!n.isIntegerKey(a)?s.value:s}return n.isObject(s)?e?le(s):se(s):s}}["includes","indexOf","lastIndexOf"].forEach((e=>{const t=Array.prototype[e];y[e]=function(...e){const n=pe(this);for(let e=0,t=this.length;e{const t=Array.prototype[e];y[e]=function(...e){u();const n=t.apply(this,e);return m(),n}}));var O=I(),R=I(!0);function I(e=!1){return function(t,i,a,r){let o=t[i];if(!e&&(a=pe(a),o=pe(o),!n.isArray(t)&&ge(o)&&!ge(a)))return o.value=a,!0;const s=n.isArray(t)&&n.isIntegerKey(i)?Number(i)(console.warn(`Set operation on key "${String(t)}" failed: target is readonly.`,e),!0),deleteProperty:(e,t)=>(console.warn(`Delete operation on key "${String(t)}" failed: target is readonly.`,e),!0)},w=n.extend({},A,{get:T,set:R}),x=n.extend({},D,{get:C}),M=e=>n.isObject(e)?se(e):e,L=e=>n.isObject(e)?le(e):e,P=e=>e,k=e=>Reflect.getPrototypeOf(e);function U(e,t,n=!1,i=!1){const a=pe(e=e.__v_raw),r=pe(t);t!==r&&!n&&E(a,"get",t),!n&&E(a,"get",r);const{has:o}=k(a),s=i?P:n?L:M;return o.call(a,t)?s(e.get(t)):o.call(a,r)?s(e.get(r)):void(e!==a&&e.get(t))}function F(e,t=!1){const n=this.__v_raw,i=pe(n),a=pe(e);return e!==a&&!t&&E(i,"has",e),!t&&E(i,"has",a),e===a?n.has(e):n.has(e)||n.has(a)}function B(e,t=!1){return e=e.__v_raw,!t&&E(pe(e),"iterate",r),Reflect.get(e,"size",e)}function G(e){e=pe(e);const t=pe(this);return k(t).has.call(t,e)||(t.add(e),S(t,"add",e,e)),this}function Y(e,t){t=pe(t);const i=pe(this),{has:a,get:r}=k(i);let o=a.call(i,e);o?ne(i,a,e):(e=pe(e),o=a.call(i,e));const s=r.call(i,e);return i.set(e,t),o?n.hasChanged(t,s)&&S(i,"set",e,t,s):S(i,"add",e,t),this}function H(e){const t=pe(this),{has:n,get:i}=k(t);let a=n.call(t,e);a?ne(t,n,e):(e=pe(e),a=n.call(t,e));const r=i?i.call(t,e):void 0,o=t.delete(e);return a&&S(t,"delete",e,void 0,r),o}function V(){const e=pe(this),t=0!==e.size,i=n.isMap(e)?new Map(e):new Set(e),a=e.clear();return t&&S(e,"clear",void 0,void 0,i),a}function q(e,t){return function(n,i){const a=this,o=a.__v_raw,s=pe(o),l=t?P:e?L:M;return!e&&E(s,"iterate",r),o.forEach(((e,t)=>n.call(i,l(e),l(t),a)))}}function z(e,t,i){return function(...a){const s=this.__v_raw,l=pe(s),c=n.isMap(l),_="entries"===e||e===Symbol.iterator&&c,d="keys"===e&&c,u=s[e](...a),p=i?P:t?L:M;return!t&&E(l,"iterate",d?o:r),{next(){const{value:e,done:t}=u.next();return t?{value:e,done:t}:{value:_?[p(e[0]),p(e[1])]:p(e),done:t}},[Symbol.iterator](){return this}}}}function $(e){return function(...t){{const i=t[0]?`on key "${t[0]}" `:"";console.warn(`${n.capitalize(e)} operation ${i}failed: target is readonly.`,pe(this))}return"delete"!==e&&this}}var j={get(e){return U(this,e)},get size(){return B(this)},has:F,add:G,set:Y,delete:H,clear:V,forEach:q(!1,!1)},W={get(e){return U(this,e,!1,!0)},get size(){return B(this)},has:F,add:G,set:Y,delete:H,clear:V,forEach:q(!1,!0)},K={get(e){return U(this,e,!0)},get size(){return B(this,!0)},has(e){return F.call(this,e,!0)},add:$("add"),set:$("set"),delete:$("delete"),clear:$("clear"),forEach:q(!0,!1)},Q={get(e){return U(this,e,!0,!0)},get size(){return B(this,!0)},has(e){return F.call(this,e,!0)},add:$("add"),set:$("set"),delete:$("delete"),clear:$("clear"),forEach:q(!0,!0)};function X(e,t){const i=t?e?Q:W:e?K:j;return(t,a,r)=>"__v_isReactive"===a?!e:"__v_isReadonly"===a?e:"__v_raw"===a?t:Reflect.get(n.hasOwn(i,a)&&a in t?i:t,a,r)}["keys","values","entries",Symbol.iterator].forEach((e=>{j[e]=z(e,!1,!1),K[e]=z(e,!0,!1),W[e]=z(e,!1,!0),Q[e]=z(e,!0,!0)}));var Z={get:X(!1,!1)},J={get:X(!1,!0)},ee={get:X(!0,!1)},te={get:X(!0,!0)};function ne(e,t,i){const a=pe(i);if(a!==i&&t.call(e,a)){const t=n.toRawType(e);console.warn(`Reactive ${t} contains both the raw and reactive versions of the same object${"Map"===t?" as keys":""}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`)}}var ie=new WeakMap,ae=new WeakMap,re=new WeakMap,oe=new WeakMap;function se(e){return e&&e.__v_isReadonly?e:ce(e,!1,A,Z,ie)}function le(e){return ce(e,!0,D,ee,re)}function ce(e,t,i,a,r){if(!n.isObject(e))return console.warn(`value cannot be made reactive: ${String(e)}`),e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const o=r.get(e);if(o)return o;const s=(l=e).__v_skip||!Object.isExtensible(l)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}(n.toRawType(l));var l;if(0===s)return e;const c=new Proxy(e,2===s?a:i);return r.set(e,c),c}function _e(e){return de(e)?_e(e.__v_raw):!(!e||!e.__v_isReactive)}function de(e){return!(!e||!e.__v_isReadonly)}function ue(e){return _e(e)||de(e)}function pe(e){return e&&pe(e.__v_raw)||e}var me=e=>n.isObject(e)?se(e):e;function ge(e){return Boolean(e&&!0===e.__v_isRef)}function Ee(e,t=!1){return ge(e)?e:new class{constructor(e,t=!1){this._rawValue=e,this._shallow=t,this.__v_isRef=!0,this._value=t?e:me(e)}get value(){return E(pe(this),"get","value"),this._value}set value(e){n.hasChanged(pe(e),this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:me(e),S(pe(this),"set","value",e))}}(e,t)}function Se(e){return ge(e)?e.value:e}var fe={get:(e,t,n)=>Se(Reflect.get(e,t,n)),set:(e,t,n,i)=>{const a=e[t];return ge(a)&&!ge(n)?(a.value=n,!0):Reflect.set(e,t,n,i)}};function be(e,t){return ge(e[t])?e[t]:new class{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}(e,t)}e.ITERATE_KEY=r,e.computed=function(e){let t,i;return n.isFunction(e)?(t=e,i=()=>{console.warn("Write operation failed: computed value is readonly")}):(t=e.get,i=e.set),new class{constructor(e,t,n){this._setter=t,this._dirty=!0,this.__v_isRef=!0,this.effect=s(e,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,S(pe(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const e=pe(this);return e._dirty&&(e._value=this.effect(),e._dirty=!1),E(e,"get","value"),e._value}set value(e){this._setter(e)}}(t,i,n.isFunction(e)||!e.set)},e.customRef=function(e){return new class{constructor(e){this.__v_isRef=!0;const{get:t,set:n}=e((()=>E(this,"get","value")),(()=>S(this,"set","value")));this._get=t,this._set=n}get value(){return this._get()}set value(e){this._set(e)}}(e)},e.effect=s,e.enableTracking=p,e.isProxy=ue,e.isReactive=_e,e.isReadonly=de,e.isRef=ge,e.markRaw=function(e){return n.def(e,"__v_skip",!0),e},e.pauseTracking=u,e.proxyRefs=function(e){return _e(e)?e:new Proxy(e,fe)},e.reactive=se,e.readonly=le,e.ref=function(e){return Ee(e)},e.resetTracking=m,e.shallowReactive=function(e){return ce(e,!1,w,J,ae)},e.shallowReadonly=function(e){return ce(e,!0,x,te,oe)},e.shallowRef=function(e){return Ee(e,!0)},e.stop=function(e){e.active&&(c(e),e.options.onStop&&e.options.onStop(),e.active=!1)},e.toRaw=pe,e.toRef=be,e.toRefs=function(e){ue(e)||console.warn("toRefs() expects a reactive object but received a plain one.");const t=n.isArray(e)?new Array(e.length):{};for(const n in e)t[n]=be(e,n);return t},e.track=E,e.trigger=S,e.triggerRef=function(e){S(pe(e),"set","value",e.value)},e.unref=Se})),S=p(((e,t)=>{t.exports=E()})),f=!1,b=!1,h=[];function T(e){!function(e){h.includes(e)||h.push(e);b||f||(f=!0,queueMicrotask(v))}(e)}function v(){f=!1,b=!0;for(let e=0;e{(void 0===t||t.includes(n))&&i.forEach((e=>e())),delete e._x_attributeCleanups[n]}))}var A=new MutationObserver(k),D=!1;function w(){A.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),D=!0}var x=[],M=!1;function L(){(x=x.concat(A.takeRecords())).length&&!M&&(M=!0,queueMicrotask((()=>{k(x),x.length=0,M=!1})))}function P(e){if(!D)return e();L(),A.disconnect(),D=!1;let t=e();return w(),t}function k(e){let t=[],n=[],i=new Map,a=new Map;for(let r=0;r1===e.nodeType&&t.push(e))),e[r].removedNodes.forEach((e=>1===e.nodeType&&n.push(e)))),"attributes"===e[r].type)){let t=e[r].target,n=e[r].attributeName,o=e[r].oldValue,s=()=>{i.has(t)||i.set(t,[]),i.get(t).push({name:n,value:t.getAttribute(n)})},l=()=>{a.has(t)||a.set(t,[]),a.get(t).push(n)};t.hasAttribute(n)&&null===o?s():t.hasAttribute(n)?(l(),s()):l()}a.forEach(((e,t)=>{I(t,e)})),i.forEach(((e,t)=>{N.forEach((n=>n(t,e)))}));for(let e of t)n.includes(e)||R.forEach((t=>t(e)));for(let e of n)t.includes(e)||O.forEach((t=>t(e)));t=null,n=null,i=null,a=null}function U(e,t,n){return e._x_dataStack=[t,...B(n||e)],()=>{e._x_dataStack=e._x_dataStack.filter((e=>e!==t))}}function F(e,t){let n=e._x_dataStack[0];Object.entries(t).forEach((([e,t])=>{n[e]=t}))}function B(e){return e._x_dataStack?e._x_dataStack:e instanceof ShadowRoot?B(e.host):e.parentNode?B(e.parentNode):[]}function G(e){return new Proxy({},{ownKeys:()=>Array.from(new Set(e.flatMap((e=>Object.keys(e))))),has:(t,n)=>e.some((e=>e.hasOwnProperty(n))),get:(t,n)=>(e.find((e=>e.hasOwnProperty(n)))||{})[n],set:(t,n,i)=>{let a=e.find((e=>e.hasOwnProperty(n)));return a?a[n]=i:e[e.length-1][n]=i,!0}})}function Y(e){let t=(n,i="")=>{Object.entries(n).forEach((([a,r])=>{let o=""===i?a:`${i}.${a}`;var s;"object"==typeof r&&null!==r&&r._x_interceptor?n[a]=r.initialize(e,o,a):"object"!=typeof(s=r)||Array.isArray(s)||null===s||r===n||r instanceof Element||t(r,o)}))};return t(e)}function H(e,t=(()=>{})){let n={initialValue:void 0,_x_interceptor:!0,initialize(t,n,i){return e(this.initialValue,(()=>function(e,t){return t.split(".").reduce(((e,t)=>e[t]),e)}(t,n)),(e=>V(t,n,e)),n,i)}};return t(n),e=>{if("object"==typeof e&&null!==e&&e._x_interceptor){let t=n.initialize.bind(n);n.initialize=(i,a,r)=>{let o=e.initialize(i,a,r);return n.initialValue=o,t(i,a,r)}}else n.initialValue=e;return n}}function V(e,t,n){if("string"==typeof t&&(t=t.split(".")),1!==t.length){if(0===t.length)throw error;return e[t[0]]||(e[t[0]]={}),V(e[t[0]],t.slice(1),n)}e[t[0]]=n}var q={};function z(e,t){q[e]=t}function $(e,t){return Object.entries(q).forEach((([n,i])=>{Object.defineProperty(e,`$${n}`,{get:()=>i(t,{Alpine:ke,interceptor:H}),enumerable:!1})})),e}function j(e,t,n={}){let i;return W(e,t)((e=>i=e),n),i}function W(...e){return K(...e)}var K=Q;function Q(e,t){let n={};$(n,e);let i=[n,...B(e)];if("function"==typeof t)return function(e,t){return(n=(()=>{}),{scope:i={},params:a=[]}={})=>{Z(n,t.apply(G([i,...e]),a))}}(i,t);let a=function(e,t){let n=function(e){if(X[e])return X[e];let t=Object.getPrototypeOf((async function(){})).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)/.test(e)?`(() => { ${e} })()`:e,i=new t(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`);return X[e]=i,i}(t);return(t=(()=>{}),{scope:i={},params:a=[]}={})=>{n.result=void 0,n.finished=!1;let r=G([i,...e]),o=n(n,r);n.finished?Z(t,n.result,r,a):o.then((e=>{Z(t,e,r,a)}))}}(i,t);return J.bind(null,e,t,a)}var X={};function Z(e,t,n,i){if("function"==typeof t){let a=t.apply(n,i);a instanceof Promise?a.then((t=>Z(e,t,n,i))):e(a)}else e(t)}function J(e,t,n,...i){try{return n(...i)}catch(n){throw console.warn(`Alpine Expression Error: ${n.message}\n\nExpression: "${t}"\n\n`,e),n}}var ee="x-";function te(e=""){return ee+e}var ne={};function ie(e,t){ne[e]=t}function ae(e,t,n){let i={},o=Array.from(t).map((s=(e,t)=>i[e]=t,({name:e,value:t})=>{let{name:n,value:i}=le.reduce(((e,t)=>t(e)),{name:e,value:t});return n!==e&&s(n,e),{name:n,value:i}})).filter(_e).map(function(e,t){return({name:n,value:i})=>{let a=n.match(de()),r=n.match(/:([a-zA-Z0-9\-:]+)/),o=n.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],s=t||e[n]||n;return{type:a?a[1]:null,value:r?r[1]:null,modifiers:o.map((e=>e.replace(".",""))),expression:i,original:s}}}(i,n)).sort(me);var s;return o.map((t=>function(e,t){let n=()=>{},i=ne[t.type]||n,o=[],s=e=>o.push(e),[l,c]=function(e){let t=()=>{};return[n=>{let i=a(n);e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach((e=>e()))}),e._x_effects.add(i),t=()=>{void 0!==i&&(e._x_effects.delete(i),r(i))}},()=>{t()}]}(e);o.push(c);let _={Alpine:ke,effect:l,cleanup:s,evaluateLater:W.bind(W,e),evaluate:j.bind(j,e)},d=()=>o.forEach((e=>e()));!function(e,t,n){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(n)}(e,t.original,d);let u=()=>{e._x_ignore||e._x_ignoreSelf||(i.inline&&i.inline(e,t,_),i=i.bind(i,e,t,_),re?oe.push(i):i())};return u.runCleanups=d,u}(e,t)))}var re=!1,oe=[];var se=(e,t)=>({name:n,value:i})=>(n.startsWith(e)&&(n=n.replace(e,t)),{name:n,value:i});var le=[];function ce(e){le.push(e)}function _e({name:e}){return de().test(e)}var de=()=>new RegExp(`^${ee}([^:^.]+)\\b`);var ue="DEFAULT",pe=["ignore","ref","data","bind","init","for","model","transition","show","if",ue,"element"];function me(e,t){let n=-1===pe.indexOf(e.type)?ue:e.type,i=-1===pe.indexOf(t.type)?ue:t.type;return pe.indexOf(n)-pe.indexOf(i)}function ge(e,t,n={}){e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0,cancelable:!0}))}var Ee=[],Se=!1;function fe(e){Ee.push(e),queueMicrotask((()=>{Se||setTimeout((()=>{be()}))}))}function be(){for(Se=!1;Ee.length;)Ee.shift()()}function he(e,t){if(e instanceof ShadowRoot)return void Array.from(e.children).forEach((e=>he(e,t)));let n=!1;if(t(e,(()=>n=!0)),n)return;let i=e.firstElementChild;for(;i;)he(i,t),i=i.nextElementSibling}function Te(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var ve=[],Ce=[];function ye(){return ve.map((e=>e()))}function Ne(e){ve.push(e)}function Oe(e){return ye().some((t=>e.matches(t)))?e:e.parentElement?Oe(e.parentElement):void 0}function Re(e,t=he){!function(e){re=!0;let t=()=>{for(;oe.length;)oe.shift()()};e(t),re=!1,t()}((()=>{t(e,((e,t)=>{ae(e,e.attributes).forEach((e=>e())),e._x_ignore&&t()}))}))}var Ie={},Ae=!1;var De=!1;function we(e){return(...t)=>De||e(...t)}var xe={};var Me,Le,Pe={get reactive(){return i},get release(){return r},get effect(){return a},get raw(){return o},version:"3.2.2",disableEffectScheduling:function(e){C=!1,e(),C=!0},setReactivityEngine:function(e){i=e.reactive,r=e.release,a=t=>e.effect(t,{scheduler:e=>{C?T(e):e()}}),o=e.raw},addRootSelector:Ne,mapAttributes:ce,evaluateLater:W,setEvaluator:function(e){K=e},closestRoot:Oe,interceptor:H,mutateDom:P,directive:ie,evaluate:j,initTree:Re,nextTick:fe,prefix:function(e){ee=e},plugin:function(e){e(ke)},magic:z,store:function(e,t){if(Ae||(Ie=i(Ie),Ae=!0),void 0===t)return Ie[e];Ie[e]=t,"object"==typeof t&&null!==t&&t.hasOwnProperty("init")&&"function"==typeof t.init&&Ie[e].init()},start:function(){var e;document.body||Te("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `