Upgrade to Vue 3
This commit is contained in:
		
							parent
							
								
									99b88e8943
								
							
						
					
					
						commit
						0dc060dd45
					
				
					 31 changed files with 7831 additions and 23277 deletions
				
			
		|  | @ -11,5 +11,5 @@ trim_trailing_whitespace = true | |||
| [*.md] | ||||
| trim_trailing_whitespace = false | ||||
| 
 | ||||
| [*.{yml,yaml}] | ||||
| [*.{yml,yaml,vue}] | ||||
| indent_size = 2 | ||||
|  |  | |||
|  | @ -15,8 +15,7 @@ | |||
|         "inertiajs/inertia-laravel": "^0.4", | ||||
|         "laravel/framework": "^8.40", | ||||
|         "laravel/tinker": "^2.5", | ||||
|         "league/glide-laravel": "^1.0", | ||||
|         "tightenco/ziggy": "^0.8.0" | ||||
|         "league/glide-laravel": "^1.0" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "facade/ignition": "^2.5", | ||||
|  |  | |||
							
								
								
									
										2154
									
								
								composer.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2154
									
								
								composer.lock
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										22264
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										22264
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										16
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
										
									
									
									
								
							|  | @ -11,23 +11,21 @@ | |||
|         "heroku-postbuild": "npm run prod" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@inertiajs/inertia": "^0.9.2", | ||||
|         "@inertiajs/inertia-vue": "^0.6.2", | ||||
|         "@inertiajs/progress": "^0.2.4", | ||||
|         "@inertiajs/inertia": "^0.10.1", | ||||
|         "@inertiajs/inertia-vue3": "^0.5.2", | ||||
|         "@inertiajs/progress": "^0.2.6", | ||||
|         "@popperjs/core": "^2.11.0", | ||||
|         "autoprefixer": "^10.2.4", | ||||
|         "eslint": "^6.8.0", | ||||
|         "eslint-plugin-vue": "^7.5.0", | ||||
|         "laravel-mix": "^6.0.6", | ||||
|         "lodash": "^4.17.21", | ||||
|         "popper.js": "^1.16.0", | ||||
|         "portal-vue": "^1.5.1", | ||||
|         "postcss": "^8.2.6", | ||||
|         "postcss-import": "^12.0.1", | ||||
|         "postcss-nesting": "^7.0.1", | ||||
|         "tailwindcss": "^2.0.3", | ||||
|         "vue": "^2.6.11", | ||||
|         "vue-loader": "^15.9.6", | ||||
|         "vue-meta": "^2.3.1", | ||||
|         "vue-template-compiler": "^2.6.12" | ||||
|         "uuid": "^8.3.2", | ||||
|         "vue": "^3.2.24", | ||||
|         "vue-loader": "^16.2.0" | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <template> | ||||
|   <Head title="Login" /> | ||||
|   <div class="p-6 bg-indigo-800 min-h-screen flex justify-center items-center"> | ||||
|     <div class="w-full max-w-md"> | ||||
|       <logo class="block mx-auto w-full max-w-xs fill-white" height="50" /> | ||||
|  | @ -22,13 +23,14 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head } from '@inertiajs/inertia-vue3' | ||||
| import Logo from '@/Shared/Logo' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
| import LoadingButton from '@/Shared/LoadingButton' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Login' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     LoadingButton, | ||||
|     Logo, | ||||
|     TextInput, | ||||
|  | @ -44,7 +46,7 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     login() { | ||||
|       this.form.post(this.route('login.store')) | ||||
|       this.form.post('/login') | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Create Contact" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl"> | ||||
|       <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('contacts')">Contacts</inertia-link> | ||||
|       <Link class="text-indigo-400 hover:text-indigo-600" href="/contacts">Contacts</Link> | ||||
|       <span class="text-indigo-400 font-medium">/</span> Create | ||||
|     </h1> | ||||
|     <div class="bg-white rounded-md shadow overflow-hidden max-w-3xl"> | ||||
|  | @ -34,14 +35,16 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
| import SelectInput from '@/Shared/SelectInput' | ||||
| import LoadingButton from '@/Shared/LoadingButton' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Create Contact' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -69,7 +72,7 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     store() { | ||||
|       this.form.post(this.route('contacts.store')) | ||||
|       this.form.post('/contacts') | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <h1 class="mb-8 font-bold text-3xl"> | ||||
|       <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('contacts')">Contacts</inertia-link> | ||||
|       <Link class="text-indigo-400 hover:text-indigo-600" href="/contacts">Contacts</Link> | ||||
|       <span class="text-indigo-400 font-medium">/</span> | ||||
|       {{ form.first_name }} {{ form.last_name }} | ||||
|     </h1> | ||||
|  | @ -39,6 +39,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Link } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
| import SelectInput from '@/Shared/SelectInput' | ||||
|  | @ -52,6 +53,7 @@ export default { | |||
|     } | ||||
|   }, | ||||
|   components: { | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -81,16 +83,16 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     update() { | ||||
|       this.form.put(this.route('contacts.update', this.contact.id)) | ||||
|       this.form.put(`/contacts/${this.contact.id}`) | ||||
|     }, | ||||
|     destroy() { | ||||
|       if (confirm('Are you sure you want to delete this contact?')) { | ||||
|         this.$inertia.delete(this.route('contacts.destroy', this.contact.id)) | ||||
|         this.$inertia.delete(`/contacts/${this.contact.id}`) | ||||
|       } | ||||
|     }, | ||||
|     restore() { | ||||
|       if (confirm('Are you sure you want to restore this contact?')) { | ||||
|         this.$inertia.put(this.route('contacts.restore', this.contact.id)) | ||||
|         this.$inertia.put(`/contacts/${this.contact.id}/restore`) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Contacts" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl">Contacts</h1> | ||||
|     <div class="mb-6 flex justify-between items-center"> | ||||
|       <search-filter v-model="form.search" class="w-full max-w-md mr-4" @reset="reset"> | ||||
|  | @ -10,10 +11,10 @@ | |||
|           <option value="only">Only Trashed</option> | ||||
|         </select> | ||||
|       </search-filter> | ||||
|       <inertia-link class="btn-indigo" :href="route('contacts.create')"> | ||||
|       <Link class="btn-indigo" href="/contacts/create"> | ||||
|         <span>Create</span> | ||||
|         <span class="hidden md:inline">Contact</span> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="bg-white rounded-md shadow overflow-x-auto"> | ||||
|       <table class="w-full whitespace-nowrap"> | ||||
|  | @ -25,32 +26,32 @@ | |||
|         </tr> | ||||
|         <tr v-for="contact in contacts.data" :key="contact.id" class="hover:bg-gray-100 focus-within:bg-gray-100"> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="route('contacts.edit', contact.id)"> | ||||
|             <Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/contacts/${contact.id}/edit`"> | ||||
|               {{ contact.name }} | ||||
|               <icon v-if="contact.deleted_at" name="trash" class="flex-shrink-0 w-3 h-3 fill-gray-400 ml-2" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               <div v-if="contact.organization"> | ||||
|                 {{ contact.organization.name }} | ||||
|               </div> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               {{ contact.city }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               {{ contact.phone }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t w-px"> | ||||
|             <inertia-link class="px-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               <icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr v-if="contacts.data.length === 0"> | ||||
|  | @ -63,6 +64,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| import pickBy from 'lodash/pickBy' | ||||
| import Layout from '@/Shared/Layout' | ||||
|  | @ -72,9 +74,10 @@ import Pagination from '@/Shared/Pagination' | |||
| import SearchFilter from '@/Shared/SearchFilter' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Contacts' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Icon, | ||||
|     Link, | ||||
|     Pagination, | ||||
|     SearchFilter, | ||||
|   }, | ||||
|  | @ -95,7 +98,7 @@ export default { | |||
|     form: { | ||||
|       deep: true, | ||||
|       handler: throttle(function() { | ||||
|         this.$inertia.get(this.route('contacts'), pickBy(this.form), { preserveState: true }) | ||||
|         this.$inertia.get('/contacts', pickBy(this.form), { preserveState: true }) | ||||
|       }, 150), | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,15 +1,19 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Dashboard" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl">Dashboard</h1> | ||||
|     <p class="mb-8 leading-normal">Hey there! Welcome to Ping CRM, a demo app designed to help illustrate how <a class="text-indigo-500 underline hover:text-orange-600" href="https://inertiajs.com">Inertia.js</a> works.</p> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Dashboard' }, | ||||
|   components: { | ||||
|     Head, | ||||
|   }, | ||||
|   layout: Layout, | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Create Organization" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl"> | ||||
|       <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('organizations')">Organizations</inertia-link> | ||||
|       <Link class="text-indigo-400 hover:text-indigo-600" href="/organizations">Organizations</Link> | ||||
|       <span class="text-indigo-400 font-medium">/</span> Create | ||||
|     </h1> | ||||
|     <div class="bg-white rounded-md shadow overflow-hidden max-w-3xl"> | ||||
|  | @ -29,14 +30,16 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
| import SelectInput from '@/Shared/SelectInput' | ||||
| import LoadingButton from '@/Shared/LoadingButton' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Create Organization' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -59,7 +62,7 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     store() { | ||||
|       this.form.post(this.route('organizations.store')) | ||||
|       this.form.post('/organizations') | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head :title="form.name" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl"> | ||||
|       <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('organizations')">Organizations</inertia-link> | ||||
|       <Link class="text-indigo-400 hover:text-indigo-600" href="/organizations">Organizations</Link> | ||||
|       <span class="text-indigo-400 font-medium">/</span> | ||||
|       {{ form.name }} | ||||
|     </h1> | ||||
|  | @ -40,25 +41,25 @@ | |||
|         </tr> | ||||
|         <tr v-for="contact in organization.contacts" :key="contact.id" class="hover:bg-gray-100 focus-within:bg-gray-100"> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="route('contacts.edit', contact.id)"> | ||||
|             <Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/contacts/${contact.id}/edit`"> | ||||
|               {{ contact.name }} | ||||
|               <icon v-if="contact.deleted_at" name="trash" class="flex-shrink-0 w-3 h-3 fill-gray-400 ml-2" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               {{ contact.city }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               {{ contact.phone }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t w-px"> | ||||
|             <inertia-link class="px-4 flex items-center" :href="route('contacts.edit', contact.id)" tabindex="-1"> | ||||
|             <Link class="px-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1"> | ||||
|               <icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr v-if="organization.contacts.length === 0"> | ||||
|  | @ -70,6 +71,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
|  | @ -78,11 +80,10 @@ import LoadingButton from '@/Shared/LoadingButton' | |||
| import TrashedMessage from '@/Shared/TrashedMessage' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo() { | ||||
|     return { title: this.form.name } | ||||
|   }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Icon, | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -109,16 +110,16 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     update() { | ||||
|       this.form.put(this.route('organizations.update', this.organization.id)) | ||||
|       this.form.put(`/organizations/${this.organization.id}`) | ||||
|     }, | ||||
|     destroy() { | ||||
|       if (confirm('Are you sure you want to delete this organization?')) { | ||||
|         this.$inertia.delete(this.route('organizations.destroy', this.organization.id)) | ||||
|         this.$inertia.delete(`/organizations/${this.organization.id}`) | ||||
|       } | ||||
|     }, | ||||
|     restore() { | ||||
|       if (confirm('Are you sure you want to restore this organization?')) { | ||||
|         this.$inertia.put(this.route('organizations.restore', this.organization.id)) | ||||
|         this.$inertia.put(`/organizations/${this.organization.id}/restore`) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Organizations" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl">Organizations</h1> | ||||
|     <div class="mb-6 flex justify-between items-center"> | ||||
|       <search-filter v-model="form.search" class="w-full max-w-md mr-4" @reset="reset"> | ||||
|  | @ -10,10 +11,10 @@ | |||
|           <option value="only">Only Trashed</option> | ||||
|         </select> | ||||
|       </search-filter> | ||||
|       <inertia-link class="btn-indigo" :href="route('organizations.create')"> | ||||
|       <Link class="btn-indigo" href="/organizations/create"> | ||||
|         <span>Create</span> | ||||
|         <span class="hidden md:inline">Organization</span> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="bg-white rounded-md shadow overflow-x-auto"> | ||||
|       <table class="w-full whitespace-nowrap"> | ||||
|  | @ -24,25 +25,25 @@ | |||
|         </tr> | ||||
|         <tr v-for="organization in organizations.data" :key="organization.id" class="hover:bg-gray-100 focus-within:bg-gray-100"> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="route('organizations.edit', organization.id)"> | ||||
|             <Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/organizations/${organization.id}/edit`"> | ||||
|               {{ organization.name }} | ||||
|               <icon v-if="organization.deleted_at" name="trash" class="flex-shrink-0 w-3 h-3 fill-gray-400 ml-2" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('organizations.edit', organization.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/organizations/${organization.id}/edit`" tabindex="-1"> | ||||
|               {{ organization.city }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('organizations.edit', organization.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/organizations/${organization.id}/edit`" tabindex="-1"> | ||||
|               {{ organization.phone }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t w-px"> | ||||
|             <inertia-link class="px-4 flex items-center" :href="route('organizations.edit', organization.id)" tabindex="-1"> | ||||
|             <Link class="px-4 flex items-center" :href="`/organizations/${organization.id}/edit`" tabindex="-1"> | ||||
|               <icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr v-if="organizations.data.length === 0"> | ||||
|  | @ -55,6 +56,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| import pickBy from 'lodash/pickBy' | ||||
| import Layout from '@/Shared/Layout' | ||||
|  | @ -64,9 +66,10 @@ import Pagination from '@/Shared/Pagination' | |||
| import SearchFilter from '@/Shared/SearchFilter' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Organizations' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Icon, | ||||
|     Link, | ||||
|     Pagination, | ||||
|     SearchFilter, | ||||
|   }, | ||||
|  | @ -87,7 +90,7 @@ export default { | |||
|     form: { | ||||
|       deep: true, | ||||
|       handler: throttle(function() { | ||||
|         this.$inertia.get(this.route('organizations'), pickBy(this.form), { preserveState: true }) | ||||
|         this.$inertia.get('/organizations', pickBy(this.form), { preserveState: true }) | ||||
|       }, 150), | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,14 +1,18 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Reports" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl">Reports</h1> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Reports' }, | ||||
|   components: { | ||||
|     Head, | ||||
|   }, | ||||
|   layout: Layout, | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Create User" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl"> | ||||
|       <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('users')">Users</inertia-link> | ||||
|       <Link class="text-indigo-400 hover:text-indigo-600" href="/users">Users</Link> | ||||
|       <span class="text-indigo-400 font-medium">/</span> Create | ||||
|     </h1> | ||||
|     <div class="bg-white rounded-md shadow overflow-hidden max-w-3xl"> | ||||
|  | @ -26,6 +27,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import FileInput from '@/Shared/FileInput' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
|  | @ -33,9 +35,10 @@ import SelectInput from '@/Shared/SelectInput' | |||
| import LoadingButton from '@/Shared/LoadingButton' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Create User' }, | ||||
|   components: { | ||||
|     FileInput, | ||||
|     Head, | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -56,7 +59,7 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     store() { | ||||
|       this.form.post(this.route('users.store')) | ||||
|       this.form.post('/users') | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head :title="`${form.first_name} ${form.last_name}`" /> | ||||
|     <div class="mb-8 flex justify-start max-w-3xl"> | ||||
|       <h1 class="font-bold text-3xl"> | ||||
|         <inertia-link class="text-indigo-400 hover:text-indigo-600" :href="route('users')">Users</inertia-link> | ||||
|         <Link class="text-indigo-400 hover:text-indigo-600" href="/users">Users</Link> | ||||
|         <span class="text-indigo-400 font-medium">/</span> | ||||
|         {{ form.first_name }} {{ form.last_name }} | ||||
|       </h1> | ||||
|  | @ -34,6 +35,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Layout from '@/Shared/Layout' | ||||
| import TextInput from '@/Shared/TextInput' | ||||
| import FileInput from '@/Shared/FileInput' | ||||
|  | @ -42,13 +44,10 @@ import LoadingButton from '@/Shared/LoadingButton' | |||
| import TrashedMessage from '@/Shared/TrashedMessage' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo() { | ||||
|     return { | ||||
|       title: `${this.form.first_name} ${this.form.last_name}`, | ||||
|     } | ||||
|   }, | ||||
|   components: { | ||||
|     FileInput, | ||||
|     Head, | ||||
|     Link, | ||||
|     LoadingButton, | ||||
|     SelectInput, | ||||
|     TextInput, | ||||
|  | @ -74,18 +73,18 @@ export default { | |||
|   }, | ||||
|   methods: { | ||||
|     update() { | ||||
|       this.form.post(this.route('users.update', this.user.id), { | ||||
|       this.form.post(`/users/${this.user.id}`, { | ||||
|         onSuccess: () => this.form.reset('password', 'photo'), | ||||
|       }) | ||||
|     }, | ||||
|     destroy() { | ||||
|       if (confirm('Are you sure you want to delete this user?')) { | ||||
|         this.$inertia.delete(this.route('users.destroy', this.user.id)) | ||||
|         this.$inertia.delete(`/users/${this.user.id}`) | ||||
|       } | ||||
|     }, | ||||
|     restore() { | ||||
|       if (confirm('Are you sure you want to restore this user?')) { | ||||
|         this.$inertia.put(this.route('users.restore', this.user.id)) | ||||
|         this.$inertia.put(`/users/${this.user.id}/restore`) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <Head title="Users" /> | ||||
|     <h1 class="mb-8 font-bold text-3xl">Users</h1> | ||||
|     <div class="mb-6 flex justify-between items-center"> | ||||
|       <search-filter v-model="form.search" class="w-full max-w-md mr-4" @reset="reset"> | ||||
|  | @ -16,10 +17,10 @@ | |||
|           <option value="only">Only Trashed</option> | ||||
|         </select> | ||||
|       </search-filter> | ||||
|       <inertia-link class="btn-indigo" :href="route('users.create')"> | ||||
|       <Link class="btn-indigo" href="/users/create"> | ||||
|         <span>Create</span> | ||||
|         <span class="hidden md:inline">User</span> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="bg-white rounded-md shadow overflow-x-auto"> | ||||
|       <table class="w-full whitespace-nowrap"> | ||||
|  | @ -30,26 +31,26 @@ | |||
|         </tr> | ||||
|         <tr v-for="user in users" :key="user.id" class="hover:bg-gray-100 focus-within:bg-gray-100"> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="route('users.edit', user.id)"> | ||||
|             <Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/users/${user.id}/edit`"> | ||||
|               <img v-if="user.photo" class="block w-5 h-5 rounded-full mr-2 -my-2" :src="user.photo" /> | ||||
|               {{ user.name }} | ||||
|               <icon v-if="user.deleted_at" name="trash" class="flex-shrink-0 w-3 h-3 fill-gray-400 ml-2" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('users.edit', user.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1"> | ||||
|               {{ user.email }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t"> | ||||
|             <inertia-link class="px-6 py-4 flex items-center" :href="route('users.edit', user.id)" tabindex="-1"> | ||||
|             <Link class="px-6 py-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1"> | ||||
|               {{ user.owner ? 'Owner' : 'User' }} | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|           <td class="border-t w-px"> | ||||
|             <inertia-link class="px-4 flex items-center" :href="route('users.edit', user.id)" tabindex="-1"> | ||||
|             <Link class="px-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1"> | ||||
|               <icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr v-if="users.length === 0"> | ||||
|  | @ -61,6 +62,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Head, Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| import pickBy from 'lodash/pickBy' | ||||
| import Layout from '@/Shared/Layout' | ||||
|  | @ -69,9 +71,10 @@ import mapValues from 'lodash/mapValues' | |||
| import SearchFilter from '@/Shared/SearchFilter' | ||||
| 
 | ||||
| export default { | ||||
|   metaInfo: { title: 'Users' }, | ||||
|   components: { | ||||
|     Head, | ||||
|     Icon, | ||||
|     Link, | ||||
|     SearchFilter, | ||||
|   }, | ||||
|   layout: Layout, | ||||
|  | @ -92,7 +95,7 @@ export default { | |||
|     form: { | ||||
|       deep: true, | ||||
|       handler: throttle(function() { | ||||
|         this.$inertia.get(this.route('users'), pickBy(this.form), { preserveState: true }) | ||||
|         this.$inertia.get('/users', pickBy(this.form), { preserveState: true }) | ||||
|       }, 150), | ||||
|     }, | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,19 +1,19 @@ | |||
| <template> | ||||
|   <button type="button" @click="show = true"> | ||||
|     <slot /> | ||||
|     <portal v-if="show" to="dropdown"> | ||||
|     <teleport v-if="show" to="#dropdown"> | ||||
|       <div> | ||||
|         <div style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998; background: black; opacity: .2" @click="show = false" /> | ||||
|         <div ref="dropdown" style="position: absolute; z-index: 99999;" @click.stop="show = autoClose ? false : true"> | ||||
|         <div ref="dropdown" style="position: absolute; z-index: 99999;" @click.stop="show = !autoClose"> | ||||
|           <slot name="dropdown" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </portal> | ||||
|     </teleport> | ||||
|   </button> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import Popper from 'popper.js' | ||||
| import { createPopper } from '@popperjs/core' | ||||
| 
 | ||||
| export default { | ||||
|   props: { | ||||
|  | @ -21,10 +21,6 @@ export default { | |||
|       type: String, | ||||
|       default: 'bottom-end', | ||||
|     }, | ||||
|     boundary: { | ||||
|       type: String, | ||||
|       default: 'scrollParent', | ||||
|     }, | ||||
|     autoClose: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|  | @ -39,11 +35,16 @@ export default { | |||
|     show(show) { | ||||
|       if (show) { | ||||
|         this.$nextTick(() => { | ||||
|           this.popper = new Popper(this.$el, this.$refs.dropdown, { | ||||
|           this.popper = createPopper(this.$el, this.$refs.dropdown, { | ||||
|             placement: this.placement, | ||||
|             modifiers: { | ||||
|               preventOverflow: { boundariesElement: this.boundary }, | ||||
|             }, | ||||
|             modifiers: [ | ||||
|               { | ||||
|                 name: 'preventOverflow', | ||||
|                 options: { | ||||
|                   altBoundary: true, | ||||
|                 }, | ||||
|               }, | ||||
|             ], | ||||
|           }) | ||||
|         }) | ||||
|       } else if (this.popper) { | ||||
|  | @ -53,7 +54,7 @@ export default { | |||
|   }, | ||||
|   mounted() { | ||||
|     document.addEventListener('keydown', e => { | ||||
|       if (e.keyCode === 27) { | ||||
|       if (e.key === 'Escape') { | ||||
|         this.show = false | ||||
|       } | ||||
|     }) | ||||
|  |  | |||
|  | @ -3,14 +3,14 @@ | |||
|     <label v-if="label" class="form-label">{{ label }}:</label> | ||||
|     <div class="form-input p-0" :class="{ error: errors.length }"> | ||||
|       <input ref="file" type="file" :accept="accept" class="hidden" @change="change" /> | ||||
|       <div v-if="!value" class="p-2"> | ||||
|       <div v-if="!modelValue" class="p-2"> | ||||
|         <button type="button" class="px-4 py-1 bg-gray-500 hover:bg-gray-700 rounded-sm text-xs font-medium text-white" @click="browse"> | ||||
|           Browse | ||||
|         </button> | ||||
|       </div> | ||||
|       <div v-else class="flex items-center justify-between p-2"> | ||||
|         <div class="flex-1 pr-1"> | ||||
|           {{ value.name }} <span class="text-gray-500 text-xs">({{ filesize(value.size) }})</span> | ||||
|           {{ modelValue.name }} <span class="text-gray-500 text-xs">({{ filesize(modelValue.size) }})</span> | ||||
|         </div> | ||||
|         <button type="button" class="px-4 py-1 bg-gray-500 hover:bg-gray-700 rounded-sm text-xs font-medium text-white" @click="remove"> | ||||
|           Remove | ||||
|  | @ -24,7 +24,7 @@ | |||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: File, | ||||
|     modelValue: File, | ||||
|     label: String, | ||||
|     accept: String, | ||||
|     errors: { | ||||
|  | @ -33,7 +33,7 @@ export default { | |||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     value(value) { | ||||
|     modelValue(value) { | ||||
|       if (!value) { | ||||
|         this.$refs.file.value = '' | ||||
|       } | ||||
|  | @ -48,10 +48,10 @@ export default { | |||
|       this.$refs.file.click() | ||||
|     }, | ||||
|     change(e) { | ||||
|       this.$emit('input', e.target.files[0]) | ||||
|       this.$emit('update:modelValue', e.target.files[0]) | ||||
|     }, | ||||
|     remove() { | ||||
|       this.$emit('input', null) | ||||
|       this.$emit('update:modelValue', null) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|  |  | |||
|  | @ -1,35 +1,43 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <portal-target name="dropdown" slim /> | ||||
|     <div id="dropdown" /> | ||||
|     <div class="md:flex md:flex-col"> | ||||
|       <div class="md:h-screen md:flex md:flex-col"> | ||||
|         <div class="md:flex md:flex-shrink-0"> | ||||
|           <div class="bg-indigo-900 md:flex-shrink-0 md:w-56 px-6 py-4 flex items-center justify-between md:justify-center"> | ||||
|             <inertia-link class="mt-1" href="/"> | ||||
|             <Link class="mt-1" href="/"> | ||||
|               <logo class="fill-white" width="120" height="28" /> | ||||
|             </inertia-link> | ||||
|             </Link> | ||||
|             <dropdown class="md:hidden" placement="bottom-end"> | ||||
|               <svg class="fill-white w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" /></svg> | ||||
|               <div slot="dropdown" class="mt-2 px-8 py-4 shadow-lg bg-indigo-800 rounded"> | ||||
|                 <main-menu /> | ||||
|               </div> | ||||
|               <template #default> | ||||
|                 <svg class="fill-white w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" /></svg> | ||||
|               </template> | ||||
|               <template #dropdown> | ||||
|                 <div class="mt-2 px-8 py-4 shadow-lg bg-indigo-800 rounded"> | ||||
|                   <main-menu /> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </dropdown> | ||||
|           </div> | ||||
|           <div class="bg-white border-b w-full p-4 md:py-0 md:px-12 text-sm md:text-md flex justify-between items-center"> | ||||
|             <div class="mt-1 mr-4">{{ $page.props.auth.user.account.name }}</div> | ||||
|             <div class="mt-1 mr-4">{{ auth.user.account.name }}</div> | ||||
|             <dropdown class="mt-1" placement="bottom-end"> | ||||
|               <div class="flex items-center cursor-pointer select-none group"> | ||||
|                 <div class="text-gray-700 group-hover:text-indigo-600 focus:text-indigo-600 mr-1 whitespace-nowrap"> | ||||
|                   <span>{{ $page.props.auth.user.first_name }}</span> | ||||
|                   <span class="hidden md:inline">{{ $page.props.auth.user.last_name }}</span> | ||||
|               <template #default> | ||||
|                 <div class="flex items-center cursor-pointer select-none group"> | ||||
|                   <div class="text-gray-700 group-hover:text-indigo-600 focus:text-indigo-600 mr-1 whitespace-nowrap"> | ||||
|                     <span>{{ auth.user.first_name }}</span> | ||||
|                     <span class="hidden md:inline">{{ auth.user.last_name }}</span> | ||||
|                   </div> | ||||
|                   <icon class="w-5 h-5 group-hover:fill-indigo-600 fill-gray-700 focus:fill-indigo-600" name="cheveron-down" /> | ||||
|                 </div> | ||||
|                 <icon class="w-5 h-5 group-hover:fill-indigo-600 fill-gray-700 focus:fill-indigo-600" name="cheveron-down" /> | ||||
|               </div> | ||||
|               <div slot="dropdown" class="mt-2 py-2 shadow-xl bg-white rounded text-sm"> | ||||
|                 <inertia-link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white" :href="route('users.edit', $page.props.auth.user.id)">My Profile</inertia-link> | ||||
|                 <inertia-link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white" :href="route('users')">Manage Users</inertia-link> | ||||
|                 <inertia-link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white w-full text-left" :href="route('logout')" method="delete" as="button">Logout</inertia-link> | ||||
|               </div> | ||||
|               </template> | ||||
|               <template #dropdown> | ||||
|                 <div class="mt-2 py-2 shadow-xl bg-white rounded text-sm"> | ||||
|                   <Link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white" :href="`/users/${auth.user.id}/edit`">My Profile</Link> | ||||
|                   <Link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white" href="/users">Manage Users</Link> | ||||
|                   <Link class="block px-6 py-2 hover:bg-indigo-500 hover:text-white w-full text-left" href="/logout" method="delete" as="button">Logout</Link> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </dropdown> | ||||
|           </div> | ||||
|         </div> | ||||
|  | @ -46,6 +54,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| import Logo from '@/Shared/Logo' | ||||
| import Dropdown from '@/Shared/Dropdown' | ||||
|  | @ -57,8 +66,12 @@ export default { | |||
|     Dropdown, | ||||
|     FlashMessages, | ||||
|     Icon, | ||||
|     Link, | ||||
|     Logo, | ||||
|     MainMenu, | ||||
|   }, | ||||
|   props: { | ||||
|     auth: Object, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -1,38 +1,40 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <div class="mb-4"> | ||||
|       <inertia-link class="flex items-center group py-3" :href="route('dashboard')"> | ||||
|       <Link class="flex items-center group py-3" href="/"> | ||||
|         <icon name="dashboard" class="w-4 h-4 mr-2" :class="isUrl('') ? 'fill-white' : 'fill-indigo-400 group-hover:fill-white'" /> | ||||
|         <div :class="isUrl('') ? 'text-white' : 'text-indigo-300 group-hover:text-white'">Dashboard</div> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="mb-4"> | ||||
|       <inertia-link class="flex items-center group py-3" :href="route('organizations')"> | ||||
|       <Link class="flex items-center group py-3" href="/organizations"> | ||||
|         <icon name="office" class="w-4 h-4 mr-2" :class="isUrl('organizations') ? 'fill-white' : 'fill-indigo-400 group-hover:fill-white'" /> | ||||
|         <div :class="isUrl('organizations') ? 'text-white' : 'text-indigo-300 group-hover:text-white'">Organizations</div> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="mb-4"> | ||||
|       <inertia-link class="flex items-center group py-3" :href="route('contacts')"> | ||||
|       <Link class="flex items-center group py-3" href="/contacts"> | ||||
|         <icon name="users" class="w-4 h-4 mr-2" :class="isUrl('contacts') ? 'fill-white' : 'fill-indigo-400 group-hover:fill-white'" /> | ||||
|         <div :class="isUrl('contacts') ? 'text-white' : 'text-indigo-300 group-hover:text-white'">Contacts</div> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|     <div class="mb-4"> | ||||
|       <inertia-link class="flex items-center group py-3" :href="route('reports')"> | ||||
|       <Link class="flex items-center group py-3" href="/reports"> | ||||
|         <icon name="printer" class="w-4 h-4 mr-2" :class="isUrl('reports') ? 'fill-white' : 'fill-indigo-400 group-hover:fill-white'" /> | ||||
|         <div :class="isUrl('reports') ? 'text-white' : 'text-indigo-300 group-hover:text-white'">Reports</div> | ||||
|       </inertia-link> | ||||
|       </Link> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Link } from '@inertiajs/inertia-vue3' | ||||
| import Icon from '@/Shared/Icon' | ||||
| 
 | ||||
| export default { | ||||
|   components: { | ||||
|     Icon, | ||||
|     Link, | ||||
|   }, | ||||
|   methods: { | ||||
|     isUrl(...urls) { | ||||
|  |  | |||
|  | @ -3,14 +3,19 @@ | |||
|     <div class="flex flex-wrap -mb-1"> | ||||
|       <template v-for="(link, key) in links"> | ||||
|         <div v-if="link.url === null" :key="key" class="mr-1 mb-1 px-4 py-3 text-sm leading-4 text-gray-400 border rounded" v-html="link.label" /> | ||||
|         <inertia-link v-else :key="key" class="mr-1 mb-1 px-4 py-3 text-sm leading-4 border rounded hover:bg-white focus:border-indigo-500 focus:text-indigo-500" :class="{ 'bg-white': link.active }" :href="link.url" v-html="link.label" /> | ||||
|         <Link v-else :key="`link-${key}`" class="mr-1 mb-1 px-4 py-3 text-sm leading-4 border rounded hover:bg-white focus:border-indigo-500 focus:text-indigo-500" :class="{ 'bg-white': link.active }" :href="link.url" v-html="link.label" /> | ||||
|       </template> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { Link } from '@inertiajs/inertia-vue3' | ||||
| 
 | ||||
| export default { | ||||
|   components: { | ||||
|     Link, | ||||
|   }, | ||||
|   props: { | ||||
|     links: Array, | ||||
|   }, | ||||
|  |  | |||
|  | @ -2,17 +2,21 @@ | |||
|   <div class="flex items-center"> | ||||
|     <div class="flex w-full bg-white shadow rounded"> | ||||
|       <dropdown :auto-close="false" class="px-4 md:px-6 rounded-l border-r hover:bg-gray-100 focus:border-white focus:ring focus:z-10" placement="bottom-start"> | ||||
|         <div class="flex items-baseline"> | ||||
|           <span class="text-gray-700 hidden md:inline">Filter</span> | ||||
|           <svg class="w-2 h-2 fill-gray-700 md:ml-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 961.243 599.998"> | ||||
|             <path d="M239.998 239.999L0 0h961.243L721.246 240c-131.999 132-240.28 240-240.624 239.999-.345-.001-108.625-108.001-240.624-240z" /> | ||||
|           </svg> | ||||
|         </div> | ||||
|         <div slot="dropdown" class="mt-2 px-4 py-6 w-screen shadow-xl bg-white rounded" :style="{ maxWidth: `${maxWidth}px` }"> | ||||
|           <slot /> | ||||
|         </div> | ||||
|         <template #default> | ||||
|           <div class="flex items-baseline"> | ||||
|             <span class="text-gray-700 hidden md:inline">Filter</span> | ||||
|             <svg class="w-2 h-2 fill-gray-700 md:ml-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 961.243 599.998"> | ||||
|               <path d="M239.998 239.999L0 0h961.243L721.246 240c-131.999 132-240.28 240-240.624 239.999-.345-.001-108.625-108.001-240.624-240z" /> | ||||
|             </svg> | ||||
|           </div> | ||||
|         </template> | ||||
|         <template #dropdown> | ||||
|           <div class="mt-2 px-4 py-6 w-screen shadow-xl bg-white rounded" :style="{ maxWidth: `${maxWidth}px` }"> | ||||
|             <slot /> | ||||
|           </div> | ||||
|         </template> | ||||
|       </dropdown> | ||||
|       <input class="relative w-full px-6 py-3 rounded-r focus:ring" autocomplete="off" type="text" name="search" placeholder="Search…" :value="value" @input="$emit('input', $event.target.value)" /> | ||||
|       <input class="relative w-full px-6 py-3 rounded-r focus:ring" autocomplete="off" type="text" name="search" placeholder="Search…" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> | ||||
|     </div> | ||||
|     <button class="ml-3 text-sm text-gray-500 hover:text-gray-700 focus:text-indigo-500" type="button" @click="$emit('reset')">Reset</button> | ||||
|   </div> | ||||
|  | @ -26,7 +30,7 @@ export default { | |||
|     Dropdown, | ||||
|   }, | ||||
|   props: { | ||||
|     value: String, | ||||
|     modelValue: String, | ||||
|     maxWidth: { | ||||
|       type: Number, | ||||
|       default: 300, | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
|   <div> | ||||
|   <div :class="$class"> | ||||
|     <label v-if="label" class="form-label" :for="id">{{ label }}:</label> | ||||
|     <select :id="id" ref="input" v-model="selected" v-bind="$attrs" class="form-select" :class="{ error: error }"> | ||||
|       <slot /> | ||||
|  | @ -9,27 +9,35 @@ | |||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { v4 as uuid } from 'uuid' | ||||
| 
 | ||||
| export default { | ||||
|   inheritAttrs: false, | ||||
|   props: { | ||||
|     id: { | ||||
|       type: String, | ||||
|       default() { | ||||
|         return `select-input-${this._uid}` | ||||
|         return `select-input-${uuid()}` | ||||
|       }, | ||||
|     }, | ||||
|     value: [String, Number, Boolean], | ||||
|     label: String, | ||||
|     class: String, | ||||
|     error: String, | ||||
|     label: String, | ||||
|     modelValue: [String, Number, Boolean], | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       selected: this.value, | ||||
|       selected: this.modelValue, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     $class() { | ||||
|       return this.class | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     selected(selected) { | ||||
|       this.$emit('input', selected) | ||||
|       this.$emit('update:modelValue', selected) | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|  |  | |||
|  | @ -1,28 +1,36 @@ | |||
| <template> | ||||
|   <div> | ||||
|   <div :class="$class"> | ||||
|     <label v-if="label" class="form-label" :for="id">{{ label }}:</label> | ||||
|     <input :id="id" ref="input" v-bind="$attrs" class="form-input" :class="{ error: error }" :type="type" :value="value" @input="$emit('input', $event.target.value)" /> | ||||
|     <input :id="id" ref="input" v-bind="$attrs" class="form-input" :class="{ error: error }" :type="type" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> | ||||
|     <div v-if="error" class="form-error">{{ error }}</div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { v4 as uuid } from 'uuid' | ||||
| 
 | ||||
| export default { | ||||
|   inheritAttrs: false, | ||||
|   props: { | ||||
|     id: { | ||||
|       type: String, | ||||
|       default() { | ||||
|         return `text-input-${this._uid}` | ||||
|         return `text-input-${uuid()}` | ||||
|       }, | ||||
|     }, | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|     }, | ||||
|     value: String, | ||||
|     label: String, | ||||
|     class: String, | ||||
|     error: String, | ||||
|     label: String, | ||||
|     modelValue: String, | ||||
|   }, | ||||
|   computed: { | ||||
|     $class() { | ||||
|       return this.class | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     focus() { | ||||
|  |  | |||
|  | @ -1,24 +1,32 @@ | |||
| <template> | ||||
|   <div> | ||||
|   <div :class="$class"> | ||||
|     <label v-if="label" class="form-label" :for="id">{{ label }}:</label> | ||||
|     <textarea :id="id" ref="input" v-bind="$attrs" class="form-textarea" :class="{ error: error }" :value="value" @input="$emit('input', $event.target.value)" /> | ||||
|     <textarea :id="id" ref="input" v-bind="$attrs" class="form-textarea" :class="{ error: error }" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> | ||||
|     <div v-if="error" class="form-error">{{ error }}</div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { v4 as uuid } from 'uuid' | ||||
| 
 | ||||
| export default { | ||||
|   inheritAttrs: false, | ||||
|   props: { | ||||
|     id: { | ||||
|       type: String, | ||||
|       default() { | ||||
|         return `textarea-input-${this._uid}` | ||||
|         return `textarea-input-${uuid()}` | ||||
|       }, | ||||
|     }, | ||||
|     value: String, | ||||
|     label: String, | ||||
|     class: String, | ||||
|     error: String, | ||||
|     label: String, | ||||
|     modelValue: String, | ||||
|   }, | ||||
|   computed: { | ||||
|     $class() { | ||||
|       return this.class | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     focus() { | ||||
|  |  | |||
							
								
								
									
										25
									
								
								resources/js/app.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								resources/js/app.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,24 +1,17 @@ | |||
| import Vue from 'vue' | ||||
| import VueMeta from 'vue-meta' | ||||
| import PortalVue from 'portal-vue' | ||||
| import { createApp, h } from 'vue' | ||||
| import { InertiaProgress } from '@inertiajs/progress' | ||||
| import { createInertiaApp } from '@inertiajs/inertia-vue' | ||||
| 
 | ||||
| Vue.config.productionTip = false | ||||
| Vue.mixin({ methods: { route: window.route } }) | ||||
| Vue.use(PortalVue) | ||||
| Vue.use(VueMeta) | ||||
| import { createInertiaApp } from '@inertiajs/inertia-vue3' | ||||
| 
 | ||||
| InertiaProgress.init() | ||||
| 
 | ||||
| createInertiaApp({ | ||||
|   resolve: name => require(`./Pages/${name}`), | ||||
|   setup({ el, app, props }) { | ||||
|     new Vue({ | ||||
|       metaInfo: { | ||||
|         titleTemplate: title => (title ? `${title} - Ping CRM` : 'Ping CRM'), | ||||
|       }, | ||||
|       render: h => h(app, props), | ||||
|     }).$mount(el) | ||||
|   title: title => `${title} - Ping CRM`, | ||||
|   setup({ el, App, props, plugin }) { | ||||
|     createApp({ | ||||
|       render: () => h(App, props), | ||||
|     }) | ||||
|       .use(plugin) | ||||
|       .mount(el) | ||||
|   }, | ||||
| }) | ||||
|  |  | |||
|  | @ -13,11 +13,8 @@ | |||
|     <script src="https://polyfill.io/v3/polyfill.min.js?features=String.prototype.startsWith" defer></script> | ||||
| 
 | ||||
|     <script src="{{ mix('/js/app.js') }}" defer></script> | ||||
|     @routes | ||||
| </head> | ||||
| <body class="font-sans leading-none text-gray-700 antialiased"> | ||||
| 
 | ||||
| @inertia | ||||
| 
 | ||||
|     @inertia | ||||
| </body> | ||||
| </html> | ||||
|  |  | |||
							
								
								
									
										15
									
								
								webpack.config.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								webpack.config.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| const path = require('path') | ||||
| 
 | ||||
| // https://stefanbauer.me/tips-and-tricks/autocompletion-for-webpack-path-aliases-in-phpstorm-when-using-laravel-mix
 | ||||
| module.exports = { | ||||
|   output: { chunkFilename: 'js/[name].js?id=[chunkhash]' }, | ||||
|   resolve: { | ||||
|     alias: { | ||||
|       '@': path.resolve('./resources/js'), | ||||
|     }, | ||||
|     extensions: ['.js', '.vue', '.json'], | ||||
|   }, | ||||
|   devServer: { | ||||
|     allowedHosts: 'all', | ||||
|   }, | ||||
| } | ||||
							
								
								
									
										6
									
								
								webpack.mix.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								webpack.mix.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,7 +1,9 @@ | |||
| const path = require('path') | ||||
| const process = require('process') | ||||
| const mix = require('laravel-mix') | ||||
| const cssImport = require('postcss-import') | ||||
| const cssNesting = require('postcss-nesting') | ||||
| const webpackConfig = require('./webpack.config') | ||||
| 
 | ||||
| /* | ||||
|  |-------------------------------------------------------------------------- | ||||
|  | @ -16,8 +18,8 @@ const cssNesting = require('postcss-nesting') | |||
| 
 | ||||
| mix | ||||
|   .js('resources/js/app.js', 'public/js') | ||||
|   .vue({ runtimeOnly: true }) | ||||
|   .alias({ '@': 'resources/js' }) | ||||
|   .vue({ runtimeOnly: (process.env.NODE_ENV || 'production') === 'production' }) | ||||
|   .webpackConfig(webpackConfig) | ||||
|   .postCss('resources/css/app.css', 'public/css', [ | ||||
|     // prettier-ignore
 | ||||
|     cssImport(), | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Claudio Dekker
						Claudio Dekker